如何在没有聚焦的情况下检测keyPress?

时间:2013-08-17 17:20:25

标签: c# forms keypress

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

如果可能,如何做到这一点?

3 个答案:

答案 0 :(得分:18)

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

在项目中定义静态类:

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

添加使用:

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

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

private KeyHandler ghk;

并在Form构造函数中:

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

将这两种方法添加到表单中:

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是您的按钮处理程序。您可以在此处传递不同的参数来更改按钮:ghk = new KeyHandler(Keys.PrintScreen, this);

现在你的程序即使没有集中注意力也会对输入作出反应。

答案 1 :(得分:11)

是的,你可以,它被称为“系统挂钩”,看看Global System Hooks in .NET

答案 2 :(得分:0)

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

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

以下是如何使用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...
    }
}