正确检测键盘布局

Dea*_*one 4 c# keyboard layout keyboard-events winforms

我有一个winforms应用程序,我需要获取用户的当前键盘布局.为此,我正在使用System.Windows.Forms.InputLanguage.CurrentInputLanguage.LayoutName.

只要用户将表单作为其活动窗口,一旦他将其他内容聚焦并更改了前一个属性不会返回正确值的语言,它就会正常工作,当表单仍然是活动窗口时,它将返回最后使用的语言.

是否有一种方法可以获得用户键盘布局的名称,即使他没有关注表单,对可以使用的内容没有任何限制.

小智 5

您可能已经知道System.Windows.Forms.InputLanguage.CurrentInputLanguage.LayoutName属性返回当前线程的键盘布局,无论您选择哪种布局,它都将保持相同的执行线程,除非您选择该窗口并更改该窗口的键盘输入布局.

也就是说,您基本上要做的是检查当前的键盘布局文化,并能够知道它何时发生变化.前一段时间我有类似的要求,我想出了以下代码,这些代码很适合我:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它像:

        new KeyboardLayoutWatcher().KeyboardLayoutChanged += (o, n) =>
        {
            this.CurrentLayoutLabel.Text = $"{o} -> {n}"; // old and new KB layout
        };
Run Code Online (Sandbox Code Playgroud)