diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 487fff3..a2c420f 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -814,6 +814,12 @@ fn run_with_x11( } } + // Re-grab if the grab was silently lost (tray started, WM took focus, etc.) + if !capture.is_grabbed() { + eprintln!("[vietc] Keyboard grab lost — re-grabbing"); + capture.grab_keyboard(); + } + thread::sleep(Duration::from_millis(10)); } } diff --git a/packaging/appimage/build-appimage.sh b/packaging/appimage/build-appimage.sh index df2ce36..bfde4f9 100644 --- a/packaging/appimage/build-appimage.sh +++ b/packaging/appimage/build-appimage.sh @@ -208,7 +208,7 @@ fi if [ -z "$NEED_ROOT" ]; then # X11: no root needed pkill -x vietc 2>/dev/null; sleep 0.3 - "$HERE/usr/bin/vietc" >"$HERE/vietc-daemon.log" 2>&1 & + "$HERE/usr/bin/vietc" >"$HOME/.config/vietc/vietc-daemon.log" 2>&1 & DAEMON_PID=$! else # Fix Wayland env for root: sudo resets XDG_RUNTIME_DIR, breaking wtype/wl-copy. diff --git a/packaging/deb/build-deb.sh b/packaging/deb/build-deb.sh index b57a75b..3d80118 100755 --- a/packaging/deb/build-deb.sh +++ b/packaging/deb/build-deb.sh @@ -12,7 +12,7 @@ echo "=== Building Viet+ .deb package v${VERSION} ===" # Build binaries (all features: x11 + wayland) echo "[1/5] Building binaries..." cargo build --release --features "x11,wayland" --manifest-path "$PROJECT_ROOT/Cargo.toml" -(cd "$PROJECT_ROOT/ui" && cargo build --release) || echo " Warning: UI tray not built (libdbus-1-dev may be missing)" +(cd "$PROJECT_ROOT/ui" && export PKG_CONFIG_PATH="/tmp/dbus-dev/extracted/usr/lib/x86_64-linux-gnu/pkgconfig:${PKG_CONFIG_PATH:-}" && export RUSTFLAGS="-L /tmp/dbus-dev/lib" && cargo build --release) || echo " Warning: UI tray not built (libdbus-1-dev may be missing)" echo " Done." # Clean and create staging diff --git a/protocol/src/x11_capture.rs b/protocol/src/x11_capture.rs index f9a1965..b381221 100644 --- a/protocol/src/x11_capture.rs +++ b/protocol/src/x11_capture.rs @@ -31,6 +31,7 @@ struct X11Lib { x_default_root_window: unsafe extern "C" fn(*mut Display) -> Window, x_grab_keyboard: unsafe extern "C" fn(*mut Display, Window, c_int, c_int, c_int, Time) -> c_int, x_ungrab_keyboard: unsafe extern "C" fn(*mut Display, Time) -> c_int, + x_pending: unsafe extern "C" fn(*mut Display) -> c_int, x_next_event: unsafe extern "C" fn(*mut Display, *mut XEvent), x_lookup_string: unsafe extern "C" fn(*mut XKeyEvent, *mut c_char, c_int, *mut KeySym, *mut c_int) -> c_int, x_utf8_lookup_string: Option c_int>, @@ -66,6 +67,7 @@ impl X11Lib { let x_default_root_window = sym!("XDefaultRootWindow"); let x_grab_keyboard = sym!("XGrabKeyboard"); let x_ungrab_keyboard = sym!("XUngrabKeyboard"); + let x_pending = sym!("XPending"); let x_next_event = sym!("XNextEvent"); let x_lookup_string = sym!("XLookupString"); let x_utf8_lookup_string = dlsym(handle, b"Xutf8LookupString\0".as_ptr() as *const c_char); @@ -83,6 +85,7 @@ impl X11Lib { x_default_root_window, x_grab_keyboard, x_ungrab_keyboard, + x_pending, x_next_event, x_lookup_string, x_utf8_lookup_string, @@ -212,11 +215,27 @@ impl X11Capture { } } + pub fn has_pending_events(&self) -> bool { + if !self.grabbed { + return false; + } + unsafe { (self.lib.x_pending)(self.display) > 0 } + } + + pub fn is_grabbed(&self) -> bool { + self.grabbed + } + pub fn next_event(&mut self) -> Option { if !self.grabbed { return None; } + // Non-blocking: only read if events are pending + if !self.has_pending_events() { + return None; + } + let mut event: XEvent = unsafe { std::mem::zeroed() }; unsafe { (self.lib.x_next_event)(self.display, &mut event);