1

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

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


w, a, s, 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, 0, 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);
        }
    }
4

1 回答 1

2

解决方案

Jimi这个堆栈溢出表单的帮助下,我能够解决我遇到的问题。

通过使用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;
于 2021-01-23T22:34:47.843 回答