简体   繁体   English

在键盘挂钩回叫中更改键盘布局

[英]Changing Keyboard Layout inside Keyboard Hook CallBack

I have a problem with changing keyboard layout inside keyboard hook. 我在更改键盘挂钩内的键盘布局时遇到问题。 In this simple code, when pressing 'A' key, it takes a lot time, to change a language, in more complicated cases, application does wrong things.. 在这个简单的代码中,按“ A”键需要花费很多时间来更改语言,在更复杂的情况下,应用程序会做错事。

Application works in tray, therefore I used hooks. 应用程序在托盘中工作,因此我使用了挂钩。 Whats wrong with my code? 我的代码有什么问题? )) Or, maybe there is different way to change keyboard layout, which works with hooks well? ))或者,也许有另外一种改变键盘布局的方法,这种方法与钩子配合得很好? Thanks for your answers. 感谢您的回答。

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);
}

Before even trying to fix this code, I have to ask a couple of silly questions: 在尝试修复此代码之前,我必须问几个愚蠢的问题:

  1. Why do you need to do this inside of a hook? 为什么需要在挂钩内执行此操作?
  2. Why do you need to do this at all? 为什么根本需要这样做? You can specify a hotkey to choose an input language in the Keyboard control panel (Region and Language → Keyboard and Languages → Change Keyboards → Advanced Key Settings). 您可以在键盘控制面板中指定一个热键以选择一种输入语言(区域和语言→键盘和语言→更改键盘→高级键设置)。 And whenever you enable multiple input languages, an icon is already placed on your taskbar. 而且,无论何时启用多种输入语言,任务栏上都会放置一个图标。 You don't need to write your own app to do either of these things. 您无需编写自己的应用程序即可执行上述任何一项操作。

Now, looking specifically at your code, what you're doing is posting the WM_INPUTLANGCHANGEREQUEST message to the foreground window. 现在,专门查看您的代码,您正在做的是将WM_INPUTLANGCHANGEREQUEST消息发布到前台窗口。 But this message is a notification . 但是此消息是通知 It informs a program that a user requested to change the input language. 它通知程序用户请求更改输入语言。 It's not designed to allow programs to make requests to other programs to change the input language. 它的目的不是允许程序向其他程序发出请求以更改输入语言。

If a program wants to change its own keyboard layout, it calls the ActivateKeyboardLayout function. 如果程序想要更改其自己的键盘布局,则将调用ActivateKeyboardLayout函数。 But it's not necessary to p/invoke this function from a .NET application. 但是不必从.NET应用程序p /调用此功能。 The framework already wraps all this up in the InputLanguage class—highly recommended. 该框架已经将所有这些都包装在InputLanguage类中-强烈建议。

Aside from that, other problems inevitably exist in code that you do not show, code that belongs to other applications. 除此之外,未显示的代码中不可避免地存在其他问题,这些代码属于其他应用程序。 The foreground window to which you post the WM_INPUTLANGCHANGEREQUEST message has the option of either accepting the change by passing the message on to DefWindowProc , or rejecting the change by returning 0 in response. 向其发布WM_INPUTLANGCHANGEREQUEST消息的前台窗口可以选择通过将消息传递给DefWindowProc来接受更改,或者通过返回0来拒绝更改。 If a broken application just returns 0 for all those messages it does not explicitly process , it won't do the right thing. 如果损坏的应用程序仅 针对未显式处理的所有消息返回0,则它将做不到正确的事情。 Or if an application has been written to explicitly reject WM_INPUTLANGCHANGEREQUEST requests, it won't do what you're expecting. 或者,如果编写了一个应用程序以明确拒绝WM_INPUTLANGCHANGEREQUEST请求,则该应用程序将无法满足您的期望。 And so on. 等等。 You have no control over these things. 您无法控制这些事情。 Remember, WM_INPUTLANGCHANGEREQUEST is just a request. 请记住, WM_INPUTLANGCHANGEREQUEST只是一个请求。

As far as the speed issue ("it takes a lot time, to change a language"), loading an input language for the first time is not guaranteed to be a lightning fast operation. 至于速度问题(“更改语言需要花费很多时间”),不能保证首次加载输入语言是一种快速的操作。 I see about a half a second delay on my machine using the normal mechanism. 我发现使用正常机制的机器延迟了大约半秒钟。 Not usually a big bottleneck; 通常没有大的瓶颈; most people don't switch back and forth that many times. 大多数人不会来回切换很多次。 If you really need to speed this up, consider caching the return value of the LoadKeyboardLayout function. 如果您确实需要加快速度,请考虑缓存LoadKeyboardLayout函数的返回值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM