Skip to content

fix(wayland): reliable clipboard copy and ydotool injection on non-US layouts - #480

Merged
jatinkrmalik merged 1 commit into
VocaHQ:mainfrom
fsioni:fix/wayland-ydotool-injection
Jul 1, 2026
Merged

fix(wayland): reliable clipboard copy and ydotool injection on non-US layouts#480
jatinkrmalik merged 1 commit into
VocaHQ:mainfrom
fsioni:fix/wayland-ydotool-injection

Conversation

@fsioni

@fsioni fsioni commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes two independent text-injection bugs on Wayland that, combined, made dictation produce nothing usable (no text in the focused field, empty clipboard) on a GNOME/Mutter + AZERTY setup.

1. Clipboard copy silently failed (_run_clipboard_command)

wl-copy (and xclip/xsel) fork a background process that keeps owning the selection in order to serve it. That child inherits the pipes created by subprocess.run(..., stderr=subprocess.PIPE), so run() blocks reading stderr until the child exits — i.e. until the clipboard is next overwritten, which may be never. The call therefore hits _clipboard_timeout and _copy_to_clipboard returns False, even though the copy actually succeeded.

Reproduced on a real session:

WARNING wl-copy failed: Command '['wl-copy', '...']' timed out after 2.5 seconds
copy_to_clipboard -> False
# ...yet:
$ wl-paste
...the exact text was on the clipboard all along

Fix: redirect stdout/stderr to DEVNULL so run() only waits for the short-lived foreground process. Measured: PIPE → timeout; DEVNULL → returns in ~0.06 s with the clipboard correctly set. I couldn't find this one reported elsewhere.

2. ydotool type scrambles text on non-US layouts (_inject_with_wayland_tool)

ydotool type emits positional evdev keycodes that the compositor re-interprets through the active keyboard layout, which ydotool assumes is US QWERTY. On AZERTY/QWERTZ/Dvorak the output is garbled (e.g. message,essqge, avecqvec) and non-ASCII characters are dropped.

The code already used clipboard paste for non-ASCII text (#362); this extends it to all text when the tool is ydotool, since Ctrl+V is both layout-independent and Unicode-safe. (ydotool key Ctrl+V uses keycodes 29+47, which map to the same physical keys on QWERTY and AZERTY.)

This completes #164: that issue was closed but only the non-ASCII case was actually fixed (via #362) — plain ASCII still garbled on non-US layouts.

Tests

  • tests/test_text_injector.py and tests/test_text_injector_ext.py pass.
  • Updated test_ydotool_ascii_* to reflect that ydotool now always pastes.
  • Added test_clipboard_command_does_not_capture_pipe as a regression guard for the PIPE→DEVNULL fix.
  • black and isort clean.

Related issues

Notes / scope

https://claude.ai/code/session_01EhyratrEE4vDWhriirUB9k

Two independent text-injection bugs on Wayland:

1. Clipboard copy silently failed. wl-copy/xclip/xsel fork a background
   process that keeps owning the selection; capturing its stderr with
   subprocess.PIPE makes run() block on the surviving child until the
   clipboard is next overwritten, so the call always hits its timeout and
   _copy_to_clipboard reports failure even though the copy succeeded.
   Redirect stdout/stderr to DEVNULL so run() only waits for the
   short-lived foreground process.

2. ydotool scrambled text on non-US keyboard layouts. `ydotool type`
   emits positional evdev keycodes that get re-interpreted through the
   active layout (assumed US QWERTY), so dictated text came out garbled on
   AZERTY/QWERTZ/Dvorak (e.g. "message" -> ",essqge") and non-ASCII was
   dropped. Always inject via clipboard paste (Ctrl+V) for ydotool, which
   is layout-independent and Unicode-safe.

Adds regression tests for both.

Claude-Session: https://claude.ai/code/session_01EhyratrEE4vDWhriirUB9k
Copilot AI review requested due to automatic review settings June 25, 2026 10:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added app Core Python application (src, packaging) tests Test suite changes labels Jun 25, 2026
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.72%. Comparing base (c64b727) to head (233af78).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #480   +/-   ##
=======================================
  Coverage   84.72%   84.72%           
=======================================
  Files          31       31           
  Lines        5068     5068           
  Branches      782      782           
=======================================
  Hits         4294     4294           
  Misses        595      595           
  Partials      179      179           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jatinkrmalik jatinkrmalik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Went through the clipboard copy fix and the ydotool layout handling, both look right.

@jatinkrmalik
jatinkrmalik merged commit 1497267 into VocaHQ:main Jul 1, 2026
11 checks passed
@jatinkrmalik

Copy link
Copy Markdown
Member

Merged, thanks a lot @fsioni! The scrambled output on AZERTY/QWERTZ layouts has tripped up a bunch of people, and that clipboard hang was a nasty one to track down. This ships in v0.13.0-beta.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Core Python application (src, packaging) tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants