How do I detect keyPress while not focused?

47,863

Solution 1

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

Solution 2

Well, if you had problems with System hooks, here is ready-made solution (based on 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:

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

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

Solution 3

The API GetAsyncKeyState() may be a perfectly acceptable alternative to setting up 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 polling the keyboard for state changes, you can use the API above.

Here is a simple demonstration of how to use GetAsyncKeyState:
Derived from 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...
    }
}
Share:
47,863

Related videos on Youtube

James Holland
Author by

James Holland

Updated on April 21, 2020

Comments

  • James Holland
    James Holland about 4 years

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

    How to do that, if possible?

  • user1696947
    user1696947 almost 9 years
    How to edit this code, if i wanted 2 different hotkeys with two different functionality? Can i check somehow in "WndProc" or "HandleHotkey" which key was pressed?
  • Hue Man
    Hue Man about 7 years
    Could this be adapted to handle key combinations? Such as CTRL-N
  • Michael
    Michael about 6 years
    shouldn't the if (prntScrnIs-->p<--ressed) be if (prntScrnIs-->P<--ressed)?
  • Gaspa79
    Gaspa79 about 4 years
    I can't believe I'm the first one to upvote this. It's better if you want reliability due to the binding hotkey limitations. In my case f12 was bound to Skype but Skype wasn't doing anything with it. Monitoring raw input was the way to go. Thanks so much Nicholas!
  • arana
    arana over 3 years
    Yes this is from my point of view the best solution, as you can use it to detect key combinations and even distinguish from left and right , shift/alt etc
  • Hugo Scott-Slade
    Hugo Scott-Slade over 3 years
    You can compare the message.wParam with the GetHashCode of the KeyHandler. They will match.