Use XInput2 for event handling
This provides smooth scrolling for touchpad devices and will enable support for touch events etc. in future.
This commit is contained in:
parent
164d47b93c
commit
94c31e42a4
5 changed files with 416 additions and 86 deletions
|
|
@ -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<GenericEventCookie<'b>> {
|
||||
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::GenericEvent => { self.process_generic_event(&mut xev); }
|
||||
|
||||
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 => ()
|
||||
};
|
||||
},
|
||||
|
||||
_ => ()
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -296,6 +281,7 @@ pub struct Window {
|
|||
/// Events that have been retreived with XLib but not dispatched with iterators yet
|
||||
pending_events: Mutex<VecDeque<Event>>,
|
||||
cursor_state: Mutex<CursorState>,
|
||||
input_handler: Mutex<XInputEventHandler>
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue