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

Time:12-04

In this program written below, using the GetKeyboardLayoutName from user32.dll. When I type the first symbol using the "English USA" layout, I get 00000409. This is fine. But when I change my layout to something else, like "English UK" or "Russian", GetKeyboardLayoutName returns the code for "English USA" - 00000409.

I tested this and if I input the first symbol in "Russian", it returns 00000419 and if I switch back to "English USA" and input a second symbol, GetKeyboardLayoutName still returns the code for "Russian" - 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);
        }
    }
}

CodePudding user response:

The problem is that a console application doesn't allow you to handle windows messages.
You could convert your application to application, make the main form hidden and subclass WndProc to handle the WM_INPUTLANGCHANGE message that triggers on the keyboard layout change:

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

Another approach is to create a hidden window via WinAPI in the console application that will receive messages. But i'd personally prefer the first approach.

CodePudding user response:

If you don't need a KLID (keyboard layout identifier) specifically, and you just need a way to identify keyboard layouts then you can use the following to get the HKL (input locale identifier):

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