#ifndef UNICODE
#define UNICODE
#endif
#define HOTKEY_REG_ERR -10
#define HOTKEY_DEC_ID 1
#define HOTKEY_INC_ID 2
#define HOTKEY_CEN_ID 3
#define WND_CHANGE_SIZE 50
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WindowProcAlt(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
SHORT ResizeWindow(HWND hwnd, int widthChange, int heightChange);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
// Register the window class.
LPCWSTR mainWndClass = L"Sample Window Class ";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = mainWndClass;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
mainWndClass, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Register hotkeys
BOOL resultOne = 0;
BOOL resultTwo = 0;
BOOL resultThree = 0;
if (!RegisterHotKey(NULL, HOTKEY_DEC_ID, MOD_CONTROL | MOD_SHIFT, '1')) {
resultOne = -1;
}
if (!RegisterHotKey(NULL, HOTKEY_INC_ID, MOD_CONTROL | MOD_SHIFT, '2')) {
resultTwo = -2;
}
if (!RegisterHotKey(NULL, HOTKEY_CEN_ID, MOD_CONTROL | MOD_SHIFT, '3')) {
resultThree = -3;
}
// Run the message loop
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0) > 0) {
UINT messageCode = msg.message;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
case WM_HOTKEY:
switch (wParam) {
case HOTKEY_DEC_ID:
ResizeWindow(hwnd, -WND_CHANGE_SIZE, -WND_CHANGE_SIZE);
break;
case HOTKEY_INC_ID:
ResizeWindow(hwnd, WND_CHANGE_SIZE, WND_CHANGE_SIZE);
break;
case HOTKEY_CEN_ID:
break;
default:
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
SHORT ResizeWindow(HWND hwnd, int widthChange, int heightChange) {
if (hwnd == NULL) {
return -1;
}
int containerWidth, containerHeight, newWndWidth, newWndHeight, x, y;
RECT rect;
if (GetWindowRect(hwnd, &rect)) {
RECT workArea = {};
SystemParametersInfo(SPI_GETWORKAREA, NULL, &workArea, NULL);
containerWidth = workArea.right - workArea.left;
containerHeight = workArea.bottom - workArea.top;
newWndWidth = rect.right - rect.left + widthChange;
newWndHeight = rect.bottom - rect.top + heightChange;
x = (containerWidth - newWndWidth) / 2;
y = (containerHeight - newWndHeight) / 2;
MoveWindow(hwnd, x, y, newWndWidth, newWndHeight, TRUE);
} else {
// std::cerr << "Failed to get window rect." << std::endl;
}
}
Initially it looked like the WM_HOTKEY
message was not being posted. Lack of window resizing told me this. I confirmed that my keys were correctly registered by looking at the values of resultOne, resultTwo, and resultThree in the debugger, all of which were 0.
I then looked into the message loop, and saw that within the message loop, the msg.message member was 786
= 0x0312
= the WM_HOTKEY
message code.
Perhaps there's a threading issue I'm missing? Any help is appreciated, thank you.
Your WindowProc
is not receiving the WM_HOTKEY
messages because you are not registering the hotkeys with your window.
The RegisterHotKey
documentation says:
Parameters
[in, optional] hWnd
Type: HWND
A handle to the window that will receive WM_HOTKEY messages generated by the hot key. If this parameter is NULL, WM_HOTKEY messages are posted to the message queue of the calling thread and must be processed in the message loop.
...
Remarks
When a key is pressed, the system looks for a match against all hot keys. Upon finding a match, the system posts the WM_HOTKEY message to the message queue of the window with which the hot key is associated. If the hot key is not associated with a window, then the WM_HOTKEY message is posted to the thread associated with the hot key.
A thread message does not have an HWND
assigned to it, so there is no window procedure for DispatchMessage()
to send the message to.
As such, you will have to process the WM_HOTKEY
messages directly inside your message loop (like the documentation above says to), eg:
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_HOTKEY) {
// do something ...
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Otherwise, you will have to do one of the following so your WindowProc
can receive the WM_HOTKEY
messages:
simply pass your HWND
to RegisterHotKey()
, eg:
RegisterHotKey(hwnd, ...)
have your message loop forward the messages to your HWND
, eg:
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_HOTKEY) {
SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}