为什么 GetKeyboardLayoutName return 在布局更改后名称相同?

Why does GetKeyboardLayoutName return the same name after a layout change?

在下面编写的程序中,使用了 user32.dll 中的 GetKeyboardLayoutName。 当我使用“English USA”布局键入第一个符号时,我得到 00000409。这很好。 但是当我将布局更改为其他内容时,例如“英国英语”或“俄语”,GetKeyboardLayoutName returns“美国英语”的代码 - 00000409。

我对此进行了测试,如果我在“俄语”中输入第一个符号,它 returns 00000419 如果我切换回“美国英语”并输入第二个符号,GetKeyboardLayoutName 仍然 returns “俄语”代码 - 00000419。

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApp2
{

    class Program
    {

        const int KL_NAMELENGTH = 9;

        [DllImport("user32.dll")]
        private static extern long GetKeyboardLayoutName(StringBuilder pwszKLID);
        public static string GetLayoutCode()
        {
            var name = new StringBuilder(KL_NAMELENGTH);
            GetKeyboardLayoutName(name);

            return name.ToString();
        }

        static void Main(string[] args)
        {
            Console.ReadKey();
            var res = GetLayoutCode();
            Console.WriteLine("\n" + res);

            Console.ReadKey();
            res = GetLayoutCode();
            Console.WriteLine("\n" + res);
        }
    }
}

问题是控制台应用程序不允许您处理 windows 消息。
您可以将您的应用程序转换为 应用程序,隐藏主窗体并子类化 WndProc 以处理在键盘布局更改时触发的 WM_INPUTLANGCHANGE 消息:

public class MyHiddenForm : Form
{
    ...

    protected override void WndProc(ref Message m)
    {
        const int WM_INPUTLANGCHANGE = 0x0051;
        if (m.Msg == WM_INPUTLANGCHANGE)
        {
            Console.WriteLine("{0:X8} {1:X8}", m.WParam.ToInt64() , m.LParam.ToInt64());
        }
        base.WndProc(ref m);
    }
}

另一种方法是在将接收消息的控制台应用程序中通过 WinAPI 创建一个隐藏的 window。但我个人更喜欢第一种方法。

如果您不需要 KLID(键盘布局标识符),而您只需要一种识别键盘布局的方法,那么您可以使用以下方法获取 HKL(输入区域设置标识符):

var focusedHWnd = GetForegroundWindow();
var activeThread = GetWindowThreadProcessId(focusedHWnd, IntPtr.Zero);
var hkl = GetKeyboardLayout(activeThread);

那是因为 GetKeyboardLayoutName() 正在请求当前线程的布局(每个线程都有自己的键盘布局,这就是为什么我们有 AttachThreadInput() 等 API)。您的控制台应用程序没有 Win32 window 线程。只有重点关注的 Win32 windows 可以通过热键本机更改其键盘布局。据我所知,无法在控制台 windows 中检测到此类语言变化 - 因为它们托管在特殊的 cmd.exe 子 window(或其他终端应用程序)中。