//hook 鼠标钩子 import win; var SetWindowsHookEx = ::User32.api("SetWindowsHookExW","pointer(int idHook,pointer lpfn, pointer hmod,INT dwThreadId)"); var CallNextHookEx = ::User32.api("CallNextHookEx","int( POINTER hhk,int nCode,INT wParam,int lParam)"); var UnhookWindowsHookEx = ::User32.api("UnhookWindowsHookEx","int(pointer hhk)"); var WH_MOUSE_LL = 14 MSLLHOOKSTRUCT = class{ struct pt ={int x;int y}; INT mouseData; INT flags; INT time; INT extraInfo; } var LowLevelMouseProc = function( nCode, wParam, lParam){ if ( ( nCode == 0/*_HC_ACTION*/ ) ) { var ll = MSLLHOOKSTRUCT(); ll = ..raw.convert(topointer(lParam),ll ); if( ( type(owner.proc) == type.function) && (owner.proc(wParam,ll.pt.x,ll.pt.y,ll.mouseData ,ll.flags & 1/*_LLMHF_INJECTED*/, ll.flags,ll.time,ll.extraInfo) ) ){ return 1; } } //MSDN: //If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. //If nCode is greater than or equal to zero, and the hook procedure did not process the message, //it is highly recommended that you call CallNextHookEx and return the value it returns; return CallNextHookEx(owner._hhk, nCode, wParam, lParam); } namespace mouse class hook{ ctor(){ var hinst = ::GetModuleHandle(); this._proc_c = ..raw.tostdcall( LowLevelMouseProc,"int(int nCode, int wParam, int lParam)",this) var hhk = SetWindowsHookEx(WH_MOUSE_LL,this._proc_c,hinst,0); this._hhk = hhk; ..table.gc(this,"close"); } close = function(){ if(hhk){ UnhookWindowsHookEx(hhk); hhk = null } } } /**details(重要说明) 低级鼠标钩子只能用于界面线程,并且依赖界面线程创建的消息循环。 低级鼠标钩子所在界面线程的任何耗时操作执行时间不应超过 200 毫秒。 耗时操作可能导致遗漏部分鼠标消息,如果耗时操作阻塞鼠标钩子消息超过一秒或超过注册表限制的更小时间, 系统可能会直接删除鼠标钩子(导致超级热键不可用)。 建议将阻塞消息循环的耗时操作放到后台工作线程内执行, 请参考:[创建多线程](../../../guide/language/thread.md)。 end details**/ /**intellisense() mouse.hook = 低级鼠标钩子。\n低级鼠标钩子只能用于包含窗口消息循环的界面线程。\n鼠标钩子所在的界面线程如果有阻塞钩子消息的耗时操作,可能导致遗漏鼠标消息。\n耗时操作阻塞鼠标钩子消息超过一秒或注册表限制的更小时间,系统可能导致钩子失效。\n建议将阻塞消息循环的耗时操作应当放到后台工作线程内执行。 mouse.hook() = 创建低级鼠标钩子\n!stdMouseHook. !stdMouseHook.proc = @.proc = function(msg,x,y,mouseData,injected,flags,timeStamp,extraInfo){ if( injected ) return;//忽略模拟按键 select(msg) { case 0x201/*_WM_LBUTTONDOWN*/{ io.print("左键按下",x,y) } case 0x202/*_WM_LBUTTONUP*/{ io.print("左键弹起",x,y) } } __/*取消调用 return true;\n注意钩子回调函数不要做耗时操作\n耗时操作应改用线程或 winform.setTimeout 异步执行*/ } !stdMouseHook.close() = 释放按键录制钩子 ?mouse.hook = !stdMouseHook. end intellisense**/