即使应用程序没有聚焦,钩子/检测窗口语言也会改变

Ron*_*Ron 9 c# wpf hook input-language

有没有办法检测即使我的应用程序不在焦点时Windows/OS语言是否发生了变化?
到目前为止,只有在应用程序集中使用时,我才能实现我想要的:

string language = "";
System.Windows.Input.InputLanguageManager.Current.InputLanguageChanged +=
new System.Windows.Input.InputLanguageEventHandler((sender, e) =>
{
    language = e.NewLanguage.DisplayName;
    MessageBox.Show(language);
});
Run Code Online (Sandbox Code Playgroud)

但是你可以理解,这不是我想要的......

我正在考虑其他解决方案,例如挂钩改变语言的键(例如alt + shift)但我无法知道当前使用的是什么语言,用户可以更改默认热键......

非常感谢你的帮助.

Mic*_*ski 9

您遇到的问题与WM_INPUTLANGCHANGE消息的工作方式有关.此消息由操作系统发送到程序,以通知它们语言更改.但是,根据文档,此消息仅发送到"最受影响的窗口".这意味着您甚至可以调用本机方法GetKeyboardLayout(顺便说一下,它由InputLanguageManager使用)但如果​​应用程序不活动,GetKeyboardLayout将始终返回最后一个已知的,过时的语言.

考虑到这一点,使用@VDohnal指向的解决方案可能是一个好主意,即找到当前最顶层的窗口并读取它的键盘布局.以下是如何在WPF应用程序中执行此操作的概念的快速证明.我使用了一个额外的线程,周期性地找到它的最顶层窗口和就绪键盘布局.代码远非完美,但它可以工作,它可以帮助您实现自己的解决方案.

public partial class MainWindow : Window
{
    [DllImport("user32.dll")]
    static extern IntPtr GetKeyboardLayout(uint idThread);
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);

    private CultureInfo _currentLanaguge;

    public MainWindow()
    {
        InitializeComponent();

        Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    HandleCurrentLanguage();
                    Thread.Sleep(500);
                }
            });
    }

    private static CultureInfo GetCurrentCulture()
    {
        var l = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero));
        return new CultureInfo((short)l.ToInt64());
    }

    private void HandleCurrentLanguage()
    {
        var currentCulture = GetCurrentCulture();
        if (_currentLanaguge == null || _currentLanaguge.LCID != currentCulture.LCID)
        {
            _currentLanaguge = currentCulture;
            MessageBox.Show(_currentLanaguge.Name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 无限期地捆绑任务池线程没有任何意义; 使用`TaskCreationOptions.LongRunning`创建任务以使用从池中分离的线程. (2认同)