I know how to use the accelerator table to setup hot keys within my app. But how do I get a hot key at global level?
I.e. My app is running, but minimised. Yet I still want it to detect and process a hot key.
If you need a system-wide hotkey then you should use RegisterHotKey
, passing in the window handle whose window procedure is responsible for handling the event. At the application level this is commonly the CFrameWnd
/CFrameWndEx
-derived window implementation.
Once the hotkey is registered, the receiving window can observe the event in its custom CWnd::OnHotKey
override. Make sure to add the ON_WM_HOTKEY()
message handler to the message map of the receiving window implementation.
For a standard, default-generated SDI/MDI application you'd need to apply the following changes.
MainFrm.h:
class CMainFrame : public CFrameWnd
{
// ...
private:
// Hot key handler routine
afx_msg void OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2);
};
MainFrm.cpp:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
// ...
// Make sure that WM_HOTKEY messages are routed to this window
ON_WM_HOTKEY()
END_MESSAGE_MAP()
// Hot key ID; can be any value in the range 0x0000 through 0xBFFF
// Allows the application to identify this hot key in case there is more than one
constexpr int MyHotKeyId = 42;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
// ...
// Register a global system-wide hot key (Ctrl+Shift+Alt+I)
if (!::RegisterHotKey(this->m_hWnd, MyHotKeyId,
MOD_ALT | MOD_SHIFT | MOD_CONTROL | MOD_NOREPEAT,
'I')) {
auto const ec = ::GetLastError();
auto const err_msg = std::format(L"RegisterHotKey failed (error: {})\n",
ec);
::OutputDebugStringW(err_msg.c_str());
// Probably a good idea to handle failure more gracefully than this:
return -1;
}
return 0;
}
void CMainFrame::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2) {
// Handle hot key; nHotKeyId is MyHotKeyId in this case
}
Note that receiving a WM_HOTKEY
message grants the receiving thread foreground activation permission. If you want your application to come to the foreground upon receiving a registered hot key, you can use the following OnHotKey
implementation:
void CMainFrame::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2) {
if (this->IsIconic()) {
this->ShowWindow(SW_RESTORE);
}
this->SetForegroundWindow();
}
No flashing the taskbar button, everything just works as intended.