using System.Runtime.InteropServices; namespace Olive.Services; internal static class PasteShortcutService { private const ushort ControlKey = 0x11; private const ushort VKey = 0x56; private const uint KeyUp = 0x0002; private const uint InputKeyboard = 1; private const int RestoreWindow = 9; private static readonly TimeSpan FocusSettleDelay = TimeSpan.FromMilliseconds(450); public static nint GetForegroundWindowHandle() { return GetForegroundWindow(); } public static async Task SendPasteAfterRestoringFocusAsync(nint targetWindow, CancellationToken cancellationToken) { RestoreTargetWindow(targetWindow); await Task.Delay(FocusSettleDelay, cancellationToken).ConfigureAwait(false); SendKeyChord(ControlKey, VKey); } private static void RestoreTargetWindow(nint targetWindow) { if (targetWindow == 0 || !IsWindow(targetWindow)) return; if (IsIconic(targetWindow)) ShowWindow(targetWindow, RestoreWindow); SetForegroundWindow(targetWindow); } private static void SendKeyChord(ushort modifierKey, ushort key) { var inputs = new[] { KeyDown(modifierKey), KeyDown(key), KeyUpInput(key), KeyUpInput(modifierKey) }; var sent = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf()); if (sent != inputs.Length) throw new InvalidOperationException("Could not send Ctrl+V to the active app."); } private static Input KeyDown(ushort key) { return new Input { Type = InputKeyboard, Data = new InputUnion { Keyboard = new KeyboardInput { VirtualKey = key } } }; } private static Input KeyUpInput(ushort key) { return new Input { Type = InputKeyboard, Data = new InputUnion { Keyboard = new KeyboardInput { VirtualKey = key, Flags = KeyUp } } }; } [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint inputCount, Input[] inputs, int inputSize); [DllImport("user32.dll")] private static extern nint GetForegroundWindow(); [DllImport("user32.dll")] private static extern bool IsWindow(nint windowHandle); [DllImport("user32.dll")] private static extern bool IsIconic(nint windowHandle); [DllImport("user32.dll")] private static extern bool ShowWindow(nint windowHandle, int commandShow); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(nint windowHandle); [StructLayout(LayoutKind.Sequential)] private struct Input { public uint Type; public InputUnion Data; } [StructLayout(LayoutKind.Explicit)] private struct InputUnion { [FieldOffset(0)] public MouseInput Mouse; [FieldOffset(0)] public KeyboardInput Keyboard; } [StructLayout(LayoutKind.Sequential)] private struct MouseInput { public int X; public int Y; public uint MouseData; public uint Flags; public uint Time; public nint ExtraInfo; } [StructLayout(LayoutKind.Sequential)] private struct KeyboardInput { public ushort VirtualKey; public ushort ScanCode; public uint Flags; public uint Time; public nint ExtraInfo; } }