WinForms 全局热键输入干扰

问题描述

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

这个程序只寻找密钥*:w,a,s,d


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


这是我的表单类:

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);
    }
}

以及它用来注册密钥的类:

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,key);
    }

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

我会接受所有建议/答案。谢谢!


更新 1

我可以使用 Jimi 建议的 GetAsyncKeyState()。虽然这不会干扰在其他窗口中输入,但它不会更新我的应用程序窗口,直到它重新成为焦点。

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);
        }
    }

解决方法

解决方案

Jimithis 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;