挂钩/检测Windows语言更改,即使应用程序不集中时 [英] Hook/detect windows language change even when app not focused

查看:95
本文介绍了挂钩/检测Windows语言更改,即使应用程序不集中时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有一种方法可以检测Windows/OS语言是否发生了变化,即使我的应用程序没有聚焦?
到目前为止,只有将应用程序的重点放在以下位置,我才能实现我想要的东西:

Is there a way to detect if the windows/os language changed even when my app is not in focus?
So far I was able to achieve what I wanted only if the app was focused using:

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

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

But as you can understand, this is not exactly what I want..

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

I was thinking about other solution such as hooking the keys that change the language (for example alt+shift) but I wont be able to know what language is currently in use and a user can change the default hotkey...

非常感谢您的帮助.

推荐答案

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

The problem you are facing is related with how WM_INPUTLANGCHANGE message works. This message is sent to programs by operating system in order to inform them about language changes. However, according to documentation this message is sent only to "to the topmost affected window". It means that you can even call a native method GetKeyboardLayout (it is used by InputLanguageManager by the way) but if an application is not active GetKeyboardLayout will always return the last known, outdated, language.

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

Taking this into account it might be a good idea to use the solution pointed by @VDohnal i.e. find the current topmost window and read keyboard layout for it. Here is a quick proof of concept how to do it inside WPF application. I used an additional thread that periodically finds the topmost window and ready keyboard layout for it. The code is far from being perfect but it works and it might help you to implement your own solution.

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

这篇关于挂钩/检测Windows语言更改,即使应用程序不集中时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆