Skip to content

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.

InterfaceDescription
ClickElementParamsParameters for clickElement.
ClickMouseParamsParameters for clickMouse.
HoverElementParamsParameters for hoverElement.
MoveMouseParamsParameters for moveMouse.
PressKeyParamsParameters for pressKey.
TypeIntoEditorParamsParameters for typeIntoEditor.
UnhoverElementParamsParameters for unhoverElement.
FunctionDescription
clickElementClicks 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.
clickMouseClicks 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 mouseMovemouseDownmouseUp 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.
hoverElementMoves 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.
moveMouseMoves 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.
pressKeyPresses a single key (optionally with modifiers) using trusted Electron keyboard input, firing the full real key pipeline — keydownkeypressbeforeinputinputkeyup. It injects a trusted keyDowncharkeyUp 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.
typeIntoEditorTypes 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).
unhoverElementMoves 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.
TypeDescription
MouseButtonThe mouse button a trusted click presses, in Electron’s sendInputEvent spelling.