C++;识别X按钮&;滚轮方向 我最近在有限的空闲时间里尝试了一个小项目,尝试用C++获得更多的经验和理解,但是我现在的程序遇到了一个障碍:
我正试图通过使用windows钩子创建一个全局低级鼠标侦听器,这在大多数情况下看起来都相当简单。然而,识别单击了哪个X鼠标按钮(MB4或MB5)和滚动滚轮的滚动方向让我非常头疼 根据微软文档,我目前试图确定的方法是正确的,但我的实现不起作用 我已经找到了一个解决X按钮问题()的有效方法,但当Microsoft代码段更干净并且应该可以工作时,这似乎有点像是跳过了不必要的障碍 虽然C++不是我最熟悉的语言,但我还是想继续学习它,并经常使用它。我希望我只是犯了一个简单的错误,因为这是我第一次使用Windows挂钩。提前感谢您提供的任何建议或帮助C++;识别X按钮&;滚轮方向 我最近在有限的空闲时间里尝试了一个小项目,尝试用C++获得更多的经验和理解,但是我现在的程序遇到了一个障碍:,c++,winapi,mouseevent,mouselistener,setwindowshookex,C++,Winapi,Mouseevent,Mouselistener,Setwindowshookex,我正试图通过使用windows钩子创建一个全局低级鼠标侦听器,这在大多数情况下看起来都相当简单。然而,识别单击了哪个X鼠标按钮(MB4或MB5)和滚动滚轮的滚动方向让我非常头疼 根据微软文档,我目前试图确定的方法是正确的,但我的实现不起作用 我已经找到了一个解决X按钮问题()的有效方法,但当Microsoft代码段更干净并且应该可以工作时,这似乎有点像是跳过了不必要的障碍 虽然C++不是我最熟悉的语言,但我还是想继续学习它,并经常使用它。我希望我只是犯了一个简单的错误,因为这是我第一次使用Win
#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;
}
#包括
#包括
静态LRESULT回调MouseHookProc(int-nCode、WPARAM-WPARAM、LPARAM-LPARAM)
{
如果(nCode>=0)
{
交换机(wParam)
{
案例WM_LBUTTONDOWN:
系统(“CLS”);
标准::cout请阅读文档:
:
[……]
wParam
[in]
键入:wParam
鼠标的标识符
消息。此参数可以是以下消息之一:
WM\u LBUTTONDOWN
,WM\u LBUTTONUP
,WM\u MOUSEMOVE
,WM\u mouseweel
,
WM_鼠标滚轮
,WM_RBUTTONDOWN
,或WM_RBUTTONUP
lParam
[in]
键入:LPARAM
指向MSLLHOOKSTRUCT
结构。
因此,wParam
可以是WM\u lbuttonown
,WM\u LBUTTONUP
,WM\u MOUSEMOVE
,WM\u mouseweel
,WM\u mouseheel
,或者WM\u RBUTTONUP
。没有神奇的方法从中获取更多信息。如果有,它将是未记录的,应该是未记录的避免
lParam
但是指向一个MSLLHOOKSTRUCT
:
:
包含有关低级鼠标输入事件的信息
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
[……]
mouseData
类型:DWORD
如果消息为WM_mouseweel
,则此成员的高位字为
控制盘增量。保留低位字。正值
表示转轮已向前旋转,远离用户;a
负值表示车轮已向后、朝向旋转
用户。一次滚轮点击定义为滚轮_DELTA
,即120
如果消息为WM_XBUTTONDOWN
,WM_XBUTTONUP
,
WM_-xbuttondblck
,WM_-NCXBUTTONDOWN
,WM_-NCXBUTTONUP
,或
WM\u ncxbuttondblck
,高阶字指定使用哪个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);
}
Microsoft代码段比较干净,应该可以工作。-代码在哪里?@Swardfish我将其链接到“X按钮单击”单词(和)。您可以对“XBUTTON1和XBUTTON2”执行Ctrl+F组合键如果你愿意的话,我也可以在这里粘贴他们的未格式化代码段。非常感谢你的回答。我正在查看你链接的所有文档,以便更好地了解所有这些是如何工作的。我仍然不明白为什么Microsoft文档会有代码段从wParams中获取附加信息。可能是过时的信息在那里?无论如何,再次感谢!@Charles No,这没有矛盾。wParam
只是一个名称,并不意味着它在任何地方都有相同的含义。我用简化的代码更新了我的答案。我想这是有意义的。所以在我链接的Microsoft文档中,GET_XBUTTON_wParam和GET_WHEEL_DELTA_wParam方法实际上并不有效从我们在这里使用的同一类型的wParam中匹配它们?此外,您提供的编辑代码没有像原始答案那样包含对X按钮的区分。@Charles您提供的编辑代码没有包含[…]–抱歉,已修复该问题。@Swardfish“要在主线程中接收消息,我必须创建一个窗口”-实际上不是,您可以使用线程消息而不是窗口消息。GetMessage()
在其HWND参数为空时支持这两种消息。您的处理程序可以使用PostThreadMessage()
将消息发布到主线程,然后GetMessage()
可以将该消息返回到main
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);
}