Хук / обнаружение изменения языка окон, даже когда приложение не сфокусировано
Есть ли способ определить, изменился ли язык 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), но я не смогу узнать, какой язык используется в данный момент, и пользователь может изменить горячую клавишу по умолчанию...
Буду признателен за вашу помощь.
1 ответ
Проблема, с которой вы сталкиваетесь, связана с тем, как работает сообщение 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);
}
}
}