winit-core/keyboard: clarify modifier docs

Emphasize the difference between logical and physical state, reference sticky mods.
This commit is contained in:
Evgeny 2025-05-21 15:40:28 +07:00 committed by GitHub
parent 5190472bee
commit 38fd3c6a99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 20 deletions

View file

@ -153,12 +153,13 @@ impl Drop for XkbState {
} }
} }
/// Represents the current state of the keyboard modifiers /// Represents the current logical state of the keyboard modifiers
/// ///
/// Each field of this struct represents a modifier and is `true` if this modifier is active. /// Each field of this struct represents a modifier and is `true` if this modifier is active.
/// ///
/// For some modifiers, this means that the key is currently pressed, others are toggled /// For some modifiers, this means that the key is logically pressed, others are toggled (like Caps
/// (like caps lock). /// Lock). But physically the key can be in any state (for example, released Shift when
/// it's active as a sticky modifier or released Caps Lock when it's toggled on)
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct ModifiersState { pub struct ModifiersState {
/// The "control" key /// The "control" key

View file

@ -808,7 +808,7 @@ pub struct KeyEvent {
pub struct Modifiers { pub struct Modifiers {
pub(crate) state: ModifiersState, pub(crate) state: ModifiersState,
// NOTE: Currently pressed modifiers keys. // NOTE: Currently active modifiers keys (logically, but not necessarily physically, pressed).
// //
// The field providing a metadata, it shouldn't be used as a source of truth. // The field providing a metadata, it shouldn't be used as a source of truth.
pub(crate) pressed_mods: ModifiersKeys, pub(crate) pressed_mods: ModifiersKeys,
@ -820,47 +820,47 @@ impl Modifiers {
Self { state, pressed_mods } Self { state, pressed_mods }
} }
/// The state of the modifiers. /// The logical state of the modifiers.
pub fn state(&self) -> ModifiersState { pub fn state(&self) -> ModifiersState {
self.state self.state
} }
/// The state of the left shift key. /// The logical state of the left shift key.
pub fn lshift_state(&self) -> ModifiersKeyState { pub fn lshift_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::LSHIFT) self.mod_state(ModifiersKeys::LSHIFT)
} }
/// The state of the right shift key. /// The logical state of the right shift key.
pub fn rshift_state(&self) -> ModifiersKeyState { pub fn rshift_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::RSHIFT) self.mod_state(ModifiersKeys::RSHIFT)
} }
/// The state of the left alt key. /// The logical state of the left alt key.
pub fn lalt_state(&self) -> ModifiersKeyState { pub fn lalt_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::LALT) self.mod_state(ModifiersKeys::LALT)
} }
/// The state of the right alt key. /// The logical state of the right alt key.
pub fn ralt_state(&self) -> ModifiersKeyState { pub fn ralt_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::RALT) self.mod_state(ModifiersKeys::RALT)
} }
/// The state of the left control key. /// The logical state of the left control key.
pub fn lcontrol_state(&self) -> ModifiersKeyState { pub fn lcontrol_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::LCONTROL) self.mod_state(ModifiersKeys::LCONTROL)
} }
/// The state of the right control key. /// The logical state of the right control key.
pub fn rcontrol_state(&self) -> ModifiersKeyState { pub fn rcontrol_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::RCONTROL) self.mod_state(ModifiersKeys::RCONTROL)
} }
/// The state of the left super key. /// The logical state of the left super key.
pub fn lsuper_state(&self) -> ModifiersKeyState { pub fn lsuper_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::LMETA) self.mod_state(ModifiersKeys::LMETA)
} }
/// The state of the right super key. /// The logical state of the right super key.
pub fn rsuper_state(&self) -> ModifiersKeyState { pub fn rsuper_state(&self) -> ModifiersKeyState {
self.mod_state(ModifiersKeys::RMETA) self.mod_state(ModifiersKeys::RMETA)
} }

View file

@ -1687,9 +1687,12 @@ pub enum KeyLocation {
} }
bitflags! { bitflags! {
/// Represents the current state of the keyboard modifiers /// Represents the current logical state of the keyboard modifiers
/// ///
/// Each flag represents a modifier and is set if this modifier is active. /// Each flag represents a modifier and is set if this modifier is active.
///
/// Note that the modifier key can be physically released with the modifier
/// still being marked as active, as in the case of sticky modifiers.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ModifiersState: u32 { pub struct ModifiersState: u32 {
@ -1707,34 +1710,39 @@ bitflags! {
} }
impl ModifiersState { impl ModifiersState {
/// Returns `true` if the shift key is pressed. /// Returns whether the shift modifier is active.
pub fn shift_key(&self) -> bool { pub fn shift_key(&self) -> bool {
self.intersects(Self::SHIFT) self.intersects(Self::SHIFT)
} }
/// Returns `true` if the control key is pressed. /// Returns whether the control modifier is active.
pub fn control_key(&self) -> bool { pub fn control_key(&self) -> bool {
self.intersects(Self::CONTROL) self.intersects(Self::CONTROL)
} }
/// Returns `true` if the alt key is pressed. /// Returns whether the alt modifier is active.
pub fn alt_key(&self) -> bool { pub fn alt_key(&self) -> bool {
self.intersects(Self::ALT) self.intersects(Self::ALT)
} }
/// Returns `true` if the meta key is pressed. /// Returns whether the meta modifier is active.
pub fn meta_key(&self) -> bool { pub fn meta_key(&self) -> bool {
self.intersects(Self::META) self.intersects(Self::META)
} }
} }
/// The state of the particular modifiers key. /// The logical state of the particular modifiers key.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModifiersKeyState { pub enum ModifiersKeyState {
/// The particular key is pressed. /// The particular modifier is active or logically, but not necessarily physically, pressed.
Pressed, Pressed,
/// The state of the key is unknown. /// The state of the key is unknown.
///
/// Can include cases when the key is active or logically pressed, for example, when a sticky
/// **Shift** is active, the OS might not preserve information that it was activated by
/// RightShift, so the state of [`ModifiersKeys::RSHIFT`] will be unknown while the state
/// of [`ModifiersState::SHIFT`] will be active.
#[default] #[default]
Unknown, Unknown,
} }