diff --git a/src/backend/producer/x11.rs b/src/backend/producer/x11.rs index 6abb812..9d9eff8 100644 --- a/src/backend/producer/x11.rs +++ b/src/backend/producer/x11.rs @@ -13,9 +13,11 @@ use crate::client::{ClientEvent, ClientHandle}; use tokio::io::unix::AsyncFd; use x11::xlib::{ - self, KeyPressMask, KeyReleaseMask, PointerMotionMask, XWhitePixel, XCloseDisplay, - XDefaultScreen, XNextEvent, XOpenDisplay, XPending, - XRootWindow, XFlush, CWOverrideRedirect, CWBackPixel, CWEventMask, XSetWindowAttributes, XCreateWindow, CopyFromParent, XMapRaised, VisibilityChangeMask, ExposureMask, XSetClassHint, XClassHint, + self, CWBackPixel, CWEventMask, CWOverrideRedirect, CopyFromParent, EnterWindowMask, + ExposureMask, KeyPress, KeyPressMask, KeyRelease, KeyReleaseMask, LeaveWindowMask, + PointerMotionMask, VisibilityChangeMask, XClassHint, XCloseDisplay, XCreateWindow, + XDefaultScreen, XFlush, XMapRaised, XNextEvent, XOpenDisplay, XPending, XRootWindow, + XSetClassHint, XSetWindowAttributes, XWhitePixel, EnterNotify, XGetInputFocus, XGrabKeyboard, XDefaultRootWindow, GrabModeAsync, CurrentTime, XGrabPointer, ButtonPressMask, ButtonReleaseMask, MotionNotify, }; pub struct X11Producer(AsyncFd); @@ -24,6 +26,7 @@ struct Inner { connection_fd: RawFd, display: *mut xlib::Display, pending_events: VecDeque<(ClientHandle, Event)>, + window: u64, } impl AsRawFd for Inner { @@ -50,19 +53,26 @@ impl X11Producer { let mut attr: XSetWindowAttributes = unsafe { std::mem::zeroed() }; attr.override_redirect = true as i32; attr.background_pixel = unsafe { XWhitePixel(display, screen) }; - attr.event_mask = ExposureMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask | PointerMotionMask; + attr.event_mask = ExposureMask + | VisibilityChangeMask + | KeyPressMask + | KeyReleaseMask + | PointerMotionMask + | EnterWindowMask + | LeaveWindowMask; let window = unsafe { XCreateWindow( - display, root_window, - 0, /* x */ - 0, /* y */ - 2560, /* min width */ - 10, /* min height */ - 0, /* border width */ - CopyFromParent, /* depth */ + display, + root_window, + 0, /* x */ + 0, /* y */ + 2560, /* min width */ + 10, /* min height */ + 0, /* border width */ + CopyFromParent, /* depth */ CopyFromParent as u32, /* class */ - ptr::null_mut(), /* Visual *visual */ - CWOverrideRedirect | CWBackPixel | CWEventMask, + ptr::null_mut(), /* Visual *visual */ + CWOverrideRedirect | CWBackPixel | CWEventMask, &mut attr as *mut _, ) }; @@ -70,21 +80,22 @@ impl X11Producer { let name = name.as_mut_ptr(); let mut class_hint = XClassHint { - res_name: name as * mut i8, - res_class: name as * mut i8, + res_name: name as *mut i8, + res_class: name as *mut i8, }; unsafe { XSetClassHint(display, window, &mut class_hint as *mut _) }; log::warn!("window: {window}"); // unsafe { XSelectInput(display, window, event_mask as i64) }; unsafe { XMapRaised(display, window) }; unsafe { XFlush(display) }; - + /* can not fail */ let connection_fd = unsafe { xlib::XConnectionNumber(display) }; let pending_events = VecDeque::new(); let inner = Inner { connection_fd, display, + window, pending_events, }; let async_fd = AsyncFd::new(inner)?; @@ -93,27 +104,46 @@ impl X11Producer { } impl Inner { - fn decode(&self, xevent: xlib::XEvent) -> Option<(u32, Event)> { - let _ = xevent; - Some(( - 0, - Event::Pointer(PointerEvent::Motion { - time: 0, - relative_x: 1., - relative_y: 0., - }), - )) + fn decode(&mut self, xevent: xlib::XEvent) -> Option<(u32, Event)> { + log::info!("decoding {xevent:?}"); + match xevent.get_type() { + t if t == KeyPress || t == KeyRelease => { + let key_event: xlib::XKeyEvent = unsafe { xevent.key }; + let code = key_event.keycode; + let linux_code = code - 8; + let state = (xevent.get_type() == KeyPress) as u8; + return Some(( + 0, + Event::Keyboard(crate::event::KeyboardEvent::Key { + time: 0, + key: linux_code, + state, + }), + )); + } + t if t == EnterNotify => { + let mut prev_win = 0; + unsafe { XGetInputFocus(self.display, &mut self.window as *mut _, &mut prev_win as * mut _) }; + unsafe { XGrabKeyboard(self.display, XDefaultRootWindow(self.display), true as i32, GrabModeAsync, GrabModeAsync, CurrentTime) }; + unsafe { XGrabPointer(self.display, XDefaultRootWindow(self.display), true as i32, (PointerMotionMask | ButtonPressMask | ButtonReleaseMask) as u32, GrabModeAsync, GrabModeAsync, self.window, 0, CurrentTime) }; + + Some((0, Event::Enter())) + } + t if t == MotionNotify => { + let pointer_event = unsafe { xevent.motion }; + let (abs_x, abs_y) = (pointer_event.x, pointer_event.y); + let event = Event::Pointer(PointerEvent::Motion { time: 0, relative_x: abs_x as f64, relative_y: abs_y as f64 }); + Some((0, event)) + } + _ => None, + } } fn dispatch(&mut self) -> io::Result { unsafe { if XPending(self.display) > 0 { let mut xevent: xlib::XEvent = std::mem::zeroed(); - if XNextEvent(self.display, &mut xevent as *mut _) != 0 { - log::info!("event: {xevent:?}"); - return Err(io::Error::last_os_error().into()); - } - log::info!("event: {xevent:?}"); + XNextEvent(self.display, &mut xevent as *mut _); if let Some(event) = self.decode(xevent) { self.pending_events.push_back(event); }