Как да открия keyPress, докато не съм фокусиран?

Опитвам се да открия натискането на бутона Print Screen, докато формулярът не е текущото активно приложение.

Как да стане това, ако е възможно?


person James Holland    schedule 17.08.2013    source източник
comment
Изглежда, че може да помогне: social.msdn.microsoft.com/Forums/en-US/   -  person Surfbutler    schedule 17.08.2013


Отговори (3)


Да, можете, нарича се „Системни кукички“, погледнете Глобални системни кукички в .NET.

person Arash    schedule 17.08.2013

Е, ако сте имали проблеми със системни кукички, ето готово решение (базирано на 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;

и в конструктора на формуляри:

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

Добавете тези 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 е вашият инструмент за натискане на бутони. Можете да промените бутона, като подадете различен параметър тук: ghk = new KeyHandler(Keys.PrintScreen, this);

Сега вашата програма реагира на въвеждане на бутон, дори ако не е фокусиран.

person Przemysław Kalita    schedule 17.08.2013
comment
Как да редактирам този код, ако исках 2 различни клавишни комбинации с две различни функции? Мога ли да проверя по някакъв начин в WndProc или HandleHotkey кой клавиш е натиснат? - person user1696947; 15.07.2015
comment
Може ли това да се адаптира за обработка на клавишни комбинации? Като например CTRL-N - person MrVimes; 26.04.2017
comment
Можете да сравните message.wParam с GetHashCode на KeyHandler. Те ще съвпадат. - person Hugo Scott-Slade; 04.01.2021

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...
    }
}
person Nicholas Miller    schedule 18.01.2018
comment
не трябва ли if (prntScrnIs-->p<--ressed) да е if (prntScrnIs-->P<--ressed)? - person Michael; 02.07.2018
comment
Не мога да повярвам, че съм първият, който гласува за това. По-добре е, ако искате надеждност поради ограниченията на обвързващите клавишни комбинации. В моя случай f12 беше свързан със Skype, но Skype не правеше нищо с него. Мониторингът на необработения вход беше правилният начин. Благодаря много Николас! - person Gaspa79; 20.04.2020
comment
Да, от моя гледна точка това е най-доброто решение, тъй като можете да го използвате за откриване на клавишни комбинации и дори за разграничаване от ляво и дясно, shift/alt и т.н. - person arana; 04.12.2020