Temporarily switch to English layout for injection

This commit is contained in:
Misaka
2026-05-15 22:44:31 +08:00
parent ddd15f1067
commit 0c2cbbfccd

View File

@@ -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
{