{"record":{"id":"d97d79be91073c71","repo":"stablyai/orca","slug":"hotkey-combinations-require-xdotool","errorCode":null,"errorMessage":"hotkey combinations require xdotool","messagePattern":"hotkey combinations require xdotool","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"native/computer-use-linux/runtime.py","lineNumber":941,"sourceCode":"\ndef press_key(raw):\n    name = key_name(raw)\n    if len(name) == 1:\n        Atspi.generate_keyboard_event(0, name, Atspi.KeySynthType.STRING)\n        return\n    if Gdk is None:\n        raise RuntimeError(\"GDK is required for non-character key synthesis\")\n    Atspi.generate_keyboard_event(Gdk.keyval_from_name(name), None, Atspi.KeySynthType.PRESSRELEASE)\n\n\ndef hotkey(raw):\n    key_spec = re.sub(r\"(?i)commandorcontrol|cmdorctrl\", \"ctrl\", str(raw))\n    xdotool = shutil.which(\"xdotool\")\n    if xdotool:\n        subprocess.run([xdotool, \"key\", key_spec], check=True)\n        return\n    if \"+\" in key_spec:\n        raise RuntimeError(\"hotkey combinations require xdotool\")\n    press_key(key_spec)\n\n\ndef type_text(value):\n    Atspi.generate_keyboard_event(0, str(value), Atspi.KeySynthType.STRING)\n\n\ndef paste_text(value):\n    text = str(value)\n    previous = read_clipboard()\n    try:\n        write_clipboard(text)\n        hotkey(\"ctrl+v\")\n        # Why: X11 paste consumers may read the selection after the key event\n        # returns, so keep the pasted text as the owner briefly before restore.\n        time.sleep(CLIPBOARD_PASTE_SETTLE_SECONDS)\n    finally:\n        if previous is not None:","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/native/computer-use-linux/runtime.py#L923-L959","documentation":"Raised by hotkey (runtime.py:941) when the key spec contains '+' (a chord) and xdotool is not installed. For chords, the runtime cannot fall back to AT-SPI press_key (which handles only a single key), so it requires xdotool to issue the combination. Single-key specs without '+' would instead fall through to press_key.","triggerScenarios":"Calling the 'hotkey' tool with operation['key'] like 'ctrl+c', 'alt+tab', 'shift+ctrl+t' on a host where shutil.which('xdotool') is None. cmdorctrl/cmdorctrl are normalized to ctrl earlier (runtime.py:935) so they don't change this outcome.","commonSituations":"Minimal/container environments without xdotool; Wayland-only systems where xdotool isn't useful; assuming AT-SPI can synthesize arbitrary chords (it cannot here).","solutions":["Install xdotool (apt install xdotool / dnf install xdotool) on an X11 session.","If only a single key is needed, send a key without '+' so it routes to press_key instead.","On Wayland, use a Wayland-native tool; xdotool chord synthesis is X11-only."],"exampleFix":"// before: no xdotool, chord fails\n{\"tool\":\"hotkey\",\"key\":\"ctrl+c\"}\n# after (shell):\nsudo apt install xdotool","handlingStrategy":"validation","validationCode":"import shutil\n\ndef can_hotkey_chord():\n    return shutil.which(\"xdotool\") is not None\n\nif \"+\" in key_spec and not can_hotkey_chord():\n    raise EnvironmentError(\"install xdotool to use key chords\")","typeGuard":"import shutil\n\ndef supports_hotkey_chords() -> bool:\n    return shutil.which(\"xdotool\") is not None","tryCatchPattern":"try:\n    run_operation(op)\nexcept RuntimeError as e:\n    if \"hotkey combinations require xdotool\" in str(e):\n        # split chord into individual press_key calls as a fallback\n        pass\n    else:\n        raise","preventionTips":["Install xdotool (on X11) if you issue keyboard chords.","Probe for xdotool at startup and disable chord UI when missing.","Prefer single-key press_key when xdotool is unavailable."],"tags":["environment","computer-use","keyboard","xdotool","hotkey","python"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}