开发中我们很多时候会遇到使用钩子的情况。
用户按下了个按键,我怎么捕捉的到?好,如果焦点在自己的Form里的话,简单,重写ProcessDialogKey方法即可。。如果焦点在其他应用程序呢,Windows不会给我的Form发送按键消息,想捕捉这个按键就可以用钩子了。。。
同样,捕获鼠标也是如此。。不仅是键盘鼠标消息,挂上WH_GETMESSAGE钩子之后我们可以获得其他更多的消息。
前两天看到一个VB写的类,把它给改成C#的了,以组件(Component)形式使用,直接拖到设计器里就好,然后,给这个组件添加事件(KeyUp、KeyDown、MouseUp……)。那么当用户有这些动作的时候就会触发这些事件了,用起来是不是很方便……![]()
设计预览:(像Timer组件一样简简单单的拖进来即可)

代码:
1
/**//*
2
* Copyright (c) 2008 黑色珊瑚::Tsorgy.Utils, Reserved.
3
*
4
* Filename: @(#)Hook.cs
5
* Create by: TsOrgY
6
* Email: tsorgy@gmail.com
7
* Date: 2008/12/20 16:30:09
8
*
9
* Classname: Hook
10
* Description: 钩子组件.
11
*
12
*/
13
14
using System;
15
using System.Runtime.InteropServices;
16
using System.Reflection;
17
using System.ComponentModel;
18
19
namespace Tsorgy.Utils
{
20
21
/**//// <summary>
22
/// 钩子工具类.
23
/// </summary>
24
[DefaultEvent("KeyUp")]
25
[DefaultProperty("Tag")]
26
public class Hook : Component
{
27
* 属性 *#region * 属性 *
28
private bool _enabled = true;
29
/**//// <summary>
30
/// 获取或设置一个布尔值,表示该钩子是否可用.
31
/// </summary>
32
[Description("一个布尔值,表示该钩子是否可用。")]
33
[Category("Behavior")]
34
[DefaultValue(true)]
35
public bool Enabled
{
36
get
{ return _enabled; }
37
set
{
38
if (_enabled == value)
39
return;
40
_enabled = value;
41
if (!this.DesignMode)
{
42
if (value)
43
SetHook();
44
else
45
RemoveHook();
46
}
47
}
48
}
49
50
/**//// <summary>
51
/// 获取或设置一个任意字符串,表示某种类型的用户状态.
52
/// </summary>
53
[Description("任意字符串,表示某种类型的用户状态。")]
54
[Localizable(false)]
55
[Bindable(true)]
56
[TypeConverter(typeof(StringConverter))]
57
[DefaultValue((string) null)]
58
public object Tag
{ get; set; }
59
#endregion
60
61
* 事件 *#region * 事件 *
62
public delegate void KeyDownHandler(int keyCode, ShiftKey shift);
63
public delegate void KeyUpHandler(int keyCode, ShiftKey shift);
64
public delegate void SystemKeyDownHandler(int keyCode);
65
public delegate void SystemKeyUpHandler(int keyCode);
66
public delegate void MouseDownHandler(Button button, ShiftKey shift, int x, int y);
67
public delegate void MouseUpHandler(Button button, ShiftKey shift, int x, int y);
68
public delegate void MouseMoveHandler(Button button, ShiftKey shift, int x, int y);
69
70
/**//// <summary>
71
/// 当键盘按下时触发.
72
/// </summary>
73
[Description("键盘按下时触发")]
74
[Category("Behavior")]
75
public event KeyDownHandler KeyDown;
76
/**//// <summary>
77
/// 当键盘弹起时触发.
78
/// </summary>
79
[Description("键盘弹起时触发")]
80
[Category("Behavior")]
81
public event KeyUpHandler KeyUp;
82
/**//// <summary>
83
/// 当系统键盘按下时触发.
84
/// </summary>
85
[Description("系统键盘按下时触发")]
86
[Category("Behavior")]
87
public event SystemKeyDownHandler SystemKeyDown;
88
/**//// <summary>
89
/// 当系统键盘弹起时触发.
90
/// </summary>
91
[Description("系统键盘弹起时触发")]
92
[Category("Behavior")]
93
public event SystemKeyUpHandler SystemKeyUp;
94
/**//// <summary>
95
/// 当鼠标按下时触发.
96
/// </summary>
97
[Description("鼠标按下时触发")]
98
[Category("Behavior")]
99
public event MouseDownHandler MouseDown;
100
/**//// <summary>
101
/// 当鼠标弹起时触发.
102
/// </summary>
103
[Description("鼠标弹起时触发")]
104
[Category("Behavior")]
105
public event MouseUpHandler MouseUp;
106
/**//// <summary>
107
/// 当鼠标移动时触发.
108
/// </summary>
109
[Description("鼠标移动时触发")]
110
[Category("Behavior")]
111
public event MouseMoveHandler MouseMove;
112
#endregion
113
114
* 公共方法 *#region * 公共方法 *
115
/**//// <summary>
116
/// 设置钩子.
117
/// </summary>
118
/// <returns></returns>
119
public bool SetHook()
{
120
bool rtn = true;
121
if (hJournalHook != 0 || hAppHook != 0)
122
rtn = rtn && RemoveHook();
123
if (rtn)
{
124
IntPtr instance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);
125
hJournalHook = SetWindowsHookEx(WH_JOURNALRECORD, procJournal, instance, 0);
126
hAppHook = SetWindowsHookEx(WH_GETMESSAGE, procAppHook, instance, GetCurrentThreadId());
127
}
128
129
return rtn && hJournalHook != 0 && hAppHook != 0;
130
}
131
132
/**//// <summary>
133
/// 卸载钩子.
134
/// </summary>
135
public bool RemoveHook()
{
136
bool rtn = UnhookWindowsHookEx(hAppHook);
137
rtn = rtn && UnhookWindowsHookEx(hJournalHook);
138
139
return rtn;
140
}
141
#endregion
142
143
- 枚举 -#region - 枚举 -
144
/**//// <summary>
145
/// 上档键枚举.
146
/// </summary>
147
public enum ShiftKey
{
148
None = 0,
149
Shift = 1,
150
Control = 2,
151
ControlShift = 3,
152
Menu = 4,
153
MenuShift = 5,
154
ControlMenu = 6,
155
ControlMenuShift = 7
156
}
157
158
/**//// <summary>
159
/// 当前鼠标键枚举.
160
/// </summary>
161
public enum Button
{
162
Left = 1,
163
Right = 2,
164
LeftRight = 3,
165
Middle = 4,
166
LeftMiddle = 5,
167
RightMiddle = 6,
168
LeftRightMiddle = 7
169
}
170
#endregion
171
172
- API 相关 -#region - API 相关 -
173
/**//// <summary>
174
/// 消息类型.
175
/// </summary>
176
private enum MessageType
{
177
WM_CANCELJOURNAL = 0x4B,
178
WM_KEYDOWN = 0x100,
179
WM_KEYUP = 0x101,
180
WM_MOUSEMOVE = 0x200,
181
WM_LBUTTONDOWN = 0x201,
182
WM_LBUTTONUP = 0x202,
183
WM_LBUTTONDBLCLK = 0x203,
184
WM_RBUTTONDOWN = 0x204,
185
WM_RBUTTONUP = 0x205,
186
WM_RBUTTONDBLCLK = 0x206,
187
WM_MBUTTONDOWN = 0x207,
188
WM_MBUTTONUP = 0x208,
189
WM_MBUTTONDBLCLK = 0x209,
190
WM_MOUSEWHEEL = 0x20A,
191
WM_SYSTEMKEYDOWN = 0x104,
192
WM_SYSTEMKEYUP = 0x105
193
}
194
// API 类型.
195
/**//// <summary>
196
/// API 点.
197
/// </summary>
198
private struct PointApi
{
199
public int x
{ get; set; }
200
public int y
{ get; set; }
201
}
202
/**//// <summary>
203
/// 消息.
204
/// </summary>
205
private struct TMsg
{
206
public int hwnd
{ get; set; }
207
public int message
{ get; set; }
208
public int wParam
{ get; set; }
209
public int lParam
{ get; set; }
210
public int time
{ get; set; }
211
public PointApi pt
{ get; set; }
212
}
213
/**//// <summary>
214
/// 事件消息.
215
/// </summary>
216
private struct EventMsg
{
217
public int wMsg
{ get; set; }
218
public int lParamLow
{ get; set; }
219
public int lParamHigh
{ get; set; }
220
public int msgTime
{ get; set; }
221
public int hWndMsg
{ get; set; }
222
}
223
224
// API 函数声明.
225
public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
226
227
[DllImport("user32.dll")]
228
private static extern int CallNextHookEx(int hHook, int nCode, int wParam, IntPtr lParam);
229
[DllImport("user32.dll")]
230
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
231
[DllImport("user32.dll")]
232
private static extern bool UnhookWindowsHookEx(int idHook);
233
[DllImport("User32.dll")]
234
private static extern short GetAsyncKeyState(int vKey);
235
[DllImport("kernel32.dll")]
236
public static extern int GetCurrentThreadId();
237
238
// API 常量.
239
private const int WH_JOURNALRECORD = 0;
240
private const int WH_GETMESSAGE = 3;
241
#endregion
242
243
- 回调函数 -#region - 回调函数 -
244
/**//// <summary>
245
/// Journal 回调.
246
/// </summary>
247
/// <param name="nCode"></param>
248
/// <param name="wParam"></param>
249
/// <param name="lParam"></param>
250
/// <returns></returns>
251
private int JournalRecordProc(int nCode, int wParam, IntPtr lParam)
{
252
if (nCode < 0)
{
253
return CallNextHookEx(hJournalHook, nCode, wParam, lParam);
254
}
255
FireEvent(lParam);
256
return CallNextHookEx(hJournalHook, nCode, wParam, lParam);
257
}
258
259
/**//// <summary>
260
/// 应用程序钩子 回调.
261
/// </summary>
262
/// <param name="nCode"></param>
263
/// <param name="wParam"></param>
264
/// <param name="lParam"></param>
265
/// <returns></returns>
266
private int AppHookProc(int nCode, int wParam, IntPtr lParam)
{
267
if (nCode < 0)
{
268
return CallNextHookEx(hAppHook, nCode, wParam, lParam);
269
}
270
TMsg msg = (TMsg) Marshal.PtrToStructure(lParam, typeof(TMsg));
271
switch ((MessageType) msg.message)
{
272
case MessageType.WM_CANCELJOURNAL:
273
if (wParam == 1)
274
FireEvent(new IntPtr((int) MessageType.WM_CANCELJOURNAL));
275
break;
276
default:
277
break;
278
}
279
return CallNextHookEx(hAppHook, nCode, wParam, lParam);
280
}
281
282
#endregion
283
284
- 全局变量 -#region - 全局变量 -
285
// 全局变量.
286
private int hJournalHook, hAppHook;
287
private HookProc procJournal, procAppHook;
288
#endregion
289
290
- 构造方法 -#region - 构造方法 -
291
/**//// <summary>
292
/// 初始化 <see cref="StepMania.Utils.Hook"/> 类的新实例.
293
/// </summary>
294
public Hook()
{
295
if (!this.DesignMode)
{
296
hJournalHook = 0;
297
hAppHook = 0;
298
procAppHook = new HookProc(AppHookProc);
299
procJournal = new HookProc(JournalRecordProc);
300
301
SetHook();
302
}
303
}
304
#endregion
305
306
- 私有方法 -#region - 私有方法 -
307
/**//// <summary>
308
/// 取得当前上档键状态.
309
/// </summary>
310
/// <returns></returns>
311
private ShiftKey GetShiftNow()
{
312
ShiftKey shift = ShiftKey.None;
313
if (GetAsyncKeyState(0x10) != 0) //Shift
314
shift |= ShiftKey.Shift;
315
if (GetAsyncKeyState(0x11) != 0) //Control
316
shift |= ShiftKey.Control;
317
if (GetAsyncKeyState(0x12) != 0) //Menu
318
shift |= ShiftKey.Menu;
319
return shift;
320
}
321
322
/**//// <summary>
323
/// 取得当前鼠标按钮状态.
324
/// </summary>
325
/// <returns></returns>
326
private Button GetButtonNow()
{
327
Button button = Button.Left;
328
if (GetAsyncKeyState(0x1) != 0)
329
button |= Button.Left;
330
if (GetAsyncKeyState(0x2) != 0)
331
button |= Button.Right;
332
if (GetAsyncKeyState(0x4) != 0)
333
button |= Button.Middle;
334
return button;
335
}
336
337
/**//// <summary>
338
/// 得到消息,分析后触发事件.
339
/// </summary>
340
/// <param name="lParam"></param>
341
private void FireEvent(IntPtr lParam)
{
342
if (lParam.ToInt32() == (int) MessageType.WM_CANCELJOURNAL)
{
343
hJournalHook = 0;
344
SetHook();
345
return;
346
}
347
EventMsg EMSG = (EventMsg) Marshal.PtrToStructure(lParam, typeof(EventMsg));
348
switch ((MessageType) EMSG.wMsg)
{
349
case MessageType.WM_KEYDOWN:
350
if (KeyDown != null)
351
KeyDown(EMSG.lParamLow & 0xFF, GetShiftNow());
352
break;
353
case MessageType.WM_KEYUP:
354
if (KeyUp != null)
355
KeyUp(EMSG.lParamLow & 0xFF, GetShiftNow());
356
break;
357
case MessageType.WM_MOUSEMOVE:
358
if (MouseMove != null)
359
MouseMove(GetButtonNow(), GetShiftNow(), EMSG.lParamLow, EMSG.lParamHigh);
360
break;
361
case MessageType.WM_LBUTTONDOWN:
362
case MessageType.WM_RBUTTONDOWN:
363
case MessageType.WM_MBUTTONDOWN:
364
if (MouseDown != null)
365
MouseDown((Button) (Math.Pow(2, (EMSG.wMsg - 513) / 3)), GetShiftNow(),
366
EMSG.lParamLow, EMSG.lParamHigh);
367
break;
368
case MessageType.WM_LBUTTONUP:
369
case MessageType.WM_RBUTTONUP:
370
case MessageType.WM_MBUTTONUP:
371
if (MouseUp != null)
372
MouseUp((Button) (Math.Pow(2, (EMSG.wMsg - 513) / 3)), GetShiftNow(),
373
EMSG.lParamLow, EMSG.lParamHigh);
374
break;
375
case MessageType.WM_SYSTEMKEYDOWN:
376
if (SystemKeyDown != null)
377
SystemKeyDown(EMSG.lParamLow & 0xFF);
378
break;
379
case MessageType.WM_SYSTEMKEYUP:
380
if (SystemKeyUp != null)
381
SystemKeyUp(EMSG.lParamLow & 0xFF);
382
break;
383
default:
384
break;
385
}
386
}
387
#endregion
388
389
| 重写方法 |#region | 重写方法 |
390
/**//// <summary>
391
/// 释放由 <see cref="T:System.ComponentModel.Component"></see> 占用的非托管资源,还可以另外再释放托管资源.
392
/// </summary>
393
/// <param name="disposing">为 true 则释放托管资源和非托管资源;为 false 则仅释放非托管资源。</param>
394
protected override void Dispose(bool disposing)
{
395
RemoveHook();
396
base.Dispose(disposing);
397
}
398
#endregion
399
}
400
}
401

浙公网安备 33010602011771号