From a204197e6d01913f9b97db3c2ed5f31e43dbf76e Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 5 Mar 2024 21:31:33 -0800 Subject: [PATCH] Set keyboard LEDs (capslock, numlock, scrollock) It doesn't seem there's currently a way to iterate over input devices, so this adds a `Vec` of libinput keyboard devices. When run with the kms backend. Not the most elegant solution, but it doesn't seem practical to add a type generic to `Devices` given how backends are handled, and `Device` can't be made into a trait object. Another trait could be added, but this is fine, and technically should perform better (but if it actually had to iterate over many keyboards, something has gone very wrong). --- src/input/mod.rs | 35 +++++++++++++++++++++++++++++------ src/wayland/handlers/seat.rs | 9 ++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 3ea64652..593d5603 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -33,7 +33,7 @@ use smithay::{ }, desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType}, input::{ - keyboard::{FilterResult, KeysymHandle, XkbConfig}, + keyboard::{FilterResult, KeysymHandle, LedState, XkbConfig}, pointer::{ AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, @@ -76,7 +76,11 @@ pub struct SupressedKeys(RefCell)>>); #[derive(Default, Debug)] pub struct ModifiersShortcutQueue(RefCell>); #[derive(Default)] -pub struct Devices(RefCell>>); +pub struct Devices { + capabilities: RefCell>>, + // Used for updating keyboard leds on kms backend + keyboards: RefCell>, +} impl Default for SeatId { fn default() -> SeatId { @@ -138,9 +142,9 @@ impl ModifiersShortcutQueue { } impl Devices { - fn add_device(&self, device: &D) -> Vec { + fn add_device(&self, device: &D) -> Vec { let id = device.id(); - let mut map = self.0.borrow_mut(); + let mut map = self.capabilities.borrow_mut(); let caps = [ DeviceCapability::Keyboard, DeviceCapability::Pointer, @@ -156,22 +160,41 @@ impl Devices { .filter(|c| map.values().flatten().all(|has| *c != *has)) .collect::>(); map.insert(id, caps); + + if device.has_capability(DeviceCapability::Keyboard) { + if let Some(device) = ::downcast_ref::(device) { + self.keyboards.borrow_mut().push(device.clone()); + } + } + new_caps } pub fn has_device(&self, device: &D) -> bool { - self.0.borrow().contains_key(&device.id()) + self.capabilities.borrow().contains_key(&device.id()) } fn remove_device(&self, device: &D) -> Vec { let id = device.id(); - let mut map = self.0.borrow_mut(); + + let mut keyboards = self.keyboards.borrow_mut(); + if let Some(idx) = keyboards.iter().position(|x| x.id() == id) { + keyboards.remove(idx); + } + + let mut map = self.capabilities.borrow_mut(); map.remove(&id) .unwrap_or(Vec::new()) .into_iter() .filter(|c| map.values().flatten().all(|has| *c != *has)) .collect() } + + pub fn update_led_state(&self, led_state: LedState) { + for keyboard in self.keyboards.borrow_mut().iter_mut() { + keyboard.led_update(led_state.into()); + } + } } pub fn add_seat( diff --git a/src/wayland/handlers/seat.rs b/src/wayland/handlers/seat.rs index 929c92cb..6ef87138 100644 --- a/src/wayland/handlers/seat.rs +++ b/src/wayland/handlers/seat.rs @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ + input::Devices, shell::focus::target::{KeyboardFocusTarget, PointerFocusTarget}, state::State, }; use smithay::{ delegate_seat, - input::{pointer::CursorImageStatus, SeatHandler, SeatState}, + input::{keyboard::LedState, pointer::CursorImageStatus, SeatHandler, SeatState}, reexports::wayland_server::Resource, wayland::{ seat::WaylandFocus, selection::data_device::set_data_device_focus, @@ -49,6 +50,12 @@ impl SeatHandler for State { set_primary_focus(dh, seat, Some(client)) } } + + fn led_state_changed(&mut self, seat: &smithay::input::Seat, led_state: LedState) { + let userdata = seat.user_data(); + let devices = userdata.get::().unwrap(); + devices.update_led_state(led_state); + } } delegate_seat!(State);