Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions winit-android/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ pub use crate::event_loop::{
ActiveEventLoop, EventLoop, EventLoopProxy, PlatformSpecificEventLoopAttributes,
PlatformSpecificWindowAttributes, Window,
};
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on Android.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}

/// Additional methods on [`EventLoop`] that are specific to Android.
pub trait EventLoopExtAndroid {
Expand Down
42 changes: 37 additions & 5 deletions winit-appkit/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use winit_core::keyboard::{

use super::ffi;

/// Ignores ALL modifiers.
pub fn get_modifierless_char(scancode: u16) -> Key {
pub fn scancode_to_key(scancode: u16, modifiers: u32) -> Key {
let Some(ptr) = NonNull::new(unsafe { ffi::TISCopyCurrentKeyboardLayoutInputSource() }) else {
tracing::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr");
return Key::Unidentified(NativeKey::MacOS(scancode));
Expand All @@ -35,7 +34,6 @@ pub fn get_modifierless_char(scancode: u16) -> Key {

let mut result_len = 0;
let mut dead_keys = 0;
let modifiers = 0;
let mut string = [0; 16];
let translate_result = unsafe {
ffi::UCKeyTranslate(
Expand Down Expand Up @@ -106,8 +104,8 @@ pub(crate) fn create_key_event(ns_event: &NSEvent, is_press: bool, is_repeat: bo

let key_from_code = code_to_key(physical_key, scancode);
let (logical_key, key_without_modifiers) = if matches!(key_from_code, Key::Unidentified(_)) {
// `get_modifierless_char/key_without_modifiers` ignores ALL modifiers.
let key_without_modifiers = get_modifierless_char(scancode);
// `scancode_to_key/key_without_modifiers` ignores ALL modifiers with no flags
let key_without_modifiers = scancode_to_key(scancode, 0u32);

let modifiers = ns_event.modifierFlags();
let has_ctrl = modifiers.contains(NSEventModifierFlags::Control);
Expand Down Expand Up @@ -628,3 +626,37 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
_ => return PhysicalKey::Unidentified(NativeKeyCode::MacOS(scancode as u16)),
})
}

/// Query the logical key for a physical key under the current keyboard layout.
///
/// Note: `num_lock` is ignored on macOS as it doesn't have traditional NumLock.
pub fn physical_to_logical_key(
keycode: KeyCode,
modifiers: ModifiersState,
caps_lock: bool,
_num_lock: bool,
) -> Key {
let Some(scancode) = physicalkey_to_scancode(PhysicalKey::Code(keycode)) else {
return Key::Unidentified(NativeKey::Unidentified);
};

// UCKeyTranslate modifier format (Carbon modifiers >> 8)
let mut uc_modifiers = 0u32;
if modifiers.meta_key() {
uc_modifiers |= 1; // cmdKey
}
if modifiers.shift_key() {
uc_modifiers |= 2; // shiftKey
}
if caps_lock {
uc_modifiers |= 4; // alphaLock
}
if modifiers.alt_key() {
uc_modifiers |= 8; // optionKey
}
if modifiers.control_key() {
uc_modifiers |= 16; // controlKey
}

scancode_to_key(scancode as u16, uc_modifiers)
}
2 changes: 1 addition & 1 deletion winit-appkit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ use winit_core::event_loop::ActiveEventLoop;
use winit_core::monitor::MonitorHandle;
use winit_core::window::{PlatformWindowAttributes, Window};

pub use self::event::{physicalkey_to_scancode, scancode_to_physicalkey};
pub use self::event::{physical_to_logical_key, physicalkey_to_scancode, scancode_to_physicalkey};
use self::event_loop::ActiveEventLoop as AppKitActiveEventLoop;
pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use self::monitor::MonitorHandle as AppKitMonitorHandle;
Expand Down
11 changes: 11 additions & 0 deletions winit-orbital/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
use std::{fmt, str};

pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on Orbital.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}

macro_rules! os_error {
($error:expr) => {{ winit_core::error::OsError::new(line!(), file!(), $error) }};
Expand Down
11 changes: 11 additions & 0 deletions winit-uikit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ use winit_core::window::{PlatformWindowAttributes, Window};
pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use self::monitor::MonitorHandle as UIKitMonitorHandle;
use self::window::Window as UIKitWindow;
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on iOS.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}

/// Additional methods on [`Window`] that are specific to iOS.
pub trait WindowExtIOS {
Expand Down
11 changes: 11 additions & 0 deletions winit-web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ use winit_core::window::{PlatformWindowAttributes, Window};
pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use self::web_sys as backend;
use self::window::Window as WebWindow;
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on Web.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}
use crate::cursor::CustomCursorFuture as PlatformCustomCursorFuture;
use crate::event_loop::ActiveEventLoop as WebActiveEventLoop;
use crate::main_thread::{MainThreadMarker, MainThreadSafe};
Expand Down
11 changes: 11 additions & 0 deletions winit-win32/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ use self::icon::{RaiiIcon, SelectedCursor};
pub use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
pub use self::monitor::{MonitorHandle, VideoModeHandle};
pub use self::window::Window;
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on Windows.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}

/// Window Handle type used by Win32 API
pub type HWND = *mut c_void;
Expand Down
34 changes: 34 additions & 0 deletions winit/src/platform/key_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Query logical keys from physical key codes under the current keyboard layout.

use crate::keyboard::{Key, KeyCode, ModifiersState};

/// Extension trait for [`KeyCode`] to query logical key mappings.
pub trait KeyCodeExtKeyMap {
/// Returns the logical key that would be produced by this physical key
/// with the given modifiers under the current keyboard layout.
///
/// # Example
///
/// ```ignore
/// use winit::keyboard::{KeyCode, ModifiersState};
/// use winit::platform::key_map::KeyCodeExtKeyMap;
///
/// // Get what the 'A' key produces with Shift held
/// let key = KeyCode::KeyA.physical_to_logical_key(ModifiersState::SHIFT, false, false);
/// ```
///
/// ## Platform Support
///
/// - **macOS**: Supported, does not use `num_lock`.
/// - **Other platforms**: Not yet implemented, returns `Key::Unidentified`.
fn to_logical_key(self, modifiers: ModifiersState, caps_lock: bool, num_lock: bool) -> Key;
}

impl KeyCodeExtKeyMap for KeyCode {
#[inline]
fn to_logical_key(self, modifiers: ModifiersState, caps_lock: bool, num_lock: bool) -> Key {
crate::platform_impl::platform::physical_to_logical_key(
self, modifiers, caps_lock, num_lock,
)
}
}
13 changes: 13 additions & 0 deletions winit/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,16 @@ pub use winit_x11 as x11;
pub mod scancode;
#[cfg(any(x11_platform, wayland_platform, docsrs))]
pub mod startup_notify;

#[cfg(any(
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
android_platform,
ios_platform,
web_platform,
orbital_platform,
docsrs
))]
pub mod key_map;
11 changes: 11 additions & 0 deletions winit/src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ use std::time::Duration;

pub(crate) use winit_common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
use winit_core::application::ApplicationHandler;
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NativeKey};

/// Stub implementation for physical to logical key mapping on Linux.
pub fn physical_to_logical_key(
_keycode: KeyCode,
_modifiers: ModifiersState,
_caps_lock: bool,
_num_lock: bool,
) -> Key {
Key::Unidentified(NativeKey::Unidentified)
}
use winit_core::error::{EventLoopError, NotSupportedError};
use winit_core::event_loop::ActiveEventLoop;
use winit_core::event_loop::pump_events::PumpStatus;
Expand Down
Loading