Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul device events API and add gamepad support on Windows #804

Merged
merged 39 commits into from
Jun 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
700e65e
Initial implementation
francesca64 Nov 4, 2018
b552370
Corrected RAWINPUT buffer sizing
francesca64 Nov 4, 2018
8c7f720
Mostly complete XInput implementation
francesca64 Nov 4, 2018
666a391
XInput triggers
francesca64 Nov 4, 2018
da57daa
Add preliminary CHANGELOG entry.
francesca64 Nov 4, 2018
89b6cb7
match unix common API to evl 2.0
elinorbgr Nov 15, 2018
ae6ca46
wayland: eventloop2.0
elinorbgr Nov 15, 2018
e67c500
Merge onto EL2.0 branch
Osspial Feb 15, 2019
7164a69
make EventLoopProxy require T: 'static
elinorbgr Feb 15, 2019
4202b60
Merge branch 'evl2' of https://github.com/vberger/winit into el2-win-joy
Osspial Feb 15, 2019
de20a68
Revamp device event API, as well as several misc. fixes on Windows:
Osspial Feb 24, 2019
8d2826c
Add MouseEvent documentation and Device ID debug passthrough
Osspial Feb 24, 2019
abea210
Improve type safety on get_raw_input_data
Osspial Mar 1, 2019
eb6d43e
Remove button_id field from MouseEvent::Button in favor of utton
Osspial Mar 1, 2019
2f4e18a
Remove regex dependency on Windows
Osspial Mar 1, 2019
e76f47e
Remove axis filtering in XInput
Osspial Mar 1, 2019
7775524
Make gamepads not use lazy_static
Osspial Mar 2, 2019
a3468c3
Publicly expose gamepad rumble
Osspial Mar 3, 2019
437ead3
Unstack DeviceEvent and fix examples/tests
Osspial Mar 3, 2019
36b95e2
Add HANDLE retrieval method to DeviceExtWindows
Osspial Mar 3, 2019
b48bd27
Add distinction between non-joystick axes and joystick axes.
Osspial Mar 4, 2019
0b0066b
Add ability to get gamepad port
Osspial Mar 4, 2019
81eb196
Fix xinput controller hot swapping
Osspial Mar 4, 2019
a44aafa
Add functions for enumerating attached devices
Osspial Mar 4, 2019
8fe2e2c
Clamp input to [0.0, 1.0] on gamepad rumble
Osspial Mar 4, 2019
5334537
Expose gamepad rumble errors
Osspial Mar 4, 2019
af110f9
Add method to check if device is still connected
Osspial Mar 5, 2019
ffbb7b9
Add docs
Osspial Mar 5, 2019
ca6cc12
Rename AxisHint and ButtonHint to GamepadAxis and GamepadButton
Osspial Mar 5, 2019
17a9eae
Merge branch 'eventloop-2.0' into el2-win-joy
Osspial Mar 5, 2019
8fee08a
Add CHANGELOG entry
Osspial Mar 5, 2019
f29b53d
Update CHANGELOG.md
Osspial Mar 6, 2019
d65b9d8
Add HidId and MovedAbsolute
Osspial Mar 7, 2019
1e589d9
Merge branch 'eventloop-2.0' into el2-win-joy
Osspial May 29, 2019
ef5bdd5
Merge branch 'master' into el2-win-joy
Osspial Jun 19, 2019
b3f03c3
Fix xinput deprecation warnings
Osspial Jun 19, 2019
0bc48d6
Add ability to retrieve gamepad battery level
Osspial Jun 20, 2019
592d891
Fix weird imports in gamepad example
Osspial Jun 20, 2019
7bb1118
Update CHANGELOG.md
Osspial Jun 20, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@
- On Wayland, the window now exists even if nothing has been drawn.
- On Windows, fix initial dimensions of a fullscreen window.

- Improve event API documentation.
- Overhaul device event API:
- **Breaking**: `Event::DeviceEvent` split into `MouseEvent`, `KeyboardEvent`, and `GamepadEvent`.
- **Breaking**: Remove `DeviceEvent::Text` variant.
- **Breaking**: `DeviceId` split into `MouseId`, `KeyboardId`, and `GamepadHandle`.
- **Breaking**: Removed device IDs from `WindowEvent` variants.
- Add `enumerate` function on device ID types to list all attached devices of that type.
- Add `is_connected` function on device ID types check if the specified device is still available.
- **Breaking**: On Windows, rename `DeviceIdExtWindows` to `DeviceExtWindows`.
- Add `handle` function to retrieve the underlying `HANDLE`.
- On Windows, fix duplicate device events getting sent if Winit managed multiple windows.
- On Windows, raw mouse events now report Mouse4 and Mouse5 presses and releases.
- Added gamepad support on Windows via raw input and XInput.

# Version 0.19.1 (2019-04-08)

- On Wayland, added a `get_wayland_display` function to `EventsLoopExt`.
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ objc = "0.2.3"

[target.'cfg(target_os = "windows")'.dependencies]
bitflags = "1"
rusty-xinput = "1.0"

[target.'cfg(target_os = "windows")'.dependencies.winapi]
version = "0.3.6"
Expand All @@ -49,6 +50,7 @@ features = [
"commctrl",
"dwmapi",
"errhandlingapi",
"hidpi",
"hidusage",
"libloaderapi",
"objbase",
Expand All @@ -64,6 +66,7 @@ features = [
"wingdi",
"winnt",
"winuser",
"xinput",
]

[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion examples/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() {

event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
Event::WindowEvent { event: WindowEvent::KeyboardInput(KeyboardInput { state: ElementState::Pressed, .. }), .. } => {
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
window.set_cursor_icon(CURSORS[cursor_idx]);
if cursor_idx < CURSORS.len() - 1 {
Expand Down
13 changes: 5 additions & 8 deletions examples/cursor_grab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@ fn main() {
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput {
input: KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
},
WindowEvent::KeyboardInput(KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
} => {
}) => {
use winit::event::VirtualKeyCode::*;
match key {
Escape => *control_flow = ControlFlow::Exit,
Expand Down
12 changes: 4 additions & 8 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,11 @@ fn main() {
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(virtual_code),
state,
..
},
WindowEvent::KeyboardInput(KeyboardInput {
virtual_keycode: Some(virtual_code),
state,
..
} => match (virtual_code, state) {
}) => match (virtual_code, state) {
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
(VirtualKeyCode::F, ElementState::Pressed) => {
#[cfg(target_os = "macos")]
Expand Down
41 changes: 41 additions & 0 deletions examples/gamepad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
extern crate winit;
use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent};
use winit::event::device::{GamepadEvent, GamepadHandle};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let event_loop = EventLoop::new();

let _window = WindowBuilder::new()
.with_title("The world's worst video game")
.build(&event_loop)
.unwrap();

println!("enumerating gamepads:");
for gamepad in GamepadHandle::enumerate(&event_loop) {
println!(" gamepad={:?}\tport={:?}\tbattery level={:?}", gamepad, gamepad.port(), gamepad.battery_level());
}

let deadzone = 0.12;

event_loop.run(move |event, _, control_flow| {
match event {
Event::GamepadEvent(gamepad_handle, event) => {
match event {
// Discard any Axis events that has a corresponding Stick event.
GamepadEvent::Axis{stick: true, ..} => (),

// Discard any Stick event that falls inside the stick's deadzone.
GamepadEvent::Stick{x_value, y_value, ..}
if (x_value.powi(2) + y_value.powi(2)).sqrt() < deadzone
=> (),

_ => println!("[{:?}] {:#?}", gamepad_handle, event)
}
},
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => *control_flow = ControlFlow::Exit,
_ => ()
}
});
}
58 changes: 58 additions & 0 deletions examples/gamepad_rumble.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
extern crate winit;
use winit::event_loop::EventLoop;
use std::time::Instant;

#[derive(Debug, Clone)]
enum Rumble {
None,
Left,
Right,
}

fn main() {
let event_loop = EventLoop::new();

// You should generally use `GamepadEvent::Added/Removed` to detect gamepads, as doing that will
// allow you to more easily support gamepad hotswapping. However, we're using `enumerate` here
// because it makes this example more concise.
let gamepads = winit::event::device::GamepadHandle::enumerate(&event_loop).collect::<Vec<_>>();

let rumble_patterns = &[
(0.5, Rumble::None),
(2.0, Rumble::Left),
(0.5, Rumble::None),
(2.0, Rumble::Right),
];
let mut rumble_iter = rumble_patterns.iter().cloned().cycle();

let mut active_pattern = rumble_iter.next().unwrap();
let mut timeout = active_pattern.0;
let mut timeout_start = Instant::now();

event_loop.run(move |_, _, _| {
if timeout <= active_pattern.0 {
let t = (timeout / active_pattern.0) * std::f64::consts::PI;
let intensity = t.sin();

for g in &gamepads {
let result = match active_pattern.1 {
Rumble::Left => g.rumble(intensity, 0.0),
Rumble::Right => g.rumble(0.0, intensity),
Rumble::None => Ok(()),
};

if let Err(e) = result {
println!("Rumble failed: {:?}", e);
}
}

timeout = (Instant::now() - timeout_start).as_millis() as f64 / 1000.0;
} else {
active_pattern = rumble_iter.next().unwrap();
println!("Rumbling {:?} for {:?} seconds", active_pattern.1, active_pattern.0);

timeout = 0.0;
timeout_start = Instant::now();
}
});
}
12 changes: 4 additions & 8 deletions examples/handling_close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,11 @@ fn main() {
// closing the window. How to close the window is detailed in the handler for
// the Y key.
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(virtual_code),
state: Released,
..
},
WindowEvent::KeyboardInput(KeyboardInput {
virtual_keycode: Some(virtual_code),
state: Released,
..
} => match virtual_code {
}) => match virtual_code {
Y => {
if close_requested {
// This is where you'll want to do any cleanup you need.
Expand Down
8 changes: 4 additions & 4 deletions examples/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ fn main() {
thread::spawn(move || {
while let Ok(event) = rx.recv() {
match event {
WindowEvent::KeyboardInput { input: KeyboardInput {
WindowEvent::KeyboardInput (KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
}, .. } => {
}) => {
window.set_title(&format!("{:?}", key));
let state = !modifiers.shift;
use self::VirtualKeyCode::*;
Expand Down Expand Up @@ -99,9 +99,9 @@ fn main() {
match event {
WindowEvent::CloseRequested
| WindowEvent::Destroyed
| WindowEvent::KeyboardInput { input: KeyboardInput {
| WindowEvent::KeyboardInput(KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Escape),
.. }, .. } => {
.. }) => {
window_senders.remove(&window_id);
},
_ => if let Some(tx) = window_senders.get(&window_id) {
Expand Down
2 changes: 1 addition & 1 deletion examples/multiwindow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() {
*control_flow = ControlFlow::Exit;
}
},
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. } => {
WindowEvent::KeyboardInput(KeyboardInput { state: ElementState::Pressed, .. }) => {
let window = Window::new(&event_loop).unwrap();
windows.insert(window.id(), window);
},
Expand Down
12 changes: 4 additions & 8 deletions examples/resizable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,11 @@ fn main() {
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Space),
state: ElementState::Released,
..
},
WindowEvent::KeyboardInput(KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Space),
state: ElementState::Released,
..
} => {
}) => {
resizable = !resizable;
println!("Resizable: {}", resizable);
window.set_resizable(resizable);
Expand Down
Loading