.NET 的钩子组件……(封装起来使得你不用写代码即可完成钩子的设置)
2008-12-24 02:04 Tsanie 阅读(3412) 评论(24) 收藏 举报开发中我们很多时候会遇到使用钩子的情况。
用户按下了个按键,我怎么捕捉的到?好,如果焦点在自己的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


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

195


196

197

198



199



200



201

202


203

204

205



206



207



208



209



210



211



212

213


214

215

216



217



218



219



220



221



222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243


244


245

246

247

248

249

250

251



252



253

254

255

256

257

258

259


260

261

262

263

264

265

266



267



268

269

270

271



272

273

274

275

276

277

278

279

280

281

282

283

284


285

286

287

288

289

290


291


292

293

294



295



296

297

298

299

300

301

302

303

304

305

306


307


308

309

310

311



312

313

314

315

316

317

318

319

320

321

322


323

324

325

326



327

328

329

330

331

332

333

334

335

336

337


338

339

340

341



342



343

344

345

346

347

348



349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389


390


391

392

393

394



395

396

397

398

399

400

401
