加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – firemonkey和全球热键?

发布时间:2020-12-15 09:18:29 所属栏目:大数据 来源:网络整理
导读:我正在寻找一种方法来加速firemonkey应用程序中的全局热键(仅限 Windows,至少目前为止). 经过一些挫折和谷歌搜索后,这应该工作: 用winapi电话注册热键 RegisterHotKey(FmxHandleToHWND(form1.Handle),MOD_CONTROL,$41); 它返回true. 然后在表单的过程中捕获
我正在寻找一种方法来加速firemonkey应用程序中的全局热键(仅限 Windows,至少目前为止).
经过一些挫折和谷歌搜索后,这应该工作:
用winapi电话注册热键

RegisterHotKey(FmxHandleToHWND(form1.Handle),MOD_CONTROL,$41);

它返回true.
然后在表单的过程中捕获热键

procedure WMHotKey(var Msg: TWMHotKey); message WM_HOTKEY;

但这个从未被称为.
我之前习惯在vcl应用程序中这样做,所以我的猜测是firemonkey以不同的方式处理消息.
所以问题是:如何在firemonkey app中捕获全局热键?

编辑:应用该解决方案的一些示例.我创建了一个小班的单元

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
http://www.swissdelphicenter.ch/torry/showcode.php?id=147
希望它有意义

解决方法

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来销毁窗口.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读