Skip to content

Commit ab17bc1

Browse files
ArturKovacsmaroidermsiglreith
authored
New keyboard API for Windows (#1788)
* Introducing the new `KeyEvent` and renaming old stuff * Implemented physical_key on Windows * Ran cargo fmt * Progress with the keyboard's windows implementation * Add proper handling of dead keys * Add translation for non-printable virtual keys * Run `cargo fmt` * Fix for AltGraph not being reported * Synthesize key events when focus enters or leaves * Minor improvements * Remove obsolete API * Fix numlock and pause not being reported correctly * Ran `cargo fmt` * Fix numpad keys being reported incorrectly * Update examples * Ran `cargo fmt` * Add documentation for `ScanCode` * Add key binding example * Use consistent modifier key names #1343 * WONT COMPILE transitioning to new keyboard API * WONT COMPILE Implement new keyboard layout preparation * WONT COMPILE new keyboard API progress * Main compile errors fixed for keyboard * Fix bugs in new keyboard handling * Remove obsolete code * Fix examples * Ran `cargo fmt` * Fix build error with serde * Ran `cargo fmt` * Tweaks in the Windows keyboard implementation * Add `KeyCodeExtScancode` * Add `reset_dead_keys` * Improve the documentation for `Key` and `KeyCode` * Rename the meta key to super * Address feedback for the keyboard API * Fix for rustdoc Co-authored-by: Markus Røyset <maroider@protonmail.com> * Improve documentation Co-authored-by: Markus Røyset <maroider@protonmail.com> * Fix for arrow keys being reported as unidentified. And minor improvements * Fix media keys reporting Unidentified * Don't report text on key release events * Fix for NumLock being reported as Pause in raw input * Fix for strange behaviour around NumLock and Pause * Fix for NumLock being ineffective * Fix for location not being reported correctly * `RawKeyEvent`s now report repeat * Don't report text for synthetic key releases * Address feedback - Add the `Space` variant to the `to_text` function. - Mark `get_kbd_state` safe. - Change `[MaybeUninit<u8>; 256]` to `MaybeUninit<[u8; 256]>` * Filter `Unidentified` from PrtSc key device events * Don't report incorrect `RawKeyEvent` for shift + numpad * AltGraph is not reported again * Document Windows specific behaviour for shift+numpad * Fix typo * Dead keys now affect characters from logical_key * Prevent Pause and NumLock mappings in window events * Apply suggestions from code review Co-authored-by: Markus Røyset <maroider@protonmail.com> * Ran `cargo fmt` * Add W3C license for `Key` and `KeyCode` * Extend documentation according to feedback * Ignore NumLock in `key_without_modifiers` * Remove unused `key_code_to_non_char_key` * Remove empty event.rs file * Use space for resetting dead keys * Fix reporting multiple graphemes in logical_key * Avoid incorrect synthetic keypress during setfocus * Fixed the AltGr keypress not being reported when the AltGr key is pressed and released in a very quick succession * Filter fake Ctrl events when pressing AltGr * Improve code quality * Remove `repeat` from `RawKeyEvent` * Allow fractional scroll in raw mouse events * Fix typo Co-authored-by: Markus Siglreithmaier <m.siglreith@gmail.com> * Remove unused imports * Remove unused variable * Remove unnecessary `unwrap()` Co-authored-by: Markus Siglreithmaier <m.siglreith@gmail.com> * Avoid using the deprecated `into_rgba()` * Fix IME crash Co-authored-by: Markus Røyset <maroider@protonmail.com> Co-authored-by: Markus Siglreithmaier <m.siglreith@gmail.com>
1 parent 10a94c0 commit ab17bc1

29 files changed

+4506
-1260
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ log = "0.4"
3131
serde = { version = "1", optional = true, features = ["serde_derive"] }
3232
raw-window-handle = "0.3"
3333
bitflags = "1"
34+
nameof = "1"
3435

3536
[dev-dependencies]
3637
image = "0.23.12"
@@ -57,6 +58,7 @@ features = ["display_link"]
5758

5859
[target.'cfg(target_os = "windows")'.dependencies]
5960
parking_lot = "0.11"
61+
unicode-segmentation = "1.7.1"
6062

6163
[target.'cfg(target_os = "windows")'.dependencies.winapi]
6264
version = "0.3.6"
@@ -80,6 +82,7 @@ features = [
8082
"winerror",
8183
"wingdi",
8284
"winnt",
85+
"winnls",
8386
"winuser",
8487
]
8588

examples/control_flow.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use std::{thread, time};
22

33
use simple_logger::SimpleLogger;
44
use winit::{
5-
event::{Event, KeyboardInput, WindowEvent},
5+
event::{ElementState, Event, KeyEvent, WindowEvent},
66
event_loop::{ControlFlow, EventLoop},
7+
keyboard::Key,
78
window::WindowBuilder,
89
};
910

@@ -38,7 +39,7 @@ fn main() {
3839
let mut close_requested = false;
3940

4041
event_loop.run(move |event, _, control_flow| {
41-
use winit::event::{ElementState, StartCause, VirtualKeyCode};
42+
use winit::event::StartCause;
4243
println!("{:?}", event);
4344
match event {
4445
Event::NewEvents(start_cause) => {
@@ -52,31 +53,33 @@ fn main() {
5253
close_requested = true;
5354
}
5455
WindowEvent::KeyboardInput {
55-
input:
56-
KeyboardInput {
57-
virtual_keycode: Some(virtual_code),
56+
event:
57+
KeyEvent {
58+
logical_key: key,
5859
state: ElementState::Pressed,
5960
..
6061
},
6162
..
62-
} => match virtual_code {
63-
VirtualKeyCode::Key1 => {
63+
} => match key {
64+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
65+
// See the `key_binding` example
66+
Key::Character("1") => {
6467
mode = Mode::Wait;
6568
println!("\nmode: {:?}\n", mode);
6669
}
67-
VirtualKeyCode::Key2 => {
70+
Key::Character("2") => {
6871
mode = Mode::WaitUntil;
6972
println!("\nmode: {:?}\n", mode);
7073
}
71-
VirtualKeyCode::Key3 => {
74+
Key::Character("3") => {
7275
mode = Mode::Poll;
7376
println!("\nmode: {:?}\n", mode);
7477
}
75-
VirtualKeyCode::R => {
78+
Key::Character("r") => {
7679
request_redraw = !request_redraw;
7780
println!("\nrequest_redraw: {}\n", request_redraw);
7881
}
79-
VirtualKeyCode::Escape => {
82+
Key::Escape => {
8083
close_requested = true;
8184
}
8285
_ => (),

examples/cursor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use simple_logger::SimpleLogger;
22
use winit::{
3-
event::{ElementState, Event, KeyboardInput, WindowEvent},
3+
event::{ElementState, Event, KeyEvent, WindowEvent},
44
event_loop::{ControlFlow, EventLoop},
55
window::{CursorIcon, WindowBuilder},
66
};
@@ -21,8 +21,8 @@ fn main() {
2121
Event::WindowEvent {
2222
event:
2323
WindowEvent::KeyboardInput {
24-
input:
25-
KeyboardInput {
24+
event:
25+
KeyEvent {
2626
state: ElementState::Pressed,
2727
..
2828
},

examples/cursor_grab.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use simple_logger::SimpleLogger;
22
use winit::{
3-
event::{DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, WindowEvent},
3+
event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent},
44
event_loop::{ControlFlow, EventLoop},
5+
keyboard::{Key, ModifiersState},
56
window::WindowBuilder,
67
};
78

@@ -23,19 +24,23 @@ fn main() {
2324
Event::WindowEvent { event, .. } => match event {
2425
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
2526
WindowEvent::KeyboardInput {
26-
input:
27-
KeyboardInput {
27+
event:
28+
KeyEvent {
29+
logical_key: key,
2830
state: ElementState::Released,
29-
virtual_keycode: Some(key),
3031
..
3132
},
3233
..
3334
} => {
34-
use winit::event::VirtualKeyCode::*;
35+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
36+
// See the `key_binding` example
3537
match key {
36-
Escape => *control_flow = ControlFlow::Exit,
37-
G => window.set_cursor_grab(!modifiers.shift()).unwrap(),
38-
H => window.set_cursor_visible(modifiers.shift()),
38+
Key::Escape => *control_flow = ControlFlow::Exit,
39+
Key::Character(ch) => match ch.to_lowercase().as_str() {
40+
"g" => window.set_cursor_grab(!modifiers.shift_key()).unwrap(),
41+
"h" => window.set_cursor_visible(modifiers.shift_key()),
42+
_ => (),
43+
},
3944
_ => (),
4045
}
4146
}

examples/fullscreen.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::io::{stdin, stdout, Write};
22

33
use simple_logger::SimpleLogger;
4-
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
4+
use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
55
use winit::event_loop::{ControlFlow, EventLoop};
6+
use winit::keyboard::Key;
67
use winit::monitor::{MonitorHandle, VideoMode};
78
use winit::window::{Fullscreen, WindowBuilder};
89

@@ -38,30 +39,33 @@ fn main() {
3839
Event::WindowEvent { event, .. } => match event {
3940
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
4041
WindowEvent::KeyboardInput {
41-
input:
42-
KeyboardInput {
43-
virtual_keycode: Some(virtual_code),
44-
state,
42+
event:
43+
KeyEvent {
44+
logical_key: key,
45+
state: ElementState::Pressed,
4546
..
4647
},
4748
..
48-
} => match (virtual_code, state) {
49-
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
50-
(VirtualKeyCode::F, ElementState::Pressed) => {
49+
} => match key {
50+
Key::Escape => *control_flow = ControlFlow::Exit,
51+
52+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
53+
// See the `key_binding` example
54+
Key::Character("f") => {
5155
if window.fullscreen().is_some() {
5256
window.set_fullscreen(None);
5357
} else {
5458
window.set_fullscreen(fullscreen.clone());
5559
}
5660
}
57-
(VirtualKeyCode::S, ElementState::Pressed) => {
61+
Key::Character("s") => {
5862
println!("window.fullscreen {:?}", window.fullscreen());
5963
}
60-
(VirtualKeyCode::M, ElementState::Pressed) => {
64+
Key::Character("m") => {
6165
let is_maximized = window.is_maximized();
6266
window.set_maximized(!is_maximized);
6367
}
64-
(VirtualKeyCode::D, ElementState::Pressed) => {
68+
Key::Character("d") => {
6569
decorations = !decorations;
6670
window.set_decorations(decorations);
6771
}

examples/handling_close.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use simple_logger::SimpleLogger;
22
use winit::{
3-
event::{Event, KeyboardInput, WindowEvent},
3+
event::{ElementState, Event, KeyEvent, WindowEvent},
44
event_loop::{ControlFlow, EventLoop},
5+
keyboard::Key,
56
window::WindowBuilder,
67
};
78

@@ -17,10 +18,6 @@ fn main() {
1718
let mut close_requested = false;
1819

1920
event_loop.run(move |event, _, control_flow| {
20-
use winit::event::{
21-
ElementState::Released,
22-
VirtualKeyCode::{N, Y},
23-
};
2421
*control_flow = ControlFlow::Wait;
2522

2623
match event {
@@ -44,16 +41,18 @@ fn main() {
4441
// the Y key.
4542
}
4643
WindowEvent::KeyboardInput {
47-
input:
48-
KeyboardInput {
49-
virtual_keycode: Some(virtual_code),
50-
state: Released,
44+
event:
45+
KeyEvent {
46+
logical_key: key,
47+
state: ElementState::Released,
5148
..
5249
},
5350
..
5451
} => {
55-
match virtual_code {
56-
Y => {
52+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
53+
// See the `key_binding` example
54+
match key {
55+
Key::Character("y") => {
5756
if close_requested {
5857
// This is where you'll want to do any cleanup you need.
5958
println!("Buh-bye!");
@@ -66,7 +65,7 @@ fn main() {
6665
*control_flow = ControlFlow::Exit;
6766
}
6867
}
69-
N => {
68+
Key::Character("n") => {
7069
if close_requested {
7170
println!("Your window will continue to stay by your side.");
7271
close_requested = false;

examples/key_binding.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use simple_logger::SimpleLogger;
2+
use winit::{
3+
dpi::LogicalSize,
4+
event::{ElementState, Event, KeyEvent, WindowEvent},
5+
event_loop::{ControlFlow, EventLoop},
6+
keyboard::{Key, ModifiersState},
7+
window::WindowBuilder,
8+
};
9+
10+
/////////////////////////////////////////////////////////////////////////////
11+
// WARNING: This is not available on all platforms (for example on the web).
12+
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
13+
/////////////////////////////////////////////////////////////////////////////
14+
15+
fn main() {
16+
SimpleLogger::new().init().unwrap();
17+
let event_loop = EventLoop::new();
18+
19+
let _window = WindowBuilder::new()
20+
.with_inner_size(LogicalSize::new(400.0, 200.0))
21+
.build(&event_loop)
22+
.unwrap();
23+
24+
let mut modifiers = ModifiersState::default();
25+
26+
event_loop.run(move |event, _, control_flow| {
27+
*control_flow = ControlFlow::Wait;
28+
29+
match event {
30+
Event::WindowEvent { event, .. } => match event {
31+
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
32+
WindowEvent::ModifiersChanged(new_state) => {
33+
modifiers = new_state;
34+
}
35+
WindowEvent::KeyboardInput { event, .. } => {
36+
handle_key_event(modifiers, event);
37+
}
38+
_ => (),
39+
},
40+
_ => (),
41+
};
42+
});
43+
}
44+
45+
fn handle_key_event(modifiers: ModifiersState, event: KeyEvent) {
46+
if event.state == ElementState::Pressed && !event.repeat {
47+
match event.key_without_modifiers() {
48+
Key::Character("1") => {
49+
if modifiers.shift_key() {
50+
println!("Shift + 1 | logical_key: {:?}", event.logical_key);
51+
} else {
52+
println!("1");
53+
}
54+
}
55+
_ => (),
56+
}
57+
}
58+
}

examples/minimize.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
extern crate winit;
22

33
use simple_logger::SimpleLogger;
4-
use winit::event::{Event, VirtualKeyCode, WindowEvent};
4+
5+
use winit::event::{Event, WindowEvent};
56
use winit::event_loop::{ControlFlow, EventLoop};
7+
use winit::keyboard::Key;
68
use winit::window::WindowBuilder;
79

810
fn main() {
@@ -25,12 +27,14 @@ fn main() {
2527

2628
// Keyboard input event to handle minimize via a hotkey
2729
Event::WindowEvent {
28-
event: WindowEvent::KeyboardInput { input, .. },
30+
event: WindowEvent::KeyboardInput { event, .. },
2931
window_id,
3032
} => {
3133
if window_id == window.id() {
32-
// Pressing the 'M' key will minimize the window
33-
if input.virtual_keycode == Some(VirtualKeyCode::M) {
34+
// Pressing the 'm' key will minimize the window
35+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
36+
// See the `key_binding` example
37+
if let Key::Character("m") = event.logical_key {
3438
window.set_minimized(true);
3539
}
3640
}

0 commit comments

Comments
 (0)