use smithay::backend::input::{Event, InputEvent, KeyboardKeyEvent}; use smithay::utils::SERIAL_COUNTER; use smithay::wayland::input_method::InputMethodSeat; use smithay::wayland::virtual_keyboard::{ VirtualKeyboardBackend, VirtualKeyboardHandler, VirtualKeyboardSpecialEvent, }; use crate::Ferese; impl VirtualKeyboardHandler for Ferese { fn process_virtual_keyboard_event(&mut self, event: InputEvent) { let keyboard = self.seat.get_keyboard().expect("seat has a keyboard"); if self.session_lock.active() { // Synthetic input never enters a lock surface. Still reconcile // keys from a departing/previously active auxiliary device. let device = match &event { InputEvent::Keyboard { event } => Some(event.device()), InputEvent::DeviceRemoved { device } => Some(device.clone()), _ => None, }; if let Some(device) = device { self.super_tap.cancel(); keyboard.release_source(self, device.source()); } return; } match event { InputEvent::DeviceAdded { device } | InputEvent::Special(VirtualKeyboardSpecialEvent::KeymapChanged { device }) => { if let Some(keymap) = device.keymap() { let current = keyboard.with_xkb_state(self, |context| { context.xkb().lock().unwrap().keymap_as_string() }); if current != *keymap && let Err(error) = keyboard.set_keymap_from_string(self, keymap.to_string()) { tracing::warn!(%error, "invalid virtual keyboard keymap"); } } } InputEvent::Keyboard { event } => { let device = event.device(); let grab_client = self.seat.input_method().keyboard_grab_client(); if grab_client.is_some() && grab_client == device.client() { // An IME forwards keys it did not consume. The physical path // already updated XKB and compositor shortcuts: forwarding // through that path again would recurse into the IME grab. keyboard.input_forward_bypassing_grab( self, event.key_code(), event.state(), SERIAL_COUNTER.next_serial(), event.time(), true, ); } else { self.process_input_event_from_source::( InputEvent::Keyboard { event }, device.source(), ); } } InputEvent::Special(VirtualKeyboardSpecialEvent::Modifiers { device, mods_depressed, mods_latched, mods_locked, group, }) => { let grab_client = self.seat.input_method().keyboard_grab_client(); if grab_client.is_some() && grab_client == device.client() { // The physical path already owns these modifiers. An // asynchronous IME echo must not restore an old mask after // the physical release has arrived. return; } keyboard.with_xkb_state(self, |mut context| { context.set_modifier_mask(mods_depressed, mods_latched, mods_locked, group) }); } InputEvent::DeviceRemoved { device } => { self.super_tap.cancel(); keyboard.release_source(self, device.source()); } _ => (), } } }