Key capture without window focus

I have an application that always checks if a key like F12 is pressed. This is not necessary in the focus of my main window of my application. I tried this code:

public int a = 1; // DLL libraries used to manage hotkeys [DllImport("user32.dll")] public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); [DllImport("user32.dll")] public static extern bool UnregisterHotKey(IntPtr hWnd, int id); const int MYACTION_HOTKEY_ID = 1; public Form1() { InitializeComponent(); // Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8 // Compute the addition of each combination of the keys you want to be pressed // ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6... RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); } protected override void WndProc(ref Message m) { if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID) { a++; MessageBox.Show(a.ToString()); } base.WndProc(ref m); } 

I put 0 on this line RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); so that only if F12 is pressed, it will be captured.

But that did not work. How can i solve this?

Here I could not understand some lines, for example:

 const int MYACTION_HOTKEY_ID = 1; m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID base.WndProc(ref m); 

Can someone help me understand these lines?

+4
source share
4 answers

There are no errors in the code. But this will not work here, because the F12 key is reserved, you can try with another key, for example F10 , F11 , etc.

+1
source

But that did not work. How can i solve this?

What does "it didn't work" mean? The code in your question looks right to me.

The only reason it might not work is because the RegisterHotKey function returns an error and you are not checking for it. To make this work, you need to add the SetLastError attribute to your declaration, which is why the runtime caches the Win32 error code that it sets. Once this is done, you can check this error code (if the function returns false ) by calling the function GetLastWin32Error . I recommend using the result of this function to throw and throw a Win32Exception .

Modify the RegisterHotKey declaration as follows:

 [DllImport("user32.dll", PreserveSig = false)] public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, Keys key); 

And your function call as follows:

 if (!RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, Keys.F12)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } 

As soon as this happens, I suspect that you will see the exception received with the error message:

Hotkey already registered

Well, that makes debugging a lot easier, now no! Most likely, you need to select another hotkey, as the RegisterHotKey function documentation explicitly states that:

The F12 key is reserved for use by the debugger at any time, so it should not be registered as a hot key. Even if you do not debug the application, F12 is reserved in case the resident kernel debugging mode or the debugger is on time.

When I run the code and register F11 as a hotkey, it works fine for me.


Here I could not understand some lines, for example:

 const int MYACTION_HOTKEY_ID = 1; m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID base.WndProc(ref m); 

Can someone help me understand these lines?

Sure:

  • The first line declares a constant value that uniquely identifies the hotkey that you set using the RegisterHotKey function. More specifically, it corresponds to the id parameter of a function. You passed it on your first call.

  • The window procedure ( WndProc ) checks whether the message ( Msg ) WM_HOTKEY . The WM_HOTKEY message WM_HOTKEY automatically sent to your window when the hotkey that you registered using the RegisterHotKey function is pressed.

    In fact, you should not use the magic number 0x0312 , because you are not the only one who does not know what this means. Define a constant instead and use it instead:

     const int WM_HOTKEY = 0x0312; m.Msg == WM_HOTKEY 

    The second part of this conditional test (the part after && ) checks the wParam field of the message to see if the hotkey you registered has been pressed. Remember that MYACTION_HOTKEY_ID is the unique identifier for your hotkey. The WM_HOTKEY message WM_HOTKEY tells us that the wParam check is how we determine which hotkey was pressed.

  • This calls the base class window procedure. In other words, you made an overridden virtual WndProc method that allows you to add additional code (your WM_HOTKEY processing). When you are done with your additional logic, you want to continue the logic of the base class, so forward the message.

+2
source

To do a similar thing, I applied a low-level keyboard using SetWindowsHookEx . This suppresses all keyboard messages passing through Windows and allows you to check them and, if necessary, prevent their further progress.

Take a look at my KeyboardHandling project in my RocketLauncher GitHub hobby project . You can take what you need directly from it. I will make a nuget package soon too.

+1
source

I don’t know why, but I feel this is related to the question this ... so I will try to explain it again:

 const int MYACTION_HOTKEY_ID = 1; 

- This is the place where you store the integer that is used to identify the hotkey. If you need to register more than the hotkey, you will have to declare other integer fields that identify the other hotkeys:

 const int ANOTHER_ACTION_HOTKEY_ID = 2; const int AND_ANOTHER_ACTION_HOTKEY_ID = 3; 

Then

 m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID 

is a condition that lets you know which hotkey has been entered by the user.

0x0312 (also declared as WM_HOTKEY in the documentation, you can find here ) to find out if a registered hotkey is pressed:

When a key is pressed, the system searches for a match with all the hot keys. Finding a match, the system sends the WM_HOTKEY message to the message queue of the window with which the hotkey is associated. If the hotkey is not associated with a window, the WM_HOTKEY message is sent to the stream associated with the hotkey.


According to the documentation, you cannot use the F12 hotkey:

The F12 key is reserved for use by the debugger at any time, so it should not be registered as a hot key. Even if you do not debug the application, F12 is reserved if the kernel mode debugger or the debugger is on time.

0
source

Source: https://habr.com/ru/post/1469451/


All Articles