Skip to content

Commit

Permalink
Merge pull request #164 from Ralith/rich-input
Browse files Browse the repository at this point in the history
Richer input events
  • Loading branch information
tomaka authored May 7, 2017
2 parents 689d052 + 22bc119 commit 15aafc2
Show file tree
Hide file tree
Showing 19 changed files with 993 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 15aafc2

Please sign in to comment.