【问题标题】:How to obtain keyboard layout for Microsoft Edge and other windows hosted in ApplicationFrameHost.exe如何获取 Microsoft Edge 和 ApplicationFrameHost.exe 中托管的其他窗口的键盘布局
【发布时间】:2019-01-27 11:22:46
【问题描述】:

众所周知,Windows 的键盘布局是特定于线程的。当布局更改时,shell 会向前台线程发送一条消息。因此,如果想要获得最新的系统范围的键盘布局,则必须执行以下操作:

const HWND foregroundWindow = ::GetForegroundWindow();
const DWORD foregroundThread = ::GetWindowThreadProcessId(foregroundWindow, NULL);
const HKL layout = ::GetKeyboardLayout(foregroundThread);

这适用于大多数原生 Windows 应用程序。

但是,UWP 应用程序和包括 Microsoft Edge 在内的多个系统应用程序将其窗口托管在 ApplicationFrameHost.exe 中。这会导致::GetForegroundWindow() 返回所述进程的窗口,从而导致几个奇怪的问题,包括misdetection of the foreground process 和检测实际键盘布局的麻烦。

ApplicationFrameHost.exe 的线程根本不会对系统范围的键盘布局更改做出反应。似乎他们没有托管实际的重点 UI 元素。 ::GetForegroundWindow() 只返回框架窗口,但实际的 UI 元素有自己的线程,并且可能由自己的进程托管。因此,前台框架窗口根本没有收到相应的布局更改消息,并且它的线程有一个陈旧的HKL 与之关联。

如何检测前台进程的正确 HKL?

【问题讨论】:

    标签: windows winapi uwp microsoft-edge keyboard-layout


    【解决方案1】:

    诀窍是完全停止依赖GetForegroundWindow() 方法。

    相反,我通过使用古怪且违反直觉的 documented specific usecase of GetGUIThreadInfo() 解决了这个问题。

    如果您将零作为第一个参数传递给此函数,它将返回前台线程的信息——即接收实际用户输入的线程!

    这个线程也会及时收到来自 shell 的 HKL 相关消息,所以键盘布局不会过时。

    GUITHREADINFO gti = { sizeof(GUITHREADINFO) };
    
    // fetching the foreground thread info
    ::GetGUIThreadInfo(0, &gti);
    
    // you may also fallback to other window handles in the GUITHREADINFO
    // if the `hwndFocus == NULL`
    const DWORD thread = ::GetWindowThreadProcessId(gti.hwndFocus, NULL);
    const HKL layout = ::GetKeyboardLayout(thread);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-14
      • 2015-11-05
      • 2010-09-20
      • 2016-05-24
      • 1970-01-01
      • 2013-07-19
      • 2021-06-23
      • 2023-03-25
      相关资源
      最近更新 更多