* fix(app): stabilize native terminal keyboard input Terminal focus requests blurred and remounted the hidden input even when the software keyboard was already visible, causing visible IME cycles and leaving clipboard commits coupled to stale native text. Keep focus requests idempotent while resetting only the native input buffer. * test(app): remove misleading keyboard device scenario Agent Device cannot durably assert software-keyboard continuity or commit a keyboard clipboard suggestion, so the scenario overstated coverage already owned by focused input-policy tests. * fix(app): derive terminal keyboard focus from visibility Use the keyboard-controller inset as the source of truth so a system-dismissed keyboard cannot leave focus activation suppressed. Avoid a duplicate focus request while explicitly showing the keyboard. * fix(app): track terminal keyboard visibility across layouts Keep keyboard visibility independent from compact-only terminal padding so tablet taps remain idempotent while the software keyboard is open.
72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
import type { Ref } from "react";
|
|
import type { ITheme } from "@xterm/xterm";
|
|
import type { TerminalState } from "@getpaseo/protocol/messages";
|
|
import type { TerminalInputModeState } from "@getpaseo/protocol/terminal-input-mode";
|
|
import type { TerminalOutputData } from "../terminal/runtime/terminal-emulator-runtime";
|
|
import type {
|
|
TerminalLocalFileLinkSource,
|
|
TerminalLocalFileLinkTarget,
|
|
} from "../terminal/local-links/terminal-local-link-provider";
|
|
import type { TerminalClipboardWriter } from "../terminal/native-renderer/terminal-selection";
|
|
import type { PendingTerminalModifiers } from "../utils/terminal-keys";
|
|
import type { TerminalRendererReadyChange } from "../utils/terminal-renderer-readiness";
|
|
|
|
export interface TerminalEmulatorHandle {
|
|
writeOutput: (data: TerminalOutputData) => void;
|
|
restoreOutput: (data: TerminalOutputData) => void;
|
|
renderSnapshot: (state: TerminalState | null) => void;
|
|
paste: (text: string) => void;
|
|
copySelection: (clipboard: TerminalClipboardWriter) => Promise<string>;
|
|
clear: () => void;
|
|
claimSize: () => void;
|
|
showKeyboard: () => void;
|
|
blur: () => void;
|
|
}
|
|
|
|
export interface TerminalEmulatorProps {
|
|
dom?: unknown;
|
|
ref: Ref<TerminalEmulatorHandle>;
|
|
streamKey: string;
|
|
supportsTerminalInputModeReplay: boolean;
|
|
testId?: string;
|
|
xtermTheme?: ITheme;
|
|
scrollbackLines: number;
|
|
fontFamily?: string;
|
|
fontSize?: number;
|
|
keyboardInset?: number;
|
|
isKeyboardVisible?: boolean;
|
|
swipeGesturesEnabled?: boolean;
|
|
onSwipeLeft?: () => void;
|
|
onSwipeRight?: () => void;
|
|
initialSnapshot?: TerminalState | null;
|
|
onInput?: (data: string) => Promise<void> | void;
|
|
onFocus?: () => Promise<void> | void;
|
|
onResize?: (input: {
|
|
rows: number;
|
|
cols: number;
|
|
shouldClaim: boolean;
|
|
forceClaim?: boolean;
|
|
}) => Promise<void> | void;
|
|
onTerminalKey?: (input: {
|
|
key: string;
|
|
ctrl: boolean;
|
|
shift: boolean;
|
|
alt: boolean;
|
|
meta: boolean;
|
|
}) => Promise<void> | void;
|
|
onPendingModifiersConsumed?: () => Promise<void> | void;
|
|
onInputModeChange?: (state: TerminalInputModeState) => Promise<void> | void;
|
|
onSelectionChange?: (hasSelection: boolean) => void;
|
|
onResolveLocalFileLink?: (
|
|
source: TerminalLocalFileLinkSource,
|
|
) => Promise<TerminalLocalFileLinkTarget | null> | TerminalLocalFileLinkTarget | null;
|
|
onOpenLocalFileLink?: (
|
|
target: TerminalLocalFileLinkTarget,
|
|
disposition: "main" | "side",
|
|
) => Promise<void> | void;
|
|
onRendererReadyChange?: (change: TerminalRendererReadyChange) => void;
|
|
pendingModifiers?: PendingTerminalModifiers;
|
|
focusRequestToken?: number;
|
|
resizeRequestToken?: number;
|
|
}
|