Files
Olive/Olive/Services/PasteShortcutService.cs
T

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;
}
}