feat: real key-event typing in send_keys/type - #30
Open
4EYES44 wants to merge 4 commits into
Open
Conversation
Replace Element.send_keys' single bare char-event-per-character
dispatch with a faithful keyDown+keyUp sequence (Shift wrapping for
shifted chars), using Input.insertText as the fallback for characters
outside the US layout map. \n/\r/\r\n each produce one Enter; \t
produces Tab.
- New botasaurus_driver/core/keys.py: US-layout KEYBOARD_LAYOUT,
SHIFT_CHARS, VK_CODES maps, resolve_key(), dispatch_key(), and
type_text() (the per-character dispatch loop with \r\n collapse and
insertText fallback, no cadence).
- Element.send_keys now calls keys.type_text(self._tab, text),
preserving raise_if_disconnected / self.update / the docstring.
- bypass_insecure_connection_warning (tab.py) untouched; still calls
body.send_keys("thisisunsafe") through the new path.
No cadence, no field_selector, no _resolve_tab -- those are split out
to a separate follow-up per Plan-human-type.md section 6.
Self-contained script (no pytest) that launches a headless Driver, opens a local HTML harness page capturing keydown/keypress/keyup/ input/beforeinput, and asserts the 8 properties from Plan-human-type.md section 8: 1. event ordering and count (ab -> 6 events, no missing keyup, no doubled keypress) 2. event.code never empty for mapped printable ASCII 3. keyCode fidelity (keydown 65, keypress 97 for "a") 4. Shift state and pairing for "@" 5. \n/\r/\r\n -> one Enter + one submit; \t -> Tab; " " -> click 6. Unicode round-trip (é中😀) 7. final value equals input string 8. bypass_insecure_connection_warning (SKIP if badssl unreachable) Exits non-zero on FAIL; SKIP is not a failure. Runnable as `python3 demo_typing.py` without pip install via sys.path insert.
Document that type/send_keys now dispatches real keydown/keyup (with insertText fallback for unmapped chars and CRLF collapsed to one Enter), placed next to the existing type example. Public API unchanged.
Typing "thisisunsafe" into Chrome's SSL interstitial makes the page advance past the warning, which navigates the document and invalidates the body node. The rewritten Element.send_keys ends with self.update(), which calls cdp.dom.resolve_node on that now-stale body node and raises "No node with given id found". Route the bypass through the keyboard helper directly on the tab instead, skipping Element.send_keys' trailing self.update(). The typing dispatch is unchanged; only the stale-node cleanup at this one call site is avoided. Verified: demo_typing.py now passes all 8 tests against real Chrome, including test_bypass_insecure_connection_warning (title advances from "Privacy error" to "self-signed.badssl.com").
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: real key-event typing in
send_keys/typeSummary
Element.send_keys(and thereforeDriver.type) now dispatches real CDP key events —keyDown+keyUpper character with correctcode,key,windowsVirtualKeyCode, and Shift-wrapping for shifted characters — instead of a single syntheticcharevent per character. Characters without a physical key (emoji, non-Latin scripts, IME input) fall back toInput.insertText. The public API is unchanged.Problem
The previous
send_keysimplemented typing as oneInput.dispatchKeyEvent("char", text=char)per character. That synthetic event:code/windowsVirtualKeyCode, so pages that readevent.codeorevent.keyCodesee empty/zero values.keydown/keyuppair, so listeners on those events (very common — captchas, masked inputs, JS frameworks, "press Enter to submit") never fire.bypass_insecure_connection_warning(), which relies on typingthisisunsafeinto Chrome's SSL interstitial — the interstitial listens for real key events and ignoreschar-only dispatch.Solution
New
botasaurus_driver/core/keys.pycentralizes key-event dispatch:KEYBOARD_LAYOUT/SHIFT_CHARS/VK_CODESmaps resolve each character to its physical-keycode, Windows VK code, and whether Shift is required.resolve_key(char)→ key info, orNonefor unmapped characters.dispatch_key(tab, char)emits therawKeyDown-Shift (if needed) →keyDown-with-text →keyUp→ Shift-keyUpsequence with faithfulunmodified_text/text.type_text(tab, text)walks the string, routing unmapped chars toInput.insertText, and collapsing\r\nto a single Enter.Element.send_keysnow callskeys.type_text(self._tab, text).Behavior
keydown/keyupwith correctcode/keyCode, Shift held for capitals and symbols.\n,\r, and\r\n→ one Enter (NumpadEnter/Entercode, VK 13); CRLF counts as a single Enter.\t→ Tab.你好,👋, IME output) →Input.insertText(char), the standard CDP primitive for non-keypress text insertion — no fabricated VK codes.bypass_insecure_connection_warning()works again becausethisisunsafenow produces real key events the interstitial accepts.Testing
demo_typing.pyis a self-contained gate script (no external deps beyond the driver) that launches a browser against a local HTML harness page which captures every keyboard event, then asserts:keydown/keypress/keyupordering and count for"ab".codeis never empty for any mapped printable character.keyCodefidelity for a sample of letters/digits/symbols (matchesVK_CODES).\n,\r, and\r\neach produce exactly one Enter.你好 👋reaches the input viainsertTextand the final.valuematches.bypass_insecure_connection_warning()succeeds against a bad-SSL page.Run with:
python demo_typing.py(exits non-zero on any failure).Compatibility
driver.type(selector, text)andelement.send_keys(text)signatures and behavior from the caller's perspective are identical.cdp.input_primitives already imported by the driver.Out of scope
type_humanAPI — not introduced;send_keysis fixed in place per the "fix the existing API" approach.Files
botasaurus_driver/core/keys.py(new, 124 lines) — key maps + dispatch.botasaurus_driver/core/element.py(+2/-3) —send_keyscallskeys.type_text.demo_typing.py(new, 386 lines) — gate script.README.md(+7) — short note next to thetypeexample.