Delphi检测嵌入式应用程序中的击键

时间:2014-01-28 22:19:20

标签: delphi delphi-xe2 hotkeys multiprocess

我正在开发一个多进程应用程序,其中每个文档都在一个新进程中打开。 它的行为类似于Google Chrome。

一切正常,除此之外:

当嵌入式应用程序中的任何控件处于活动状态时,主窗口(包含嵌入式窗口)不会收到击键(例如Ctrl + N等)。 我理解这样一个事实,即嵌入式窗口在不同的进程中运行,这就是它不起作用的原因。

我需要做什么:

  • 主窗口应检测嵌入窗口中按下的键击
  • 如果主窗口有分配给击键的内容,主窗口应该会收到键盘快捷键而不是嵌入的表格。

一些重要细节:

  • 我可以控制两个进程的源代码(它是相同的exe,具有不同的行为)
  • 我正在使用按键动作
  • 更新:我使用WM_COPYDATA进行IPC(发送记录)
  • 更新:只有一个UI流程(又名主窗口)

嵌入代码:

此代码将其他进程的窗口嵌入主UI窗口。 它由WM_COPYDATA处理程序根据接收的值直接调用。

procedure TWTextAppFrame.adoptChild(WindowHandle: Cardinal; Container: TWinControl);
var
  WindowStyle : Integer;
  FAppThreadID: Cardinal;
  ts          : TTabSheet;
begin

  /// Set running app window styles.

  WindowStyle := GetWindowLong(WindowHandle, GWL_STYLE);
  WindowStyle := (WindowStyle and not WS_POPUP) or WS_CHILD;

  SetWindowLong(WindowHandle, GWL_STYLE, WindowStyle);


  /// Attach container app input thread to the running app input thread, so that
  ///  the running app receives user input.
  FAppThreadID := GetWindowThreadProcessId(WindowHandle, nil);
  AttachThreadInput(GetCurrentThreadId, FAppThreadId, True);

  /// Changing parent of the running app to our provided container control

  /// The window will be embedded on a tabsheet
  ts := TTabSheet.Create(Self);
  ts.TabVisible := false;
  ts.PageControl := WindowPages;
  ts.Tag := WindowHandle;

  Winapi.Windows.SetParent(WindowHandle,ts.Handle);
  SendMessage(Container.Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0);
  UpdateWindow(WindowHandle);

  /// This prevents the parent control to redraw on the area of its child windows (the running app)
  SetWindowLong(Container.Handle, GWL_STYLE, GetWindowLong(Container.Handle,GWL_STYLE) or WS_CLIPCHILDREN);
  /// Make the running app to fill all the client area of the container
  SetWindowPos(
      WindowHandle,
      0,
      0,
      0,
      Container.ClientWidth,
      Container.
      ClientHeight,SWP_NOZORDER
  );

  /// This creates a small object which holds some info about the embedded window
  /// (Document dirty status, embedded window handle, file name, etc. )
  /// The main window uses this to identify an embedded window, and also for tracking the processes
  AddHandleToControlList(WindowHandle,PChar('win'+IntToStr(WindowHandle)), 0, 0, 0, 0, alClient,ts);

  /// Page control holding all the tabsheet
  WindowPages.ActivePage := ts;

  /// activate the embedded window
  SetForegroundWindow(WindowHandle);
end;

这是子进程通知主窗口的方式:

/// Record sent through

TSendData = Packed Record
  sender: Cardinal; /// The handle of the sender window
  s  : WideString;  /// String data
  i  : Integer;  /// Integer data, usually and identifier for a function (defined with constants)
  i2 : Integer; /// Status, or other integer data
  b  : boolean; /// boolean information 
End;

var WData: TSendData;

///...

WData.sender := Self.Handle;
WData.i := WE_SETPARENT;

/// SendCommand is a wrapper function around the WM_COPYDATA sending code
SendCommand(Self.Handle, MainWindow, WData);

到目前为止我有什么?

我使用WM_COPYDATA作为IPC。

还没有任何代码,只有一个想法,即将热键列表发送到嵌入的表单,并将它们注册为那里的操作。当以嵌入的形式执行操作时,按键将被发送到主窗体。

这个想法不是一个优雅的解决方案,我想知道,如果有一个更好的解决方案,如果有,那会是什么。

0 个答案:

没有答案