obsidian/desktop-trusted-input
Desktop-only trusted input helpers that drive the real Electron renderer via webContents.sendInputEvent, so keystrokes, pointer moves and clicks flow through the same trusted input pipeline a real user produces (unlike untrusted dispatchEvent, which CodeMirror, the CSS :hover engine and every e.isTrusted guard in Obsidian ignore).
These are the importable-module twins of the base helpers the obsidian-integration-testing harness seeds into the lib bag; the two copies are kept behaviorally in sync by hand (see the project CLAUDE.md). Desktop-only: they depend on window.electron.
This is the desktop arm. Import it directly only as a deliberate platform commitment; the cross-platform entry point is the trusted-input facade, which dispatches to this module or to mobile-trusted-input per call.
Interfaces
Section titled “Interfaces”| Interface | Description |
|---|---|
| ClickElementParams | Parameters for clickElement. |
| ClickMouseParams | Parameters for clickMouse. |
| HoverElementParams | Parameters for hoverElement. |
| MoveMouseParams | Parameters for moveMouse. |
| PressKeyParams | Parameters for pressKey. |
| TypeIntoEditorParams | Parameters for typeIntoEditor. |
| UnhoverElementParams | Parameters for unhoverElement. |
Functions
Section titled “Functions”| Function | Description |
|---|---|
| clickElement | Clicks the center of an element using trusted Electron pointer input. The element-relative counterpart of clickMouse, mirroring the moveMouse / hoverElement split. Use clickMouse directly when the point to click is not the element’s center — the markdown editor’s margin, for instance, lies inside cm.scrollDOM but outside .cm-sizer, so no element’s center lands on it. Must be awaited. Nothing here needs to wait, but the cross-platform twins do — on mobile the injection is a round-trip to the host, because the renderer cannot produce a trusted event itself — so the signature is the same on both platforms and a caller never rewrites its awaits when it grows a mobile lane. |
| clickMouse | Clicks at the given web-contents coordinates using trusted Electron pointer input, so Chromium synthesizes a real click (or contextmenu, for the right button) with isTrusted === true. This is what element.dispatchEvent(new MouseEvent('click')) cannot do: Obsidian and CodeMirror gate on isTrusted, so a dispatched event silently exercises nothing while the test still passes. Obsidian 1.13.7’s markdown viewport (margin) menu, for example, opens from cm.scrollDOM.addEventListener('contextmenu', (e) => \{ if (!e.defaultPrevented && e.isTrusted && …) \}) — a dispatched contextmenu never gets past that check. It is the low-level primitive: a single trusted mouseMove → mouseDown → mouseUp at one point, with no waiting for any effect (callers poll their own readiness signal). The leading move is what puts the pointer over the hit-test target before the button goes down. Prefer clickElement for element-relative clicks. Must be awaited — see clickElement. |
| hoverElement | Moves the mouse pointer to the center of an element using trusted Electron pointer input, then polls until the element actually matches :hover. Because the move is trusted, the real :hover state takes effect in the CSS engine — unlike dispatchEvent(new MouseEvent('mouseover')), which is untrusted and never sets :hover. It targets the single window’s global pointer, so only one element is hovered at a time. |
| moveMouse | Moves the mouse pointer to the given web-contents coordinates using a trusted Electron pointer move. A trusted move updates the real pointer state in the CSS engine, so :hover rules genuinely apply. This is the low-level primitive: it performs a single move and does not wait for any state to settle (callers poll their own readiness signal). Prefer hoverElement / unhoverElement for element-relative moves. Must be awaited — see clickElement. |
| pressKey | Presses a single key (optionally with modifiers) using trusted Electron keyboard input, firing the full real key pipeline — keydown → keypress → beforeinput → input → keyup. It injects a trusted keyDown → char → keyUp sequence, delivered to the window’s DOM-focused element — unlike dispatchEvent(new KeyboardEvent(...)), which is untrusted and ignored by CodeMirror. Use it for special keys ('Enter', 'Escape', 'Tab', arrow keys) and modifier combinations. It does not poll for any effect; the caller focuses the target first, then awaits the expected effect. Must be awaited — see clickElement. |
| typeIntoEditor | Types text into a CodeMirror Editor using trusted Electron keyboard input. This focuses the editor (caret to end) and presses every code point of text via pressKey — the same trusted sequence a real user produces — so the text reaches the document only if the editor genuinely holds focus. After injecting the keystrokes it polls until the document reflects the input, or a bounded timeout elapses (the expected outcome when the editor is read-only or focus was stolen). |
| unhoverElement | Moves the mouse pointer to a point just outside an element’s bounding box using a trusted Electron pointer move, then polls until the element no longer matches :hover. The inverse of hoverElement. When an element spans the full viewport (no point outside its box is reachable), use moveMouse directly to move the pointer to a known empty coordinate instead. |
| Type | Description |
|---|---|
| MouseButton | The mouse button a trusted click presses, in Electron’s sendInputEvent spelling. |