winapi — C ++ Идентификация кнопок X & amp; Колесо прокрутки

Недавно я в течение своего ограниченного свободного времени экспериментировал с небольшим проектом, чтобы попытаться получить больше опыта и понимания с C ++, но я столкнулся с препятствиями в своей текущей программе:

Я пытаюсь создать глобальный низкоуровневый слушатель мыши с помощью хука окон, что в большинстве случаев кажется довольно простым. Тем не мение, определить, какая кнопка мыши была нажата (MB4 или MB5) и в каком направлении вращалось колесо прокрутки причиняет мне много головной боли

Согласно документам Microsoft, в настоящее время я пытаюсь определить соответствующие Кнопка X нажата а также направление колеса прокрутки это правильно, но моя реализация этого не работает.

Мне удалось найти одно рабочее решение проблемы кнопки X (последнее сообщение сегмента кода в этой теме форума), но это немного похоже на прыжки через ненужные обручи, когда сегмент кода Microsoft чище и должен Работа.

Хотя C ++ не мой самый знакомый язык, я хотел бы продолжать изучать его и использовать его чаще. Я надеюсь, что просто делаю простую ошибку, так как я впервые работаю с хуками Windows. Заранее благодарю за любой совет или помощь, которую может предложить любой человек!

#include <iostream>
#include <windows.h>

static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0)
{
switch(wParam)
{
case WM_LBUTTONDOWN:
system("CLS");
std::cout << "left mouse button down\n";
break;
case WM_LBUTTONUP:
std::cout << "left mouse button up\n";
break;
case WM_RBUTTONDOWN:
system("CLS");
std::cout << "right mouse button down\n";
break;
case WM_RBUTTONUP:
std::cout << "right mouse button up\n";
break;
case WM_MBUTTONDOWN:
system("CLS");
std::cout << "middle mouse button down\n";
break;
case WM_MBUTTONUP:
std::cout << "middle mouse button up\n";
break;
case WM_MOUSEWHEEL:
if(GET_WHEEL_DELTA_WPARAM(wParam) > 0)
std::cout << "mouse wheel scrolled up\n";
else if(GET_WHEEL_DELTA_WPARAM(wParam) < 0)
std::cout << "mouse wheel scrolled down\n";
else //always goes here
std::cout << "unknown mouse wheel scroll direction\n";
break;
case WM_XBUTTONDOWN:
system("CLS");
if(GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
std::cout << "X1 mouse button down\n";
else if(GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
std::cout << "X2 mouse button down\n";
else //always goes here
std::cout << "unknown X mouse button down\n";
break;
case WM_XBUTTONUP:
if(GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
std::cout << "X1 mouse button up\n";
else if(GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
std::cout << "X2 mouse button up\n";
else //always goes here
std::cout << "unknown X mouse button up\n";
break;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main()
{
HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
MSG msg;

while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

UnhookWindowsHookEx(mouseHook);
return 0;
}

1

Решение

Пожалуйста, прочитайте документацию:

Функция обратного вызова LowLevelMouseProc:

[…]

wParam [в] Тип: 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, старшее слово этого члена
колесо дельта
. Слово младшего разряда зарезервировано. Положительная ценность
указывает на то, что колесо было повернуто вперед от пользователя;
отрицательное значение указывает, что колесо было повернуто назад, в направлении
Пользователь. Один щелчок колеса определяется как WHEEL_DELTA, что составляет 120.

Если сообщение WM_XBUTTONDOWN, WM_XBUTTONUP,
WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, или же
WM_NCXBUTTONDBLCLK, старшее слово указывает, какая кнопка X была
нажата или отпущена
, и младшее слово зарезервировано. Это значение
может быть одним или несколькими из следующих значений. Иначе, mouseData является
не используется.

Значение Значение
XBUTTON1 0x0001 Первый Х
Кнопка была нажата или отпущена.
XBUTTON2 0x0002 Второй Х
Кнопка была нажата или отпущена.

Таким образом, упрощенная версия вашего обратного вызова может выглядеть так:

#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 + С.

Чтобы убедиться 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);
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]