CnKeyBlocker.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnKeyBlocker;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包
  24. * 单元名称:通过键盘钩子屏蔽系统键的组件
  25. * 单元作者:匿名
  26. * 移 植:刘啸 (liuxiao@cnpack.org)
  27. * 备 注:此组件通过实现键盘钩子来屏蔽某些系统键,但 Ctrl+Alt+Del 组合键可能
  28. * 因为系统自身处理原因而无法屏蔽。
  29. * 开发平台:PWinXP + Delphi 7.0 (Build 8.1)
  30. * 兼容测试:PWin2003 + Delphi 7.0 (Build 8.1)
  31. * 本 地 化:该单元中无字符串资源
  32. * 单元标识:$Id$
  33. * 修改记录:2008.10.24 v1.1
  34. * 加入一简陋事件
  35. * 2008.05.29 v1.0
  36. * 移植单元
  37. ================================================================================
  38. |</PRE>}
  39. interface
  40. {$I CnPack.inc}
  41. uses
  42. SysUtils, Classes, windows, ShlObj, Registry, Shellapi, Messages;
  43. type
  44. TCnBlockKeyEvent = procedure(VirtualKey: Cardinal) of object;
  45. TCnKeyBlocker = class(TComponent)
  46. private
  47. FBCAD: Boolean;
  48. FBAT: Boolean;
  49. FBCE: Boolean;
  50. FEnabled: Boolean;
  51. FBAE: Boolean;
  52. FBCR: Boolean;
  53. FBCK: Boolean;
  54. FBP: Boolean;
  55. FBS: Boolean;
  56. FCKC: Cardinal;
  57. FBWA: Boolean;
  58. FBCAE: Boolean;
  59. FOnBlockKey: TCnBlockKeyEvent;
  60. procedure SetBCAD(const Value: Boolean);
  61. procedure SetBAT(const Value: Boolean);
  62. procedure SetBCE(const Value: Boolean);
  63. procedure SetEnabled(const Value: Boolean);
  64. procedure SetBAE(const Value: Boolean);
  65. procedure SetBCK(const Value: Boolean);
  66. procedure SetBCR(const Value: Boolean);
  67. procedure SetBP(const Value: Boolean);
  68. procedure SetBS(const Value: Boolean);
  69. procedure SetBWA(const Value: Boolean);
  70. procedure SetBCAE(const Value: Boolean);
  71. protected
  72. procedure UpdateKeyBlock;
  73. procedure DoBlock(VirtualKey: Cardinal);
  74. property BlockCtrlAltDelete: Boolean read FBCAD write SetBCAD;
  75. {* 是否屏蔽 Ctrl+Alt+Delete 键,此属性可能无法工作,暂时不开放}
  76. public
  77. constructor Create(AOwner: TComponent); override;
  78. destructor Destroy; override;
  79. published
  80. property BlockAltTab: Boolean read FBAT write SetBAT;
  81. {* 是否屏蔽 Alt+Tab 键}
  82. property BlockCtrlEsc: Boolean read FBCE write SetBCE;
  83. {* 是否屏蔽 Ctrl+Esc 键}
  84. property BlockAltEsc: Boolean read FBAE write SetBAE;
  85. {* 是否屏蔽 Alt+Esc 键}
  86. property BlockCtrlEnter: Boolean read FBCR write SetBCR;
  87. {* 是否屏蔽 Ctrl+Enter 键}
  88. property BlockSleep: Boolean read FBS write SetBS;
  89. {* 是否屏蔽 Sleep 休眠键}
  90. property BlockPower: Boolean read FBP write SetBP;
  91. {* 是否屏蔽 Power 电源键}
  92. property BlockWinApps: Boolean read FBWA write SetBWA;
  93. {* 是否屏蔽 Windows 键}
  94. property BlockCtrlAltEnter: Boolean read FBCAE write SetBCAE;
  95. {* 是否屏蔽 Ctrl+Alt+Enter 键}
  96. property CustomKeyCode: Cardinal read FCKC write FCKC default 0;
  97. {* 自定义的屏蔽键}
  98. property BlockCustomKey: Boolean read FBCK write SetBCK;
  99. {* 是否屏蔽自定义键}
  100. property Enabled: Boolean read FEnabled write SetEnabled default False;
  101. {* 是否使能屏蔽功能}
  102. property OnBlockKey: TCnBlockKeyEvent read FOnBlockKey write FOnBlockKey;
  103. {* 屏蔽键时触发的事件,由于复杂性,参数中只指明虚拟键,并且由于挂接机制本身
  104. 的机制,此事件无 Sender。}
  105. end;
  106. implementation
  107. const
  108. LLKHF_ALTDOWN = KF_ALTDOWN shr 8;
  109. WH_KEYBOARD_LL = 13;
  110. type
  111. PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
  112. KBDLLHOOKSTRUCT = packed record
  113. vkCode: DWORD;
  114. scanCode: DWORD;
  115. flags: DWORD;
  116. Time: DWORD;
  117. dwExtraInfo: DWORD;
  118. end;
  119. var
  120. hhkNTKeyboard: HHOOK = 0;
  121. aBCAD: Boolean = False;
  122. aBWA: Boolean = False;
  123. aBCE: Boolean = False;
  124. aBAT: Boolean = False;
  125. aBAE: Boolean = False;
  126. aBCR: Boolean = False;
  127. aBCAE: Boolean = False;
  128. aBP: Boolean = False;
  129. aaBS: Boolean = False;
  130. aBCK: Boolean = False;
  131. aCKC: Cardinal = 0;
  132. FKeyBlocker: TCnKeyBlocker = nil;
  133. { TCnKeyBlocker }
  134. constructor TCnKeyBlocker.Create(AOwner: TComponent);
  135. begin
  136. inherited Create(AOwner);
  137. FKeyBlocker := Self;
  138. end;
  139. procedure EnableCTRLALTDEL(YesNo: Boolean);
  140. const
  141. sRegPolicies = '\Software\Microsoft\Windows\CurrentVersion\Policies';
  142. begin
  143. with TRegistry.Create do
  144. try
  145. RootKey := HKEY_CURRENT_USER;
  146. if OpenKey(sRegPolicies + '\System\', True) then
  147. begin
  148. case YesNo of
  149. False:
  150. begin
  151. WriteInteger('DisableTaskMgr', 1); //任务管理
  152. WriteInteger('DisableLockWorkstation', 1); //用户锁定计算机
  153. WriteInteger('DisableChangePassword', 1); //用户更改口令
  154. end;
  155. True:
  156. begin
  157. WriteInteger('DisableTaskMgr', 0);
  158. WriteInteger('DisableLockWorkstation', 0);
  159. WriteInteger('DisableChangePassword', 0);
  160. end;
  161. end;
  162. end;
  163. CloseKey;
  164. if OpenKey(sRegPolicies + '\Explorer\', True) then
  165. begin
  166. case YesNo of
  167. False:
  168. begin
  169. WriteInteger('NoChangeStartMenu', 1); //开始菜单
  170. WriteInteger('NoClose', 1); // 关闭系统菜单
  171. WriteInteger('NoLogOff', 1); //注销菜单
  172. WriteInteger('NoRun', 1); //运行菜单
  173. WriteInteger('NoSetFolders', 1); //设置菜单
  174. end;
  175. True:
  176. begin
  177. WriteInteger('NoChangeStartMenu', 0);
  178. WriteInteger('NoClose', 0);
  179. WriteInteger('NoLogOff', 0);
  180. WriteInteger('NoRun', 0);
  181. end;
  182. end;
  183. end;
  184. CloseKey;
  185. finally
  186. Free;
  187. end;
  188. end;
  189. function LowLevelKeyboardFunc(nCode: INTEGER; w_Param: WPARAM;
  190. l_Param: LPARAM): LRESULT; stdcall;
  191. var
  192. boolKey: Boolean;
  193. p: PKBDLLHOOKSTRUCT;
  194. const
  195. VK_SLEEP = $5F;
  196. VK_POWER = $5E;
  197. begin
  198. boolKey := False;
  199. p := nil;
  200. if nCode = HC_ACTION then
  201. begin
  202. case w_Param of
  203. WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP:
  204. begin
  205. p := PKBDLLHOOKSTRUCT(l_Param);
  206. //---------!-~------------------------------------------------
  207. { if ((GetAsyncKeyState(VK_RBUTTON) and $8000) <> 0) then boolKey := True;
  208. if (CHAR(p.vkCode) >= '!') and (CHAR(p.vkCode) <= '~') and
  209. ((GetKeyState(VK_CONTROL) and $8000) <> 0) then boolKey := True;
  210. if (p.vkCode = VK_SPACE) and
  211. ((GetKeyState(VK_CONTROL) and $8000) <> 0) then boolKey := True; }
  212. //---------F1-F12 ----------------------------------------------
  213. { if (p.vkCode = VK_F1) or (p.vkCode = VK_F2) or (p.vkCode = VK_F3) or
  214. (p.vkCode = VK_F4) or (p.vkCode = VK_F5) or (p.vkCode = VK_F6) or
  215. (p.vkCode = VK_F7) or (p.vkCode = VK_F8) or (p.vkCode = VK_F9) or
  216. (p.vkCode = VK_F10) or (p.vkCode = VK_F11) or (p.vkCode = VK_F12) then
  217. boolKey := True;
  218. if ((p.vkCode = VK_F1) or (p.vkCode = VK_F2) or (p.vkCode = VK_F3) or
  219. (p.vkCode = VK_F4) or (p.vkCode = VK_F5) or (p.vkCode = VK_F6) or
  220. (p.vkCode = VK_F7) or (p.vkCode = VK_F8) or (p.vkCode = VK_F9) or
  221. (p.vkCode = VK_F10) or (p.vkCode = VK_F11) or (p.vkCode = VK_F12)) and
  222. (((GetKeyState(VK_MENU) and $8000) <> 0) or ((GetKeyState(VK_CONTROL) and $8000) <> 0)
  223. or ((GetKeyState(VK_SHIFT)and$8000) <> 0)) then
  224. boolKey := True; }
  225. //-------系统热键---------------------------------------------
  226. //WIN(Left or Right)+APPS
  227. if aBWA then
  228. begin
  229. if (p.vkCode = VK_LWIN) or (p.vkCode = VK_RWIN) or (p.vkCode = VK_APPS) then
  230. boolKey := True;
  231. end;
  232. //CTRL+ESC
  233. if aBCE then
  234. begin
  235. if (p.vkCode = VK_ESCAPE) and ((GetKeyState(VK_CONTROL) and $8000) <> 0) then
  236. boolKey := True;
  237. end;
  238. //ALT+TAB
  239. if aBAT then
  240. begin
  241. if (p.vkCode = VK_TAB) and ((GetAsyncKeyState(VK_MENU) and $8000) <> 0) then
  242. boolKey := True;
  243. end;
  244. //ALT+ESC
  245. if aBAE then
  246. begin
  247. if (p.vkCode = VK_ESCAPE) and ((p.flags and LLKHF_ALTDOWN) <> 0) then
  248. boolKey := True;
  249. end;
  250. //CTRL+ENTER
  251. if aBCR then
  252. begin
  253. if (p.vkCode = VK_RETURN) and ((GetKeyState(VK_CONTROL) and $8000) <> 0) then
  254. boolKey := True;
  255. end;
  256. //CTRL+ALT+ENTR
  257. if aBCAE then
  258. begin
  259. if (p.vkCode = VK_RETURN) and ((p.flags and LLKHF_ALTDOWN) <> 0)
  260. and ((GetKeyState(VK_CONTROL) and $8000) <> 0) then
  261. boolKey := True;
  262. end;
  263. //POWER
  264. if aBP then
  265. begin
  266. if (p.vkCode = VK_POWER) then
  267. boolKey := True;
  268. end;
  269. //SLEEP
  270. if aaBS then
  271. begin
  272. if (p.vkCode = VK_SLEEP) then
  273. boolKey := True;
  274. end;
  275. //Custom
  276. if aBCK then
  277. begin
  278. if (p.vkCode = aCKC) then
  279. boolKey := True;
  280. end;
  281. //如果有其他要屏闭的键,添加在此处
  282. end;
  283. end;
  284. end;
  285. //捕获这些组合键,按键消息由自己处理,必须返回 1
  286. if boolKey and (p <> nil) then
  287. begin
  288. FKeyBlocker.DoBlock(p.vkCode);
  289. Result := 1;
  290. Exit;
  291. end;
  292. //其他的按键,交由别的线程处理(过滤)
  293. Result := CallNextHookEx(0, nCode, w_Param, l_Param);
  294. end;
  295. destructor TCnKeyBlocker.Destroy;
  296. begin
  297. Enabled := False;
  298. FKeyBlocker := nil;
  299. inherited Destroy;
  300. end;
  301. procedure TCnKeyBlocker.DoBlock(VirtualKey: Cardinal);
  302. begin
  303. if Assigned(FOnBlockKey) then
  304. FOnBlockKey(VirtualKey);
  305. end;
  306. procedure TCnKeyBlocker.SetBAE(const Value: Boolean);
  307. begin
  308. FBAE := Value;
  309. aBAE := FBAE;
  310. end;
  311. procedure TCnKeyBlocker.SetBAT(const Value: Boolean);
  312. begin
  313. FBAT := Value;
  314. aBAT := FBAT;
  315. end;
  316. procedure TCnKeyBlocker.SetBCAD(const Value: Boolean);
  317. begin
  318. FBCAD := Value;
  319. aBCAD := FBCAD;
  320. end;
  321. procedure TCnKeyBlocker.SetBCAE(const Value: Boolean);
  322. begin
  323. FBCAE := Value;
  324. aBCAE := FBCAE;
  325. end;
  326. procedure TCnKeyBlocker.SetBCE(const Value: Boolean);
  327. begin
  328. FBCE := Value;
  329. aBCE := FBCE;
  330. end;
  331. procedure TCnKeyBlocker.SetBCK(const Value: Boolean);
  332. begin
  333. FBCK := Value;
  334. aBCK := FBCK;
  335. end;
  336. procedure TCnKeyBlocker.SetBCR(const Value: Boolean);
  337. begin
  338. FBCR := Value;
  339. aBCR := FBCR;
  340. end;
  341. procedure TCnKeyBlocker.SetBP(const Value: Boolean);
  342. begin
  343. FBP := Value;
  344. aBP := FBP;
  345. end;
  346. procedure TCnKeyBlocker.SetBS(const Value: Boolean);
  347. begin
  348. FBS := Value;
  349. aaBS := FBS;
  350. end;
  351. procedure TCnKeyBlocker.SetBWA(const Value: Boolean);
  352. begin
  353. FBWA := Value;
  354. aBWA := FBWA;
  355. end;
  356. procedure TCnKeyBlocker.SetEnabled(const Value: Boolean);
  357. begin
  358. FEnabled := Value;
  359. UpdateKeyBlock;
  360. end;
  361. procedure TCnKeyBlocker.UpdateKeyBlock;
  362. begin
  363. if csDesigning in ComponentState then
  364. Exit;
  365. case FEnabled of
  366. True:
  367. begin
  368. if hhkNTKeyboard <> 0 then
  369. Exit;
  370. hhkNTKeyboard := SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardFunc, HInstance, 0);
  371. if FBCAD then
  372. begin
  373. EnableCTRLALTDEL(False);
  374. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  375. end;
  376. end;
  377. False:
  378. begin
  379. if hhkNTKeyboard = 0 then
  380. Exit;
  381. UnhookWindowsHookEx(hhkNTKeyboard); // 卸载钩子
  382. EnableCTRLALTDEL(True);
  383. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  384. hhkNTKeyboard := 0;
  385. end;
  386. end;
  387. end;
  388. end.