Reputation: 51
I'm working on (yet another) keyboard layout switcher and got strange troubles with Skype window (ver 6.22 on win7 x64). Any combinations of GetForegroundWindow() / GetFocus() / GetParentWindow() don't succeed to change the layout only inside the message input and, even more strange, only if more than one character is entered. Other cases work perfectly nice except wpf apps which refuse to obey without focusedHandle 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 things, so any help will be kindly appreciated, thank you.
Upvotes: 3
Views: 2098
Reputation: 1
Best way with Windows 10 -- is emulate keys for switch keyboard layout, like this:
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);
Upvotes: 0
Reputation: 1
You should try this: PostMessage(hWnd,WM_INPUTLANGCHANGEREQUEST,0,(LPARAM)HKL_NEXT);
P.S.:
Under Windows 10 any WM_INPUTLANGCHANGEREQUEST
crashes Skype.
Upvotes: 0
Reputation: 51
After disassembling some of working products i've figured out that i was close to the right algorythm 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 in finding PostMessage target hWnd, but in skype's input handling. I have solved it by adding a tiny delay before WM_INPUTLANGCHANGEREQUEST
so skype can properly process all the input sent to it. Now i have to get things working without this delay but this is another story.
Upvotes: 2