Skip to content

Commit 15aafc2

Browse files
authored
Merge pull request #164 from Ralith/rich-input
Richer input events
2 parents 689d052 + 22bc119 commit 15aafc2

19 files changed

Lines changed: 993 additions & 785 deletions

File tree

examples/cursor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate winit;
22

3-
use winit::{Event, ElementState, MouseCursor, WindowEvent};
3+
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput};
44

55
fn main() {
66
let events_loop = winit::EventsLoop::new();
@@ -13,7 +13,7 @@ fn main() {
1313

1414
events_loop.run_forever(|event| {
1515
match event {
16-
Event::WindowEvent { event: WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _), .. } => {
16+
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
1717
println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
1818
window.set_cursor(cursors[cursor_idx]);
1919
if cursor_idx < cursors.len() - 1 {

examples/fullscreen.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ fn main() {
3737
winit::Event::WindowEvent { event, .. } => {
3838
match event {
3939
winit::WindowEvent::Closed => events_loop.interrupt(),
40-
winit::WindowEvent::KeyboardInput(_, _, Some(winit::VirtualKeyCode::Escape), _) => events_loop.interrupt(),
40+
winit::WindowEvent::KeyboardInput {
41+
input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, ..
42+
} => events_loop.interrupt(),
4143
_ => ()
4244
}
4345
},
46+
_ => {}
4447
}
4548
});
4649
}

examples/grabbing.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate winit;
22

3-
use winit::{WindowEvent, ElementState};
3+
use winit::{WindowEvent, ElementState, KeyboardInput};
44

55
fn main() {
66
let events_loop = winit::EventsLoop::new();
@@ -16,7 +16,7 @@ fn main() {
1616
match event {
1717
winit::Event::WindowEvent { event, .. } => {
1818
match event {
19-
WindowEvent::KeyboardInput(ElementState::Pressed, _, _, _) => {
19+
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => {
2020
if grabbed {
2121
grabbed = false;
2222
window.set_cursor_state(winit::CursorState::Normal)
@@ -30,13 +30,14 @@ fn main() {
3030

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

33-
a @ WindowEvent::MouseMoved(_, _) => {
33+
a @ WindowEvent::MouseMoved { .. } => {
3434
println!("{:?}", a);
3535
},
3636

3737
_ => (),
3838
}
39-
},
39+
}
40+
_ => {}
4041
}
4142
});
4243
}

src/api_transition.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ macro_rules! gen_api_transition {
5757
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5858
pub struct WindowId(usize);
5959

60+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
61+
pub struct DeviceId;
62+
6063
pub struct Window2 {
6164
pub window: ::std::sync::Arc<Window>,
6265
events_loop: ::std::sync::Weak<EventsLoop>,

src/events.rs

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use std::path::PathBuf;
2-
use WindowId;
2+
use {WindowId, DeviceId, AxisId, ButtonId};
33

44
#[derive(Clone, Debug)]
55
pub enum Event {
66
WindowEvent {
77
window_id: WindowId,
88
event: WindowEvent,
9-
}
9+
},
10+
DeviceEvent {
11+
device_id: DeviceId,
12+
event: DeviceEvent,
13+
},
1014
}
1115

1216
#[derive(Clone, Debug)]
@@ -35,31 +39,36 @@ pub enum WindowEvent {
3539
Focused(bool),
3640

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

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

4551
/// The cursor has entered the window.
46-
MouseEntered,
52+
MouseEntered { device_id: DeviceId },
4753

4854
/// The cursor has left the window.
49-
MouseLeft,
55+
MouseLeft { device_id: DeviceId },
5056

5157
/// A mouse wheel movement or touchpad scroll occurred.
52-
MouseWheel(MouseScrollDelta, TouchPhase),
58+
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase },
5359

54-
/// An event from the mouse has been received.
55-
MouseInput(ElementState, MouseButton),
60+
/// An mouse button press has been received.
61+
MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton },
5662

5763
/// Touchpad pressure event.
5864
///
5965
/// At the moment, only supported on Apple forcetouch-capable macbooks.
6066
/// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
6167
/// is being pressed) and stage (integer representing the click level).
62-
TouchpadPressure(f32, i64),
68+
TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },
69+
70+
/// Motion on some analog axis not otherwise handled. May overlap with mouse motion.
71+
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
6372

6473
/// The window needs to be redrawn.
6574
Refresh,
@@ -73,6 +82,48 @@ pub enum WindowEvent {
7382
Touch(Touch)
7483
}
7584

85+
/// Represents raw hardware events that are not associated with any particular window.
86+
///
87+
/// Useful for interactions that diverge significantly from a conventional 2D GUI, such as 3D camera or first-person
88+
/// game controls. Many physical actions, such as mouse movement, can produce both device and window events. Because
89+
/// window events typically arise from virtual devices (corresponding to GUI cursors and keyboard focus) the device IDs
90+
/// may not match.
91+
///
92+
/// Note that these events are delivered regardless of input focus.
93+
#[derive(Clone, Debug)]
94+
pub enum DeviceEvent {
95+
Added,
96+
Removed,
97+
Motion { axis: AxisId, value: f64 },
98+
Button { button: ButtonId, state: ElementState },
99+
Key(KeyboardInput),
100+
Text { codepoint: char },
101+
}
102+
103+
#[derive(Debug, Clone, Copy)]
104+
pub struct KeyboardInput {
105+
/// Identifies the physical key pressed
106+
///
107+
/// This should not change if the user adjusts the host's keyboard map. Use when the physical location of the
108+
/// key is more important than the key's host GUI semantics, such as for movement controls in a first-person
109+
/// game.
110+
pub scancode: ScanCode,
111+
112+
pub state: ElementState,
113+
114+
/// Identifies the semantic meaning of the key
115+
///
116+
/// Use when the semantics of the key are more important than the physical location of the key, such as when
117+
/// implementing appropriate behavior for "page up."
118+
pub virtual_keycode: Option<VirtualKeyCode>,
119+
120+
/// Modifier keys active at the time of this input.
121+
///
122+
/// This is tracked internally to avoid tracking errors arising from modifier key state changes when events from
123+
/// this device are not being delivered to the application, e.g. due to keyboard focus being elsewhere.
124+
pub modifiers: ModifiersState
125+
}
126+
76127
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
77128
pub enum TouchPhase {
78129
Started,
@@ -98,13 +149,14 @@ pub enum TouchPhase {
98149
///
99150
/// Touch may be cancelled if for example window lost focus.
100151
pub struct Touch {
152+
pub device_id: DeviceId,
101153
pub phase: TouchPhase,
102154
pub location: (f64,f64),
103155
/// unique identifier of a finger.
104156
pub id: u64
105157
}
106158

107-
pub type ScanCode = u8;
159+
pub type ScanCode = u32;
108160

109161
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
110162
pub enum ElementState {

src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@ pub struct Window {
169169
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
170170
pub struct WindowId(platform::WindowId);
171171

172+
/// Identifier of an input device.
173+
///
174+
/// Whenever you receive an event arising from a particular input device, this event contains a `DeviceId` which
175+
/// identifies its origin. Note that devices may be virtual (representing an on-screen cursor and keyboard focus) or
176+
/// physical. Virtual devices typically aggregate inputs from multiple physical devices.
177+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
178+
pub struct DeviceId(platform::DeviceId);
179+
180+
/// Identifier for a specific analog axis on some device.
181+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182+
pub struct AxisId(u32);
183+
184+
/// Identifier for a specific button on some device.
185+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
186+
pub struct ButtonId(u32);
187+
172188
/// Provides a way to retreive events from the windows that were registered to it.
173189
// TODO: document usage in multiple threads
174190
pub struct EventsLoop {

src/platform/ios/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ impl Window {
287287
let phase: i32 = msg_send![touch, phase];
288288

289289
state.events_queue.push_back(Event::Touch(Touch {
290+
device_id: DEVICE_ID,
290291
id: touch_id,
291292
location: (location.x as f64, location.y as f64),
292293
phase: match phase {
@@ -495,3 +496,6 @@ impl<'a> Iterator for PollEventsIterator<'a> {
495496
}
496497
}
497498
}
499+
500+
// Constant device ID, to be removed when this backend is updated to report real device IDs.
501+
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);

src/platform/linux/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ pub enum WindowId {
5858
Wayland(wayland::WindowId)
5959
}
6060

61+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
62+
pub enum DeviceId {
63+
#[doc(hidden)]
64+
X(x11::DeviceId),
65+
#[doc(hidden)]
66+
Wayland(wayland::DeviceId)
67+
}
68+
6169
#[derive(Clone)]
6270
pub enum MonitorId {
6371
#[doc(hidden)]
@@ -137,8 +145,8 @@ impl Window2 {
137145
}
138146
},
139147

140-
UnixBackend::X(ref connec) => {
141-
x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X)
148+
UnixBackend::X(_) => {
149+
x11::Window2::new(events_loop, window, pl_attribs).map(Window2::X)
142150
},
143151
UnixBackend::Error(_) => {
144152
// If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
@@ -308,8 +316,8 @@ impl EventsLoop {
308316
EventsLoop::Wayland(wayland::EventsLoop::new(ctxt.clone()))
309317
},
310318

311-
UnixBackend::X(_) => {
312-
EventsLoop::X(x11::EventsLoop::new())
319+
UnixBackend::X(ref ctxt) => {
320+
EventsLoop::X(x11::EventsLoop::new(ctxt.clone()))
313321
},
314322

315323
UnixBackend::Error(_) => {

0 commit comments

Comments
 (0)