use std::os::unix::io::OwnedFd; use std::{ fmt, sync::{Arc, Mutex}, }; use tracing::debug; use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::Error::NoKeymap; use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::{ self, ZwpVirtualKeyboardV1, }; use wayland_server::{ backend::ClientId, protocol::wl_keyboard::{KeyState, KeymapFormat}, Client, DataInit, Dispatch, DisplayHandle, Resource, }; use xkbcommon::xkb; use crate::input::keyboard::{KeyboardTarget, KeymapFile, ModifiersState}; use crate::{ input::{Seat, SeatHandler}, utils::SERIAL_COUNTER, wayland::seat::{keyboard::for_each_focused_kbds, WaylandFocus}, }; use super::VirtualKeyboardManagerState; #[derive(Debug, Default)] pub(crate) struct VirtualKeyboard { state: Option, } struct VirtualKeyboardState { keymap: KeymapFile, mods: ModifiersState, state: xkb::State, } impl fmt::Debug for VirtualKeyboardState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VirtualKeyboardState") .field("keymap", &self.keymap) .field("mods", &self.mods) .field("state", &self.state.get_raw_ptr()) .finish() } } // This is OK because all parts of `xkb` will remain on the // same thread unsafe impl Send for VirtualKeyboard {} /// Handle to a virtual keyboard instance #[derive(Debug, Clone, Default)] pub(crate) struct VirtualKeyboardHandle { pub(crate) inner: Arc>, } /// User data of ZwpVirtualKeyboardV1 object pub struct VirtualKeyboardUserData { pub(super) handle: VirtualKeyboardHandle, pub(crate) seat: Seat, } impl fmt::Debug for VirtualKeyboardUserData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VirtualKeyboardUserData") .field("handle", &self.handle) .field("seat", &self.seat.arc) .finish() } } impl Dispatch, D> for VirtualKeyboardManagerState where D: Dispatch>, D: SeatHandler + 'static, ::KeyboardFocus: WaylandFocus, { fn request( user_data: &mut D, _client: &Client, virtual_keyboard: &ZwpVirtualKeyboardV1, request: zwp_virtual_keyboard_v1::Request, data: &VirtualKeyboardUserData, _dh: &DisplayHandle, _data_init: &mut DataInit<'_, D>, ) { match request { zwp_virtual_keyboard_v1::Request::Keymap { format, fd, size } => { update_keymap(data, format, fd, size as usize); } zwp_virtual_keyboard_v1::Request::Key { time, key, state } => { // Ensure keymap was initialized. let mut virtual_data = data.handle.inner.lock().unwrap(); let vk_state = match virtual_data.state.as_mut() { Some(vk_state) => vk_state, None => { virtual_keyboard.post_error(NoKeymap, "`key` sent before keymap."); return; } }; // Ensure virtual keyboard's keymap is active. let keyboard_handle = data.seat.get_keyboard().unwrap(); let mut internal = keyboard_handle.arc.internal.lock().unwrap(); let focus = internal.focus.as_mut().map(|(focus, _)| focus); keyboard_handle.send_keymap(user_data, &focus, &vk_state.keymap, vk_state.mods); if let Some(wl_surface) = focus.and_then(|f| f.wl_surface()) { for_each_focused_kbds(&data.seat, &wl_surface, |kbd| { // This should be wl_keyboard::KeyState, but the protocol does not state // the parameter is an enum. let key_state = if state == 1 { KeyState::Pressed } else { KeyState::Released }; kbd.key(SERIAL_COUNTER.next_serial().0, time, key, key_state); }); } } zwp_virtual_keyboard_v1::Request::Modifiers { mods_depressed, mods_latched, mods_locked, group, } => { // Ensure keymap was initialized. let mut virtual_data = data.handle.inner.lock().unwrap(); let state = match virtual_data.state.as_mut() { Some(state) => state, None => { virtual_keyboard.post_error(NoKeymap, "`modifiers` sent before keymap."); return; } }; // Update virtual keyboard's modifier state. state .state .update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group); state.mods.update_with(&state.state); // Ensure virtual keyboard's keymap is active. let keyboard_handle = data.seat.get_keyboard().unwrap(); let mut internal = keyboard_handle.arc.internal.lock().unwrap(); let focus = internal.focus.as_mut().map(|(focus, _)| focus); let keymap_changed = keyboard_handle.send_keymap(user_data, &focus, &state.keymap, state.mods); // Report modifiers change to all keyboards. if !keymap_changed { if let Some(focus) = focus { focus.modifiers(&data.seat, user_data, state.mods, SERIAL_COUNTER.next_serial()); } } } zwp_virtual_keyboard_v1::Request::Destroy => { // Nothing to do } _ => unreachable!(), } } fn destroyed( _state: &mut D, _client: ClientId, _virtual_keyboard: &ZwpVirtualKeyboardV1, _data: &VirtualKeyboardUserData, ) { } } /// Handle the zwp_virtual_keyboard_v1::keymap request. /// /// The `true` returns when keymap was properly loaded. fn update_keymap(data: &VirtualKeyboardUserData, format: u32, fd: OwnedFd, size: usize) where D: SeatHandler + 'static, { // Only libxkbcommon compatible keymaps are supported. if format != KeymapFormat::XkbV1 as u32 { debug!("Unsupported keymap format: {format:?}"); return; } let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); // SAFETY: we can map the keymap into the memory. let new_keymap = match unsafe { xkb::Keymap::new_from_fd( &context, fd, size, xkb::KEYMAP_FORMAT_TEXT_V1, xkb::KEYMAP_COMPILE_NO_FLAGS, ) } { Ok(Some(new_keymap)) => new_keymap, Ok(None) => { debug!("Invalid libxkbcommon keymap"); return; } Err(err) => { debug!("Could not map the keymap: {err:?}"); return; } }; // Store active virtual keyboard map. let mut inner = data.handle.inner.lock().unwrap(); let mods = inner.state.take().map(|state| state.mods).unwrap_or_default(); inner.state = Some(VirtualKeyboardState { mods, keymap: KeymapFile::new(&new_keymap), state: xkb::State::new(&new_keymap), }); }