protocols/keyboard-layout: Send ei modifiers on group change

This makes `cosmic-osk` show a group change on `super+space`. Previously
a change like that wouldn't be sent until a keyboard input changed the
modifier state, for instance releasing the shift key.
This commit is contained in:
Ian Douglas Scott 2026-09-02 12:49:01 -07:00 • committed by Victoria Brekenfeld
parent 0d75928579
commit 8ec1ffb740
5 changed files with 19 additions and 11 deletions

View file

@ -842,7 +842,9 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
} }
if !state.common.ei_seats.is_empty() { if !state.common.ei_seats.is_empty() {
let seat = state.common.shell.read().seats.last_active().clone(); let seat = state.common.shell.read().seats.last_active().clone();
state.broadcast_ei_keyboard_modifiers(&seat); if let Some(keyboard) = seat.get_keyboard() {
state.broadcast_ei_keyboard_modifiers(&keyboard);
}
} }
state.common.config.cosmic_conf.xkb_config = value; state.common.config.cosmic_conf.xkb_config = value;
} }

View file

@ -49,6 +49,7 @@ use smithay::{
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
input::{ input::{
Seat, Seat,
keyboard::KeyboardHandle,
keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState}, keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState},
pointer::{ pointer::{
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
@ -1907,13 +1908,7 @@ impl State {
/// Mirror the seat's current modifier state to every libei sender with a keyboard via /// Mirror the seat's current modifier state to every libei sender with a keyboard via
/// `ei_keyboard.modifiers` /// `ei_keyboard.modifiers`
pub(crate) fn broadcast_ei_keyboard_modifiers(&self, seat: &Seat<State>) { pub(crate) fn broadcast_ei_keyboard_modifiers(&self, keyboard: &KeyboardHandle<State>) {
if self.common.ei_seats.is_empty() {
return;
}
let Some(keyboard) = seat.get_keyboard() else {
return;
};
let s = keyboard.modifier_state().serialized; let s = keyboard.modifier_state().serialized;
for ei_seat in self.common.ei_seats.values() { for ei_seat in self.common.ei_seats.values() {
ei_seat.keyboard_modifiers(s.depressed, s.locked, s.latched, s.layout_effective); ei_seat.keyboard_modifiers(s.depressed, s.locked, s.latched, s.layout_effective);
@ -1958,7 +1953,7 @@ impl State {
) -> FilterResult<Option<(Action, shortcuts::Binding)>> { ) -> FilterResult<Option<(Action, shortcuts::Binding)>> {
if previous_modifiers != *modifiers { if previous_modifiers != *modifiers {
seat.set_last_modifier_change(backend_id, serial); seat.set_last_modifier_change(backend_id, serial);
self.broadcast_ei_keyboard_modifiers(seat); self.broadcast_ei_keyboard_modifiers(&seat.get_keyboard().unwrap());
} }
let current_focus = seat.get_keyboard().unwrap().current_focus(); let current_focus = seat.get_keyboard().unwrap().current_focus();

View file

@ -124,7 +124,9 @@ pub fn setup_ei(
data.update_ei_input_method(); data.update_ei_input_method();
// Notify the remaining libei clients of the now-cleared modifier state // Notify the remaining libei clients of the now-cleared modifier state
let seat = data.common.shell.read().seats.last_active().clone(); let seat = data.common.shell.read().seats.last_active().clone();
data.broadcast_ei_keyboard_modifiers(&seat); if let Some(keyboard) = seat.get_keyboard() {
data.broadcast_ei_keyboard_modifiers(&keyboard);
}
} }
EiInputEvent::Event(event) => { EiInputEvent::Event(event) => {
use smithay::backend::input::{InputEvent, KeyboardKeyEvent}; use smithay::backend::input::{InputEvent, KeyboardKeyEvent};

View file

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use smithay::input::keyboard::KeyboardHandle;
use crate::state::State; use crate::state::State;
use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState}; use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState};
@ -7,4 +9,8 @@ impl KeyboardLayoutHandler for State {
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState { fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState {
&mut self.common.keyboard_layout_state &mut self.common.keyboard_layout_state
} }
fn group_changed(&mut self, keyboard: &KeyboardHandle<Self>) {
self.broadcast_ei_keyboard_modifiers(keyboard);
}
} }

View file

@ -17,8 +17,10 @@ use smithay::{
use std::mem; use std::mem;
use wayland_backend::server::{ClientId, GlobalId}; use wayland_backend::server::{ClientId, GlobalId};
pub trait KeyboardLayoutHandler { pub trait KeyboardLayoutHandler: SeatHandler {
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState; fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState;
/// Group has been changed through the protocol
fn group_changed(&mut self, keyboard: &KeyboardHandle<Self>);
} }
#[derive(Debug)] #[derive(Debug)]
@ -57,6 +59,7 @@ impl KeyboardLayoutState {
let active_layout = handle.with_xkb_state(state, |context| { let active_layout = handle.with_xkb_state(state, |context| {
context.xkb().lock().unwrap().active_layout() context.xkb().lock().unwrap().active_layout()
}); });
state.group_changed(handle);
if *last_layout != Some(active_layout) { if *last_layout != Some(active_layout) {
keyboard_layout.group(active_layout.0); keyboard_layout.group(active_layout.0);
*last_layout = Some(active_layout); *last_layout = Some(active_layout);