delphi – firemonkey和全球热键?
我正在寻找一种方法来加速firemonkey应用程序中的全局热键(仅限
Windows,至少目前为止).
经过一些挫折和谷歌搜索后,这应该工作: 用winapi电话注册热键 RegisterHotKey(FmxHandleToHWND(form1.Handle),MOD_CONTROL,$41); 它返回true. procedure WMHotKey(var Msg: TWMHotKey); message WM_HOTKEY; 但这个从未被称为. 编辑:应用该解决方案的一些示例.我创建了一个小班的单元 unit fire_hotkey; interface uses windows,messages,allocatehwnd; type TMsgHandler = procedure (var Msg: TMessage) of object; THotClass = class(TObject) fMsgHandlerHWND : HWND; proc:TMsgHandler; constructor Create; procedure init; destructor Destroy; override; end; implementation { hotClass } constructor THotClass.Create; begin inherited; end; destructor THotClass.Destroy; begin ThreadDeallocateHWnd(fMsgHandlerHWND); inherited; end; procedure THotClass.init; begin fMsgHandlerHWND := ThreadAllocateHWnd(proc,true); end; end. 然后我的主窗体有一个处理热键事件的过程: procedure TformEditor.WMHotKey(var Msg: TMessage); begin if Msg.Msg = WM_HOTKEY then begin //call lua function or sth //... end else Msg.Result := DefWindowProc(hotkeyGrabber.fMsgHandlerHWND,Msg.Msg,Msg.wParam,Msg.lParam); end; 并且有一个全球热键抓取:THotClass;在表单创建时初始化: hotkeyGrabber:=THotClass.Create; hotkeyGrabber.proc:=WMHotKey; hotkeyGrabber.init; 在那之后你应该像通常的vcl应用程序一样注册热键,他们将是cought 解决方法
FMX框架不会将消息路由到您的表单.因此,永远不会调用您的WMHotKey,因为FMX框架从不调用Dispatch.您可以通过检查FMX.Platform.Win单元的实现部分中声明的WndProc方法来查看这种情况.
解决此问题的最简单方法是通过调用CreateWindow创建自己的窗口.然后为该窗口实现一个窗口过程来处理WM_HOTKEY消息. 我已经包装了这样的低级API调用: unit AllocateHWnd; interface uses System.SysUtils,System.Classes,System.SyncObjs,Winapi.Messages,Winapi.Windows; function ThreadAllocateHWnd(AMethod: TWndMethod; MessageOnly: Boolean): HWND; procedure ThreadDeallocateHWnd(Wnd: HWND); implementation const GWL_METHODCODE = SizeOf(Pointer)*0; GWL_METHODDATA = SizeOf(Pointer)*1; ThreadAllocateHWndClassName = 'MyCompanyName_ThreadAllocateHWnd'; var ThreadAllocateHWndLock: TCriticalSection; ThreadAllocateHWndClassRegistered: Boolean; function ThreadAllocateHWndProc(Window: HWND; Message: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var Proc: TMethod; Msg: TMessage; begin Proc.Code := Pointer(GetWindowLongPtr(Window,GWL_METHODCODE)); Proc.Data := Pointer(GetWindowLongPtr(Window,GWL_METHODDATA)); if Assigned(TWndMethod(Proc)) then begin Msg.Msg := Message; Msg.wParam := wParam; Msg.lParam := lParam; Msg.Result := 0; TWndMethod(Proc)(Msg); Result := Msg.Result end else begin Result := DefWindowProc(Window,Message,wParam,lParam); end; end; function ThreadAllocateHWnd(AMethod: TWndMethod; MessageOnly: Boolean): HWND; procedure RegisterThreadAllocateHWndClass; var WndClass: TWndClass; begin if ThreadAllocateHWndClassRegistered then begin exit; end; ZeroMemory(@WndClass,SizeOf(WndClass)); WndClass.lpszClassName := ThreadAllocateHWndClassName; WndClass.hInstance := HInstance; WndClass.lpfnWndProc := @ThreadAllocateHWndProc; WndClass.cbWndExtra := SizeOf(TMethod); Winapi.Windows.RegisterClass(WndClass); ThreadAllocateHWndClassRegistered := True; end; begin ThreadAllocateHWndLock.Acquire; Try RegisterThreadAllocateHWndClass; if MessageOnly then begin Result := CreateWindow(ThreadAllocateHWndClassName,'',HWND_MESSAGE,HInstance,nil); end else begin Result := CreateWindowEx(WS_EX_TOOLWINDOW,ThreadAllocateHWndClassName,WS_POPUP,nil); end; Win32Check(Result<>0); SetWindowLongPtr(Result,GWL_METHODDATA,NativeInt(TMethod(AMethod).Data)); SetWindowLongPtr(Result,GWL_METHODCODE,NativeInt(TMethod(AMethod).Code)); Finally ThreadAllocateHWndLock.Release; End; end; procedure ThreadDeallocateHWnd(Wnd: HWND); begin Win32Check(DestroyWindow(Wnd)); end; initialization ThreadAllocateHWndLock := TCriticalSection.Create; finalization ThreadAllocateHWndLock.Free; end. 这是VCL AllocateHWnd的线程安全版本,它因在主线程外部无法使用而臭名昭着. 你需要做的是创建一个带有窗口过程的类,即实现TWndMethod的东西.它可以是实例方法或类方法.然后只需调用ThreadAllocateHWnd来创建窗口,并将该窗口传递给RegisterHotKey.什么时候解开它,取消注册你的热键,并通过调用ThreadDeallocateHWnd来销毁窗口. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |