Skip to content

Commit 9184309

Browse files
maroiderArturKovacskchibisovdaxpedda
authored
Overhaul the Keyboard API
Overhaul the keyboard API in winit to mimic the W3C specification to achieve better crossplatform parity. The `KeyboardInput` event is now uses `KeyEvent` which consists of: - `physical_key` - a cross platform way to refer to scancodes; - `logical_key` - keysym value, which shows your key respecting the layout; - `text` - the text produced by this keypress; - `location` - the location of the key on the keyboard; - `repeat` - whether the key was produced by the repeat. And also a `platform_specific` field which encapsulates extra information on desktop platforms, like key without modifiers and text with all modifiers. The `Modifiers` were also slightly reworked as in, the information whether the left or right modifier is pressed is now also exposed on platforms where it could be queried reliably. The support was also added for the web and orbital platforms finishing the API change. This change made the `OptionAsAlt` API on macOS redundant thus it was removed all together. Co-authored-by: Artúr Kovács <[email protected]> Co-authored-by: Kirill Chibisov <[email protected]> Co-authored-by: daxpedda <[email protected]> Fixes: rust-windowing#2631. Fixes: rust-windowing#2055. Fixes: rust-windowing#2032. Fixes: rust-windowing#1904. Fixes: rust-windowing#1810. Fixes: rust-windowing#1700. Fixes: rust-windowing#1443. Fixes: rust-windowing#1343. Fixes: rust-windowing#1208. Fixes: rust-windowing#1151. Fixes: rust-windowing#812. Fixes: rust-windowing#600. Fixes: rust-windowing#361. Fixes: rust-windowing#343.
1 parent f3f46cb commit 9184309

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+9570
-3412
lines changed

.github/workflows/ci.yml

+1-5
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ jobs:
7575
env:
7676
RUST_BACKTRACE: 1
7777
CARGO_INCREMENTAL: 0
78-
PKG_CONFIG_ALLOW_CROSS: 1
7978
RUSTFLAGS: "-C debuginfo=0 --deny warnings"
8079
OPTIONS: ${{ matrix.platform.options }}
8180
FEATURES: ${{ format(',{0}', matrix.platform.features ) }}
@@ -98,12 +97,9 @@ jobs:
9897
targets: ${{ matrix.platform.target }}
9998
components: clippy
10099

101-
- name: Install Linux dependencies
102-
if: (matrix.platform.os == 'ubuntu-latest')
103-
run: sudo apt-get update && sudo apt-get install pkg-config libxkbcommon-dev
104100
- name: Install GCC Multilib
105101
if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686')
106-
run: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install g++-multilib gcc-multilib libxkbcommon-dev:i386
102+
run: sudo apt-get update && sudo apt-get install gcc-multilib
107103
- name: Install cargo-apk
108104
if: contains(matrix.platform.target, 'android')
109105
run: cargo install cargo-apk

CHANGELOG.md

+28
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,34 @@ And please only add new entries to the top of this list, right below the `# Unre
88

99
# Unreleased
1010

11+
- **Breaking:** Remove all deprecated `modifiers` fields.
12+
- **Breaking:** Overhaul keyboard input handling.
13+
- Replace `KeyboardInput` with `KeyEvent` and `RawKeyEvent`.
14+
- Change `WindowEvent::KeyboardInput` to contain a `KeyEvent`.
15+
- Change `Event::Key` to contain a `RawKeyEvent`.
16+
- Remove `Event::ReceivedCharacter`. In its place, you should use
17+
`KeyEvent.text` in combination with `WindowEvent::Ime`.
18+
- Replace `VirtualKeyCode` with the `Key` enum.
19+
- Replace `ScanCode` with the `KeyCode` enum.
20+
- Rename `ModifiersState::LOGO` to `SUPER` and `ModifiersState::CTRL` to `CONTROL`.
21+
- Add `KeyCode` to refer to keys (roughly) by their physical location.
22+
- Add `NativeKeyCode` to represent raw `KeyCode`s which Winit doesn't
23+
understand.
24+
- Add `Key` to represent the keys after they've been interpreted by the
25+
active (software) keyboard layout.
26+
- Add `NativeKey` to represent raw `Key`s which Winit doesn't understand.
27+
- Add `KeyLocation` to tell apart `Key`s which usually "mean" the same thing,
28+
but can appear simultanesouly in different spots on the same keyboard
29+
layout.
30+
- Add `Window::reset_dead_keys` to enable application-controlled cancellation
31+
of dead key sequences.
32+
- Add `KeyEventExtModifierSupplement` to expose additional (and less
33+
portable) interpretations of a given key-press.
34+
- Add `KeyCodeExtScancode`, which lets you convert between raw keycodes and
35+
`KeyCode`.
36+
- Remove `WindowExtMacOS::option_as_alt` and `WindowExtMacOS::set_option_as_alt`.
37+
- `ModifiersChanged` now uses dedicated `Modifiers` struct.
38+
- On Orbital, fix `ModifiersChanged` not being sent.
1139
- **Breaking:** `CursorIcon` is now used from the `cursor-icon` crate.
1240
- **Breaking:** `CursorIcon::Hand` is now named `CursorIcon::Pointer`.
1341
- **Breaking:** `CursorIcon::Arrow` was removed.

Cargo.toml

+11-4
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ rustdoc-args = ["--cfg", "docsrs"]
3636

3737
[features]
3838
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
39-
x11 = ["x11-dl", "mio", "percent-encoding"]
40-
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "sctk", "fnv"]
39+
x11 = ["x11-dl", "mio", "percent-encoding", "xkbcommon-dl/x11"]
40+
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "sctk", "fnv", "memmap2"]
4141
wayland-dlopen = ["wayland-backend/dlopen"]
4242
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
4343
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
4444
wayland-csd-adwaita-notitle = ["sctk-adwaita"]
4545
android-native-activity = ["android-activity/native-activity"]
4646
android-game-activity = ["android-activity/game-activity"]
47-
serde = ["dep:serde", "cursor-icon/serde"]
47+
serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde"]
4848

4949
[build-dependencies]
5050
cfg_aliases = "0.1.1"
@@ -58,6 +58,7 @@ mint = { version = "0.5.6", optional = true }
5858
once_cell = "1.12"
5959
raw_window_handle = { package = "raw-window-handle", version = "0.5" }
6060
serde = { version = "1", optional = true, features = ["serde_derive"] }
61+
smol_str = "0.2.0"
6162

6263
[dev-dependencies]
6364
image = { version = "0.24.0", default-features = false, features = ["png"] }
@@ -67,6 +68,7 @@ simple_logger = { version = "2.1.0", default_features = false }
6768
# Coordinate the next winit release with android-ndk-rs: https://github.com/rust-windowing/winit/issues/1995
6869
android-activity = "0.4.0"
6970
ndk = "0.7.0"
71+
ndk-sys = "0.4.0"
7072

7173
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
7274
core-foundation = "0.9.3"
@@ -76,6 +78,9 @@ objc2 = ">=0.3.0-beta.3, <0.3.0-beta.4" # Allow `0.3.0-beta.3.patch-leaks`
7678
core-graphics = "0.22.3"
7779
dispatch = "0.2.0"
7880

81+
[target.'cfg(target_os = "windows")'.dependencies]
82+
unicode-segmentation = "1.7.1"
83+
7984
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
8085
version = "0.45"
8186
features = [
@@ -110,13 +115,15 @@ libc = "0.2.64"
110115
mio = { version = "0.8", features = ["os-ext"], optional = true }
111116
percent-encoding = { version = "2.0", optional = true }
112117
fnv = { version = "1.0.3", optional = true }
113-
sctk = { package = "smithay-client-toolkit", version = "0.17.0", optional = true }
118+
sctk = { package = "smithay-client-toolkit", version = "0.17.0", default-features = false, features = ["calloop"], optional = true }
114119
sctk-adwaita = { version = "0.6.0", default_features = false, optional = true }
115120
wayland-client = { version = "0.30.0", optional = true }
116121
wayland-backend = { version = "0.1.0", default_features = false, features = ["client_system"], optional = true }
117122
wayland-protocols = { version = "0.30.0", features = [ "staging"], optional = true }
118123
calloop = "0.10.5"
119124
x11-dl = { version = "2.18.5", optional = true }
125+
xkbcommon-dl = { git = "https://github.com/maroider/xkbcommon-dl", rev = "900832888ad6f11011d1369befb344a9aa8a9610" }
126+
memmap2 = { version = "0.5.0", optional = true }
120127

121128
[target.'cfg(target_os = "redox")'.dependencies]
122129
orbclient = { version = "0.3.42", default-features = false }

FEATURES.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ Changes in the API that have been agreed upon but aren't implemented across all
222222

223223
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
224224
|------------------------------ | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | ------ |
225-
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |||
226-
|Event Loop 2.0 ([#459]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ || |
227-
|Keyboard Input ([#812]) || | | | || | |
225+
|New API for HiDPI ([#315] [#319]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |||
226+
|Event Loop 2.0 ([#459]) |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ ||✔️ |
227+
|Keyboard Input 2.0 ([#753]) |✔️ |✔️ |✔️ |✔️ |✔️ | |✔️ |✔️ |
228228

229229
### Completed API Reworks
230230
|Feature |Windows|MacOS |Linux x11|Linux Wayland|Android|iOS |WASM |Redox OS|
@@ -243,5 +243,5 @@ Changes in the API that have been agreed upon but aren't implemented across all
243243
[#720]: https://github.com/rust-windowing/winit/issues/720
244244
[#721]: https://github.com/rust-windowing/winit/issues/721
245245
[#750]: https://github.com/rust-windowing/winit/issues/750
246+
[#753]: https://github.com/rust-windowing/winit/issues/753
246247
[#804]: https://github.com/rust-windowing/winit/issues/804
247-
[#812]: https://github.com/rust-windowing/winit/issues/812

docs/res/ATTRIBUTION.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Image Attribution
2+
3+
These images are used in the documentation of `winit`.
4+
5+
## keyboard_*.svg
6+
7+
These files are a modified version of "[ANSI US QWERTY (Windows)](https://commons.wikimedia.org/wiki/File:ANSI_US_QWERTY_(Windows).svg)"
8+
by [Tomiĉo] (https://commons.wikimedia.org/wiki/User:Tomi%C4%89o). It is
9+
originally released under the [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en)
10+
License. Minor modifications have been made by [John Nunley](https://github.com/notgull),
11+
which have been released under the same license as a derivative work.

docs/res/keyboard_left_shift_key.svg

+1
Loading

docs/res/keyboard_numpad_1_key.svg

+1
Loading

docs/res/keyboard_right_shift_key.svg

+1
Loading

docs/res/keyboard_standard_1_key.svg

+1
Loading

examples/child_window.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ fn main() {
55
use raw_window_handle::HasRawWindowHandle;
66
use winit::{
77
dpi::{LogicalPosition, LogicalSize, Position},
8-
event::{ElementState, Event, KeyboardInput, WindowEvent},
8+
event::{ElementState, Event, KeyEvent, WindowEvent},
99
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
1010
window::{Window, WindowBuilder, WindowId},
1111
};
@@ -59,8 +59,8 @@ fn main() {
5959
println!("cursor entered in the window {window_id:?}");
6060
}
6161
WindowEvent::KeyboardInput {
62-
input:
63-
KeyboardInput {
62+
event:
63+
KeyEvent {
6464
state: ElementState::Pressed,
6565
..
6666
},

examples/control_flow.rs

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

55
use simple_logger::SimpleLogger;
66
use winit::{
7-
event::{Event, KeyboardInput, WindowEvent},
7+
event::{ElementState, Event, KeyEvent, WindowEvent},
88
event_loop::EventLoop,
9+
keyboard::Key,
910
window::WindowBuilder,
1011
};
1112

@@ -40,7 +41,7 @@ fn main() {
4041
let mut close_requested = false;
4142

4243
event_loop.run(move |event, _, control_flow| {
43-
use winit::event::{ElementState, StartCause, VirtualKeyCode};
44+
use winit::event::StartCause;
4445
println!("{event:?}");
4546
match event {
4647
Event::NewEvents(start_cause) => {
@@ -54,31 +55,33 @@ fn main() {
5455
close_requested = true;
5556
}
5657
WindowEvent::KeyboardInput {
57-
input:
58-
KeyboardInput {
59-
virtual_keycode: Some(virtual_code),
58+
event:
59+
KeyEvent {
60+
logical_key: key,
6061
state: ElementState::Pressed,
6162
..
6263
},
6364
..
64-
} => match virtual_code {
65-
VirtualKeyCode::Key1 => {
65+
} => match key.as_ref() {
66+
// WARNING: Consider using `key_without_modifers()` if available on your platform.
67+
// See the `key_binding` example
68+
Key::Character("1") => {
6669
mode = Mode::Wait;
6770
println!("\nmode: {mode:?}\n");
6871
}
69-
VirtualKeyCode::Key2 => {
72+
Key::Character("2") => {
7073
mode = Mode::WaitUntil;
7174
println!("\nmode: {mode:?}\n");
7275
}
73-
VirtualKeyCode::Key3 => {
76+
Key::Character("3") => {
7477
mode = Mode::Poll;
7578
println!("\nmode: {mode:?}\n");
7679
}
77-
VirtualKeyCode::R => {
80+
Key::Character("r") => {
7881
request_redraw = !request_redraw;
7982
println!("\nrequest_redraw: {request_redraw}\n");
8083
}
81-
VirtualKeyCode::Escape => {
84+
Key::Escape => {
8285
close_requested = true;
8386
}
8487
_ => (),

examples/cursor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use simple_logger::SimpleLogger;
44
use winit::{
5-
event::{ElementState, Event, KeyboardInput, WindowEvent},
5+
event::{ElementState, Event, KeyEvent, WindowEvent},
66
event_loop::EventLoop,
77
window::{CursorIcon, WindowBuilder},
88
};
@@ -23,8 +23,8 @@ fn main() {
2323
Event::WindowEvent {
2424
event:
2525
WindowEvent::KeyboardInput {
26-
input:
27-
KeyboardInput {
26+
event:
27+
KeyEvent {
2828
state: ElementState::Pressed,
2929
..
3030
},

examples/cursor_grab.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

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

@@ -25,35 +26,37 @@ fn main() {
2526
Event::WindowEvent { event, .. } => match event {
2627
WindowEvent::CloseRequested => control_flow.set_exit(),
2728
WindowEvent::KeyboardInput {
28-
input:
29-
KeyboardInput {
29+
event:
30+
KeyEvent {
31+
logical_key: key,
3032
state: ElementState::Released,
31-
virtual_keycode: Some(key),
3233
..
3334
},
3435
..
3536
} => {
36-
use winit::event::VirtualKeyCode::*;
3737
let result = match key {
38-
Escape => {
38+
Key::Escape => {
3939
control_flow.set_exit();
4040
Ok(())
4141
}
42-
G => window.set_cursor_grab(CursorGrabMode::Confined),
43-
L => window.set_cursor_grab(CursorGrabMode::Locked),
44-
A => window.set_cursor_grab(CursorGrabMode::None),
45-
H => {
46-
window.set_cursor_visible(modifiers.shift());
47-
Ok(())
48-
}
42+
Key::Character(ch) => match ch.to_lowercase().as_str() {
43+
"g" => window.set_cursor_grab(CursorGrabMode::Confined),
44+
"l" => window.set_cursor_grab(CursorGrabMode::Locked),
45+
"a" => window.set_cursor_grab(CursorGrabMode::None),
46+
"h" => {
47+
window.set_cursor_visible(modifiers.shift_key());
48+
Ok(())
49+
}
50+
_ => Ok(()),
51+
},
4952
_ => Ok(()),
5053
};
5154

5255
if let Err(err) = result {
5356
println!("error: {err}");
5457
}
5558
}
56-
WindowEvent::ModifiersChanged(m) => modifiers = m,
59+
WindowEvent::ModifiersChanged(new) => modifiers = new.state(),
5760
_ => (),
5861
},
5962
Event::DeviceEvent { event, .. } => match event {

examples/drag_window.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
use simple_logger::SimpleLogger;
44
use winit::{
5-
event::{
6-
ElementState, Event, KeyboardInput, MouseButton, StartCause, VirtualKeyCode, WindowEvent,
7-
},
5+
event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent},
86
event_loop::EventLoop,
7+
keyboard::Key,
98
window::{Window, WindowBuilder, WindowId},
109
};
1110

@@ -45,14 +44,14 @@ fn main() {
4544
name_windows(entered_id, switched, &window_1, &window_2)
4645
}
4746
WindowEvent::KeyboardInput {
48-
input:
49-
KeyboardInput {
47+
event:
48+
KeyEvent {
5049
state: ElementState::Released,
51-
virtual_keycode: Some(VirtualKeyCode::X),
50+
logical_key: Key::Character(c),
5251
..
5352
},
5453
..
55-
} => {
54+
} if c == "x" => {
5655
switched = !switched;
5756
name_windows(entered_id, switched, &window_1, &window_2);
5857
println!("Switched!")

0 commit comments

Comments
 (0)