【问题标题】:Hook/detect windows language change even when app not focused即使应用程序没有聚焦,也可以挂钩/检测 Windows 语言更改
【发布时间】:2014-11-05 23:41:12
【问题描述】:

有没有一种方法可以检测 Windows/os 语言是否发生变化,即使我的应用程序没有获得焦点?
到目前为止,只有当应用程序专注于使用时,我才能实现我想要的:

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

但正如你所理解的,这并不是我想要的......

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

非常感谢您的帮助。

【问题讨论】:

  • 您实际上并未更改流程的输入语言。仅适用于前台的任何进程。语言栏的正常行为。
  • @HansPassant 我不明白,但我想要的是每当语言发生变化时挂钩......
  • @Run - 我想确认一件事。当焦点返回到您的应用程序时,将生成 InputLanguageChanged 事件对您来说还不够。
  • @MichałKomorowski 是的,你是对的。我想在输入语言发生变化时调用函数,无论我的应用是否处于焦点。
  • @Ron 我认为 Hans 的意思是输入语言你的应用程序中实际上并没有改变,直到它被带到前台.

标签: c# wpf hook input-language


【解决方案1】:

您面临的问题与 WM_INPUTLANGCHANGE 消息的工作方式有关。此消息由操作系统发送给程序,以通知它们有关语言的更改。但是,根据documentation,此消息仅发送到“最顶层受影响的窗口”。这意味着您甚至可以调用原生方法 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);
        }
    }
}

【讨论】:

  • 这就够了。我想做的就是在语言更改时显示一个带有当前语言的气球框+播放声音。我没有给你赏金,因为正如你所说,可能会有更好或“完美”的解决方案。除非有更好的解决方案,否则我会在结束前 1 天给你赏金
  • 无限期地占用一个任务池线程是没有意义的;使用TaskCreationOptions.LongRunning 创建任务以使用从池中分离的线程。
  • @MikeStrobel 如何使用它?
  • @Ron Task.Factory.StartNew(() => { ... }, TaskCreationOptions.LongRunning)
  • @MichalKomorowski 你的解决方案有一个错误。有时,当我在窗口之间切换或最小化-最大化时,它会自发地显示消息框两次,一次使用前一种语言,一次使用当前语言。我不明白为什么..
猜你喜欢
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
  • 2011-07-01
  • 2011-09-03
  • 2017-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多