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.
This commit is contained in:
parent
cca68004ab
commit
f87e37ebff
2 changed files with 34 additions and 14 deletions
|
|
@ -171,15 +171,20 @@ struct XKeyEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
union XEventData {
|
struct XEvent {
|
||||||
key: XKeyEvent,
|
// XEvent is a union — all variants share offset 0
|
||||||
|
// sizeof(XEvent) = 192 on x86_64 (long pad[24])
|
||||||
|
_bytes: [u8; 192],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
impl XEvent {
|
||||||
struct XEvent {
|
fn event_type(&self) -> c_int {
|
||||||
_type: c_int,
|
unsafe { std::ptr::read_unaligned(self._bytes.as_ptr() as *const c_int) }
|
||||||
_pad: [u8; 24],
|
}
|
||||||
data: XEventData,
|
|
||||||
|
fn key(&self) -> &XKeyEvent {
|
||||||
|
unsafe { &*(self._bytes.as_ptr() as *const XKeyEvent) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeySym = u64;
|
type KeySym = u64;
|
||||||
|
|
@ -308,7 +313,18 @@ impl X11Capture {
|
||||||
tv_usec: ((timeout_ms % 1000) * 1000) as i64,
|
tv_usec: ((timeout_ms % 1000) * 1000) as i64,
|
||||||
};
|
};
|
||||||
let n = select(fd + 1, &mut readfds, std::ptr::null_mut(), std::ptr::null_mut(), &mut timeout);
|
let n = select(fd + 1, &mut readfds, std::ptr::null_mut(), std::ptr::null_mut(), &mut timeout);
|
||||||
n > 0 && fd_isset(fd, &readfds)
|
if n > 0 && fd_isset(fd, &readfds) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// Log on first timeout to diagnose
|
||||||
|
static mut LOGGED: bool = false;
|
||||||
|
if !LOGGED {
|
||||||
|
eprintln!("[vietc] X11 select timeout (fd={}, n={}, timeout={}ms) — no events arriving", fd, n, timeout_ms);
|
||||||
|
eprintln!("[vietc] Keyboard grab may not be working. Check if another app grabbed the keyboard.");
|
||||||
|
LOGGED = true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,7 +343,7 @@ impl X11Capture {
|
||||||
(self.lib.x_next_event)(self.display, &mut event);
|
(self.lib.x_next_event)(self.display, &mut event);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _type = event._type;
|
let _type = event.event_type();
|
||||||
|
|
||||||
// Handle FocusIn/FocusOut — reset engine state when focus changes
|
// Handle FocusIn/FocusOut — reset engine state when focus changes
|
||||||
if _type == FOCUS_OUT {
|
if _type == FOCUS_OUT {
|
||||||
|
|
@ -343,7 +359,7 @@ impl X11Capture {
|
||||||
return self.next_event();
|
return self.next_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
let key_event = unsafe { &event.data.key };
|
let key_event = event.key();
|
||||||
let ch = self.lookup_key(key_event);
|
let ch = self.lookup_key(key_event);
|
||||||
Some(X11KeyEvent {
|
Some(X11KeyEvent {
|
||||||
keycode: key_event.keycode,
|
keycode: key_event.keycode,
|
||||||
|
|
|
||||||
|
|
@ -201,9 +201,13 @@ struct XSelectionRequestEvent {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct XEvent {
|
struct XEvent {
|
||||||
_type: c_int,
|
_bytes: [u8; 192],
|
||||||
_pad: [u8; 24],
|
}
|
||||||
data: [u64; 6],
|
|
||||||
|
impl XEvent {
|
||||||
|
fn event_type(&self) -> c_int {
|
||||||
|
unsafe { std::ptr::read_unaligned(self._bytes.as_ptr() as *const c_int) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct X11Injector {
|
pub struct X11Injector {
|
||||||
|
|
@ -298,7 +302,7 @@ impl X11Injector {
|
||||||
while (self.lib.x_pending)(self.display) > 0 {
|
while (self.lib.x_pending)(self.display) > 0 {
|
||||||
let mut event: XEvent = std::mem::zeroed();
|
let mut event: XEvent = std::mem::zeroed();
|
||||||
(self.lib.x_next_event)(self.display, &mut event);
|
(self.lib.x_next_event)(self.display, &mut event);
|
||||||
if event._type == SELECTION_REQUEST {
|
if event.event_type() == SELECTION_REQUEST {
|
||||||
let req = &*(&event as *const XEvent as *const XSelectionRequestEvent);
|
let req = &*(&event as *const XEvent as *const XSelectionRequestEvent);
|
||||||
self.handle_selection_request(req);
|
self.handle_selection_request(req);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue