visual-c++mfcdialoghotkeys

Handling hotkeys when modeless popups are active


Is there a standard way to handle this situation? I ask because in Notepad++ the hotkey F3> still works even when the Find popup window has focus.

In my application the main dialog is using the accelerator table to map F3> to a resource ID which is subsequently mapped to the function performing the find action.

But, pressing F3> when the modeless Find window is focussed with not trigger the find as it eats the hotkey itself. From my perspective I think I have two approaches:

  1. Add an accelerator table to the Find window for the same hotkey and post a message to the parent when triggered.
  2. Use PreTranslateMessage to detect the hotkey and post a message that way.

Is there any other approach that one can use with MFC architecture? I don't think using RegisterHotkey is the way to go, but I could be wrong!


Solution

  • Registering Hotkeys

    Actually, using RegisterHotKey etc. was the way to go!

    I added the following functions to my MSAFind namespace:

    // Registers hotkeys (CTRL+F and F3) for find and repeat commands.
    static void RegisterHotKeys(HWND hWnd) {
        if (!RegisterHotKey(hWnd, ID_EDIT_FIND, MOD_CONTROL, 'F')) {
            TRACE(L"Failed to register CTRL + F as a hotkey!\n");
        }
        if (!RegisterHotKey(hWnd, ID_EDIT_REPEAT, 0, VK_F3)) {
            TRACE(L"Failed to register F3 as a hotkey!\n");
        }
    }
    
    // Unregisters the hotkeys to release associated resources.
    static void UnregisterHotKeys(HWND hWnd) noexcept {
        UnregisterHotKey(hWnd, ID_EDIT_FIND);
        UnregisterHotKey(hWnd, ID_EDIT_REPEAT);
    }
    
    // Processes hotkey events and triggers the corresponding actions.
    static void OnHotKey(CWnd* pWnd, UINT nHotKeyId, UINT nKey1, UINT nKey2) {
        if (pWnd) {
            switch (nHotKeyId)
            {
            case ID_EDIT_FIND:
                pWnd->PostMessage(WM_COMMAND, ID_EDIT_FIND);
                break;
            case ID_EDIT_REPEAT:
                pWnd->PostMessage(theApp.UWM_FIND_NEXT_MSG);
                break;
            default:
                // Log an error, display a message, or take no action for unrecognized hotkey IDs.
                TRACE(L"Unhandled hotkey ID: %u\n", nHotKeyId);
                break;
            }
        }
    }
    

    And, I call them respectively in my respective dialog classes that invoke Find functionality. This approach works fine and the hotkeys work, irrespective of the popup having focus.


    Alternative

    I take onboard the comments made about the side-effect of using RegisterHotkey being system wide. In which case the simplest solution is to use PreTranslateMessage:

    BOOL CMyFindDialog::PreTranslateMessage(MSG* pMsg)
    {
        if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F3)
        {
            // Handle the F3 key press here
            CWnd* pWnd = GetParent();
            if (pWnd) {
                pWnd->PostMessage(theApp.UWM_FIND_NEXT_MSG);
            }
    
            return true; // Message handled
        }
    
    
        return __super::PreTranslateMessage(pMsg);
    }