Correctly determine the keyboard layout

I have a winforms application where I need to get the current user keyboard layout. For this I use System.Windows.Forms.InputLanguage.CurrentInputLanguage.LayoutName.

This works fine as long as the user has the form as his active window, as soon as he focuses on something else and changes the language, the previous property will not return the correct value, it will return the last language used, while the form was still the active window.

Is there a way to get the name of the keyboard layout for users, even if it does not focus the form, there are no restrictions on what you can use.

+4
source share
2 answers

As you already know, the System.Windows.Forms.InputLanguage.CurrentInputLanguage.LayoutName property returns the keyboard layout for the current stream, and no matter which layout you choose, it will remain the same for the executable stream if you do not select that window and change keyboard input location for this window.

However, what you are basically trying to do is check out the current keyboard layout culture and find out when it will change. Some time ago, I had a similar requirement, and I came up with the following code that served me well:

public delegate void KeyboardLayoutChanged(int oldCultureInfo, int newCultureInfo);

class KeyboardLayoutWatcher : IDisposable
{
    private readonly Timer _timer;
    private int _currentLayout = 1033;


    public KeyboardLayoutChanged KeyboardLayoutChanged;

    public KeyboardLayoutWatcher()
    {
        _timer = new Timer(new TimerCallback(CheckKeyboardLayout), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
    }

    [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hwnd, IntPtr proccess);
    [DllImport("user32.dll")] static extern IntPtr GetKeyboardLayout(uint thread);
    public int GetCurrentKeyboardLayout()
    {
        try
        {
            IntPtr foregroundWindow = GetForegroundWindow();
            uint foregroundProcess = GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero);
            int keyboardLayout = GetKeyboardLayout(foregroundProcess).ToInt32() & 0xFFFF;

            if (keyboardLayout == 0)
            {
                // something has gone wrong - just assume English
                keyboardLayout = 1033;
            }
            return keyboardLayout;
        }
        catch (Exception ex)
        {
            // if something goes wrong - just assume English
            return 1033;
        }
    }

    private void CheckKeyboardLayout(object sender)
    {
        var layout = GetCurrentKeyboardLayout();
        if (_currentLayout != layout && KeyboardLayoutChanged != null)
        {
            KeyboardLayoutChanged(_currentLayout, layout);
            _currentLayout = layout;
        }

    }

    private void ReleaseUnmanagedResources()
    {
        _timer.Dispose();
    }

    public void Dispose()
    {
        ReleaseUnmanagedResources();
        GC.SuppressFinalize(this);
    }

    ~KeyboardLayoutWatcher()
    {
        ReleaseUnmanagedResources();
    }
}

And use it like:

        new KeyboardLayoutWatcher().KeyboardLayoutChanged += (o, n) =>
        {
            this.CurrentLayoutLabel.Text = $"{o} -> {n}"; // old and new KB layout
        };
+5
source

, . Windows . , Windows , .

, ( ) Windows. , , . , , . , , . , Windows -.

, , ( ), . , . - , . InputLanguage.DefaultInputLanguage. . , OnActivated , ( ).

+1

Source: https://habr.com/ru/post/1680530/


All Articles