From 94c31e42a44b2621ae1ddc02b36ee5f0ee0bc16a Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Mon, 22 Jun 2015 22:49:48 +0100 Subject: Use XInput2 for event handling This provides smooth scrolling for touchpad devices and will enable support for touch events etc. in future. --- src/api/x11/window.rs | 159 +++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 86 deletions(-) (limited to 'src/api/x11/window.rs') diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index 15e27ce..300fdb5 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -2,10 +2,12 @@ use {Event, BuilderAttribs, MouseCursor}; use CreationError; use CreationError::OsError; use libc; +use std::borrow::Borrow; use std::{mem, ptr}; use std::cell::Cell; use std::sync::atomic::AtomicBool; use std::collections::VecDeque; +use std::slice::from_raw_parts; use std::sync::{Arc, Mutex}; use Api; @@ -20,6 +22,7 @@ use api::egl::Context as EglContext; use platform::MonitorID as PlatformMonitorID; +use super::input::XInputEventHandler; use super::{events, ffi}; use super::{MonitorID, XConnection}; @@ -106,8 +109,64 @@ impl WindowProxy { } } +// XEvents of type GenericEvent store their actual data +// in an XGenericEventCookie data structure. This is a wrapper +// to extract the cookie from a GenericEvent XEvent and release +// the cookie data once it has been processed +struct GenericEventCookie<'a> { + display: &'a XConnection, + cookie: ffi::XGenericEventCookie +} + +impl<'a> GenericEventCookie<'a> { + fn from_event<'b>(display: &'b XConnection, event: ffi::XEvent) -> Option> { + unsafe { + let mut cookie: ffi::XGenericEventCookie = From::from(event); + if (display.xlib.XGetEventData)(display.display, &mut cookie) == ffi::True { + Some(GenericEventCookie{display: display, cookie: cookie}) + } else { + None + } + } + } +} + +impl<'a> Drop for GenericEventCookie<'a> { + fn drop(&mut self) { + unsafe { + let xlib = &self.display.xlib; + (xlib.XFreeEventData)(self.display.display, &mut self.cookie); + } + } +} + pub struct PollEventsIterator<'a> { - window: &'a Window, + window: &'a Window +} + +impl<'a> PollEventsIterator<'a> { + fn queue_event(&mut self, event: Event) { + self.window.pending_events.lock().unwrap().push_back(event); + } + + fn process_generic_event(&mut self, event: &ffi::XEvent) { + if let Some(cookie) = GenericEventCookie::from_event(self.window.x.display.borrow(), *event) { + match cookie.cookie.evtype { + ffi::XI_DeviceChanged...ffi::XI_LASTEVENT => { + match self.window.input_handler.lock() { + Ok(mut handler) => { + match handler.translate_event(&cookie.cookie) { + Some(event) => self.queue_event(event), + None => {} + } + }, + Err(_) => {} + } + }, + _ => {} + } + } + } } impl<'a> Iterator for PollEventsIterator<'a> { @@ -126,7 +185,10 @@ impl<'a> Iterator for PollEventsIterator<'a> { let res = unsafe { (self.window.x.display.xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::ClientMessage, &mut xev) }; if res == 0 { - return None; + let res = unsafe { (self.window.x.display.xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::GenericEvent, &mut xev) }; + if res == 0 { + return None; + } } } @@ -164,93 +226,16 @@ impl<'a> Iterator for PollEventsIterator<'a> { return Some(Refresh); }, - ffi::MotionNotify => { - use events::Event::MouseMoved; - let event: &ffi::XMotionEvent = unsafe { mem::transmute(&xev) }; - return Some(MouseMoved((event.x as i32, event.y as i32))); - }, - - ffi::KeyPress | ffi::KeyRelease => { - use events::Event::{KeyboardInput, ReceivedCharacter}; - use events::ElementState::{Pressed, Released}; - let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&mut xev) }; - - if event.type_ == ffi::KeyPress { - let raw_ev: *mut ffi::XKeyEvent = event; - unsafe { (self.window.x.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window.x.window) }; + ffi::KeyPress | ffi::KeyRelease => { + let mut event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&mut xev) }; + let events = self.window.input_handler.lock().unwrap().translate_key_event(&mut event); + for event in events { + self.queue_event(event); } - - let state = if xev.get_type() == ffi::KeyPress { Pressed } else { Released }; - - let mut kp_keysym = 0; - - let written = unsafe { - use std::str; - - let mut buffer: [u8; 16] = [mem::uninitialized(); 16]; - let raw_ev: *mut ffi::XKeyEvent = event; - let count = (self.window.x.display.xlib.Xutf8LookupString)(self.window.x.ic, mem::transmute(raw_ev), - mem::transmute(buffer.as_mut_ptr()), - buffer.len() as libc::c_int, &mut kp_keysym, ptr::null_mut()); - - str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string() - }; - - { - let mut pending = self.window.pending_events.lock().unwrap(); - for chr in written.chars() { - pending.push_back(ReceivedCharacter(chr)); - } - } - - let mut keysym = unsafe { - (self.window.x.display.xlib.XKeycodeToKeysym)(self.window.x.display.display, event.keycode as ffi::KeyCode, 0) - }; - - if (ffi::XK_KP_Space as libc::c_ulong <= keysym) && (keysym <= ffi::XK_KP_9 as libc::c_ulong) { - keysym = kp_keysym - }; - - let vkey = events::keycode_to_element(keysym as libc::c_uint); - - return Some(KeyboardInput(state, event.keycode as u8, vkey)); - }, - - ffi::ButtonPress | ffi::ButtonRelease => { - use events::Event::{MouseInput, MouseWheel}; - use events::ElementState::{Pressed, Released}; - use events::MouseButton::{Left, Right, Middle}; - use events::MouseScrollDelta::{LineDelta}; - - let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) }; - - let state = if xev.get_type() == ffi::ButtonPress { Pressed } else { Released }; - - let button = match event.button { - ffi::Button1 => Some(Left), - ffi::Button2 => Some(Middle), - ffi::Button3 => Some(Right), - ffi::Button4 => { - let delta = LineDelta(0.0, 1.0); - self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta)); - None - } - ffi::Button5 => { - let delta = LineDelta(0.0, -1.0); - self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta)); - None - } - _ => None - }; - - match button { - Some(button) => - return Some(MouseInput(state, button)), - None => () - }; }, + ffi::GenericEvent => { self.process_generic_event(&mut xev); } - _ => () + _ => {} }; } } @@ -296,6 +281,7 @@ pub struct Window { /// Events that have been retreived with XLib but not dispatched with iterators yet pending_events: Mutex>, cursor_state: Mutex, + input_handler: Mutex } impl Window { @@ -608,6 +594,7 @@ impl Window { pixel_format: pixel_format, pending_events: Mutex::new(VecDeque::new()), cursor_state: Mutex::new(CursorState::Normal), + input_handler: Mutex::new(XInputEventHandler::new(display, window, ic)) }; // returning -- cgit v1.2.3