🔒 Repository is read-only – file editing is disabled.
PaganDE/smithay-0.7.0/src/wayland/virtual_keyboard/virtual_keyboard_handle.rs main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
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<VirtualKeyboardState>,
}
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<Mutex<VirtualKeyboard>>,
}
/// User data of ZwpVirtualKeyboardV1 object
pub struct VirtualKeyboardUserData<D: SeatHandler> {
pub(super) handle: VirtualKeyboardHandle,
pub(crate) seat: Seat<D>,
}
impl<D: SeatHandler> fmt::Debug for VirtualKeyboardUserData<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VirtualKeyboardUserData")
.field("handle", &self.handle)
.field("seat", &self.seat.arc)
.finish()
}
}
impl<D> Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>, D> for VirtualKeyboardManagerState
where
D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
D: SeatHandler + 'static,
<D as SeatHandler>::KeyboardFocus: WaylandFocus,
{
fn request(
user_data: &mut D,
_client: &Client,
virtual_keyboard: &ZwpVirtualKeyboardV1,
request: zwp_virtual_keyboard_v1::Request,
data: &VirtualKeyboardUserData<D>,
_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<D>,
) {
}
}
/// Handle the zwp_virtual_keyboard_v1::keymap request.
///
/// The `true` returns when keymap was properly loaded.
fn update_keymap<D>(data: &VirtualKeyboardUserData<D>, 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),
});
}