/** * @file * * Translates a mobile trusted-input request into the ordered Chrome DevTools Protocol `Input.*` commands * that realize it (see **L39**). * * Pure and synchronous by design: the WebView connection ({@link WebViewCdpConnection}) sends whatever this * returns, so every decision that is worth a test — the touch pair a tap expands into, the dwell a * long-press adds, the `rawKeyDown` → `char` → `keyUp` shape a key press mirrors from the desktop twin, the * modifier bitmask — lives here rather than inside the transport's I/O path. * * The request travels renderer → host as JSON (the renderer computes the coordinates, because only it can * see the DOM), so both the request and the command shapes are deliberately plain data. */ /** * The name of the `Runtime.addBinding` function the host exposes on the page so the renderer can hand it an * input request mid-closure. * * It is passed *into* the serialized bootstrap closure as data rather than referenced from it, because that * closure may not read outer scope (**L15**) — so this stays the single definition. */ export declare const MOBILE_INPUT_BINDING_NAME = "__obsidianIntegrationTestingInput"; /** * How long the renderer waits for the host to service one input request before giving up. * * Generous relative to the work (a tap is two CDP commands; a long-press adds a 600ms dwell): the point is * to fail with a legible error rather than hang the closure until the whole run times out. Passed into the * bootstrap closure as data, for the same reason as {@link MOBILE_INPUT_BINDING_NAME}. */ export declare const MOBILE_INPUT_TIMEOUT_IN_MILLISECONDS = 15000; /** * A single Chrome DevTools Protocol command. * * It once also carried a `delayBeforeInMilliseconds`, so the host would sleep between the two halves of a * long-press. That dwell is gone: the gesture is now one `Input.synthesizeTapGesture` that holds itself * for its own `duration`, so no command in any sequence needs to be spaced from the one before it, and a * knob nothing sets is worse than no knob. */ export interface CdpInputCommand { /** * The CDP method name, e.g. `Input.dispatchTouchEvent`. */ readonly method: string; /** * The CDP method parameters. */ readonly params: Record; } /** * What the renderer hands to the host binding: one request, plus the id to answer it on. * * The renderer builds this literal inside the serialized bootstrap closure, which cannot import (**L15**), * so the shape is declared here and mirrored there. They are one wire format; change them together. */ export interface MobileInputEnvelope { /** * The request id the renderer is waiting on. */ readonly id: string; /** * What to inject. */ readonly request: MobileInputRequest; } /** * Anything the renderer can ask the host to inject. */ export type MobileInputRequest = MobileKeyInputRequest | MobilePointerInputRequest; /** * A trusted key press to inject on mobile. */ export interface MobileKeyInputRequest { /** * The key to press, in the same spelling the desktop twin takes: either a named key * (`Enter`, `Escape`, `Tab`, `Backspace`, `Delete`, an arrow) or a single printable character. */ readonly key: string; /** * Discriminant. */ readonly kind: 'key'; /** * Modifiers already resolved to their platform-independent lowercase names by the renderer's * `toElectronModifiers` — the one mapping a key press and a click share, so `'Mod'` cannot mean two * different things (**L17**). */ readonly modifiers: readonly string[]; } /** * A trusted pointer gesture to inject on mobile, in CSS pixels within the WebView's own viewport. * * No device-pixel conversion is involved: CDP takes page coordinates, so `devicePixelRatio` and the * WebView's offset under the status bar never enter the picture (they would for native injection). */ export interface MobilePointerInputRequest { /** * `tap` is the touch analog of a left click; `longPress` is the mobile context-menu gesture, i.e. what a * desktop right click means here. */ readonly kind: 'longPress' | 'tap'; /** * See {@link MobileKeyInputRequest.modifiers}. */ readonly modifiers: readonly string[]; /** * The viewport x coordinate, in CSS pixels. */ readonly x: number; /** * The viewport y coordinate, in CSS pixels. */ readonly y: number; } /** * Builds the expression the host evaluates to claim one input request before injecting it. * * CDP delivers `Runtime.bindingCalled` to **every** attached session, so each Node process holding an * input channel to this WebView services the same request and injects the same gesture. The claim is * what makes the injection exactly-once across all of them: the page is the only thing every host * shares, and it runs the racing evaluates one after another on its single thread, so exactly one of * them gets `true`. * * Optional chaining for the same reason as {@link buildResolveInputExpression}, and it is why * {@link checkInputClaimGranted} treats a non-`false` result as claimed: a page that has dropped the * namespace yields `undefined`, and injecting twice is a far better failure than never injecting. * * @param id - The request id to claim. * @returns A self-contained expression to pass to `Runtime.evaluate`. */ export declare function buildClaimInputExpression(id: string): string; /** * Builds the expression the host evaluates to answer one input request. * * Optional chaining throughout: by the time the host answers, the page may have navigated and dropped the * namespace, and a `TypeError` inside this evaluate would be reported as an injection failure that already * succeeded. * * @param id - The request id the renderer is waiting on. * @param errorMessage - Why the injection failed, when it did. Omit on success. * @returns A self-contained expression to pass to `Runtime.evaluate`. */ export declare function buildResolveInputExpression(id: string, errorMessage?: string): string; /** * Reads a `Runtime.evaluate` result for {@link buildClaimInputExpression} and says whether to inject. * * **Deliberately fails OPEN.** Only a literal `false` — the page actively saying another host already * claimed this id — stops the injection. A missing namespace, a page mid-navigation, or any result * shape this does not recognize yields `true`, because a gesture injected twice is a far better * failure than a gesture never injected at all: the first is a doubled tap, the second is a test that * hangs until the renderer's timeout and reports nothing useful. * * @param result - The raw `Runtime.evaluate` result object. * @returns Whether this host should perform the injection. */ export declare function checkInputClaimGranted(result: unknown): boolean; /** * The first code point of a non-empty string. * * `String.prototype.codePointAt` is typed `number | undefined`, so every call site would otherwise carry a * `?? fallback` that no input can ever reach — a dead branch under the 100% coverage gate. Throwing here * keeps that impossible case in ONE place, where a unit test can reach it directly, instead of spreading * unreachable fallbacks (or coverage suppressions) across the module. * * @param text - A non-empty string. * @returns Its first code point. * @throws When `text` is empty. */ export declare function codePointOf(text: string): number; /** * Translates a mobile input request into the ordered CDP commands that realize it. * * @param request - What the renderer asked the host to inject. * @returns The commands to send, in order. */ export declare function toCdpInputCommands(request: MobileInputRequest): CdpInputCommand[]; /** * Folds resolved modifier names into CDP's bitmask. * * Unknown names are ignored rather than throwing: the renderer's `toElectronModifiers` is exhaustive over * Obsidian's `Modifier` union, so an unknown name here would mean the two copies have already drifted, and * failing the whole gesture is a worse outcome than pressing it unmodified. * * @param modifiers - Resolved lowercase modifier names. * @returns The CDP modifier bitmask. */ export declare function toCdpModifiers(modifiers: readonly string[]): number;