Пожалуйста, ознакомьтесь с документацией:
Функция обратного вызова LowLevelMouseProc :
[...]
wParam
[in]Тип: WPARAM
Идентификатор сообщения мыши.Этот параметр может быть одним из следующих сообщений:WM_LBUTTONDOWN
, WM_LBUTTONUP
, WM_MOUSEMOVE
, WM_MOUSEWHEEL
, WM_MOUSEHWHEEL
, WM_RBUTTONDOWN
или WM_RBUTTONUP
.lParam
[в]Тип: LPARAM
Указатель на структуру MSLLHOOKSTRUCT
.
То есть wParam
может быть WM_LBUTTONDOWN
, WM_LBUTTONUP
, WM_MOUSEMOVE
, WM_MOUSEWHEEL
, WM_MOUSEHWHEEL
, WM_RBUTTONDOWN
или WM_RBUTTONUP
.Нет никакого волшебного способа получить больше информации из этого.И если бы это было так, это было бы недокументировано и этого следует избегать.
lParam
однако указывает на структуру MSLLHOOKSTRUCT
:
tagMSLLHOOKSTRUCT :
Содержит информацию о низкоуровневом событии ввода мыши.
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
[...]
mouseData
Тип: DWORD
Если сообщение WM_MOUSEWHEEL
, старшее слово этого члена - это колесо delta .Слово младшего разряда зарезервировано.Положительное значение указывает на то, что колесо было повернуто вперед от пользователя;отрицательное значение указывает, что колесо было повернуто назад, к пользователю.Один щелчок колеса определяется как WHEEL_DELTA
, что равно 120.
Если сообщение WM_XBUTTONDOWN
, WM_XBUTTONUP
, WM_XBUTTONDBLCLK
, WM_NCXBUTTONDOWN
, WM_NCXBUTTONUP
или WM_NCXBUTTONDBLCLK
, старшее слово указывает, какая кнопка X была нажата или отпущена , а младшее слово зарезервировано.Это значение может быть одним или несколькими из следующих значений.В противном случае mouseData
не используется.Значение ЗначениеXBUTTON1
0x0001 Первая кнопка X была нажата или отпущена.XBUTTON2
0x0002 Вторая кнопка X была нажата или отпущена.
Таким образом, упрощенная версия вашего обратного вызова может выглядеть так:
#include <iostream>
#include <type_traits> // std::make_signed_t<>
#include <windows.h>
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode != HC_ACTION) // Nothing to do :(
return CallNextHookEx(NULL, nCode, wParam, lParam);
MSLLHOOKSTRUCT *info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
char const *button_name[] = { "Left", "Right", "Middle", "X" };
enum { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_XBUTTON, BTN_NONE } button = BTN_NONE;
char const *up_down[] = { "up", "down" };
bool down = false;
switch (wParam)
{
case WM_LBUTTONDOWN: down = true;
case WM_LBUTTONUP: button = BTN_LEFT;
break;
case WM_RBUTTONDOWN: down = true;
case WM_RBUTTONUP: button = BTN_RIGHT;
break;
case WM_MBUTTONDOWN: down = true;
case WM_MBUTTONUP: button = BTN_MIDDLE;
break;
case WM_XBUTTONDOWN: down = true;
case WM_XBUTTONUP: button = BTN_XBUTTON;
break;
case WM_MOUSEWHEEL:
// the hi order word might be negative, but WORD is unsigned, so
// we need some signed type of an appropriate size:
down = static_cast<std::make_signed_t<WORD>>(HIWORD(info->mouseData)) < 0;
std::cout << "Mouse wheel scrolled " << up_down[down] << '\n';
break;
}
if (button != BTN_NONE) {
std::cout << button_name[button];
if (button == BTN_XBUTTON)
std::cout << HIWORD(info->mouseData);
std::cout << " mouse button " << up_down[down] << '\n';
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Относительно вашего main()
:
Поскольку в вашем приложении нет окон, нетсообщения будут отправлены на него и GetMessage()
никогда не вернется.Это делает сообщение бесполезным.Одного вызова на GetMessage()
достаточно, чтобы дать Windows возможность вызвать установленный обратный вызов.Однако проблема в том, что код после вызова GetMessage()
никогда не будет выполнен, потому что единственные способы завершить программу - закрыть окно или нажать Ctrl + C .
Чтобы убедиться, что UnhookWindowsHookEx()
вызван, я бы предложил установить ConsoleCtrlHandler:
HHOOK hook = NULL;
BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
{
if (hook) {
std::cout << "Unhooking " << hook << '\n';
UnhookWindowsHookEx(hook);
hook = NULL; // ctrl_handler might be called multiple times
std::cout << "Bye :(";
std::cin.get(); // gives the user 5 seconds to read our last output
}
return TRUE;
}
int main()
{
SetConsoleCtrlHandler(ctrl_handler, TRUE);
hook = SetWindowsHookExW(WH_MOUSE_LL, MouseHookProc, nullptr, 0);
if (!hook) {
std::cerr << "SetWindowsHookExW() failed. Bye :(\n\n";
return EXIT_FAILURE;
}
std::cout << "Hook set: " << hook << '\n';
GetMessageW(nullptr, nullptr, 0, 0);
}