C# 如何在未聚焦时检测 keyPress?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18291448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:50:05  来源:igfitidea点击:

How do I detect keyPress while not focused?

c#formskeypress

提问by James Holland

I am trying to detect the Print Screenbutton press while the form is not the current active application.

Print Screen当表单不是当前活动的应用程序时,我试图检测按钮按下。

How to do that, if possible?

如果可能,该怎么做?

采纳答案by Arash

Yes you can, it's called "System hooks", take a look at Global System Hooks in .NET.

是的,你可以,它被称为“系统钩子”,看看.NET 中的全局系统钩子

回答by Przemys?aw Kalita

Well, if you had problems with System hooks, here is ready-made solution (based on http://www.dreamincode.net/forums/topic/180436-global-hotkeys/):

好吧,如果您遇到 System hooks 的问题,这里是现成的解决方案(基于http://www.dreamincode.net/forums/topic/180436-global-hotkeys/):

Define static class in your project:

在您的项目中定义静态类:

public static class Constants
{
    //windows message id for hotkey
    public const int WM_HOTKEY_MSG_ID = 0x0312;
}

Define class in your project:

在您的项目中定义类:

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

add usings:

添加用途:

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

now, in your Form, add field:

现在,在您的表单中,添加字段:

private KeyHandler ghk;

and in Form constructor:

并在表单构造函数中:

ghk = new KeyHandler(Keys.PrintScreen, this);
ghk.Register();

Add those 2 methods to your form:

将这 2 个方法添加到您的表单中:

private void HandleHotkey()
{
        // Do stuff...
}

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

HandleHotkey is your button press handler. You can change the button by passing different parameter here: ghk = new KeyHandler(Keys.PrintScreen, this);

HandleHotkey 是您的按钮按下处理程序。您可以通过在此处传递不同的参数来更改按钮:ghk = new KeyHandler(Keys.PrintScreen, this);

Now your program reacts for buton input even if not focused.

现在,即使没有聚焦,您的程序也会对按钮输入做出反应。

回答by Nicholas Miller

The API GetAsyncKeyState()may be a perfectly acceptable alternative to setting up Windows Hook.

APIGetAsyncKeyState()可能是设置 Windows Hook 的完全可接受的替代方法。

This depends on how you desire to receive the input. If you prefer event-driven notifications, then a hook is the way to go; however, if you prefer pollingthe keyboard for state changes, you can use the API above.

这取决于您希望如何接收输入。如果你更喜欢事件驱动的通知,那么钩子就是你要走的路;但是,如果您更喜欢轮询键盘状态更改,则可以使用上面的 API。

Here is a simple demonstration of how to use GetAsyncKeyState:
Derived from Pinvoke.NET

以下是如何使用的简单演示GetAsyncKeyState
派生自Pinvoke.NET

[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(int vKey);

private static readonly int VK_SNAPSHOT = 0x2C; //This is the print-screen key.

//Assume the timer is setup with Interval = 16 (corresponds to ~60FPS).
private System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();

private void timer1_Tick(object sender, EventArgs e)
{
    short keyState = GetAsyncKeyState(VK_SNAPSHOT);

    //Check if the MSB is set. If so, then the key is pressed.
    bool prntScrnIsPressed = ((keyState >> 15) & 0x0001) == 0x0001;

    //Check if the LSB is set. If so, then the key was pressed since
    //the last call to GetAsyncKeyState
    bool unprocessedPress = ((keyState >> 0)  & 0x0001) == 0x0001;

    if (prntScrnIsPressed)
    {
        //TODO Execute client code...
    }

    if (unprocessedPress)
    {
        //TODO Execute client code...
    }
}