Can't send WM_INPUTLANGCHANGEREQUEST to some controls
I am working (yet another) keyboard layout switcher and got strange problems with Skype window (ver. 6.22 on win7 x64). Any combinations of GetForegroundWindow () / GetFocus () / GetParentWindow () cannot change the layout just inside the message input and, even weirder , only if more than one character is entered . Other cases work fine except wpf apps which refuse to obey without a Focused Handle stuff.
public static void SetNextKeyboardLayout()
{
IntPtr hWnd = GetForegroundWindow();
uint processId;
uint activeThreadId = GetWindowThreadProcessId(hWnd, out processId);
uint currentThreadId = GetCurrentThreadId();
AttachThreadInput(activeThreadId, currentThreadId, true);
IntPtr focusedHandle = GetFocus();
AttachThreadInput(activeThreadId, currentThreadId, false);
PostMessage(focusedHandle == IntPtr.Zero ? hWnd : focusedHandle, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_FORWARD, HKL_NEXT);
}
I'm new to winapi stuff so any help would be kindly appreciated, thanks.
source to share
After disassembling some work products, I found out that I was close to the correct algorithm, which looks like this:
public static void SetNextKeyboardLayout()
{
IntPtr hWnd = IntPtr.Zero;
var threadId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
var currentThreadId = GetCurrentThreadId();
var info = new GUITHREADINFO();
info.cbSize = Marshal.SizeOf(info);
var success = GetGUIThreadInfo(threadId, ref info);
// target = hwndCaret || hwndFocus || (AttachThreadInput + GetFocus) || hwndActive || GetForegroundWindow
AttachThreadInput(threadId, currentThreadId, true);
IntPtr focusedHandle = GetFocus();
AttachThreadInput(threadId, currentThreadId, false);
if (success)
{
if (info.hwndCaret != IntPtr.Zero) { hWnd = info.hwndCaret; }
else if (info.hwndFocus != IntPtr.Zero) { hWnd = info.hwndFocus; }
else if (focusedHandle != IntPtr.Zero) { hWnd = focusedHandle; }
else if (info.hwndActive != IntPtr.Zero) { hWnd = info.hwndActive; }
}
else
{
hWnd = focusedHandle;
}
if (hWnd == IntPtr.Zero) { hWnd = GetForegroundWindow(); }
PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_FORWARD, HKL_NEXT);
}
But the problem was not the PostMessage target hWnd search, but the skype input handling. I solved this by adding a tiny delay before WM_INPUTLANGCHANGEREQUEST
so that skype can properly handle all the data sent to it. Now I need to get everything to work without this delay, but that's another story.
source to share
The best way with Windows 10 is to emulate the keys for the keyboard layout of the keyboard, for example:
keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_SPACE,0, KEYEVENTF_EXTENDEDKEY, 0);
Sleep(10);
keybd_event(VK_SPACE,0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
keybd_event(VK_LWIN, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
source to share