gpt4 book ai didi

C++ 识别 X 按钮和滚轮方向

转载 作者:行者123 更新时间:2023-11-30 04:54:39 25 4
gpt4 key购买 nike

我最近在有限的空闲时间里尝试了一个小项目,试图获得更多的 C++ 经验和理解,但我在当前的程序中遇到了障碍:

我正在尝试使用 Windows Hook 创建一个全局低级鼠标监听器,大多数事情看起来相当简单。但是,识别单击了哪个 X 鼠标按钮(MB4 或 MB5)以及滚动滚轮的方向让我很头疼。

根据 Microsoft 文档,我目前尝试识别合适的 X button clicked 的方式和 scroll wheel direction是正确的,但我的实现不起作用。

我已经找到了解决 X 按钮问题的有效解决方案 (the last code segment post in this forum thread),但当 Microsoft 代码段更清晰并且应该工作时,这似乎有点像跳过不必要的圈套.

虽然 C++ 不是我最熟悉的语言,但我想继续学习它并经常使用它。我希望我只是犯了一个简单的错误,因为这是我第一次使用 Windows Hook 。提前感谢您提供任何建议或帮助!

#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;
}

最佳答案

请阅读文档:

LowLevelMouseProc callback function :

[...]

wParam [in]
Type: WPARAM
The identifier of the mouse message. This parameter can be one of the following messages:
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.

lParam [in]
Type: LPARAM
A pointer to an MSLLHOOKSTRUCT structure.

所以 wParam 可以是 WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_MOUSEHWHEELWM_RBUTTONDOWNWM_RBUTTONUP。没有神奇的方法可以从中获取更多信息。即使有,也不会记录在案,应该避免。

lParam 但是指向一个 MSLLHOOKSTRUCT:

tagMSLLHOOKSTRUCT structure :

Contains information about a low-level mouse input event.

typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;

[...]

mouseData
Type: DWORD

If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta. The low-order word is reserved. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.

If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, and the low-order word is reserved. This value can be one or more of the following values. Otherwise, mouseData is not used.

Value Meaning
XBUTTON1 0x0001 The first X button was pressed or released.
XBUTTON2 0x0002 The second X button was pressed or released.

因此您的回调的简化版本可能如下所示:

#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 有机会调用已安装的 Hook 回调。但问题是,调用 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);
}

关于C++ 识别 X 按钮和滚轮方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53466611/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com