Commit graph

10 commits

Author SHA1 Message Date
Khoa Vo
d1a5f36606 fix: remove XGrabKeyboard from XRecord path — it blocks event delivery
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().
2026-06-26 10:13:27 +07:00
Khoa Vo
3510cd7384 fix: correct XRecordRange layout (32 bytes, device_events at offset 18)
- 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
2026-06-26 10:05:22 +07:00
Khoa Vo
12ac8b0c24 fix: XRecordRange struct layout — client_spec (4 bytes) before device_events 2026-06-26 09:59:29 +07:00
Khoa Vo
e35c034157 fix: replace XGrabKeyboard capture with XRecord extension
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.
2026-06-26 09:52:04 +07:00
Khoa Vo
f87e37ebff fix: XEvent was a struct but X11 defines it as a union — all fields at offset 0
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.
2026-06-26 09:38:25 +07:00
Khoa Vo
cca68004ab fix: use select() on X11 fd for reliable event detection
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.
2026-06-26 09:32:47 +07:00
Khoa Vo
d6ded6e706 fix: add XSelectInput on root window so X server delivers key events to our connection
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.
2026-06-26 09:27:15 +07:00
Khoa Vo
666f1b400e fix: non-blocking XPending event loop + auto re-grab on grab loss
- 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
2026-06-26 09:17:47 +07:00
Khoa Vo
3858aa955c feat: implement Backspace-Replay pattern for perfect engine sync
- Add Engine::replay_keystrokes() — creates fresh engine and replays
  all keystrokes to compute correct screen output from scratch
- Add Daemon::replay_and_inject() — tracks keystroke history and
  screen output, computes diff (backspaces + new text) on each keypress
- Add Daemon::replay_backspace() — pops from history, replays, diffs
- Handle flush chars (space, period, etc.) separately — commit word,
  type char, clear history
- Add FocusIn/FocusOut detection for engine reset on focus loss
- Add CPU pinning (P-cores 0-3) + nice(-10) priority boost
- Clean up 9 dead code warnings (unused fields, constants, types)
- Add replay_keystrokes tests for Telex, VNI, and backspace
- 255 tests pass (was 252)
2026-06-26 08:40:38 +07:00
Khoa Vo
bb0847a38f X11 capture: proper key tracking, direct clipboard, VNI default
- X11 keyboard capture via XGrabKeyboard (no input group needed)
- Direct X11 clipboard for Unicode injection (no xclip/xdotool dependency)
- Proper KeyPress/KeyRelease tracking (fix Ctrl+C, Alt+Tab, held keys)
- Default input_method=vni, start_enabled=false
- AppImage: bundled xclip, proper keyboard+VN SVG icon
- Deb: Recommends libxtst6, xclip
2026-06-26 07:56:52 +07:00