-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInputSimulator.cs
More file actions
138 lines (120 loc) · 4.3 KB
/
Copy pathInputSimulator.cs
File metadata and controls
138 lines (120 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace ShiftHappens
{
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public static class InputSimulator
{
// Re-entrancy guard: keeps the hook from processing our own fake typing
public static bool IsSimulating { get; private set; }
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
public static void EraseAndReplace(int wordLength, string replacement)
{
IsSimulating = true;
try
{
var inputs = new List<INPUT>();
// 1. Add Backspaces (Down and Up for each)
for (int i = 1; i < wordLength; i++)
{
inputs.Add(CreateKeyInput(0x08, true)); // Backspace Down
inputs.Add(CreateKeyInput(0x08, false)); // Backspace Up
}
// 2. Add Replacement Symbols (Unicode)
foreach (char c in replacement)
{
inputs.Add(CreateUnicodeInput(c, true)); // Char Down
inputs.Add(CreateUnicodeInput(c, false)); // Char Up
}
// 3. Send the entire batch to the Kernel
uint sent = SendInput((uint)inputs.Count, inputs.ToArray(), Marshal.SizeOf(typeof(INPUT)));
System.Diagnostics.Debug.WriteLine($"Sent {sent} of {inputs.Count} inputs.");
if (sent == 0)
{
int error = Marshal.GetLastWin32Error();
System.Diagnostics.Debug.WriteLine($"Windows Error Code: {error}");
}
}
finally
{
// Always reset the guard, even if something crashes
IsSimulating = false;
}
}
private static INPUT CreateKeyInput(ushort wVk, bool keyDown)
{
return new INPUT
{
type = 1, // INPUT_KEYBOARD
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = wVk,
wScan = 0,
dwFlags = keyDown ? 0u : 0x0002u, // 0 or KEYEVENTF_KEYUP
time = 0,
dwExtraInfo = IntPtr.Zero
}
}
};
}
private static INPUT CreateUnicodeInput(char c, bool keyDown)
{
const uint KEYEVENTF_UNICODE = 0x0004;
const uint KEYEVENTF_KEYUP = 0x0002;
return new INPUT
{
type = 1,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = 0,
wScan = (ushort)c,
dwFlags = keyDown ? KEYEVENTF_UNICODE : (KEYEVENTF_UNICODE | KEYEVENTF_KEYUP),
time = 0,
dwExtraInfo = IntPtr.Zero
}
}
};
}
// --- Win32 Structs (Absolute Standards) ---
[StructLayout(LayoutKind.Explicit, Size = 40)] // Force 40 bytes (standard 64-bit size)
public struct INPUT
{
[FieldOffset(0)] public uint type;
[FieldOffset(8)] public InputUnion u; // Skip 4 bytes of padding automatically
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)] public KEYBDINPUT ki;
[FieldOffset(0)] public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
}
}