5

We have a very large in-house MFC app. It has a main window with a menubar, and hundreds of unique subwindows (without menubars) that display on top of the main window (not all simultaneously). These subwindows are implemented as CDialogs but run modelessly (via CreateWindow, not DoModal). Their parent HWND is set to NULL.

We recently got a feature request--allow a particular menubar accelerator from the main window to work, even when one of the subwindows is the active window. It would make sense from a user perspective.

This could be faked pretty easily with an application-wide keyboard hook, watching for that exact keystroke, but I was wondering if there is a cleaner way?

jww
  • 97,681
  • 90
  • 411
  • 885
StilesCrisis
  • 15,972
  • 4
  • 39
  • 62
  • The phrase *"display on top of the main window"* is vague. Are those `CDialog`s children of the main window, or owned by the main window? – IInspectable May 14 '15 at 18:44
  • 1
    No, their parent is `NULL`. `Create(IDD, NULL); ShowWindow(SW_SHOW);` – StilesCrisis May 14 '15 at 18:48
  • You cannot answer an *"A or B"* question with *"No"*. – IInspectable May 14 '15 at 18:50
  • 1
    They are not children of the main window. They are not owned by the main window. They are created on the heap via `new` and then `CWnd::Create` is called with a parent `HWND` of `NULL`. – StilesCrisis May 14 '15 at 18:52
  • The how are they moved in front of the main window? And if this is done manually, why aren't they owned by the main window? – IInspectable May 14 '15 at 19:00
  • I think `WS_POPUP` causes that behavior automatically? Not 100% sure. – StilesCrisis May 14 '15 at 19:04
  • What you're doing should already work, assuming you don't have any modal message loops. The main message loop gets the keyboard message, and then passes it to TranslateAccelerator, and that will send the command to the main window, assuming you passed the main window to TranslateAccelerator. – Raymond Chen May 14 '15 at 19:05
  • @RaymondChen: unfortunately it doesn't just work. When the main window has focus, the accelerator works fine. As soon as a subwindow is frontmost, the main window accelerators no longer activate. – StilesCrisis May 14 '15 at 19:24
  • Is the main window and the `CDialog`-derived windows created on the same thread? – IInspectable May 14 '15 at 19:33
  • Same thread. We don't do much threading in our UI code at all. – StilesCrisis May 14 '15 at 19:40
  • When the subwindow has focus, who is calling `GetMessage`? After that call to `GetMessage`, is there a call to `TranslateAccelerator` that passes the main window as the first parameter? Oh wait, you say this is a menu accelerator. So duplicate the menu accelerator in your keyboard accelerator table, so that `TranslateAccelerator` will translate it. – Raymond Chen May 15 '15 at 07:01
  • MFC runs the event loop. The accelerator already exists in the keyboard accelerator table. – StilesCrisis May 15 '15 at 13:58
  • MFC passes the keypress to `CWinApp::PreTranslateMessage` which hands it to `CFrameWnd::PreTranslateMessage` which translates it with `TranslateAccelerator()` + `GetDefaultAccelerator()`. Follow the message through - it should hit that translate. Check that it's the right accelerator table and the right window. Note that I'm assuming that by "menubar accelerator" you just mean a normal keyboard shortcut, such as Ctrl+C for copy; not Alt+F for File. – Raymond Chen May 23 '15 at 06:17
  • @RaymondChen: It's the "wrong" window—that was the whole point of my question. I want a particular accelerator to work across all windows in my app. – StilesCrisis May 23 '15 at 15:10
  • You can customize CWinApp::PreTranslateMessage to resolve the accelerator against a window of your choosing. Though it is supposed to pick your CFrameWnd by default, so the window should have been correct. Or perhaps it is picking the wrong frame window... – Raymond Chen May 23 '15 at 17:35
  • That's an interesting idea. I might try it next week since that sounds a little less invasive than a system-wide hotkey registration. – StilesCrisis May 23 '15 at 21:08

1 Answers1

1

You can as well use RegisterHotKey() in your main window. That will have a side effect that the new hotkey will trigger even if pressed in a different application. You can work around that by comparing GetCurrentProcessId() with GetWindowThreadProcessId(GetForegroundWindow())

Codeguard
  • 7,787
  • 2
  • 38
  • 41
  • This had the unfortunate side effect of consuming the hotkey in ALL apps. For instance, if you register a hotkey of ctrl-tab for your app, other apps which normally support ctrl-tab will no longer recognize it when it's pressed. – StilesCrisis Jun 06 '15 at 01:56
  • Sorry, didn't expect that. – Codeguard Jun 07 '15 at 11:48