3

I'm using the Window's API RegisterHotKey function to run a macro when the F2 key is pressed while a specific application is open and focused.

The problem is, this is stopping the F2 key from working for other applications, such as Excel.

How can I prevent RegisterHotKey from stopping the default action?

I have a system tray application that uses the HotKeyManager class from this answer to register hotkeys. When a specific key is pressed (for example, F2), I use the Windows API to check if a closed-source application is open and focused, and if so send it a series of SendKeys.

Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • If you care only about a specific app then RegisterHotKey() is the wrong approach. Use SetWindowsHookEx() instead to set a low-level keyboard hook, GetForegroundWindow + GetWindowThreadProcessId to find out what process owns the foreground window. – Hans Passant Sep 05 '12 at 13:26
  • Hans, you should make that an answer. I think that's the correct thing to do. – Andy Davis Sep 05 '12 at 13:29
  • 1
    From what I understand - you want your global hotkey to work only when one or more selected apps are focused. Can't you simply SendKeys the intercepted strokes if you determine that an incompatible app is in the foreground? Do you do this? – Ani Sep 05 '12 at 14:28
  • @ananthonline I didn't think to try that. I'll give it a try and let you know if it works or not, although I'm still interested in trying out `SetWindowsHookEx()` too :) – Rachel Sep 05 '12 at 14:34
  • @ananthonline That actually worked out just fine in my case. I still plan on investigating `SetWindowsHookEx` when I get more time, but for now your solution worked great. You should post it as an answer :) – Rachel Sep 05 '12 at 15:58

2 Answers2

2

RegisterHotKey is global, so it is going to trap all of those keystrokes (in other words, I don't believe it is possible to do exactly what you ask).

However, this thread Global Keyboard Hooks (C#) talks about creating a keyboard message filter, which is (I believe) more like what you are going for.

To clarify: RegisterHotKey is going to be best for things like tray apps and anywhere else where you want an OS wide keyboard short cut that doesn't rely on the app being in focus.

Application.AddMessageFilter() is what you want when you want consistent handling of a particular keystroke, but only when your app already has focus.

A way to do what you're describing and still stay in .NET would be to monitor what processes are running on the OS and only enable the global hook when your app is running.

Community
  • 1
  • 1
Andy Davis
  • 1,393
  • 1
  • 13
  • 24
  • I do not actually have access to the application code, so cannot setup a hook from within the application. The current procedure simply checks if a specific window has focus through the Windows API, and if so runs a series of SendKeys – Rachel Sep 05 '12 at 13:05
  • @Rachel Do you have access to the code of the application that runs `RegisterHotKey`? That's the one that should set up a keyboard hook. It's not clear to me from your comment whether you lack the code for that, or for the "specific application" in the first sentence of your question. If the latter, you still don't need to modify that "specific application". –  Sep 05 '12 at 13:08
  • @hvd I have access to a tray application, which runs `RegisterHotKey`. I think I may have misunderstood the code posted in the link you provided :) – Rachel Sep 05 '12 at 13:11
  • @Rachel For a tray application, you're generally going to need to RegisterHotKey because it will not have focus. Can you lay out what you're trying to do in a bit more detail? – Andy Davis Sep 05 '12 at 13:18
  • @AndyDavis Sure, I updated my question with the details. Basically the tray application listens for hotkeys and does some action. In this case, F2 is supposed to check if another closed-source application is open and focused, and if so send it a series of `SendKeys`. Let me know if I can provide any more details. – Rachel Sep 05 '12 at 13:25
  • @AndyDavis The global part of a global keyboard hook is that it applies even when another application has focus. It should work just fine here. –  Sep 05 '12 at 13:36
  • @hvd I think the issue is that it works too well. If the other app isn't running, then she would like the hook to let the keystroke continue on to its normal target. – Andy Davis Sep 05 '12 at 13:44
  • @AndyDavis Yes, and unlike with hotkeys, a global keyboard hook can look at the pressed key and decide to ignore it, passing it through to whatever application is running. –  Sep 05 '12 at 13:56
  • @hvd I'm attempting to setup a global keyboard hook, however it doesn't seem to get hit. Is it a problem that it is setup in a non-visible tray application which does not receive keyboard focus? – Rachel Sep 05 '12 at 14:05
  • @Rachel That shouldn't be a problem. My recommendation if you haven't worked with hooks before is to pick a global keyboard hook sample application, verify that it works, then strip out everything you don't need bit by bit, checking whether it still works after each step. What's left is what you should include in your own program. Hooks can make for painful debugging experiences, so starting from code known to work can make it a lot easier. If you have specific questions, of course, ask away (perhaps even as new questions here on SO) –  Sep 05 '12 at 14:16
2

From what I understand, you want your global hotkey to work only when one or more selected apps are focused. Can't you simply SendKeys the intercepted strokes if you determine that an incompatible app is in the foreground?

For example,

if (IsSpecificWindowFocused())
{
    // Do work
}
else
{
    // Resend the key to whatever window is current
    SendKeys.Send("{F2}");
}
Ani
  • 10,826
  • 3
  • 27
  • 46
  • Thanks, this works fine for my situation. I still plan on looking into global keyboard hooks at some point, but this was a nice easy solution that fixed my immediate problem :) – Rachel Sep 05 '12 at 16:11
  • So if you're only interested in it a tiny subset of time, why captrue it ALL the time? As per the [other answer](http://stackoverflow.com/a/12282062/588306), if you want one that is specific to a single application, create one that is specific to a single application. – Deanna Sep 06 '12 at 15:17
  • @Deanna As I understand the OP's question "I use the Windows API to check if a closed-source application is open and focused and if so send it a series of SendKeys" - the application that needs to be sent the "macro" cannot be altered. In this case, a global hotkey is the only option. – Ani Sep 06 '12 at 15:30
  • Also see this comment from the linked answer - http://stackoverflow.com/questions/12281442/how-can-i-prevent-registerhotkey-from-stopping-the-default-key-action/12285500#comment16473124_12282062 – Ani Sep 06 '12 at 15:43