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

Revise Key, KeyCode enums #3143

Merged
merged 11 commits into from
Oct 19, 2023
4 changes: 2 additions & 2 deletions examples/ime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use winit::{
dpi::{PhysicalPosition, PhysicalSize},
event::{ElementState, Event, Ime, WindowEvent},
event_loop::EventLoop,
keyboard::{Key, KeyCode},
keyboard::Key,
window::{ImePurpose, WindowBuilder},
};

Expand Down Expand Up @@ -69,7 +69,7 @@ fn main() -> Result<(), impl std::error::Error> {
WindowEvent::KeyboardInput { event, .. } => {
println!("key: {event:?}");

if event.state == ElementState::Pressed && event.physical_key == KeyCode::F2 {
if event.state == ElementState::Pressed && event.logical_key == Key::F2 {
ime_allowed = !ime_allowed;
window.set_ime_allowed(ime_allowed);
println!("\nIME allowed: {ime_allowed}\n");
Expand Down
4 changes: 2 additions & 2 deletions examples/resizable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
keyboard::KeyCode,
keyboard::{KeyCode, PhysicalKey},
window::WindowBuilder,
};

Expand Down Expand Up @@ -34,7 +34,7 @@ fn main() -> Result<(), impl std::error::Error> {
WindowEvent::KeyboardInput {
event:
KeyEvent {
physical_key: KeyCode::Space,
physical_key: PhysicalKey::Code(KeyCode::Space),
state: ElementState::Released,
..
},
Expand Down
6 changes: 3 additions & 3 deletions examples/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
keyboard::KeyCode,
keyboard::Key,
window::{Fullscreen, WindowBuilder},
};

Expand Down Expand Up @@ -39,13 +39,13 @@ pub fn main() -> Result<(), impl std::error::Error> {
WindowEvent::KeyboardInput {
event:
KeyEvent {
physical_key: KeyCode::KeyF,
logical_key: Key::Character(c),
state: ElementState::Released,
..
},
..
},
} if window_id == window.id() => {
} if window_id == window.id() && c == "f" => {
if window.fullscreen().is_some() {
window.set_fullscreen(None);
} else {
Expand Down
6 changes: 3 additions & 3 deletions examples/window_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use winit::{
dpi::{LogicalSize, PhysicalSize},
event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, WindowEvent},
event_loop::{DeviceEvents, EventLoop},
keyboard::{Key, KeyCode},
keyboard::{Key, KeyCode, PhysicalKey},
window::{Fullscreen, WindowBuilder},
};

Expand Down Expand Up @@ -51,14 +51,14 @@ fn main() -> Result<(), impl std::error::Error> {
}),
..
} => match physical_key {
KeyCode::KeyM => {
PhysicalKey::Code(KeyCode::KeyM) => {
if minimized {
minimized = !minimized;
window.set_minimized(minimized);
window.focus_window();
}
}
KeyCode::KeyV => {
PhysicalKey::Code(KeyCode::KeyV) => {
if !visible {
visible = !visible;
window.set_visible(visible);
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ pub enum DeviceEvent {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RawKeyEvent {
pub physical_key: keyboard::KeyCode,
pub physical_key: keyboard::PhysicalKey,
pub state: ElementState,
}

Expand Down Expand Up @@ -703,7 +703,7 @@ pub struct KeyEvent {
/// `Fn` and `FnLock` key events are *exceedingly unlikely* to be emitted by Winit. These keys
/// are usually handled at the hardware or OS level, and aren't surfaced to applications. If
/// you somehow see this in the wild, we'd like to know :)
pub physical_key: keyboard::KeyCode,
pub physical_key: keyboard::PhysicalKey,

// Allowing `broken_intra_doc_links` for `logical_key`, because
// `key_without_modifiers` is not available on all platforms
Expand Down
24 changes: 17 additions & 7 deletions src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,24 +187,34 @@ impl std::fmt::Debug for NativeKey {

/// Represents the location of a physical key.
///
/// This type is a superset of [`KeyCode`], including an [`Unidentified`](Self::Unidentified)
/// variant.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PhysicalKey {
/// A known key code
Code(KeyCode),
/// This variant is used when the key cannot be translated to a [`KeyCode`]
///
/// The native keycode is provided (if available) so you're able to more reliably match
/// key-press and key-release events by hashing the [`PhysicalKey`]. It is also possible to use
/// this for keybinds for non-standard keys, but such keybinds are tied to a given platform.
Unidentified(NativeKeyCode),
}

/// Code representing the location of a physical key
///
/// This mostly conforms to the UI Events Specification's [`KeyboardEvent.code`] with a few
/// exceptions:
/// - The keys that the specification calls "MetaLeft" and "MetaRight" are named "SuperLeft" and
/// "SuperRight" here.
/// - The key that the specification calls "Super" is reported as `Unidentified` here.
/// - The `Unidentified` variant here, can still identify a key through it's `NativeKeyCode`.
///
/// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum KeyCode {
/// This variant is used when the key cannot be translated to any other variant.
///
/// The native keycode is provided (if available) so you're able to more reliably match
/// key-press and key-release events by hashing the [`KeyCode`]. It is also possible to use
/// this for keybinds for non-standard keys, but such keybinds are tied to a given platform.
Unidentified(NativeKeyCode),
/// <kbd>`</kbd> on a US keyboard. This is also called a backtick or grave.
/// This is the <kbd>半角</kbd>/<kbd>全角</kbd>/<kbd>漢字</kbd>
/// (hankaku/zenkaku/kanji) key on Japanese keyboards
Expand Down
29 changes: 22 additions & 7 deletions src/platform/scancode.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#![cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform))]

use crate::keyboard::KeyCode;
use crate::keyboard::{KeyCode, PhysicalKey};

// TODO: Describe what this value contains for each platform

/// Additional methods for the [`KeyCode`] type that allow the user to access the platform-specific
/// Additional methods for the [`PhysicalKey`] type that allow the user to access the platform-specific
/// scancode.
///
/// [`KeyCode`]: crate::keyboard::KeyCode
pub trait KeyCodeExtScancode {
/// [`PhysicalKey`]: crate::keyboard::PhysicalKey
pub trait PhysicalKeyExtScancode {
/// The raw value of the platform-specific physical key identifier.
///
/// Returns `Some(key_id)` if the conversion was succesful; returns `None` otherwise.
Expand All @@ -18,13 +18,28 @@ pub trait KeyCodeExtScancode {
/// - **Wayland/X11**: A 32-bit linux scancode, which is X11/Wayland keycode subtracted by 8.
fn to_scancode(self) -> Option<u32>;

/// Constructs a `KeyCode` from a platform-specific physical key identifier.
/// Constructs a `PhysicalKey` from a platform-specific physical key identifier.
///
/// Note that this conversion may be lossy, i.e. converting the returned `KeyCode` back
/// Note that this conversion may be lossy, i.e. converting the returned `PhysicalKey` back
/// using `to_scancode` might not yield the original value.
///
/// ## Platform-specific
/// - **Wayland/X11**: A 32-bit linux scancode. When building from X11/Wayland keycode subtract
/// `8` to get the value you wanted.
fn from_scancode(scancode: u32) -> KeyCode;
fn from_scancode(scancode: u32) -> PhysicalKey;
}

impl PhysicalKeyExtScancode for KeyCode
where
PhysicalKey: PhysicalKeyExtScancode,
{
#[inline]
fn from_scancode(scancode: u32) -> PhysicalKey {
<PhysicalKey as PhysicalKeyExtScancode>::from_scancode(scancode)
}

#[inline]
fn to_scancode(self) -> Option<u32> {
<PhysicalKey as PhysicalKeyExtScancode>::to_scancode(PhysicalKey::Code(self))
}
}
10 changes: 5 additions & 5 deletions src/platform_impl/android/keycodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use android_activity::{
AndroidApp,
};

use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode};
use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode, PhysicalKey};

pub fn to_physical_keycode(keycode: Keycode) -> KeyCode {
match keycode {
pub fn to_physical_key(keycode: Keycode) -> PhysicalKey {
PhysicalKey::Code(match keycode {
Keycode::A => KeyCode::KeyA,
Keycode::B => KeyCode::KeyB,
Keycode::C => KeyCode::KeyC,
Expand Down Expand Up @@ -155,8 +155,8 @@ pub fn to_physical_keycode(keycode: Keycode) -> KeyCode {
Keycode::Sleep => KeyCode::Sleep, // what about SoftSleep?
Keycode::Wakeup => KeyCode::WakeUp,

keycode => KeyCode::Unidentified(NativeKeyCode::Android(keycode.into())),
}
keycode => return PhysicalKey::Unidentified(NativeKeyCode::Android(keycode.into())),
})
}

/// Tries to map the `key_event` to a `KeyMapChar` containing a unicode character or dead key accent
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ impl<T: 'static> EventLoop<T> {
device_id: event::DeviceId(DeviceId(key.device_id())),
event: event::KeyEvent {
state,
physical_key: keycodes::to_physical_keycode(keycode),
physical_key: keycodes::to_physical_key(keycode),
logical_key: keycodes::to_logical(key_char, keycode),
location: keycodes::to_location(keycode),
repeat: key.repeat_count() > 0,
Expand Down
33 changes: 21 additions & 12 deletions src/platform_impl/linux/common/keymap.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
//! Convert XKB keys to Winit keys.

use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode};
use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode, PhysicalKey};

/// Map the raw X11-style keycode to the `KeyCode` enum.
///
/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses.
pub fn raw_keycode_to_keycode(keycode: u32) -> KeyCode {
pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey {
scancode_to_keycode(keycode.saturating_sub(8))
}

/// Map the linux scancode to Keycode.
///
/// Both X11 and Wayland use keys with `+ 8` offset to linux scancode.
pub fn scancode_to_keycode(scancode: u32) -> KeyCode {
pub fn scancode_to_keycode(scancode: u32) -> PhysicalKey {
// The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as
// libxkbcommon's documentation seems to suggest that the keycode values we're interested in
// are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,
Expand All @@ -21,8 +21,8 @@ pub fn scancode_to_keycode(scancode: u32) -> KeyCode {
// Some of the keycodes are likely superfluous for our purposes, and some are ones which are
// difficult to test the correctness of, or discover the purpose of. Because of this, they've
// either been commented out here, or not included at all.
match scancode {
0 => KeyCode::Unidentified(NativeKeyCode::Xkb(0)),
PhysicalKey::Code(match scancode {
0 => return PhysicalKey::Unidentified(NativeKeyCode::Xkb(0)),
1 => KeyCode::Escape,
2 => KeyCode::Digit1,
3 => KeyCode::Digit2,
Expand Down Expand Up @@ -256,7 +256,7 @@ pub fn scancode_to_keycode(scancode: u32) -> KeyCode {
// 237 => KeyCode::BLUETOOTH,
// 238 => KeyCode::WLAN,
// 239 => KeyCode::UWB,
240 => KeyCode::Unidentified(NativeKeyCode::Unidentified),
240 => return PhysicalKey::Unidentified(NativeKeyCode::Unidentified),
// 241 => KeyCode::VIDEO_NEXT,
// 242 => KeyCode::VIDEO_PREV,
// 243 => KeyCode::BRIGHTNESS_CYCLE,
Expand All @@ -265,14 +265,23 @@ pub fn scancode_to_keycode(scancode: u32) -> KeyCode {
// 246 => KeyCode::WWAN,
// 247 => KeyCode::RFKILL,
// 248 => KeyCode::KEY_MICMUTE,
_ => KeyCode::Unidentified(NativeKeyCode::Xkb(scancode)),
}
_ => return PhysicalKey::Unidentified(NativeKeyCode::Xkb(scancode)),
})
}

pub fn keycode_to_scancode(keycode: KeyCode) -> Option<u32> {
match keycode {
KeyCode::Unidentified(NativeKeyCode::Unidentified) => Some(240),
KeyCode::Unidentified(NativeKeyCode::Xkb(raw)) => Some(raw),
pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
let code = match key {
PhysicalKey::Code(code) => code,
PhysicalKey::Unidentified(code) => {
return match code {
NativeKeyCode::Unidentified => Some(240),
NativeKeyCode::Xkb(raw) => Some(raw),
_ => None,
};
}
};

match code {
KeyCode::Escape => Some(1),
KeyCode::Digit1 => Some(2),
KeyCode::Digit2 => Some(3),
Expand Down
8 changes: 4 additions & 4 deletions src/platform_impl/linux/common/xkb_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::platform_impl::common::keymap;
use crate::platform_impl::KeyEventExtra;
use crate::{
event::ElementState,
keyboard::{Key, KeyCode, KeyLocation},
keyboard::{Key, KeyLocation, PhysicalKey},
};

// TODO: Wire this up without using a static `AtomicBool`.
Expand Down Expand Up @@ -391,7 +391,7 @@ impl KbdState {
) -> KeyEvent {
let mut event =
KeyEventResults::new(self, keycode, !repeat && state == ElementState::Pressed);
let physical_key = event.keycode();
let physical_key = event.physical_key();
let (logical_key, location) = event.key();
let text = event.text();
let (key_without_modifiers, _) = event.key_without_modifiers();
Expand Down Expand Up @@ -498,8 +498,8 @@ impl<'a> KeyEventResults<'a> {
}
}

fn keycode(&mut self) -> KeyCode {
keymap::raw_keycode_to_keycode(self.keycode)
fn physical_key(&mut self) -> PhysicalKey {
keymap::raw_keycode_to_physicalkey(self.keycode)
}

pub fn key(&mut self) -> (Key, KeyLocation) {
Expand Down
10 changes: 5 additions & 5 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use crate::{
EventLoopWindowTarget as RootELW,
},
icon::Icon,
keyboard::{Key, KeyCode},
keyboard::{Key, PhysicalKey},
platform::{
modifier_supplement::KeyEventExtModifierSupplement, pump_events::PumpStatus,
scancode::KeyCodeExtScancode,
scancode::PhysicalKeyExtScancode,
},
window::{
ActivationToken, CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme,
Expand Down Expand Up @@ -633,13 +633,13 @@ impl KeyEventExtModifierSupplement for KeyEvent {
}
}

impl KeyCodeExtScancode for KeyCode {
fn from_scancode(scancode: u32) -> KeyCode {
impl PhysicalKeyExtScancode for PhysicalKey {
fn from_scancode(scancode: u32) -> PhysicalKey {
common::keymap::scancode_to_keycode(scancode)
}

fn to_scancode(self) -> Option<u32> {
common::keymap::keycode_to_scancode(self)
common::keymap::physicalkey_to_scancode(self)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ impl<T: 'static> EventProcessor<T> {
if keycode < KEYCODE_OFFSET as u32 {
return;
}
let physical_key = keymap::raw_keycode_to_keycode(keycode);
let physical_key = keymap::raw_keycode_to_physicalkey(keycode);

callback(Event::DeviceEvent {
device_id,
Expand Down
Loading
Loading