Skip to content

Commit 7496bb1

Browse files
committed
Add KeyboardHandle::advertise_modifier_state
1 parent 34feb6b commit 7496bb1

File tree

2 files changed

+60
-8
lines changed

2 files changed

+60
-8
lines changed

src/input/keyboard/mod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -938,12 +938,12 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
938938
///
939939
/// The `filter` argument is expected to be a closure which will peek at the generated input
940940
/// as interpreted by the keymap before it is forwarded to the focused client. If this closure
941-
/// returns [`FilterResult::Forward`], the input will not be sent to the client. If it returns
942-
/// [`FilterResult::Intercept`] a value can be passed to be returned by the whole function.
941+
/// returns [`FilterResult::Forward`], the input will be sent to the client. If it returns
942+
/// [`FilterResult::Intercept`], a value can be passed to be returned by the whole function.
943943
/// This mechanism can be used to implement compositor-level key bindings for example.
944944
///
945-
/// The module [`keysyms`] exposes definitions of all possible keysyms
946-
/// to be compared against. This includes non-character keysyms, such as XF86 special keys.
945+
/// The module [`keysyms`] exposes definitions of all possible keysyms to be compared against.
946+
/// This includes non-character keysyms, such as XF86 special keys.
947947
#[instrument(level = "trace", parent = &self.arc.span, skip(self, data, filter))]
948948
pub fn input<T, F>(
949949
&self,
@@ -1090,6 +1090,9 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
10901090
}
10911091

10921092
/// Set the modifiers state.
1093+
///
1094+
/// Note that the round-trip from XKB state to serialized form and back to XKB state is lossy,
1095+
/// as documented in [`xkb::State::update_mask`].
10931096
pub fn set_modifier_state(&self, mods_state: ModifiersState) -> u32 {
10941097
let internal = &mut self.arc.internal.lock().unwrap();
10951098

@@ -1129,6 +1132,18 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
11291132
modifiers_changed
11301133
}
11311134

1135+
/// Advertises changed modifier state using [`KeyboardTarget::modifiers`].
1136+
///
1137+
/// Use this with [`KeyboardHandle::set_modifier_state`] when necessary.
1138+
pub fn advertise_modifier_state(&self, data: &mut D) {
1139+
let internal = &mut *self.arc.internal.lock().unwrap();
1140+
1141+
if let Some((focus, _)) = internal.focus.as_mut() {
1142+
let seat = self.get_seat(data);
1143+
focus.modifiers(&seat, data, internal.mods_state, SERIAL_COUNTER.next_serial());
1144+
};
1145+
}
1146+
11321147
/// Get the current led state
11331148
pub fn led_state(&self) -> LedState {
11341149
self.arc.internal.lock().unwrap().led_state

src/input/keyboard/modifiers_state.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ use xkbcommon::xkb;
44
///
55
/// Each field of this struct represents a modifier and is `true` if this modifier is active.
66
///
7-
/// For some modifiers, this means that the key is currently pressed, others are toggled
7+
/// For some modifiers, this means that the key is currently pressed, others are toggled/locked
88
/// (like caps lock).
9+
///
10+
/// **Note:** The XKB state should usually be the single source of truth, and the
11+
/// serialization is lossy and will not survive round trips. This is documented in
12+
/// [`xkb::State::update_mask`].
913
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
1014
pub struct ModifiersState {
1115
/// The "control" key
@@ -30,12 +34,19 @@ pub struct ModifiersState {
3034
/// The "ISO level 5 shift" key
3135
pub iso_level5_shift: bool,
3236

33-
/// Serialized modifier state, as send e.g. by the wl_keyboard protocol
37+
/// Cached serialized modifier state, e.g. for sending in `wl_keyboard.modifiers`.
38+
///
39+
/// Note that this may have outdated information compared to the other fields, and that
40+
/// this is not updated in [`ModifiersState::serialize_back`].
3441
pub serialized: SerializedMods,
3542
}
3643

3744
impl ModifiersState {
38-
/// Update the modifiers state from an xkb state
45+
/// Updates the high-level modifiers state from an XKB state.
46+
///
47+
/// **Note:** The XKB state should usually be the single source of truth, and the
48+
/// serialization is lossy and will not survive round trips. This is documented in
49+
/// [`xkb::State::update_mask`].
3950
pub fn update_with(&mut self, state: &xkb::State) {
4051
self.ctrl = state.mod_name_is_active(&xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
4152
self.alt = state.mod_name_is_active(&xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
@@ -49,7 +60,33 @@ impl ModifiersState {
4960
self.serialized = serialize_modifiers(state);
5061
}
5162

52-
/// Serialize modifier state back to be sent to xkb.
63+
/// Serializes the high-level modifiers state to be sent to XKB e.g. in
64+
/// `wl_keyboard.modifiers`.
65+
///
66+
/// **Note:** The XKB state should usually be the single source of truth, and the
67+
/// serialization is lossy and will not survive round trips. This is documented in
68+
/// [`xkb::State::update_mask`].
69+
///
70+
/// Note that cached serialized state is stored in [`ModifiersState::serialized`], but it may
71+
/// have outdated information. This function ignores that field. You should update the cached
72+
/// serialized state after using this function, like so:
73+
///
74+
/// ```no_run
75+
/// use smithay::input::keyboard::ModifiersState;
76+
///
77+
/// let mut mods_state: ModifiersState;
78+
/// # mods_state = todo!();
79+
/// # let xkb_state = todo!();
80+
///
81+
/// // Update the information
82+
/// mods_state.ctrl = true;
83+
///
84+
/// // Serialize e.g. for sending in `wl_keyboard.modifiers`
85+
/// let serialized = mods_state.serialize_back(&xkb_state);
86+
///
87+
/// // Update the cached serialized state
88+
/// mods_state.serialized = serialized;
89+
/// ```
5390
pub fn serialize_back(&self, state: &xkb::State) -> SerializedMods {
5491
let keymap = state.get_keymap();
5592

0 commit comments

Comments
 (0)