You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows11更新KB5060829/KB5062553后Delphi中TTouchKeyboard抢占TChromium焦点问题

针对Windows 11 KB更新后TChromium与TTouchKeyboard触摸焦点冲突的解决方案思路

问题核心

Windows 11安装KB5060829/KB5062553更新后,触摸点击同一窗体中的TTouchKeyboard会夺走TChromium内网页输入元素的焦点,仅触摸操作受影响,常规VCL控件无此问题,拦截WM_MOUSEACTIVATE无效。

可行解决方案思路

1. 拦截TTouchKeyboard的触摸专属消息,阻止控件激活

触摸操作触发的是WM_POINTERDOWN/WM_TOUCH系列消息(而非传统鼠标消息),可以通过自定义TTouchKeyboard子类拦截这些消息,避免控件获得激活:

type
  TCustomTouchKeyboard = class(TTouchKeyboard)
  protected
    procedure WndProc(var Message: TMessage); override;
  end;

procedure TCustomTouchKeyboard.WndProc(var Message: TMessage);
begin
  // 拦截触摸按下消息,阻止控件激活
  case Message.Msg of
    WM_POINTERDOWN, WM_TOUCH:
      begin
        // 先执行原按键逻辑(保留键盘功能)
        inherited;
        // 阻止控件获得焦点激活
        Message.Result := 0;
        Exit;
      end;
    WM_ACTIVATE:
      begin
        // 拦截激活消息,拒绝成为活动控件
        if WA_ACTIVE = Message.WParam then
        begin
          Message.Result := 0;
          Exit;
        end;
      end;
  end;
  inherited;
end;

将原TTouchKeyboard替换为这个自定义类使用。

2. 按键触发后强制恢复TChromium焦点

在TTouchKeyboard的按键事件中,先处理输入传递,再强制将焦点切回TChromium或网页输入元素:

procedure TMainForm.TouchKeyboardKeyPress(Sender: TObject; var Key: Char);
begin
  // 1. 将按键事件直接发送给TChromium(通过CEF API)
  if Chromium1.Browser <> nil then
  begin
    var KeyEvent := TCefKeyEvent.Create;
    try
      KeyEvent.windows_key_code := Ord(Key);
      KeyEvent.type_ := KEYEVENT_CHAR;
      Chromium1.Browser.GetHost.SendKeyEvent(KeyEvent);
    finally
      KeyEvent.Free;
    end;
  end;

  // 2. 恢复TChromium控件焦点
  Chromium1.SetFocus;

  // 3. 可选:执行JS让网页原输入框重新聚焦
  if Chromium1.Browser <> nil then
    Chromium1.Browser.MainFrame.ExecuteJavaScript('document.activeElement.focus();', '', 0);
end;

3. 修改TChromium窗口属性,增强焦点锁定

在Chromium初始化后,修改窗口样式以强化焦点保持:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  // 在Chromium初始化后,添加控件父窗口样式增强焦点优先级
  if Chromium1.HandleAllocated then
  begin
    SetWindowLongPtr(Chromium1.Handle, GWL_EXSTYLE, 
      GetWindowLongPtr(Chromium1.Handle, GWL_EXSTYLE) or WS_EX_CONTROLPARENT);
  end;
end;

也可在CEF的OnAfterCreated事件中强制锁定焦点:

procedure TMainForm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
  browser.GetHost.SetFocus(True);
end;

4. 拦截主窗体的焦点变更消息

在主窗体的WndProc中拦截WM_SETFOCUS消息,当目标控件是TTouchKeyboard时,强制将焦点切回TChromium:

procedure TMainForm.WndProc(var Message: TMessage);
begin
  if Message.Msg = WM_SETFOCUS then
  begin
    // 判断即将获得焦点的是TTouchKeyboard
    if TWinControl(Message.WParam) = TouchKeyboard1 then
    begin
      // 强制将焦点切回TChromium
      Chromium1.SetFocus;
      Message.Result := 0;
      Exit;
    end;
  end;
  inherited;
end;

内容的提问来源于stack exchange,提问作者Koen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:35:18