1

我在更改键盘挂钩内的键盘布局时遇到问题。在这个简单的代码中,当按下'A'键时,改变语言需要很长时间,在更复杂的情况下,应用程序会做错事。

应用程序在托盘中工作,因此我使用了钩子。我的代码有什么问题?)) 或者,也许有不同的方法来改变键盘布局,这适用于钩子?感谢您的回答。

private static bool nextKey = false;

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
    uint tpid = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
    ushort currentLayout = GetKeyboardLayout(tpid);

    if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) {
        if (nextKey) {
            Console.WriteLine("changing to english...");
            PostMessage(GetForegroundWindow(), 0x0050, 0, (int) LoadKeyboardLayout("00000409", 0x00000001));
            nextKey = false;
        }

        int vkCode = Marshal.ReadInt32(lParam);

        if (vkCode == 0x41 && currentLayout == 0x409) { // if language is rus and 'A' pressed
            Console.WriteLine("changing to russian...");
            PostMessage(GetForegroundWindow(), 0x0050, 0, (int) LoadKeyboardLayout("00000419", 0x00000001));
            nextKey = true;
        }
    }
    return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
4

1 回答 1

0

在尝试修复此代码之前,我不得不问几个愚蠢的问题:

  1. 为什么你需要在钩子里面做这个?
  2. 为什么你需要这样做?您可以指定热键以在键盘控制面板中选择输入语言(区域和语言 → 键盘和语言 → 更改键盘 → 高级键设置)。并且每当您启用多种输入语言时,您的任务栏上都会放置一个图标。你不需要编写自己的应用程序来做这些事情。

现在,专门查看您的代码,您正在做的是将WM_INPUTLANGCHANGEREQUEST消息发布到前台窗口。但是这个消息是一个通知。它通知程序用户请求更改输入语言。它并非旨在允许程序向其他程序发出更改输入语言的请求。

如果一个程序想要改变它自己的键盘布局,它会调用这个ActivateKeyboardLayout函数。但是没有必要从 .NET 应用程序 p/invoke 这个函数。该框架已经将所有这些都包含在InputLanguage类中——强烈推荐。

除此之外,您未显示的代码,属于其他应用程序的代码中不可避免地存在其他问题。您向其发布消息的前台窗口可以WM_INPUTLANGCHANGEREQUEST选择通过将消息传递到 来接受更改DefWindowProc,或者通过返回 0 作为响应来拒绝更改。如果一个损坏的应用程序只为它没有明确处理的所有消息返回 0 ,它就不会做正确的事情。或者,如果一个应用程序被编写为明确拒绝WM_INPUTLANGCHANGEREQUEST请求,它不会做你所期望的。等等。你无法控制这些事情。记住,WM_INPUTLANGCHANGEREQUEST只是一个请求。

至于速度问题(“改变语言需要很多时间”),第一次加载输入语言并不能保证是闪电般的快速操作。我看到使用正常机制在我的机器上延迟了大约半秒。通常不是大瓶颈;大多数人不会来回切换那么多次。如果您确实需要加快速度,请考虑缓存LoadKeyboardLayout函数的返回值。

于 2013-05-26T08:53:48.347 回答