Skip to content

Commit

Permalink
Richer input events
Browse files Browse the repository at this point in the history
This expands input events to represent sub-pixel mouse positions, devices responsible for generating events, and raw
device-oriented events. The X11 back end is refactored to make full use of the new expressiveness. Other backends have
had new functionality minimally stubbed out, save for the macos backend which already supports sub-pixel mouse
positions.
  • Loading branch information
Ralith committed Apr 23, 2017
1 parent 544ee13 commit a55ac6e
Show file tree
Hide file tree
Showing 19 changed files with 997 additions and 785 deletions.
4 changes: 2 additions & 2 deletions examples/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate winit;

use winit::{Event, ElementState, MouseCursor, WindowEvent};
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput};

fn main() {
let events_loop = winit::EventsLoop::new();
Expand All @@ -13,7 +13,7 @@ fn main() {

events_loop.run_forever(|event| {
match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _), .. } => {
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
window.set_cursor(cursors[cursor_idx]);
if cursor_idx < cursors.len() - 1 {
Expand Down
5 changes: 4 additions & 1 deletion examples/fullscreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ fn main() {
winit::Event::WindowEvent { event, .. } => {
match event {
winit::WindowEvent::Closed => events_loop.interrupt(),
winit::WindowEvent::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape), _) => events_loop.interrupt(),
winit::WindowEvent::KeyboardInput {
input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, ..
} => events_loop.interrupt(),
_ => ()
}
},
_ => {}
}
});
}
9 changes: 5 additions & 4 deletions examples/grabbing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate winit;

use winit::{WindowEvent, ElementState};
use winit::{WindowEvent, ElementState, KeyboardInput};

fn main() {
let events_loop = winit::EventsLoop::new();
Expand All @@ -16,7 +16,7 @@ fn main() {
match event {
winit::Event::WindowEvent { event, .. } => {
match event {
WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _) => {
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => {
if grabbed {
grabbed = false;
window.set_cursor_state(winit::CursorState::Normal)
Expand All @@ -30,13 +30,14 @@ fn main() {

WindowEvent::Closed => events_loop.interrupt(),

a @ WindowEvent::MouseMoved(_, _) => {
a @ WindowEvent::MouseMoved { .. } => {
println!("{:?}", a);
},

_ => (),
}
},
}
_ => {}
}
});
}
3 changes: 3 additions & 0 deletions src/api_transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ macro_rules! gen_api_transition {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(usize);

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;

pub struct Window2 {
pub window: ::std::sync::Arc<Window>,
events_loop: ::std::sync::Weak<EventsLoop>,
Expand Down
76 changes: 64 additions & 12 deletions src/events.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::path::PathBuf;
use WindowId;
use {WindowId, DeviceId, AxisId, ButtonId};

#[derive(Clone, Debug)]
pub enum Event {
WindowEvent {
window_id: WindowId,
event: WindowEvent,
}
},
DeviceEvent {
device_id: DeviceId,
event: DeviceEvent,
},
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -35,31 +39,36 @@ pub enum WindowEvent {
Focused(bool),

/// An event from the keyboard has been received.
KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>, ModifiersState),
KeyboardInput { device_id: DeviceId, input: KeyboardInput },

/// The cursor has moved on the window.
///
/// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
MouseMoved(i32, i32),
/// `position` is (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this
/// data is limited by the display area and it may have been transformed by the OS to implement effects such as
/// mouse acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
MouseMoved { device_id: DeviceId, position: (f64, f64) },

/// The cursor has entered the window.
MouseEntered,
MouseEntered { device_id: DeviceId },

/// The cursor has left the window.
MouseLeft,
MouseLeft { device_id: DeviceId },

/// A mouse wheel movement or touchpad scroll occurred.
MouseWheel(MouseScrollDelta, TouchPhase),
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase },

/// An event from the mouse has been received.
MouseInput(ElementState, MouseButton),
/// An mouse button press has been received.
MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton },

/// Touchpad pressure event.
///
/// At the moment, only supported on Apple forcetouch-capable macbooks.
/// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
/// is being pressed) and stage (integer representing the click level).
TouchpadPressure(f32, i64),
TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },

/// Motion on some analog axis not otherwise handled. May overlap with mouse motion.
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },

/// The window needs to be redrawn.
Refresh,
Expand All @@ -73,6 +82,48 @@ pub enum WindowEvent {
Touch(Touch)
}

/// Represents raw hardware events that are not associated with any particular window.
///
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
/// may not match.
///
/// Note that these events are delivered regardless of input focus.
#[derive(Clone, Debug)]
pub enum DeviceEvent {
Added,
Removed,
Motion { axis: AxisId, value: f64 },
Button { button: ButtonId, state: ElementState },
Key(KeyboardInput),
Text { codepoint: char },
}

#[derive(Debug, Clone, Copy)]
pub struct KeyboardInput {
/// Identifies the physical key pressed
///
/// This should not change if the user adjusts the host's keyboard map. Use when the physical location of the
/// key is more important than the key's host GUI semantics, such as for movement controls in a first-person
/// game.
pub scancode: ScanCode,

pub state: ElementState,

/// Identifies the semantic meaning of the key
///
/// Use when the semantics of the key are more important than the physical location of the key, such as when
/// implementing appropriate behavior for "page up."
pub virtual_keycode: Option<VirtualKeyCode>,

/// Modifier keys active at the time of this input.
///
/// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from
/// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere.
pub modifiers: ModifiersState
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
Started,
Expand All @@ -98,13 +149,14 @@ pub enum TouchPhase {
///
/// Touch may be cancelled if for example window lost focus.
pub struct Touch {
pub device_id: DeviceId,
pub phase: TouchPhase,
pub location: (f64,f64),
/// unique identifier of a finger.
pub id: u64
}

pub type ScanCode = u8;
pub type ScanCode = u32;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,22 @@ pub struct Window {
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(platform::WindowId);

/// Identifier of an input device.
///
/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(platform::DeviceId);

/// Identifier for a specific analog axis on some device.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AxisId(u32);

/// Identifier for a specific button on some device.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ButtonId(u32);

/// Provides a way to retreive events from the windows that were registered to it.
// TODO: document usage in multiple threads
pub struct EventsLoop {
Expand Down
4 changes: 4 additions & 0 deletions src/platform/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ impl Window {
let phase: i32 = msg_send![touch, phase];

state.events_queue.push_back(Event::Touch(Touch {
device_id: DEVICE_ID,
id: touch_id,
location: (location.x as f64, location.y as f64),
phase: match phase {
Expand Down Expand Up @@ -495,3 +496,6 @@ impl<'a> Iterator for PollEventsIterator<'a> {
}
}
}

// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
16 changes: 12 additions & 4 deletions src/platform/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ pub enum WindowId {
Wayland(wayland::WindowId)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DeviceId {
#[doc(hidden)]
X(x11::DeviceId),
#[doc(hidden)]
Wayland(wayland::DeviceId)
}

#[derive(Clone)]
pub enum MonitorId {
#[doc(hidden)]
Expand Down Expand Up @@ -137,8 +145,8 @@ impl Window2 {
}
},

UnixBackend::X(ref connec) => {
x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X)
UnixBackend::X(_) => {
x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
},
UnixBackend::Error(_) => {
// If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
Expand Down Expand Up @@ -308,8 +316,8 @@ impl EventsLoop {
EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
},

UnixBackend::X(_) => {
EventsLoop::X(x11::EventsLoop::new())
UnixBackend::X(ref ctxt) => {
EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
},

UnixBackend::Error(_) => {
Expand Down
Loading

0 comments on commit a55ac6e

Please sign in to comment.