Temporarily switch to English layout for injection
This commit is contained in:
@@ -7,10 +7,13 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
private const uint InputKeyboard = 1;
|
||||
private const uint KeyEventFKeyUp = 0x0002;
|
||||
private const uint KeyEventFUnicode = 0x0004;
|
||||
private const uint KlfActivate = 0x00000001;
|
||||
private const uint WmInputLangChangeRequest = 0x0050;
|
||||
private const ushort VirtualKeyA = 0x41;
|
||||
private const ushort VirtualKeyBack = 0x08;
|
||||
private const ushort VirtualKeyControl = 0x11;
|
||||
private const ushort VirtualKeyReturn = 0x0D;
|
||||
private static readonly IntPtr EnglishKeyboardLayout = LoadKeyboardLayout("00000409", KlfActivate);
|
||||
|
||||
public void InsertText(string text)
|
||||
{
|
||||
@@ -20,6 +23,7 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
}
|
||||
|
||||
AppLogger.Info($"Injecting text length: {text.Length}");
|
||||
using var keyboardLayoutScope = KeyboardLayoutScope.SwitchForegroundWindowToEnglish();
|
||||
foreach (var character in text)
|
||||
{
|
||||
AppLogger.Info($"Injecting char U+{(int)character:X4}: {character}");
|
||||
@@ -121,6 +125,66 @@ public sealed class KeyboardInjectionService : IKeyboardInjectionService
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint processId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetKeyboardLayout(uint threadId);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr LoadKeyboardLayout(string keyboardLayoutId, uint flags);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool PostMessage(IntPtr windowHandle, uint message, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
private sealed class KeyboardLayoutScope : IDisposable
|
||||
{
|
||||
private readonly IntPtr foregroundWindow;
|
||||
private readonly IntPtr originalKeyboardLayout;
|
||||
|
||||
private KeyboardLayoutScope(IntPtr foregroundWindow, IntPtr originalKeyboardLayout)
|
||||
{
|
||||
this.foregroundWindow = foregroundWindow;
|
||||
this.originalKeyboardLayout = originalKeyboardLayout;
|
||||
}
|
||||
|
||||
public static KeyboardLayoutScope SwitchForegroundWindowToEnglish()
|
||||
{
|
||||
var foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow == IntPtr.Zero)
|
||||
{
|
||||
AppLogger.Error("Cannot switch keyboard layout because no foreground window was found.");
|
||||
return new KeyboardLayoutScope(IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
|
||||
var threadId = GetWindowThreadProcessId(foregroundWindow, out _);
|
||||
var originalKeyboardLayout = GetKeyboardLayout(threadId);
|
||||
AppLogger.Info($"Switching foreground keyboard layout from 0x{originalKeyboardLayout.ToInt64():X} to 0x{EnglishKeyboardLayout.ToInt64():X}.");
|
||||
|
||||
if (EnglishKeyboardLayout != IntPtr.Zero)
|
||||
{
|
||||
PostMessage(foregroundWindow, WmInputLangChangeRequest, IntPtr.Zero, EnglishKeyboardLayout);
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
|
||||
return new KeyboardLayoutScope(foregroundWindow, originalKeyboardLayout);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (foregroundWindow == IntPtr.Zero || originalKeyboardLayout == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppLogger.Info($"Restoring foreground keyboard layout to 0x{originalKeyboardLayout.ToInt64():X}.");
|
||||
PostMessage(foregroundWindow, WmInputLangChangeRequest, IntPtr.Zero, originalKeyboardLayout);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct INPUT
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user