#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;
}
}
Первоначально казалось, что сообщение WM_HOTKEY
не публикуется. Об этом мне рассказало отсутствие изменения размера окна. Я подтвердил, что мои ключи были правильно зарегистрированы, просмотрев в отладчике значения resultOne, resultTwo и resultThree, все из которых были равны 0.
Затем я заглянул в цикл сообщений и увидел, что внутри цикла сообщений элементом msg.message был 786
= 0x0312
= код сообщения WM_HOTKEY
.
Возможно, есть проблема с потоками, которую я упускаю? Любая помощь приветствуется, спасибо.
Ваш WindowProc
не получает сообщения WM_HOTKEY
, потому что вы не зарегистрировали горячие клавиши в своем окне.
В документации RegisterHotKey говорится:
Параметры
[in, необязательно] hWnd
Тип: ХВНД
Дескриптор окна, которое будет получать сообщения WM_HOTKEY, сгенерированные горячей клавишей. Если этот параметр имеет значение NULL, сообщения WM_HOTKEY отправляются в очередь сообщений вызывающего потока и должны обрабатываться в цикле сообщений.
...
Примечания
При нажатии клавиши система ищет совпадение со всеми горячими клавишами. При обнаружении совпадения система отправляет сообщение WM_HOTKEY в очередь сообщений окна, с которым связана горячая клавиша. Если горячая клавиша не связана с окном, сообщение WM_HOTKEY отправляется в поток, связанный с горячей клавишей.
Сообщению ветки не присвоен HWND
, поэтому нет оконной процедуры, куда DispatchMessage()
можно было бы отправить сообщение.
Таким образом, вам придется обрабатывать сообщения WM_HOTKEY
непосредственно внутри вашего цикла сообщений (как сказано в документации выше), например:
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_HOTKEY) {
// do something ...
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
В противном случае вам придется выполнить одно из следующих действий, чтобы ваш WindowProc
мог получать сообщения WM_HOTKEY
:
просто передайте свой HWND
RegisterHotKey()
, например:
RegisterHotKey(hwnd, ...)
пусть ваш цикл сообщений пересылает сообщения на ваш HWND
, например:
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_HOTKEY) {
SendMessage(hwnd, msg.message, msg.wParam, msg.lParam);
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
@xvymnp Это тоже часть ответа на этот вопрос . Вторая часть головоломки такова: Сообщения тредов съедаются модальными циклами (MessageBox()
раскручивает модальный цикл сообщений). На этот вопрос вполне можно ответить, даже если трое разработчиков, не использующих Windows, не согласны с этим.
Я чувствую себя невероятно глупо. Большое спасибо. +1 за Гамбит.