Display all platform-specific documentation on docs.rs (#3076)

This commit is contained in:
Mads Marquart
2024-01-04 12:54:35 +01:00
committed by GitHub
parent 8b3de7cedf
commit 42dbc4748e
28 changed files with 810 additions and 814 deletions

View File

@@ -17,6 +17,17 @@ jobs:
- name: Check Formatting - name: Check Formatting
run: cargo fmt -- --check run: cargo fmt -- --check
docsrs:
name: Check building on docs.rs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly
- name: Check Formatting
run: cargo doc --no-deps --features=rwh_04,rwh_05,rwh_06,serde,mint,android-native-activity
env:
RUSTDOCFLAGS: '--cfg=docsrs --deny=warnings'
tests: tests:
name: Test ${{ matrix.toolchain }} ${{ matrix.platform.name }} name: Test ${{ matrix.toolchain }} ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }}

View File

@@ -28,6 +28,8 @@ Unreleased` header.
- On Web, add the ability to toggle calling `Event.preventDefault()` on `Window`. - On Web, add the ability to toggle calling `Event.preventDefault()` on `Window`.
- **Breaking:** Remove `WindowAttributes::fullscreen()` and expose as field directly. - **Breaking:** Remove `WindowAttributes::fullscreen()` and expose as field directly.
- **Breaking:** Rename `VideoMode` to `VideoModeHandle` to represent that it doesn't hold static data. - **Breaking:** Rename `VideoMode` to `VideoModeHandle` to represent that it doesn't hold static data.
- **Breaking:** No longer export `platform::x11::XNotSupported`.
- **Breaking:** Renamed `platform::x11::XWindowType` to `platform::x11::WindowType`.
# 0.29.8 # 0.29.8

View File

@@ -18,6 +18,7 @@ features = [
"rwh_05", "rwh_05",
"rwh_06", "rwh_06",
"serde", "serde",
"mint",
# Enabled to get docs to compile # Enabled to get docs to compile
"android-native-activity", "android-native-activity",
] ]

View File

@@ -154,7 +154,11 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(feature = "cargo-clippy", deny(warnings))] #![cfg_attr(feature = "cargo-clippy", deny(warnings))]
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(
docsrs,
feature(doc_auto_cfg, doc_cfg_hide),
doc(cfg_hide(doc, docsrs))
)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
#[cfg(feature = "rwh_06")] #[cfg(feature = "rwh_06")]

View File

@@ -3,7 +3,7 @@ use crate::{
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
use android_activity::{AndroidApp, ConfigurationRef, Rect}; use self::activity::{AndroidApp, ConfigurationRef, Rect};
/// Additional methods on [`EventLoop`] that are specific to Android. /// Additional methods on [`EventLoop`] that are specific to Android.
pub trait EventLoopExtAndroid {} pub trait EventLoopExtAndroid {}
@@ -89,5 +89,16 @@ pub mod activity {
// feature enabled, so we avoid inlining it so that they're forced to view // feature enabled, so we avoid inlining it so that they're forced to view
// it on the crate's own docs.rs page. // it on the crate's own docs.rs page.
#[doc(no_inline)] #[doc(no_inline)]
#[cfg(android_platform)]
pub use android_activity::*; pub use android_activity::*;
#[cfg(not(android_platform))]
#[doc(hidden)]
pub struct Rect;
#[cfg(not(android_platform))]
#[doc(hidden)]
pub struct ConfigurationRef;
#[cfg(not(android_platform))]
#[doc(hidden)]
pub struct AndroidApp;
} }

View File

@@ -1,8 +1,5 @@
use std::os::raw::c_void; use std::os::raw::c_void;
use icrate::Foundation::MainThreadMarker;
use objc2::rc::Id;
use crate::{ use crate::{
event_loop::EventLoop, event_loop::EventLoop,
monitor::{MonitorHandle, VideoModeHandle}, monitor::{MonitorHandle, VideoModeHandle},
@@ -240,8 +237,8 @@ impl MonitorHandleExtIOS for MonitorHandle {
#[inline] #[inline]
fn ui_screen(&self) -> *mut c_void { fn ui_screen(&self) -> *mut c_void {
// SAFETY: The marker is only used to get the pointer of the screen // SAFETY: The marker is only used to get the pointer of the screen
let mtm = unsafe { MainThreadMarker::new_unchecked() }; let mtm = unsafe { icrate::Foundation::MainThreadMarker::new_unchecked() };
Id::as_ptr(self.inner.ui_screen(mtm)) as *mut c_void objc2::rc::Id::as_ptr(self.inner.ui_screen(mtm)) as *mut c_void
} }
#[inline] #[inline]

View File

@@ -1,7 +1,5 @@
use std::os::raw::c_void; use std::os::raw::c_void;
use icrate::Foundation::MainThreadMarker;
use objc2::rc::Id;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -369,8 +367,10 @@ impl MonitorHandleExtMacOS for MonitorHandle {
fn ns_screen(&self) -> Option<*mut c_void> { fn ns_screen(&self) -> Option<*mut c_void> {
// SAFETY: We only use the marker to get a pointer // SAFETY: We only use the marker to get a pointer
let mtm = unsafe { MainThreadMarker::new_unchecked() }; let mtm = unsafe { icrate::Foundation::MainThreadMarker::new_unchecked() };
self.inner.ns_screen(mtm).map(|s| Id::as_ptr(&s) as _) self.inner
.ns_screen(mtm)
.map(|s| objc2::rc::Id::as_ptr(&s) as _)
} }
} }

View File

@@ -1,38 +1,24 @@
//! Contains traits with platform-specific methods in them. //! Contains traits with platform-specific methods in them.
//! //!
//! Contains the follow OS-specific modules: //! Only the modules corresponding to the platform you're compiling to will be available.
//!
//! - `android`
//! - `ios`
//! - `macos`
//! - `unix`
//! - `windows`
//! - `web`
//!
//! And the following platform-specific modules:
//!
//! - `run_on_demand` (available on `windows`, `unix`, `macos`, `android`)
//! - `pump_events` (available on `windows`, `unix`, `macos`, `android`)
//!
//! However only the module corresponding to the platform you're compiling to will be available.
#[cfg(android_platform)] #[cfg(any(android_platform, docsrs))]
pub mod android; pub mod android;
#[cfg(ios_platform)] #[cfg(any(ios_platform, docsrs))]
pub mod ios; pub mod ios;
#[cfg(macos_platform)] #[cfg(any(macos_platform, docsrs))]
pub mod macos; pub mod macos;
#[cfg(orbital_platform)] #[cfg(any(orbital_platform, docsrs))]
pub mod orbital; pub mod orbital;
#[cfg(any(x11_platform, wayland_platform))] #[cfg(any(x11_platform, wayland_platform, docsrs))]
pub mod startup_notify; pub mod startup_notify;
#[cfg(wayland_platform)] #[cfg(any(wayland_platform, docsrs))]
pub mod wayland; pub mod wayland;
#[cfg(wasm_platform)] #[cfg(any(wasm_platform, docsrs))]
pub mod web; pub mod web;
#[cfg(windows_platform)] #[cfg(any(windows_platform, docsrs))]
pub mod windows; pub mod windows;
#[cfg(x11_platform)] #[cfg(any(x11_platform, docsrs))]
pub mod x11; pub mod x11;
#[cfg(any( #[cfg(any(
@@ -40,7 +26,8 @@ pub mod x11;
macos_platform, macos_platform,
android_platform, android_platform,
x11_platform, x11_platform,
wayland_platform wayland_platform,
docsrs,
))] ))]
pub mod run_on_demand; pub mod run_on_demand;
@@ -49,9 +36,25 @@ pub mod run_on_demand;
macos_platform, macos_platform,
android_platform, android_platform,
x11_platform, x11_platform,
wayland_platform wayland_platform,
docsrs,
))] ))]
pub mod pump_events; pub mod pump_events;
#[cfg(any(
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
docsrs
))]
pub mod modifier_supplement; pub mod modifier_supplement;
#[cfg(any(
windows_platform,
macos_platform,
x11_platform,
wayland_platform,
docsrs
))]
pub mod scancode; pub mod scancode;

View File

@@ -1,5 +1,4 @@
#![cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform))] use crate::event::KeyEvent;
use crate::keyboard::Key; use crate::keyboard::Key;
/// Additional methods for the `KeyEvent` which cannot be implemented on all /// Additional methods for the `KeyEvent` which cannot be implemented on all
@@ -22,3 +21,18 @@ pub trait KeyEventExtModifierSupplement {
/// cannot be `Dead`. /// cannot be `Dead`.
fn key_without_modifiers(&self) -> Key; fn key_without_modifiers(&self) -> Key;
} }
impl KeyEventExtModifierSupplement for KeyEvent {
#[inline]
fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific
.text_with_all_modifiers
.as_ref()
.map(|s| s.as_str())
}
#[inline]
fn key_without_modifiers(&self) -> Key {
self.platform_specific.key_without_modifiers.clone()
}
}

View File

@@ -1,5 +1,3 @@
#![cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform))]
use crate::keyboard::{KeyCode, PhysicalKey}; use crate::keyboard::{KeyCode, PhysicalKey};
// TODO: Describe what this value contains for each platform // TODO: Describe what this value contains for each platform
@@ -29,17 +27,24 @@ pub trait PhysicalKeyExtScancode {
fn from_scancode(scancode: u32) -> PhysicalKey; fn from_scancode(scancode: u32) -> PhysicalKey;
} }
impl PhysicalKeyExtScancode for KeyCode impl PhysicalKeyExtScancode for PhysicalKey {
where fn to_scancode(self) -> Option<u32> {
PhysicalKey: PhysicalKeyExtScancode, crate::platform_impl::physicalkey_to_scancode(self)
{
#[inline]
fn from_scancode(scancode: u32) -> PhysicalKey {
<PhysicalKey as PhysicalKeyExtScancode>::from_scancode(scancode)
} }
fn from_scancode(scancode: u32) -> PhysicalKey {
crate::platform_impl::scancode_to_physicalkey(scancode)
}
}
impl PhysicalKeyExtScancode for KeyCode {
#[inline] #[inline]
fn to_scancode(self) -> Option<u32> { fn to_scancode(self) -> Option<u32> {
<PhysicalKey as PhysicalKeyExtScancode>::to_scancode(PhysicalKey::Code(self)) <PhysicalKey as PhysicalKeyExtScancode>::to_scancode(PhysicalKey::Code(self))
} }
#[inline]
fn from_scancode(scancode: u32) -> PhysicalKey {
<PhysicalKey as PhysicalKeyExtScancode>::from_scancode(scancode)
}
} }

View File

@@ -4,8 +4,6 @@ use crate::{
window::{Window, WindowBuilder}, window::{Window, WindowBuilder},
}; };
use crate::platform_impl::{ApplicationName, Backend};
pub use crate::window::Theme; pub use crate::window::Theme;
/// Additional methods on [`EventLoopWindowTarget`] that are specific to Wayland. /// Additional methods on [`EventLoopWindowTarget`] that are specific to Wayland.
@@ -36,7 +34,7 @@ pub trait EventLoopBuilderExtWayland {
impl<T> EventLoopBuilderExtWayland for EventLoopBuilder<T> { impl<T> EventLoopBuilderExtWayland for EventLoopBuilder<T> {
#[inline] #[inline]
fn with_wayland(&mut self) -> &mut Self { fn with_wayland(&mut self) -> &mut Self {
self.platform_specific.forced_backend = Some(Backend::Wayland); self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::Wayland);
self self
} }
@@ -67,7 +65,10 @@ pub trait WindowBuilderExtWayland {
impl WindowBuilderExtWayland for WindowBuilder { impl WindowBuilderExtWayland for WindowBuilder {
#[inline] #[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self { fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(ApplicationName::new(general.into(), instance.into())); self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
general.into(),
instance.into(),
));
self self
} }
} }

View File

@@ -35,8 +35,13 @@ use crate::platform_impl::PlatformCustomCursorBuilder;
use crate::window::CustomCursor; use crate::window::CustomCursor;
use crate::window::{Window, WindowBuilder}; use crate::window::{Window, WindowBuilder};
#[cfg(wasm_platform)]
use web_sys::HtmlCanvasElement; use web_sys::HtmlCanvasElement;
#[cfg(not(wasm_platform))]
#[doc(hidden)]
pub struct HtmlCanvasElement;
pub trait WindowExtWebSys { pub trait WindowExtWebSys {
/// Only returns the canvas if called from inside the window context (the /// Only returns the canvas if called from inside the window context (the
/// main thread). /// main thread).
@@ -80,6 +85,11 @@ pub trait WindowBuilderExtWebSys {
/// In any case, the canvas won't be automatically inserted into the web page. /// In any case, the canvas won't be automatically inserted into the web page.
/// ///
/// [`None`] by default. /// [`None`] by default.
#[cfg_attr(
not(wasm_platform),
doc = "",
doc = "[`HtmlCanvasElement`]: #only-available-on-wasm"
)]
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self; fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
/// Sets whether `event.preventDefault()` should be called on events on the /// Sets whether `event.preventDefault()` should be called on events on the

View File

@@ -2,12 +2,9 @@ use std::{ffi::c_void, path::Path};
use crate::{ use crate::{
dpi::PhysicalSize, dpi::PhysicalSize,
event::{DeviceId, KeyEvent}, event::DeviceId,
event_loop::EventLoopBuilder, event_loop::EventLoopBuilder,
keyboard::Key,
monitor::MonitorHandle, monitor::MonitorHandle,
platform::modifier_supplement::KeyEventExtModifierSupplement,
platform_impl::WinIcon,
window::{BadIcon, Icon, Window, WindowBuilder}, window::{BadIcon, Icon, Window, WindowBuilder},
}; };
@@ -185,7 +182,14 @@ pub trait WindowBuilderExtWindows {
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look. /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
/// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect. /// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
/// ///
/// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu #[cfg_attr(
platform_windows,
doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu"
)]
#[cfg_attr(
not(platform_windows),
doc = "[`CreateMenu`]: #only-available-on-windows"
)]
fn with_menu(self, menu: HMENU) -> Self; fn with_menu(self, menu: HMENU) -> Self;
/// This sets `ICON_BIG`. A good ceiling here is 256x256. /// This sets `ICON_BIG`. A good ceiling here is 256x256.
@@ -328,27 +332,12 @@ impl IconExtWindows for Icon {
path: P, path: P,
size: Option<PhysicalSize<u32>>, size: Option<PhysicalSize<u32>>,
) -> Result<Self, BadIcon> { ) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_path(path, size)?; let win_icon = crate::platform_impl::WinIcon::from_path(path, size)?;
Ok(Icon { inner: win_icon }) Ok(Icon { inner: win_icon })
} }
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> { fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
let win_icon = WinIcon::from_resource(ordinal, size)?; let win_icon = crate::platform_impl::WinIcon::from_resource(ordinal, size)?;
Ok(Icon { inner: win_icon }) Ok(Icon { inner: win_icon })
} }
} }
impl KeyEventExtModifierSupplement for KeyEvent {
#[inline]
fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific
.text_with_all_modifers
.as_ref()
.map(|s| s.as_str())
}
#[inline]
fn key_without_modifiers(&self) -> Key {
self.platform_specific.key_without_modifiers.clone()
}
}

View File

@@ -1,3 +1,6 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{ use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget}, event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle, monitor::MonitorHandle,
@@ -5,9 +8,50 @@ use crate::{
}; };
use crate::dpi::Size; use crate::dpi::Size;
use crate::platform_impl::{ApplicationName, Backend, XLIB_ERROR_HOOKS};
pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported}; /// X window type. Maps directly to
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowType {
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
/// root window clicks.
Desktop,
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
Dock,
/// Toolbar windows. "Torn off" from the main application.
Toolbar,
/// Pinnable menu windows. "Torn off" from the main application.
Menu,
/// A small persistent utility window, such as a palette or toolbox.
Utility,
/// The window is a splash screen displayed as an application is starting up.
Splash,
/// This is a dialog window.
Dialog,
/// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
/// This property is typically used on override-redirect windows.
DropdownMenu,
/// A popup menu that usually appears when the user right clicks on an object.
/// This property is typically used on override-redirect windows.
PopupMenu,
/// A tooltip window. Usually used to show additional information when hovering over an object with the cursor.
/// This property is typically used on override-redirect windows.
Tooltip,
/// The window is a notification.
/// This property is typically used on override-redirect windows.
Notification,
/// This should be used on the windows that are popped up by combo boxes.
/// This property is typically used on override-redirect windows.
Combo,
/// This indicates the the window is being dragged.
/// This property is typically used on override-redirect windows.
Dnd,
/// This is a normal, top-level window.
#[default]
Normal,
}
/// The first argument in the provided hook will be the pointer to `XDisplay` /// The first argument in the provided hook will be the pointer to `XDisplay`
/// and the second one the pointer to [`XErrorEvent`]. The returned `bool` is an /// and the second one the pointer to [`XErrorEvent`]. The returned `bool` is an
@@ -38,7 +82,10 @@ pub type XWindow = u32;
pub fn register_xlib_error_hook(hook: XlibErrorHook) { pub fn register_xlib_error_hook(hook: XlibErrorHook) {
// Append new hook. // Append new hook.
unsafe { unsafe {
XLIB_ERROR_HOOKS.lock().unwrap().push(hook); crate::platform_impl::XLIB_ERROR_HOOKS
.lock()
.unwrap()
.push(hook);
} }
} }
@@ -70,7 +117,7 @@ pub trait EventLoopBuilderExtX11 {
impl<T> EventLoopBuilderExtX11 for EventLoopBuilder<T> { impl<T> EventLoopBuilderExtX11 for EventLoopBuilder<T> {
#[inline] #[inline]
fn with_x11(&mut self) -> &mut Self { fn with_x11(&mut self) -> &mut Self {
self.platform_specific.forced_backend = Some(Backend::X); self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
self self
} }
@@ -102,13 +149,13 @@ pub trait WindowBuilderExtX11 {
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self; fn with_name(self, general: impl Into<String>, instance: impl Into<String>) -> Self;
/// Build window with override-redirect flag; defaults to false. Only relevant on X11. /// Build window with override-redirect flag; defaults to false.
fn with_override_redirect(self, override_redirect: bool) -> Self; fn with_override_redirect(self, override_redirect: bool) -> Self;
/// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`. Only relevant on X11. /// Build window with `_NET_WM_WINDOW_TYPE` hints; defaults to `Normal`.
fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self; fn with_x11_window_type(self, x11_window_type: Vec<WindowType>) -> Self;
/// Build window with base size hint. Only implemented on X11. /// Build window with base size hint.
/// ///
/// ``` /// ```
/// # use winit::dpi::{LogicalSize, PhysicalSize}; /// # use winit::dpi::{LogicalSize, PhysicalSize};
@@ -155,7 +202,10 @@ impl WindowBuilderExtX11 for WindowBuilder {
#[inline] #[inline]
fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self { fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.platform_specific.name = Some(ApplicationName::new(general.into(), instance.into())); self.platform_specific.name = Some(crate::platform_impl::ApplicationName::new(
general.into(),
instance.into(),
));
self self
} }
@@ -166,7 +216,7 @@ impl WindowBuilderExtX11 for WindowBuilder {
} }
#[inline] #[inline]
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self { fn with_x11_window_type(mut self, x11_window_types: Vec<WindowType>) -> Self {
self.platform_specific.x11.x11_window_types = x11_window_types; self.platform_specific.x11.x11_window_types = x11_window_types;
self self
} }

View File

@@ -6,13 +6,13 @@ use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyC
/// ///
/// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses. /// X11-style keycodes are offset by 8 from the keycodes the Linux kernel uses.
pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey { pub fn raw_keycode_to_physicalkey(keycode: u32) -> PhysicalKey {
scancode_to_keycode(keycode.saturating_sub(8)) scancode_to_physicalkey(keycode.saturating_sub(8))
} }
/// Map the linux scancode to Keycode. /// Map the linux scancode to Keycode.
/// ///
/// Both X11 and Wayland use keys with `+ 8` offset to linux scancode. /// Both X11 and Wayland use keys with `+ 8` offset to linux scancode.
pub fn scancode_to_keycode(scancode: u32) -> PhysicalKey { pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// The keycode values are taken from linux/include/uapi/linux/input-event-codes.h, as // 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 // 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, // are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,

View File

@@ -398,8 +398,8 @@ impl KbdState {
let text_with_all_modifiers = event.text_with_all_modifiers(); let text_with_all_modifiers = event.text_with_all_modifiers();
let platform_specific = KeyEventExtra { let platform_specific = KeyEventExtra {
key_without_modifiers,
text_with_all_modifiers, text_with_all_modifiers,
key_without_modifiers,
}; };
KeyEvent { KeyEvent {

View File

@@ -15,41 +15,36 @@ use once_cell::sync::Lazy;
use smol_str::SmolStr; use smol_str::SmolStr;
#[cfg(x11_platform)] #[cfg(x11_platform)]
use crate::platform::x11::XlibErrorHook; use self::x11::{X11Error, XConnection, XError, XNotSupported};
#[cfg(x11_platform)]
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
use crate::{ use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size}, dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError}, error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
event::KeyEvent,
event_loop::{ event_loop::{
AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed, AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
EventLoopWindowTarget as RootELW, EventLoopWindowTarget as RootELW,
}, },
icon::Icon, icon::Icon,
keyboard::{Key, PhysicalKey}, keyboard::Key,
platform::{ platform::pump_events::PumpStatus,
modifier_supplement::KeyEventExtModifierSupplement, pump_events::PumpStatus,
scancode::PhysicalKeyExtScancode,
},
window::{ window::{
ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme,
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel, UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
}, },
}; };
#[cfg(x11_platform)]
pub use x11::XNotSupported;
#[cfg(x11_platform)]
use x11::{util::WindowType as XWindowType, X11Error, XConnection, XError};
pub(crate) use self::common::keymap::{physicalkey_to_scancode, scancode_to_physicalkey};
pub(crate) use crate::cursor::OnlyCursorImage as PlatformCustomCursor; pub(crate) use crate::cursor::OnlyCursorImage as PlatformCustomCursor;
pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder; pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
pub(crate) use crate::icon::RgbaIcon as PlatformIcon; pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
pub(crate) use crate::platform_impl::Fullscreen; pub(crate) use crate::platform_impl::Fullscreen;
pub mod common; pub(crate) mod common;
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
pub mod wayland; pub(crate) mod wayland;
#[cfg(x11_platform)] #[cfg(x11_platform)]
pub mod x11; pub(crate) mod x11;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum Backend { pub(crate) enum Backend {
@@ -640,33 +635,8 @@ impl Window {
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct KeyEventExtra { pub struct KeyEventExtra {
pub key_without_modifiers: Key,
pub text_with_all_modifiers: Option<SmolStr>, pub text_with_all_modifiers: Option<SmolStr>,
} pub key_without_modifiers: Key,
impl KeyEventExtModifierSupplement for KeyEvent {
#[inline]
fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific
.text_with_all_modifiers
.as_ref()
.map(|s| s.as_str())
}
#[inline]
fn key_without_modifiers(&self) -> Key {
self.platform_specific.key_without_modifiers.clone()
}
}
impl PhysicalKeyExtScancode for PhysicalKey {
fn from_scancode(scancode: u32) -> PhysicalKey {
common::keymap::scancode_to_keycode(scancode)
}
fn to_scancode(self) -> Option<u32> {
common::keymap::physicalkey_to_scancode(self)
}
} }
/// Hooks for X11 errors. /// Hooks for X11 errors.

View File

@@ -14,11 +14,9 @@ mod xdisplay;
pub(crate) use self::{ pub(crate) use self::{
monitor::{MonitorHandle, VideoModeHandle}, monitor::{MonitorHandle, VideoModeHandle},
window::UnownedWindow, window::UnownedWindow,
xdisplay::XConnection, xdisplay::{XConnection, XError, XNotSupported},
}; };
pub use self::xdisplay::{XError, XNotSupported};
use calloop::generic::Generic; use calloop::generic::Generic;
use calloop::EventLoop as Loop; use calloop::EventLoop as Loop;
use calloop::{ping::Ping, Readiness}; use calloop::{ping::Ping, Readiness};

View File

@@ -1,8 +1,6 @@
use crate::platform::x11::WindowType;
use std::sync::Arc; use std::sync::Arc;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::*; use super::*;
#[derive(Debug)] #[derive(Debug)]
@@ -23,50 +21,6 @@ impl From<bool> for StateOperation {
} }
} }
/// X window type. Maps directly to
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowType {
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
/// root window clicks.
Desktop,
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
Dock,
/// Toolbar windows. "Torn off" from the main application.
Toolbar,
/// Pinnable menu windows. "Torn off" from the main application.
Menu,
/// A small persistent utility window, such as a palette or toolbox.
Utility,
/// The window is a splash screen displayed as an application is starting up.
Splash,
/// This is a dialog window.
Dialog,
/// A dropdown menu that usually appears when the user clicks on an item in a menu bar.
/// This property is typically used on override-redirect windows.
DropdownMenu,
/// A popup menu that usually appears when the user right clicks on an object.
/// This property is typically used on override-redirect windows.
PopupMenu,
/// A tooltip window. Usually used to show additional information when hovering over an object with the cursor.
/// This property is typically used on override-redirect windows.
Tooltip,
/// The window is a notification.
/// This property is typically used on override-redirect windows.
Notification,
/// This should be used on the windows that are popped up by combo boxes.
/// This property is typically used on override-redirect windows.
Combo,
/// This indicates the the window is being dragged.
/// This property is typically used on override-redirect windows.
Dnd,
/// This is a normal, top-level window.
#[default]
Normal,
}
impl WindowType { impl WindowType {
pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> xproto::Atom { pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> xproto::Atom {
use self::WindowType::*; use self::WindowType::*;

View File

@@ -26,6 +26,7 @@ use crate::{
error::{ExternalError, NotSupportedError, OsError as RootOsError}, error::{ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, InnerSizeWriter, WindowEvent}, event::{Event, InnerSizeWriter, WindowEvent},
event_loop::AsyncRequestSerial, event_loop::AsyncRequestSerial,
platform::x11::WindowType,
platform_impl::{ platform_impl::{
x11::{ x11::{
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender,
@@ -635,10 +636,7 @@ impl UnownedWindow {
flusher.map(Some) flusher.map(Some)
} }
fn set_window_types( fn set_window_types(&self, window_types: Vec<WindowType>) -> Result<VoidCookie<'_>, X11Error> {
&self,
window_types: Vec<util::WindowType>,
) -> Result<VoidCookie<'_>, X11Error> {
let atoms = self.xconn.atoms(); let atoms = self.xconn.atoms();
let hint_atom = atoms[_NET_WM_WINDOW_TYPE]; let hint_atom = atoms[_NET_WM_WINDOW_TYPE];
let atoms: Vec<_> = window_types let atoms: Vec<_> = window_types

View File

@@ -260,7 +260,7 @@ impl fmt::Display for XError {
/// Error returned if this system doesn't have XLib or can't create an X connection. /// Error returned if this system doesn't have XLib or can't create an X connection.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum XNotSupported { pub(crate) enum XNotSupported {
/// Failed to load one or several shared libraries. /// Failed to load one or several shared libraries.
LibraryOpenError(ffi::OpenError), LibraryOpenError(ffi::OpenError),

View File

@@ -19,9 +19,6 @@ use crate::{
Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey, Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey,
NativeKeyCode, PhysicalKey, NativeKeyCode, PhysicalKey,
}, },
platform::{
modifier_supplement::KeyEventExtModifierSupplement, scancode::PhysicalKeyExtScancode,
},
platform_impl::platform::ffi, platform_impl::platform::ffi,
}; };
@@ -31,19 +28,6 @@ pub struct KeyEventExtra {
pub key_without_modifiers: Key, pub key_without_modifiers: Key,
} }
impl KeyEventExtModifierSupplement for KeyEvent {
fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific
.text_with_all_modifiers
.as_ref()
.map(|s| s.as_str())
}
fn key_without_modifiers(&self) -> Key {
self.platform_specific.key_without_modifiers.clone()
}
}
pub fn get_modifierless_char(scancode: u16) -> Key { pub fn get_modifierless_char(scancode: u16) -> Key {
let mut string = [0; 16]; let mut string = [0; 16];
let input_source; let input_source;
@@ -127,8 +111,7 @@ pub(crate) fn create_key_event(
let state = if is_press { Pressed } else { Released }; let state = if is_press { Pressed } else { Released };
let scancode = unsafe { ns_event.keyCode() }; let scancode = unsafe { ns_event.keyCode() };
let mut physical_key = let mut physical_key = key_override.unwrap_or_else(|| scancode_to_physicalkey(scancode as u32));
key_override.unwrap_or_else(|| PhysicalKey::from_scancode(scancode as u32));
let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() { let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() {
None None
@@ -189,8 +172,8 @@ pub(crate) fn create_key_event(
state, state,
text, text,
platform_specific: KeyEventExtra { platform_specific: KeyEventExtra {
key_without_modifiers,
text_with_all_modifiers, text_with_all_modifiers,
key_without_modifiers,
}, },
} }
} }
@@ -415,9 +398,8 @@ pub(super) fn dummy_event() -> Option<Id<NSEvent>> {
} }
} }
impl PhysicalKeyExtScancode for PhysicalKey { pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
fn to_scancode(self) -> Option<u32> { let code = match physical_key {
let code = match self {
PhysicalKey::Code(code) => code, PhysicalKey::Code(code) => code,
PhysicalKey::Unidentified(_) => return None, PhysicalKey::Unidentified(_) => return None,
}; };
@@ -538,7 +520,7 @@ impl PhysicalKeyExtScancode for PhysicalKey {
} }
} }
fn from_scancode(scancode: u32) -> PhysicalKey { pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
PhysicalKey::Code(match scancode { PhysicalKey::Code(match scancode {
0x00 => KeyCode::KeyA, 0x00 => KeyCode::KeyA,
0x01 => KeyCode::KeyS, 0x01 => KeyCode::KeyS,
@@ -679,4 +661,3 @@ impl PhysicalKeyExtScancode for PhysicalKey {
_ => return PhysicalKey::Unidentified(NativeKeyCode::MacOS(scancode as u16)), _ => return PhysicalKey::Unidentified(NativeKeyCode::MacOS(scancode as u16)),
}) })
} }
}

View File

@@ -18,7 +18,7 @@ mod window_delegate;
use std::fmt; use std::fmt;
pub(crate) use self::{ pub(crate) use self::{
event::KeyEventExtra, event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra},
event_loop::{ event_loop::{
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
}, },

View File

@@ -22,15 +22,15 @@ use objc2::{
use super::cursor::{default_cursor, invisible_cursor}; use super::cursor::{default_cursor, invisible_cursor};
use super::event::{code_to_key, code_to_location}; use super::event::{code_to_key, code_to_location};
use super::event::{lalt_pressed, ralt_pressed}; use super::event::{lalt_pressed, ralt_pressed};
use crate::platform_impl::scancode_to_physicalkey;
use crate::{ use crate::{
dpi::{LogicalPosition, LogicalSize}, dpi::{LogicalPosition, LogicalSize},
event::{ event::{
DeviceEvent, ElementState, Event, Ime, Modifiers, MouseButton, MouseScrollDelta, DeviceEvent, ElementState, Event, Ime, Modifiers, MouseButton, MouseScrollDelta,
TouchPhase, WindowEvent, TouchPhase, WindowEvent,
}, },
keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey, PhysicalKey}, keyboard::{Key, KeyCode, KeyLocation, ModifiersState, NamedKey},
platform::macos::{OptionAsAlt, WindowExtMacOS}, platform::macos::{OptionAsAlt, WindowExtMacOS},
platform::scancode::PhysicalKeyExtScancode,
platform_impl::platform::{ platform_impl::platform::{
app_state::AppState, app_state::AppState,
event::{create_key_event, event_mods}, event::{create_key_event, event_mods},
@@ -915,7 +915,7 @@ impl WinitView {
'send_event: { 'send_event: {
if is_flags_changed_event && unsafe { ns_event.keyCode() } != 0 { if is_flags_changed_event && unsafe { ns_event.keyCode() } != 0 {
let scancode = unsafe { ns_event.keyCode() }; let scancode = unsafe { ns_event.keyCode() };
let physical_key = PhysicalKey::from_scancode(scancode as u32); let physical_key = scancode_to_physicalkey(scancode as u32);
// We'll correct the `is_press` later. // We'll correct the `is_press` later.
let mut event = create_key_event(ns_event, false, false, Some(physical_key)); let mut event = create_key_event(ns_event, false, false, Some(physical_key));

View File

@@ -39,7 +39,6 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::{ use crate::{
event::{ElementState, KeyEvent}, event::{ElementState, KeyEvent},
keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey}, keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey},
platform::scancode::PhysicalKeyExtScancode,
platform_impl::platform::{ platform_impl::platform::{
event_loop::ProcResult, event_loop::ProcResult,
keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE}, keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE},
@@ -455,7 +454,7 @@ impl KeyEventBuilder {
return None; return None;
} }
let scancode = scancode as ExScancode; let scancode = scancode as ExScancode;
let physical_key = PhysicalKey::from_scancode(scancode as u32); let physical_key = scancode_to_physicalkey(scancode as u32);
let mods = if caps_lock_on { let mods = if caps_lock_on {
WindowsModifiers::CAPS_LOCK WindowsModifiers::CAPS_LOCK
} else { } else {
@@ -484,7 +483,7 @@ impl KeyEventBuilder {
let mut event = event_info.finalize(); let mut event = event_info.finalize();
event.logical_key = logical_key; event.logical_key = logical_key;
event.platform_specific.text_with_all_modifers = text; event.platform_specific.text_with_all_modifiers = text;
Some(MessageAsKeyEvent { Some(MessageAsKeyEvent {
event, event,
is_synthetic: true, is_synthetic: true,
@@ -545,7 +544,7 @@ impl PartialKeyEventInfo {
} else { } else {
new_ex_scancode(lparam_struct.scancode, lparam_struct.extended) new_ex_scancode(lparam_struct.scancode, lparam_struct.extended)
}; };
let physical_key = PhysicalKey::from_scancode(scancode as u32); let physical_key = scancode_to_physicalkey(scancode as u32);
let location = get_location(scancode, layout.hkl as HKL); let location = get_location(scancode, layout.hkl as HKL);
let kbd_state = get_kbd_state(); let kbd_state = get_kbd_state();
@@ -666,7 +665,7 @@ impl PartialKeyEventInfo {
state: self.key_state, state: self.key_state,
repeat: self.is_repeat, repeat: self.is_repeat,
platform_specific: KeyEventExtra { platform_specific: KeyEventExtra {
text_with_all_modifers: char_with_all_modifiers, text_with_all_modifiers: char_with_all_modifiers,
key_without_modifiers: self.key_without_modifiers, key_without_modifiers: self.key_without_modifiers,
}, },
} }
@@ -943,16 +942,15 @@ fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
} }
} }
impl PhysicalKeyExtScancode for PhysicalKey { pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
fn to_scancode(self) -> Option<u32> { // See `scancode_to_physicalkey` for more info
// See `from_scancode` for more info
let hkl = unsafe { GetKeyboardLayout(0) }; let hkl = unsafe { GetKeyboardLayout(0) };
let primary_lang_id = primarylangid(loword(hkl as u32)); let primary_lang_id = primarylangid(loword(hkl as u32));
let is_korean = primary_lang_id as u32 == LANG_KOREAN; let is_korean = primary_lang_id as u32 == LANG_KOREAN;
let code = match self { let code = match physical_key {
PhysicalKey::Code(code) => code, PhysicalKey::Code(code) => code,
PhysicalKey::Unidentified(code) => { PhysicalKey::Unidentified(code) => {
return match code { return match code {
@@ -1126,7 +1124,7 @@ impl PhysicalKeyExtScancode for PhysicalKey {
} }
} }
fn from_scancode(scancode: u32) -> PhysicalKey { pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html // See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
// and: https://www.w3.org/TR/uievents-code/ // and: https://www.w3.org/TR/uievents-code/
// and: The widget/NativeKeyToDOMCodeName.h file in the firefox source // and: The widget/NativeKeyToDOMCodeName.h file in the firefox source
@@ -1284,4 +1282,3 @@ impl PhysicalKeyExtScancode for PhysicalKey {
_ => return PhysicalKey::Unidentified(NativeKeyCode::Windows(scancode as u16)), _ => return PhysicalKey::Unidentified(NativeKeyCode::Windows(scancode as u16)),
}) })
} }
}

View File

@@ -53,8 +53,7 @@ use windows_sys::Win32::{
use crate::{ use crate::{
keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey}, keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey},
platform::scancode::PhysicalKeyExtScancode, platform_impl::{loword, primarylangid, scancode_to_physicalkey},
platform_impl::{loword, primarylangid},
}; };
pub(crate) static LAYOUT_CACHE: Lazy<Mutex<LayoutCache>> = pub(crate) static LAYOUT_CACHE: Lazy<Mutex<LayoutCache>> =
@@ -336,7 +335,7 @@ impl LayoutCache {
if scancode == 0 { if scancode == 0 {
continue; continue;
} }
let keycode = match PhysicalKey::from_scancode(scancode) { let keycode = match scancode_to_physicalkey(scancode) {
PhysicalKey::Code(code) => code, PhysicalKey::Code(code) => code,
// TODO: validate that we can skip on unidentified keys (probably never occurs?) // TODO: validate that we can skip on unidentified keys (probably never occurs?)
_ => continue, _ => continue,
@@ -388,7 +387,7 @@ impl LayoutCache {
} }
let native_code = NativeKey::Windows(vk as VIRTUAL_KEY); let native_code = NativeKey::Windows(vk as VIRTUAL_KEY);
let key_code = match PhysicalKey::from_scancode(scancode) { let key_code = match scancode_to_physicalkey(scancode) {
PhysicalKey::Code(code) => code, PhysicalKey::Code(code) => code,
// TODO: validate that we can skip on unidentified keys (probably never occurs?) // TODO: validate that we can skip on unidentified keys (probably never occurs?)
_ => continue, _ => continue,

View File

@@ -11,6 +11,7 @@ pub(crate) use self::{
EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes,
}, },
icon::{SelectedCursor, WinIcon}, icon::{SelectedCursor, WinIcon},
keyboard::{physicalkey_to_scancode, scancode_to_physicalkey},
monitor::{MonitorHandle, VideoModeHandle}, monitor::{MonitorHandle, VideoModeHandle},
window::Window, window::Window,
}; };
@@ -90,7 +91,7 @@ pub type OsError = std::io::Error;
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct KeyEventExtra { pub struct KeyEventExtra {
pub text_with_all_modifers: Option<SmolStr>, pub text_with_all_modifiers: Option<SmolStr>,
pub key_without_modifiers: Key, pub key_without_modifiers: Key,
} }

View File

@@ -27,11 +27,11 @@ use windows_sys::Win32::{
}, },
}; };
use super::scancode_to_physicalkey;
use crate::{ use crate::{
event::ElementState, event::ElementState,
event_loop::DeviceEvents, event_loop::DeviceEvents,
keyboard::{KeyCode, PhysicalKey}, keyboard::{KeyCode, PhysicalKey},
platform::scancode::PhysicalKeyExtScancode,
platform_impl::platform::util, platform_impl::platform::util,
}; };
@@ -284,7 +284,7 @@ pub fn get_keyboard_physical_key(keyboard: RAWKEYBOARD) -> Option<PhysicalKey> {
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503 // https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
PhysicalKey::Code(KeyCode::NumLock) PhysicalKey::Code(KeyCode::NumLock)
} else { } else {
PhysicalKey::from_scancode(scancode as u32) scancode_to_physicalkey(scancode as u32)
}; };
if keyboard.VKey == VK_SHIFT { if keyboard.VKey == VK_SHIFT {
if let PhysicalKey::Code(code) = physical_key { if let PhysicalKey::Code(code) = physical_key {