How to detect CTRL+keypress shortcut at any time in C#

时间:2018-03-31 07:36:09

标签: c# forms keyboard-shortcuts

In a C# Windows Form I would like transcode information: when user press CTRL+I, the app detect the key press combination, it takes the code in the clipboard and transcode it.

I find out this code:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        switch (msg.Msg)
        {
            case 0x100:
            case 0x104:
                switch (keyData)
                {
                    case Keys.Control | Keys.I:
                        MessageBox.Show("Ctrl + I pressed");
                        break;
                }
                break;
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }

This works fine when windows form has focus.

I would like detect the combination when the app is minimized as tray icon.

SOLUTION:

keyboardhook.cs:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TrayIconForm
{
    public static class Constants
    {
    public const int NOMOD = 0x0000;
    public const int ALT = 0x0001;
    public const int CTRL = 0x0002;
    public const int SHIFT = 0x0004;
    public const int WIN = 0x0008;

    public const int WM_HOTKEY_MSG_ID = 0x0312;
    }
public class KeyHandler
{
    [DllImport("user32.dll")]
    private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
    [DllImport("user32.dll")]
    private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

    private int modifier;
    private int key;
    private IntPtr hWnd;
    private int id;
    public KeyHandler(int modifier, Keys key, Form form)
    {
        this.modifier = modifier;
        this.key = (int)key;
        this.hWnd = form.Handle;
        id = this.GetHashCode();
    }
    public override int GetHashCode()
    {
        return modifier ^ key ^ hWnd.ToInt32();
    }
    public bool Register()
    {
        return RegisterHotKey(hWnd, id, modifier, key);
    }
    public bool Unregiser()
    {
        return UnregisterHotKey(hWnd, id);
    }
}
}

Information.cs (Form):

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TrayIconForm
{
public partial class Information : Form
{
    private KeyHandler ghk;

    public Information()
    {
        InitializeComponent();

        ghk = new KeyHandler(Constants.CTRL, Keys.I, this);
        ghk.Register();

    }
    private void HandleHotkey()
    {
        string s = Get_Copy();

        notifyIcon1.BalloonTipText = s;
        notifyIcon1.BalloonTipTitle = "You have pressed CTRL+i";
        notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;

        notifyIcon1.Visible = true;
        notifyIcon1.ShowBalloonTip(500);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
            HandleHotkey();
        base.WndProc(ref m);
    }

    private string Get_Copy()
    {
        string r;
        // Retrieves data from Clipboard
        IDataObject iData = Clipboard.GetDataObject();
        // Is Data Text?
        if (iData.GetDataPresent(DataFormats.Text))
            r = (String)iData.GetData(DataFormats.Text);
        else
            r = "nothing";
        return r;
    }
    private void Information_Resize(object sender, EventArgs e)
    {
        if (FormWindowState.Minimized == this.WindowState)
        {
            notifyIcon1.BalloonTipText =  "My application still working...";
            notifyIcon1.BalloonTipTitle = "My Sample Application";
            notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;

            notifyIcon1.Visible = true;
            notifyIcon1.ShowBalloonTip(500);
            this.Hide();
        }
        else if (FormWindowState.Normal == this.WindowState)
        {
            notifyIcon1.Visible = false;
        }
    }
}
}

2 个答案:

答案 0 :(得分:0)

这只是实例化它,对事件进行子视图并且你已经完成了。这不是我的剧本。不久之前我搜索了很久但是我找到了它并且效果很好。如果按下的键(存储在事件args中)是你的键,那么你订阅了你可以查看的事件,当你按下控件时你可以用Keyboard.iskeydown(key.lctrl)查看然后你可以做组合应该做什么。

using System; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Windows.Input;

namespace <yournamespace>
{
    public class LowLevelKeyboardListener
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        public event EventHandler<KeyPressedArgs> OnKeyPressed;

        private LowLevelKeyboardProc _proc;
        private IntPtr _hookID = IntPtr.Zero;

        public LowLevelKeyboardListener()
        {
            _proc = HookCallback;
        }

        public void HookKeyboard()
        {
            _hookID = SetHook(_proc);
        }

        public void UnHookKeyboard()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);

                if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode))); }
            }

            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    }

    public class KeyPressedArgs : EventArgs
    {
        public Key KeyPressed { get; private set; }

        public KeyPressedArgs(Key key)
        {
            KeyPressed = key;
        }
    }
}

答案 1 :(得分:0)

[DllImport("user32.dll")]
    public static extern int GetAsyncKeyState(Keys vKeys);

然后

var ctrl = GetAsyncKeyState(Keys.ControlKey) & 0x8000;
var key = GetAsyncKeyState(Keys.F10) & 0x8000; //F10 for example
if(ctrl != 0 && key != 0)
{
    //do sth
}