120 lines
3.1 KiB
C#
120 lines
3.1 KiB
C#
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<Input>());
|
|
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;
|
|
}
|
|
}
|