paste_via_clipboard() called send_keycode(22, false) which sends evdev
keycode 22 = KEY_U (letter 'u'), not KEY_BACKSPACE (evdev 14). This
caused garbled output whenever Vietnamese Unicode text was pasted via
clipboard (every VNI correction with accented characters).
send_backspace() had the same wrong evdev keycode.
- open_keyboard_device() -> open_keyboard_devices(): returns Vec of all
keyboard-capable evdev devices instead of just the first one
- run_with_evdev() polls all device FDs via single libc::poll() call
- Each device maintains independent key_state tracking
- Added XQueryKeymap/XLookupString to X11Lib in protocol crate
- X11KeymapCapture: new struct that polls X11 keymap every 10ms via
XQueryKeymap, diffs consecutive polls for press/release detection,
and uses XLookupString/Xutf8LookupString for char conversion
- run_with_x11_keymap(): replaces segfaulting XRecord-based run_with_x11
as the primary X11 fallback path
On X11 (Linux Mint, Ubuntu), clipboard-based Unicode injection was
failing — backspace was sent but the Vietnamese character never
appeared because xclip paste via Ctrl+V wasn't reliable from a
root uinput process.
Now send_string tries xdotool type first (XTest-based, doesn't touch
the user's clipboard), falling back to clipboard paste only on Wayland
or when xdotool is unavailable.
- uinput injection is now primary on X11 (XTest fallback)
- X11 XTest keycode offset +8 fixed for all send_keycode paths
- Window switch detection on every keystroke (no more gap > 100ms guard)
- Telex greyed out in tray with '(next version)' label
- Flatpak and AppImage removed; only .deb packaging
- All Cargo.toml versions bumped to 0.1.6
Debounce the clipboard restore so the user's clipboard is never written
back while a just-pasted Vietnamese word may still be read by the target
app, which caused old clipboard content to appear in the text mid-typing.
Applied to both vietc-uinputd and the in-process UinputInjector.
Add a GitHub Actions workflow that builds the .deb and AppImage on the
runner (artifacts on push/PR, GitHub Release on v* tags), and include
vietc-uinputd + vietc-xrecord in the .deb.
Co-Authored-By: vndangkhoa <vonguyendangkhoa@gmail.com>
- xclip -o read triggered unwanted paste in some apps
- Clipboard save/restore was over-engineering the Ctrl+C/V fix
- Simple clipboard write+paste is sufficient
- xdotool type depends on keyboard layout for Unicode — fails on US layout
- Backspaces were sent AFTER text (wrong order — erased what was just typed)
- Reverted to clipboard paste which is layout-independent
- xdotool types text directly into X11 focus window — no clipboard hack
- More reliable than clipboard paste (no trimming, no timing issues)
- Fallback to clipboard if xdotool not available
- Only on X11 (Wayland uses clipboard fallback)
- Splitting spaces into separate uinput events caused them to arrive
after the user's next keystrokes, resulting in 'thịtrâm' (no space).
- Now paste entire text including spaces via clipboard in one operation.
- Trailing spaces may be trimmed by some apps — but this is rarer than
the timing-induced space loss from split injection.
- \n char had no keycode mapping — now sends KEY_ENTER via uinput
- Fixed in both ASCII path and trailing-ASCII-after-unicode path
- Enter now works on single press (was being silently consumed)
- Fix Xutf8LookupString signature (missing XIC param caused all keys to map to \0)
- Port bamboo-core Vietnamese engine to Rust (bamboo.rs, input_method.rs)
- Flexible backtracking for mark/tone keys (scan up to 5 chars back)
- Correct tone placement for io, uâ, yê clusters
- Evdev capture preferred over X11 XRecord (more reliable)
- Uinput injection with correct Linux keycodes
- Vietnamese Unicode via clipboard paste + trailing ASCII via uinput
- Persistent X11 connection for Ctrl+V (no per-call dlopen overhead)
- Consume stale VNI/Telex control keys when no match found
- Fix execute_commands backspace count for evdev grabbing path
- Add vietc-uinputd privileged injection daemon
- AppImage: bundle uinputd, preserve LD_LIBRARY_PATH, fix xrecord build flags
- Remove old generated test files, add 63 focused engine tests
- Add aggressive drain loop in wait_for_event() when SKIP_RECORD_EVENTS
is true: poll 5ms + drain, repeat until quiet (up to 50ms). This closes
the timing gap where injected events arrived after drain_pipe returned
but before the flag was cleared in the next iteration.
- Remove verbose debug eprintln!/log_info from daemon (process_key,
replay, inject, toggle, window change, etc.)
- Add vietc-xrecord.c (C helper with XRecordEnableContext blocking mode)
- Update build-appimage.sh to compile and bundle C helper
XGrabKeyboard on the same display as XRecord breaks event delivery.
XRecord captures events globally without any grab needed.
Also: use XPending() before select() to check Xlib internal buffer,
and add XFlush before XRecordProcessReplies after select().
- XRecordRange is 32 bytes: core_requests(0), core_replies(2),
ext_requests(4), ext_replies(10), delivered_events(16),
device_events(18), errors(20), client_started(24), client_died(28)
- XRecordClientSpec is XID = unsigned long (8 bytes), not int (4 bytes)
- Use XRecordAllClients=3 instead of XRecordCurrentClients=1
XGrabKeyboard returns success but never delivers events to a windowless
client on modern X11. XRecord is the standard way to capture keyboard
events globally — used by xdotool, xbindkeys, and input methods.
Architecture:
- XRecord: captures all keyboard events (no grab needed)
- XGrabKeyboard: still used to block original events from reaching apps
- XTest: injects modified events
Dynamically loads libXtst.so.6 for XRecord functions.
Events flow: XRecord callback → thread-safe queue → daemon event loop.
CRITICAL BUG: XEvent was { _type, _pad[24], data } (data at offset 28)
but in X11 it's a union where ALL variants start at offset 0. This meant
event.data.key.state/keycode read from completely wrong offsets — every
keystroke produced garbage characters.
Fixed by replacing XEvent with a raw [u8; 192] byte buffer and using
event_type() and key() accessor methods that cast from offset 0.
Also fixed same bug in x11_inject.rs.
XPending returned 0 even with active keyboard grab. Using select() on
the X11 connection file descriptor with 100ms timeout to reliably detect
when the X server sends events. Also adds XSelectInput on root window
and XConnectionNumber for the fd.
Without XSelectInput, XGrabKeyboard grabs the keyboard but the X server
never sends KeyPress/KeyRelease events to our connection. Also flushes
after grab to ensure it takes effect.
- Use XPending() to check for events before XNextEvent (non-blocking)
- Add is_grabbed() and has_pending_events() public methods
- Auto re-grab keyboard when grab is silently lost (tray, WM focus)
- Fixes AppImage daemon receiving zero keystroke events
- Simplify inject_replacement_atomic: backspaces via uinput always
- paste_string skips ydotool for non-ASCII text (crashes with 'no matching keycode')
- Use xdotool (X11) or clipboard (xclip) for Vietnamese characters
- Add detailed logging at EVERY fallback step
- Remove dead ydotoold auto-start code (not available in Ubuntu package)
- Start ydotoold automatically so ydotool can handle Vietnamese chars
- Fix xclip clipboard to run as SUDO_USER when daemon is root
- Add detailed input logging for easier debugging