mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 22:31:30 +11:00
Merge pull request #510 from robertknight/x11_xinput2
Use XInput2 for event handling
This commit is contained in:
commit
7d1d035d9a
|
@ -77,16 +77,16 @@ dwmapi-sys = "0.1"
|
||||||
osmesa-sys = "0.0.5"
|
osmesa-sys = "0.0.5"
|
||||||
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
||||||
wayland-kbd = "0.2.0"
|
wayland-kbd = "0.2.0"
|
||||||
x11-dl = "=1.0.1"
|
x11-dl = "~2.0"
|
||||||
|
|
||||||
[target.x86_64-unknown-linux-gnu.dependencies]
|
[target.x86_64-unknown-linux-gnu.dependencies]
|
||||||
osmesa-sys = "0.0.5"
|
osmesa-sys = "0.0.5"
|
||||||
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
||||||
wayland-kbd = "0.2.0"
|
wayland-kbd = "0.2.0"
|
||||||
x11-dl = "=1.0.1"
|
x11-dl = "~2.0"
|
||||||
|
|
||||||
[target.arm-unknown-linux-gnueabihf.dependencies]
|
[target.arm-unknown-linux-gnueabihf.dependencies]
|
||||||
osmesa-sys = "0.0.5"
|
osmesa-sys = "0.0.5"
|
||||||
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
|
||||||
wayland-kbd = "0.2.0"
|
wayland-kbd = "0.2.0"
|
||||||
x11-dl = "=1.0.1"
|
x11-dl = "~2.0"
|
||||||
|
|
|
@ -2,6 +2,8 @@ pub use x11_dl::keysym::*;
|
||||||
pub use x11_dl::xcursor::*;
|
pub use x11_dl::xcursor::*;
|
||||||
pub use x11_dl::xf86vmode::*;
|
pub use x11_dl::xf86vmode::*;
|
||||||
pub use x11_dl::xlib::*;
|
pub use x11_dl::xlib::*;
|
||||||
|
pub use x11_dl::xinput::*;
|
||||||
|
pub use x11_dl::xinput2::*;
|
||||||
|
|
||||||
pub use self::glx::types::GLXContext;
|
pub use self::glx::types::GLXContext;
|
||||||
|
|
||||||
|
|
328
src/api/x11/input.rs
Normal file
328
src/api/x11/input.rs
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use libc;
|
||||||
|
use std::{mem, ptr};
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::slice::from_raw_parts;
|
||||||
|
|
||||||
|
use events::Event;
|
||||||
|
|
||||||
|
use super::{events, ffi};
|
||||||
|
use super::XConnection;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum AxisType {
|
||||||
|
HorizontalScroll,
|
||||||
|
VerticalScroll
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Axis {
|
||||||
|
id: i32,
|
||||||
|
device_id: i32,
|
||||||
|
axis_number: i32,
|
||||||
|
axis_type: AxisType
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct AxisValue {
|
||||||
|
device_id: i32,
|
||||||
|
axis_number: i32,
|
||||||
|
value: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputState {
|
||||||
|
/// Last-seen cursor position within a window in (x, y)
|
||||||
|
/// coordinates
|
||||||
|
cursor_pos: (f64, f64),
|
||||||
|
/// Last-seen positions of axes, used to report delta
|
||||||
|
/// movements when a new absolute axis value is received
|
||||||
|
axis_values: Vec<AxisValue>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct XInputEventHandler {
|
||||||
|
display: Arc<XConnection>,
|
||||||
|
window: ffi::Window,
|
||||||
|
ic: ffi::XIC,
|
||||||
|
axis_list: Vec<Axis>,
|
||||||
|
current_state: InputState
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XInputEventHandler {
|
||||||
|
pub fn new(display: &Arc<XConnection>, window: ffi::Window, ic: ffi::XIC) -> XInputEventHandler {
|
||||||
|
// query XInput support
|
||||||
|
let mut opcode: libc::c_int = 0;
|
||||||
|
let mut event: libc::c_int = 0;
|
||||||
|
let mut error: libc::c_int = 0;
|
||||||
|
let xinput_str = CString::new("XInputExtension").unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if (display.xlib.XQueryExtension)(display.display, xinput_str.as_ptr(), &mut opcode, &mut event, &mut error) == ffi::False {
|
||||||
|
panic!("XInput not available")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut xinput_major_ver = ffi::XI_2_Major;
|
||||||
|
let mut xinput_minor_ver = ffi::XI_2_Minor;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if (display.xinput2.XIQueryVersion)(display.display, &mut xinput_major_ver, &mut xinput_minor_ver) != ffi::Success as libc::c_int {
|
||||||
|
panic!("Unable to determine XInput version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the XInput events we want to receive.
|
||||||
|
// Button clicks and mouse events are handled via XInput
|
||||||
|
// events. Key presses are still handled via plain core
|
||||||
|
// X11 events.
|
||||||
|
let mut mask: [libc::c_uchar; 2] = [0, 0];
|
||||||
|
let mut input_event_mask = ffi::XIEventMask {
|
||||||
|
deviceid: ffi::XIAllDevices,
|
||||||
|
mask_len: mask.len() as i32,
|
||||||
|
mask: mask.as_mut_ptr()
|
||||||
|
};
|
||||||
|
let events = &[
|
||||||
|
ffi::XI_ButtonPress,
|
||||||
|
ffi::XI_ButtonRelease,
|
||||||
|
ffi::XI_Motion,
|
||||||
|
ffi::XI_Enter,
|
||||||
|
ffi::XI_Leave,
|
||||||
|
ffi::XI_FocusIn,
|
||||||
|
ffi::XI_FocusOut
|
||||||
|
];
|
||||||
|
for event in events {
|
||||||
|
ffi::XISetMask(&mut mask, *event);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
match (display.xinput2.XISelectEvents)(display.display, window, &mut input_event_mask, 1) {
|
||||||
|
status if status as u8 == ffi::Success => (),
|
||||||
|
err => panic!("Failed to select events {:?}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XInputEventHandler {
|
||||||
|
display: display.clone(),
|
||||||
|
window: window,
|
||||||
|
ic: ic,
|
||||||
|
axis_list: read_input_axis_info(display),
|
||||||
|
current_state: InputState {
|
||||||
|
cursor_pos: (0.0, 0.0),
|
||||||
|
axis_values: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate_key_event(&self, event: &mut ffi::XKeyEvent) -> Vec<Event> {
|
||||||
|
use events::Event::{KeyboardInput, ReceivedCharacter};
|
||||||
|
use events::ElementState::{Pressed, Released};
|
||||||
|
|
||||||
|
let mut translated_events = Vec::new();
|
||||||
|
|
||||||
|
let state;
|
||||||
|
if event.type_ == ffi::KeyPress {
|
||||||
|
let raw_ev: *mut ffi::XKeyEvent = event;
|
||||||
|
unsafe { (self.display.xlib.XFilterEvent)(mem::transmute(raw_ev), self.window) };
|
||||||
|
state = Pressed;
|
||||||
|
} else {
|
||||||
|
state = 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.display.xlib.Xutf8LookupString)(self.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()
|
||||||
|
};
|
||||||
|
|
||||||
|
for chr in written.chars() {
|
||||||
|
translated_events.push(ReceivedCharacter(chr));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut keysym = unsafe {
|
||||||
|
(self.display.xlib.XKeycodeToKeysym)(self.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);
|
||||||
|
|
||||||
|
translated_events.push(KeyboardInput(state, event.keycode as u8, vkey));
|
||||||
|
translated_events
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate_event(&mut self, cookie: &ffi::XGenericEventCookie) -> Option<Event> {
|
||||||
|
use events::Event::{Focused, MouseInput, MouseMoved, MouseWheel};
|
||||||
|
use events::ElementState::{Pressed, Released};
|
||||||
|
use events::MouseButton::{Left, Right, Middle};
|
||||||
|
use events::MouseScrollDelta::{PixelDelta, LineDelta};
|
||||||
|
|
||||||
|
match cookie.evtype {
|
||||||
|
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
|
||||||
|
let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
|
||||||
|
let state = if cookie.evtype == ffi::XI_ButtonPress {
|
||||||
|
Pressed
|
||||||
|
} else {
|
||||||
|
Released
|
||||||
|
};
|
||||||
|
match event_data.detail as u32 {
|
||||||
|
ffi::Button1 => Some(MouseInput(state, Left)),
|
||||||
|
ffi::Button2 => Some(MouseInput(state, Middle)),
|
||||||
|
ffi::Button3 => Some(MouseInput(state, Right)),
|
||||||
|
ffi::Button4 | ffi::Button5 => {
|
||||||
|
if event_data.flags & ffi::XIPointerEmulated == 0 {
|
||||||
|
// scroll event from a traditional wheel with
|
||||||
|
// distinct 'clicks'
|
||||||
|
let delta = if event_data.detail as u32 == ffi::Button4 {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
-1.0
|
||||||
|
};
|
||||||
|
Some(MouseWheel(LineDelta(0.0, delta)))
|
||||||
|
} else {
|
||||||
|
// emulated button event from a touch/smooth-scroll
|
||||||
|
// event. Ignore these events and handle scrolling
|
||||||
|
// via XI_Motion event handler instead
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ffi::XI_Motion => {
|
||||||
|
let event_data: &ffi::XIDeviceEvent = unsafe{mem::transmute(cookie.data)};
|
||||||
|
let axis_state = event_data.valuators;
|
||||||
|
let mask = unsafe{ from_raw_parts(axis_state.mask, axis_state.mask_len as usize) };
|
||||||
|
let mut axis_count = 0;
|
||||||
|
|
||||||
|
let mut scroll_delta = (0.0, 0.0);
|
||||||
|
for axis_id in 0..axis_state.mask_len {
|
||||||
|
if ffi::XIMaskIsSet(&mask, axis_id) {
|
||||||
|
let axis_value = unsafe{*axis_state.values.offset(axis_count)};
|
||||||
|
let delta = calc_scroll_deltas(event_data, axis_id, axis_value, &self.axis_list,
|
||||||
|
&mut self.current_state.axis_values);
|
||||||
|
scroll_delta.0 += delta.0;
|
||||||
|
scroll_delta.1 += delta.1;
|
||||||
|
axis_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if scroll_delta.0.abs() > 0.0 || scroll_delta.1.abs() > 0.0 {
|
||||||
|
Some(MouseWheel(PixelDelta(scroll_delta.0 as f32, scroll_delta.1 as f32)))
|
||||||
|
} else {
|
||||||
|
let new_cursor_pos = (event_data.event_x, event_data.event_y);
|
||||||
|
if new_cursor_pos != self.current_state.cursor_pos {
|
||||||
|
self.current_state.cursor_pos = new_cursor_pos;
|
||||||
|
Some(MouseMoved((new_cursor_pos.0 as i32, new_cursor_pos.1 as i32)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ffi::XI_Enter => {
|
||||||
|
// axis movements whilst the cursor is outside the window
|
||||||
|
// will alter the absolute value of the axes. We only want to
|
||||||
|
// report changes in the axis value whilst the cursor is above
|
||||||
|
// our window however, so clear the previous axis state whenever
|
||||||
|
// the cursor re-enters the window
|
||||||
|
self.current_state.axis_values.clear();
|
||||||
|
None
|
||||||
|
},
|
||||||
|
ffi::XI_Leave => None,
|
||||||
|
ffi::XI_FocusIn => Some(Focused(true)),
|
||||||
|
ffi::XI_FocusOut => Some(Focused(false)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input_axis_info(display: &Arc<XConnection>) -> Vec<Axis> {
|
||||||
|
let mut axis_list = Vec::new();
|
||||||
|
let mut device_count = 0;
|
||||||
|
|
||||||
|
// only get events from the master devices which are 'attached'
|
||||||
|
// to the keyboard or cursor
|
||||||
|
let devices = unsafe{
|
||||||
|
(display.xinput2.XIQueryDevice)(display.display, ffi::XIAllMasterDevices, &mut device_count)
|
||||||
|
};
|
||||||
|
for i in 0..device_count {
|
||||||
|
let device = unsafe { *(devices.offset(i as isize)) };
|
||||||
|
for k in 0..device.num_classes {
|
||||||
|
let class = unsafe { *(device.classes.offset(k as isize)) };
|
||||||
|
match unsafe { (*class)._type } {
|
||||||
|
// Note that scroll axis
|
||||||
|
// are reported both as 'XIScrollClass' and 'XIValuatorClass'
|
||||||
|
// axes. For the moment we only care about scrolling axes.
|
||||||
|
ffi::XIScrollClass => {
|
||||||
|
let scroll_class: &ffi::XIScrollClassInfo = unsafe{mem::transmute(class)};
|
||||||
|
axis_list.push(Axis{
|
||||||
|
id: scroll_class.sourceid,
|
||||||
|
device_id: device.deviceid,
|
||||||
|
axis_number: scroll_class.number,
|
||||||
|
axis_type: match scroll_class.scroll_type {
|
||||||
|
ffi::XIScrollTypeHorizontal => AxisType::HorizontalScroll,
|
||||||
|
ffi::XIScrollTypeVertical => AxisType::VerticalScroll,
|
||||||
|
_ => { unreachable!() }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
axis_list
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given an input motion event for an axis and the previous
|
||||||
|
/// state of the axes, return the horizontal/vertical
|
||||||
|
/// scroll deltas
|
||||||
|
fn calc_scroll_deltas(event: &ffi::XIDeviceEvent,
|
||||||
|
axis_id: i32,
|
||||||
|
axis_value: f64,
|
||||||
|
axis_list: &[Axis],
|
||||||
|
prev_axis_values: &mut Vec<AxisValue>) -> (f64, f64) {
|
||||||
|
let prev_value_pos = prev_axis_values.iter().position(|prev_axis| {
|
||||||
|
prev_axis.device_id == event.sourceid &&
|
||||||
|
prev_axis.axis_number == axis_id
|
||||||
|
});
|
||||||
|
let delta = match prev_value_pos {
|
||||||
|
Some(idx) => axis_value - prev_axis_values[idx].value,
|
||||||
|
None => 0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_axis_value = AxisValue{
|
||||||
|
device_id: event.sourceid,
|
||||||
|
axis_number: axis_id,
|
||||||
|
value: axis_value
|
||||||
|
};
|
||||||
|
|
||||||
|
match prev_value_pos {
|
||||||
|
Some(idx) => prev_axis_values[idx] = new_axis_value,
|
||||||
|
None => prev_axis_values.push(new_axis_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut scroll_delta = (0.0, 0.0);
|
||||||
|
|
||||||
|
for axis in axis_list.iter() {
|
||||||
|
if axis.id == event.sourceid &&
|
||||||
|
axis.axis_number == axis_id {
|
||||||
|
match axis.axis_type {
|
||||||
|
AxisType::HorizontalScroll => scroll_delta.0 = delta,
|
||||||
|
AxisType::VerticalScroll => scroll_delta.1 = delta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll_delta
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub use self::xdisplay::XConnection;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
|
||||||
mod events;
|
mod events;
|
||||||
|
mod input;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
mod window;
|
mod window;
|
||||||
mod xdisplay;
|
mod xdisplay;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use {Event, BuilderAttribs, MouseCursor};
|
||||||
use CreationError;
|
use CreationError;
|
||||||
use CreationError::OsError;
|
use CreationError::OsError;
|
||||||
use libc;
|
use libc;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
@ -20,7 +21,8 @@ use api::egl::Context as EglContext;
|
||||||
|
|
||||||
use platform::MonitorID as PlatformMonitorID;
|
use platform::MonitorID as PlatformMonitorID;
|
||||||
|
|
||||||
use super::{events, ffi};
|
use super::input::XInputEventHandler;
|
||||||
|
use super::{ffi};
|
||||||
use super::{MonitorID, XConnection};
|
use super::{MonitorID, XConnection};
|
||||||
|
|
||||||
// XOpenIM doesn't seem to be thread-safe
|
// XOpenIM doesn't seem to be thread-safe
|
||||||
|
@ -106,33 +108,69 @@ 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> {
|
pub struct PollEventsIterator<'a> {
|
||||||
window: &'a Window,
|
window: &'a Window
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PollEventsIterator<'a> {
|
impl<'a> Iterator for PollEventsIterator<'a> {
|
||||||
type Item = Event;
|
type Item = Event;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Event> {
|
fn next(&mut self) -> Option<Event> {
|
||||||
|
let xlib = &self.window.x.display.xlib;
|
||||||
|
|
||||||
|
loop {
|
||||||
if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
|
if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
|
||||||
return Some(ev);
|
return Some(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut xev = unsafe { mem::uninitialized() };
|
let mut xev = unsafe { mem::uninitialized() };
|
||||||
let res = unsafe { (self.window.x.display.xlib.XCheckMaskEvent)(self.window.x.display.display, -1, &mut xev) };
|
let res = unsafe { (xlib.XCheckMaskEvent)(self.window.x.display.display, -1, &mut xev) };
|
||||||
|
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
let res = unsafe { (self.window.x.display.xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::ClientMessage, &mut xev) };
|
let res = unsafe { (xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::ClientMessage, &mut xev) };
|
||||||
|
|
||||||
|
if res == 0 {
|
||||||
|
let res = unsafe { (xlib.XCheckTypedEvent)(self.window.x.display.display, ffi::GenericEvent, &mut xev) };
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match xev.get_type() {
|
match xev.get_type() {
|
||||||
ffi::KeymapNotify => {
|
ffi::KeymapNotify => {
|
||||||
unsafe { (self.window.x.display.xlib.XRefreshKeyboardMapping)(mem::transmute(&xev)); }
|
unsafe { (xlib.XRefreshKeyboardMapping)(mem::transmute(&xev)); }
|
||||||
},
|
},
|
||||||
|
|
||||||
ffi::ClientMessage => {
|
ffi::ClientMessage => {
|
||||||
|
@ -164,93 +202,34 @@ impl<'a> Iterator for PollEventsIterator<'a> {
|
||||||
return Some(Refresh);
|
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 => {
|
ffi::KeyPress | ffi::KeyRelease => {
|
||||||
use events::Event::{KeyboardInput, ReceivedCharacter};
|
let mut event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&mut xev) };
|
||||||
use events::ElementState::{Pressed, Released};
|
let events = self.window.input_handler.lock().unwrap().translate_key_event(&mut event);
|
||||||
let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&mut xev) };
|
for event in events {
|
||||||
|
self.window.pending_events.lock().unwrap().push_back(event);
|
||||||
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) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 => {
|
ffi::GenericEvent => {
|
||||||
use events::Event::{MouseInput, MouseWheel};
|
if let Some(cookie) = GenericEventCookie::from_event(self.window.x.display.borrow(), xev) {
|
||||||
use events::ElementState::{Pressed, Released};
|
match cookie.cookie.evtype {
|
||||||
use events::MouseButton::{Left, Right, Middle};
|
ffi::XI_DeviceChanged...ffi::XI_LASTEVENT => {
|
||||||
use events::MouseScrollDelta::{LineDelta};
|
match self.window.input_handler.lock() {
|
||||||
|
Ok(mut handler) => {
|
||||||
let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
|
match handler.translate_event(&cookie.cookie) {
|
||||||
|
Some(event) => self.window.pending_events.lock().unwrap().push_back(event),
|
||||||
let state = if xev.get_type() == ffi::ButtonPress { Pressed } else { Released };
|
None => {}
|
||||||
|
|
||||||
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 => ()
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => ()
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,6 +275,7 @@ pub struct Window {
|
||||||
/// Events that have been retreived with XLib but not dispatched with iterators yet
|
/// Events that have been retreived with XLib but not dispatched with iterators yet
|
||||||
pending_events: Mutex<VecDeque<Event>>,
|
pending_events: Mutex<VecDeque<Event>>,
|
||||||
cursor_state: Mutex<CursorState>,
|
cursor_state: Mutex<CursorState>,
|
||||||
|
input_handler: Mutex<XInputEventHandler>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -608,6 +588,7 @@ impl Window {
|
||||||
pixel_format: pixel_format,
|
pixel_format: pixel_format,
|
||||||
pending_events: Mutex::new(VecDeque::new()),
|
pending_events: Mutex::new(VecDeque::new()),
|
||||||
cursor_state: Mutex::new(CursorState::Normal),
|
cursor_state: Mutex::new(CursorState::Normal),
|
||||||
|
input_handler: Mutex::new(XInputEventHandler::new(display, window, ic))
|
||||||
};
|
};
|
||||||
|
|
||||||
// returning
|
// returning
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct XConnection {
|
||||||
pub xlib: ffi::Xlib,
|
pub xlib: ffi::Xlib,
|
||||||
pub xf86vmode: ffi::Xf86vmode,
|
pub xf86vmode: ffi::Xf86vmode,
|
||||||
pub xcursor: ffi::Xcursor,
|
pub xcursor: ffi::Xcursor,
|
||||||
|
pub xinput2: ffi::XInput2,
|
||||||
pub glx: Option<ffi::glx::Glx>,
|
pub glx: Option<ffi::glx::Glx>,
|
||||||
pub egl: Option<Egl>,
|
pub egl: Option<Egl>,
|
||||||
pub display: *mut ffi::Display,
|
pub display: *mut ffi::Display,
|
||||||
|
@ -30,6 +31,7 @@ impl XConnection {
|
||||||
let xlib = try!(ffi::Xlib::open().map_err(|_| XNotSupported));
|
let xlib = try!(ffi::Xlib::open().map_err(|_| XNotSupported));
|
||||||
let xcursor = try!(ffi::Xcursor::open().map_err(|_| XNotSupported));
|
let xcursor = try!(ffi::Xcursor::open().map_err(|_| XNotSupported));
|
||||||
let xf86vmode = try!(ffi::Xf86vmode::open().map_err(|_| XNotSupported));
|
let xf86vmode = try!(ffi::Xf86vmode::open().map_err(|_| XNotSupported));
|
||||||
|
let xinput2 = try!(ffi::XInput2::open().map_err(|_| XNotSupported));
|
||||||
|
|
||||||
unsafe extern "C" fn x_error_callback(_: *mut ffi::Display, event: *mut ffi::XErrorEvent)
|
unsafe extern "C" fn x_error_callback(_: *mut ffi::Display, event: *mut ffi::XErrorEvent)
|
||||||
-> libc::c_int
|
-> libc::c_int
|
||||||
|
@ -86,6 +88,7 @@ impl XConnection {
|
||||||
xlib: xlib,
|
xlib: xlib,
|
||||||
xf86vmode: xf86vmode,
|
xf86vmode: xf86vmode,
|
||||||
xcursor: xcursor,
|
xcursor: xcursor,
|
||||||
|
xinput2: xinput2,
|
||||||
glx: glx,
|
glx: glx,
|
||||||
egl: egl,
|
egl: egl,
|
||||||
display: display,
|
display: display,
|
||||||
|
|
Loading…
Reference in a new issue