The problem you are facing is how the WM_INPUTLANGCHANGE message works. This message is sent to programs by the operating system to inform them of language changes. However, according to the documentation , this message is sent only to "to the topmost damaged window." This means that you can even call your own GetKeyboardLayout method (by the way, it is used by InputLanguageManager), but if the application is inactive, GetKeyboardLayout will always return the last known, outdated language.
Given this, it might be a good idea to use the solution @VDohnal points to, find the current topmost window and read the keyboard layout for it. Here is a brief proof of how to do this in a WPF application. I used an additional thread, which periodically finds the topmost window and a ready-made keyboard layout for it. The code is far from perfect, but it works, and it can help you 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); } } }
MichaΕ Komorowski
source share