WinForms 全局热键输入干扰

WinForms Global Hotkey Typing Interference

我正在尝试让这个键盘挂钩在按下时将注册的键回显到标签。我的目标是在 Window 失焦时执行此操作。

This program is only looking for the keys*: w, a, s, d


我遇到的问题 运行 是我无法在任何其他程序(例如:记事本)中键入字母 w, a, s, d,而此程序是 运行。


这是我的表格 class:

Form1.cs:

public partial class Form1 : Form
{
    private KeyHandler _keyHandler;
    private List<Keys> keys = new List<Keys>() { Keys.W, Keys.A, Keys.S, Keys.D };

    public Form1()
    {
        InitializeComponent();

        foreach (var key in keys) (_keyHandler = new KeyHandler(key, this)).Register();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        label1.Text = e.KeyCode.ToString();
    }
    
    // Key Logger =======================
    private void HandleHotkey(int keyPress)
    {
        if (keyPress == 5701632)
            label1.Text = "W pressed";
        else if (keyPress == 4259840)
            label1.Text = "A pressed";
        else if (keyPress == 5439488)
            label1.Text = "S pressed";
        else if (keyPress == 4456448)
            label1.Text = "D pressed";
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Constants.WM_HOTKEY_MSG_ID)
            HandleHotkey(m.LParam.ToInt32());
        base.WndProc(ref m);
    }
}

和它用来注册密钥的class:

KeyHandler.cs:

public static class Constants
{
    //windows message id for hotkey
    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 key;
    private IntPtr hWnd;
    private int id;

    public KeyHandler(Keys key, Form form)
    {
        this.key = (int)key;
        this.hWnd = form.Handle;
        id = this.GetHashCode();
    }

    public override int GetHashCode()
    {
        return key ^ hWnd.ToInt32();
    }

    public bool Register()
    {
        return RegisterHotKey(hWnd, id, 0, key);
    }

    public bool Unregiser()
    {
        return UnregisterHotKey(hWnd, id);
    }
}

我要全部suggestions/answers。谢谢!


更新 1

我能够使用 Jimi 建议的 GetAsyncKeyState()。虽然这不会干扰输入其他 windows,但它不会更新我的应用程序 window,直到它重新聚焦。

Form1.cs

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void HandleHotkey(Keys key)
        {
            label1.Text = key.ToString() + " done";
        }

        protected override void WndProc(ref Message m)
        {
            KeyState keyState = new KeyState();
            if (keyState.GetKeyState(Keys.W) == 1) HandleHotkey(Keys.W);

            base.WndProc(ref m);
        }
    }

KeyState.cs

    public class KeyState
    {
        [DllImport("user32.dll")]
        public static extern short GetAsyncKeyState(Keys key);

        public int GetKeyState(Keys key)
        {
            return GetAsyncKeyState(key);
        }
    }

解决方案

Jimi and this stack overflow form的帮助下,我解决了我遇到的问题。

通过使用方法 GetAsyncKeyState() 和计时器,我能够不断地检查 w, a, s, d 键是否被按下。


Form1.cs

    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        public static extern short GetAsyncKeyState(Keys key);

        public Form1()
        {
            InitializeComponent();
            StartTimer(timer1_Tick);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (GetAsyncKeyState(Keys.W) <= -32767) label1.Text = Keys.W + " special";
            else if (GetAsyncKeyState(Keys.A) <= -32767) label1.Text = Keys.A + " special";
            else if (GetAsyncKeyState(Keys.S) <= -32767) label1.Text = Keys.S + " special";
            else if (GetAsyncKeyState(Keys.D) <= -32767) label1.Text = Keys.D + " special";

            else label1.Text = "Nothing Pressed";
        }

        private void StartTimer(EventHandler eventHandler)
        {
            timer1.Tick += new EventHandler(eventHandler);
            timer1.Interval = 35;
            timer1.Start();
        }
    }

将此添加到 Form1.Designer.cs

public System.Windows.Forms.Timer timer1;