-
Notifications
You must be signed in to change notification settings - Fork 0
Win32 Interop
All Windows API usage is confined to KeepPressing/Interop/. Native bindings are generated by
CsWin32 — list the wanted APIs in Interop/NativeMethods.txt and the source generator produces the
P/Invoke signatures (the KeepPressing.csproj registers that file via AdditionalFiles, and
AllowUnsafeBlocks is on because the generated INPUT union needs unsafe).
Implements the Core port with SendInput. Stateless and thread-safe.
-
Tapsends Down→Up in a singleSendInputcall, so no other input interleaves between them. -
Keyboard uses scancodes, not just virtual keys: it maps VK→scancode via
MapVirtualKeyand sendsKEYEVENTF_SCANCODE(addingKEYEVENTF_EXTENDEDKEYfor extended keys), falling back to the VK only when a key has no scancode. Raw Input / DirectInput games often ignore VK-only synthetic input but accept scancodes, so this maximizes compatibility. -
Fixed-position mouse presses add
MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESKwith coordinates normalized throughVirtualScreen(see below). The move is attached to both Down and Up, so if the physical mouse drifts during a Hold, the Up still lands at the fixed point and you don't get an accidental drag. System metrics are re-read each time to follow monitor changes. -
UIPI is silent: if
SendInputreports fewer events than sent (blocked by an elevated window), it is logged viaDebug.WriteLinerather than thrown — an exception would kill the loop. See Known Limitations #1.
Implements global hotkeys with RegisterHotKey(hWnd = NULL). Key design points:
- With a
NULLwindow handle,WM_HOTKEYis posted to the calling thread's message queue, so the whole thing runs on one dedicated background thread — no window and noWNDPROCneeded. The thread is namedKeepPressing.Hotkeysand is a background thread. -
MOD_NOREPEATis OR-ed into every registration, so holding a hotkey down doesn't retrigger it. -
Thread-affinity is respected:
RegisterHotKey/UnregisterHotKeymust be called on the thread that owns the message loop. Register/unregister requests are queued and pumped via a customWM_APP+1message; onWM_QUITthe loop unregisters everything before exiting. -
Startup handshake: the loop force-creates its message queue with
PeekMessageand signals aTaskCompletionSourcebefore anyPostThreadMessageis allowed, avoiding a lost-message race. - Registration returns
falseon conflict (another app owns the key), which the ViewModel surfaces to the user. Hotkey IDs:Toggle=1,CaptureConfirm=2,CaptureCancel=3,EmergencyStop=4.
Events fire on the listener thread, so subscribers must marshal to the UI thread — see Threading & ConfigureAwait.
A thin GetCursorPos wrapper exposing Current as a ScreenPoint. During coordinate capture the view
refreshes the live readout each render frame (CompositionTarget.Rendering) for smooth tracking rather
than polling on a ~16 ms timer; the confirmed value is read at the instant F8 is pressed.
Normalizes an absolute ScreenPoint into the 0–65535 range that MOUSEEVENTF_ABSOLUTE expects, across
the entire virtual desktop (all monitors, whose origin can be negative). The bounding rectangle
comes from GetSystemMetrics(SM_XVIRTUALSCREEN/…/SM_CYVIRTUALSCREEN).
Prevents the IME from interfering while keys are being assigned/synthesized.
- Add the function/constant/type name to
KeepPressing/Interop/NativeMethods.txt. - Reference it via the generated
Windows.Win32.PInvoke(or the generated type) — no manual[DllImport]. - Build; the generator emits the binding. Keep all such usage inside
Interop/.
Related: Architecture · Hotkeys · Threading & ConfigureAwait
KeepPressing · Releases · Issues · Licensed under Apache-2.0
Getting started
User guide
Developer guide