首页 > 解决方案 > 如何使用模态窗口将 WM_INPUTLANGCHANGEREQUEST 发送到应用程序?

问题描述

我写了一个键盘切换器,效果很好,但是如果当前应用程序打开了模式窗口,则会失败。在键盘开关上,我执行以下操作

hwnd = GetForegroundWindow();
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, handle);

在哪里

[DllImport("User32.dll", EntryPoint = "PostMessage")]
private static extern int PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

但语言没有改变。

我将如何做到这一点?


添加 get root owner 改善了情况,但并没有完全帮助。

添加调用GetDesktopWindow没有帮助:

hwnd = GetDesktopWindow();
InputLangChangeRequest(hwnd, language);
hwnd = GetRootOwner();
InputLangChangeRequest(hwnd, language);

代码在这里https://github.com/dims12/NormalKeyboardSwitcher

标签: c#winapimodal-dialogpostmessage

解决方案


利用GetAncestor

通过遍历 GetParent 返回的父窗口和所有者窗口链来检索拥有的根窗口。

如果有模态窗口或模态窗口链,这应该返回主 UI 窗口。

hwnd = GetForegroundWindow();
hwnd = GetAncestor(hwnd, GA_ROOTOWNER); //#define GA_ROOTOWNER 3


如果目标本身是基于对话框的应用程序,显然WM_INPUTLANGCHANGEREQUEST会失败(我不知道为什么!)要解决问题,您可以WM_INPUTLANGCHANGEREQUEST向对话框的后代发布消息(除了向WM_INPUTLANGCHANGEREQUEST对话框本身发送消息)

static bool MyEnumProc(IntPtr hwnd, IntPtr lParam)
{
    PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, lParam);
    return true;
}

static void Foo()
{
    //Greek input for testing:
    var hkl = LoadKeyboardLayout("00000408", KLF_ACTIVATE);
    var hwnd = GetForegroundWindow();
    if (hwnd != null)
    {
        hwnd = GetAncestor(hwnd, GA_ROOTOWNER);
        PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, (IntPtr)hkl);

        StringBuilder buf = new StringBuilder(100);
        GetClassName(hwnd, buf, 100);

        //if this is a dialog class then post message to all descendants 
        if (buf.ToString() == "#32770")
            EnumChildWindows(hwnd, MyEnumProc, (IntPtr)hkl);
    }
}

推荐阅读