feat: add keyboard command for raw keyboard input (#521)

Adds `keyboard type` and `keyboard insertText` subcommands that
operate on the currently focused element without requiring a selector.

Essential for contenteditable editors (Lexical, ProseMirror, CodeMirror,
Monaco) where `type <selector>` doesn't trigger the editor's internal
event pipeline (beforeinput/DOM mutation).

- `keyboard type <text>` — page.keyboard.type() with real keystrokes
- `keyboard insertText <text>` — page.keyboard.insertText()

Note: `keyboard press` intentionally omitted — the existing top-level
`press` command already operates on current focus.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Provi
2026-02-23 09:44:08 -06:00
committed by GitHub
co-authored by Claude Opus 4.6
parent f10f3f6425
commit ad6e206a90
9 changed files with 186 additions and 5 deletions
+14 -1
View File
@@ -442,7 +442,10 @@ const errorsSchema = baseCommandSchema.extend({
const keyboardSchema = baseCommandSchema.extend({
action: z.literal('keyboard'),
keys: z.string().min(1),
subaction: z.enum(['type', 'press', 'insertText']).optional(),
keys: z.string().min(1).optional(),
text: z.string().min(1).optional(),
delay: z.number().optional(),
});
const wheelSchema = baseCommandSchema.extend({
@@ -1058,6 +1061,16 @@ export function parseCommand(input: string): ParseResult {
};
}
if (command.action === 'keyboard') {
const sub = command.subaction ?? 'press';
if ((sub === 'type' || sub === 'insertText') && !command.text) {
return { success: false, error: `keyboard ${sub} requires text`, id };
}
if (sub === 'press' && !command.keys) {
return { success: false, error: 'keyboard press requires keys', id };
}
}
return { success: true, command };
}