在使用我自己的鼠标有问题时我的gpw1代出现了回滚的问题
python的方法
1 | from pynput.mouse import Listener |
这个代码简单好理解
c++
-
首先我们当然是需要借助
windowsapi的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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, orWM_RBUTTONUP.lParam[in]
Type:LPARAM
A pointer to anMSLLHOOKSTRUCTstructure.所以
wParam可以是WM_LBUTTONDOWN,WM_LBUTTONUP,WM_MOUSEMOVE,WM_MOUSEWHEEL,WM_MOUSEHWHEEL、WM_RBUTTONDOWN或WM_RBUTTONUP。没有神奇的方法可以从中获取更多信息。即使有,也不会记录在案,应该避免。lParam但是指向一个MSLLHOOKSTRUCT:Contains information about a low-level mouse input event.
1
2
3
4
5
6
7typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;[…]
mouseData
Type:DWORDIf 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 asWHEEL_DELTA, which is 120.If the message is
WM_XBUTTONDOWN,WM_XBUTTONUP,WM_XBUTTONDBLCLK,WM_NCXBUTTONDOWN,WM_NCXBUTTONUP, orWM_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,mouseDatais not used.Value Meaning
XBUTTON10x0001 The first X button was pressed or released.
XBUTTON20x0002 The second X button was pressed or released.因此您的回调的简化版本可能如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28HHOOK 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);
} -
使用
qt对滚动事件的监听
c sharp
-
使用
windows api -
使用
scroller view对滚动事件监听使用 XAML 声明方式:
在 XAML 中,你可以为滚动控件(例如 ScrollViewer)的相应事件添加事件处理程序。以下是一个示例,演示了如何在 XAML 中声明并处理 ScrollViewer 的滚动事件:1
2
3<ScrollViewer ScrollChanged="ScrollViewer_ScrollChanged">
<!-- 内容 -->
</ScrollViewer>在代码中定义了名为 ScrollViewer_ScrollChanged 的事件处理程序:
1
2
3
4private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
// 处理滚动事件
}在该事件处理程序中,你可以编写代码来处理滚动事件,根据需要执行相应的逻辑。使用代码绑定方式:
使用代码绑定的方式,你可以在代码中订阅滚动事件。以下是一个示例,演示了如何使用代码绑定方式监听 ScrollViewer 的滚动事件:1
2
3
4
5
6ScrollViewer scrollViewer = new ScrollViewer();
scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
// 处理滚动事件
}在这个示例中,我们创建了一个 ScrollViewer 实例,并将事件处理程序 ScrollViewer_ScrollChanged 绑定到 ScrollChanged 事件上。当滚动事件发生时,事件处理程序将被调用,你可以在其中编写逻辑来处理滚动事件。
无论是 XAML 声明方式还是代码绑定方式,你都需要根据你的实际需求,选择适合的方式来监听滚动事件,并在事件处理程序中编写相应的逻辑。
-
在 WPF 中,你可以通过以下方式来监听滚动事件:
在全局鼠标事件中在我们使用的
1
2
3
4
5LRESULT CALLBACK LowLevelMouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);我们需要在知道每个参数的意义
参数 wParam 表示鼠标事件类型。几个主要的数值如下表所示:
鼠标移动 0x200 鼠标左键按下 0x201 鼠标左键抬起 0x202 鼠标右键按下 0x204 鼠标右键抬起 0x205 鼠标滚轮滚动 0x20a 鼠标侧键按下 0x20b 鼠标侧健抬起 0x20c 鼠标水平滚轮滚动 0x20e 参数 lParam 同样是事件详细信息结构体的地址,该结构体的原型如下所示:
1
2
3
4
5
6
7typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;成员 pt 表示事件的坐标值结构体,其原型如下所示:
1
2
3
4typedef struct tagPOINT {
LONG x;
LONG y;
} POINT, *PPOINT;需要注意的是,虽然它被声明为 ‘LONG’ 类型,但它实际上只有4个字节长度。另外,如果你对结构体的了解足够深刻,一定能理解在实际开发中直接用一个 long 型来替代 POINT 类型是完全可行的,只需要知道Windows桌面编程使用的是小端序就可以了,当然,如果你理解不了这句话,那老老实实再创建一个POINT结构体来套进去就是了。
成员mouseData 不太需要关注。当事件是滚轮滚动时,它的高16位记录的是滚动方向及距离。正值表示远离用户的滚动,负值表示靠近用户的滚动,其数值恒定为120,可以理解为表示一格滚动。
成员 flags 不需要理会。
成员 time 表示事件发生时间,单位为毫秒,自系统启动以来的相对时间值。
成员 dwExtraInfo 不需要理会。
同时键盘的回调函数也是需要注意的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace KMHook
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
internal struct Keyboard_LL_Hook_Data
{
public UInt32 vkCode;
public UInt32 scanCode;
public UInt32 flags;
public UInt32 time;
public IntPtr extraInfo;
}
internal struct Mouse_LL_Hook_Data
{
internal long yx;
internal readonly int mouseData;
internal readonly uint flags;
internal readonly uint time;
internal readonly IntPtr dwExtraInfo;
}
private static IntPtr pKeyboardHook = IntPtr.Zero;
private static IntPtr pMouseHook = IntPtr.Zero;
//钩子委托声明
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
private static HookProc keyboardHookProc;
private static HookProc mouseHookProc;
//安装钩子
[]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr pInstance, int threadID);
//卸载钩子
[]
public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
[]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); //parameter 'hhk' is ignored.
private static int keyboardHookCallback(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
Keyboard_LL_Hook_Data khd = (Keyboard_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Keyboard_LL_Hook_Data));
System.Diagnostics.Debug.WriteLine($"key event:{wParam}, key code:{khd.vkCode}, event time:{khd.time}");
return 0;
}
private static int mouseHookCallback(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
Mouse_LL_Hook_Data mhd = (Mouse_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Mouse_LL_Hook_Data));
System.Diagnostics.Debug.WriteLine($"mouse event:{wParam}, ({mhd.yx & 0xffffffff},{mhd.yx >> 32})");
return 0;
}
internal static bool InsertHook()
{
bool iRet;
iRet = InsertKeyboardHook();
if (!iRet)
{
return false;
}
iRet = InsertMouseHook();
if (!iRet)
{
removeKeyboardHook();
return false;
}
return true;
}
//安装钩子方法
private static bool InsertKeyboardHook()
{
if (pKeyboardHook == IntPtr.Zero)//不存在钩子时
{
//创建钩子
keyboardHookProc = keyboardHookCallback;
pKeyboardHook = SetWindowsHookEx(13, //13表示全局键盘事件。
keyboardHookProc,
(IntPtr)0,
0);
if (pKeyboardHook == IntPtr.Zero)//如果安装钩子失败
{
removeKeyboardHook();
return false;
}
}
return true;
}
private static bool InsertMouseHook()
{
if (pMouseHook == IntPtr.Zero)
{
mouseHookProc = mouseHookCallback;
pMouseHook = SetWindowsHookEx(14, //14表示全局鼠标事件
mouseHookProc,
(IntPtr)0,
0);
if (pMouseHook == IntPtr.Zero)
{
removeMouseHook();
return false;
}
}
return true;
}
internal static bool RemoveHook()
{
bool iRet;
iRet = removeKeyboardHook();
if (iRet)
{
iRet = removeMouseHook();
}
return iRet;
}
private static bool removeKeyboardHook()
{
if (pKeyboardHook != IntPtr.Zero)
{
if (UnhookWindowsHookEx(pKeyboardHook))
{
pKeyboardHook = IntPtr.Zero;
}
else
{
return false;
}
}
return true;
}
private static bool removeMouseHook()
{
if (pMouseHook != IntPtr.Zero)
{
if (UnhookWindowsHookEx(pMouseHook))
{
pMouseHook = IntPtr.Zero;
}
else
{
return false;
}
}
return true;
}
private void Button_Install_Click(object sender, RoutedEventArgs e)
{
InsertHook();
}
private void Button_Remove_Click(object sender, RoutedEventArgs e)
{
RemoveHook();
}
}
}



