smithay/wayland/virtual_keyboard/
mod.rs

1//! Utilities for virtual keyboard support
2//!
3//! This module provides you with utilities to handle virtual keyboard instances.
4//! It can be used standalone to implement virtual keyboards or together with
5//! an input method to pass through keys from the keyboard.
6//!
7//! ```
8//! use smithay::{
9//!     delegate_seat, delegate_virtual_keyboard_manager,
10//! #   delegate_compositor
11//! };
12//! use smithay::input::{Seat, SeatState, SeatHandler, pointer::CursorImageStatus};
13//! # use smithay::wayland::compositor::{CompositorHandler, CompositorState, CompositorClientState};
14//! use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState;
15//! use smithay::reexports::wayland_server::{Display, protocol::wl_surface::WlSurface};
16//! # use smithay::reexports::wayland_server::Client;
17//!
18//! # struct State { seat_state: SeatState<Self> };
19//!
20//! delegate_seat!(State);
21//! // Delegate virtual keyboard handling for State to VirtualKeyboardManagerState.
22//! delegate_virtual_keyboard_manager!(State);
23//!
24//! # let mut display = Display::<State>::new().unwrap();
25//! # let display_handle = display.handle();
26//!
27//! let seat_state = SeatState::<State>::new();
28//!
29//! // implement the required traits
30//! impl SeatHandler for State {
31//!     type KeyboardFocus = WlSurface;
32//!     type PointerFocus = WlSurface;
33//!     type TouchFocus = WlSurface;
34//!     fn seat_state(&mut self) -> &mut SeatState<Self> {
35//!         &mut self.seat_state
36//!     }
37//!     fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) { unimplemented!() }
38//!     fn cursor_image(&mut self, seat: &Seat<Self>, image: CursorImageStatus) { unimplemented!() }
39//! }
40//!
41//! // Add the seat state to your state, create manager global and add client filter
42//! // to avoid untrusted clients requesting a new keyboard
43//! VirtualKeyboardManagerState::new::<State, _>(&display_handle, |_client| true);
44//!
45//! # impl CompositorHandler for State {
46//! #     fn compositor_state(&mut self) -> &mut CompositorState { unimplemented!() }
47//! #     fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { unimplemented!() }
48//! #     fn commit(&mut self, surface: &WlSurface) {}
49//! # }
50//! # delegate_compositor!(State);
51//! ```
52//!
53
54use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::{
55    zwp_virtual_keyboard_manager_v1::{self, ZwpVirtualKeyboardManagerV1},
56    zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
57};
58use wayland_server::{backend::GlobalId, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New};
59
60use crate::input::{Seat, SeatHandler};
61
62use self::virtual_keyboard_handle::VirtualKeyboardHandle;
63
64const MANAGER_VERSION: u32 = 1;
65
66mod virtual_keyboard_handle;
67
68pub use virtual_keyboard_handle::VirtualKeyboardUserData;
69
70/// State of wp misc virtual keyboard protocol
71#[derive(Debug)]
72pub struct VirtualKeyboardManagerState {
73    global: GlobalId,
74}
75
76/// Data associated with a VirtualKeyboardManager global.
77#[allow(missing_debug_implementations)]
78pub struct VirtualKeyboardManagerGlobalData {
79    filter: Box<dyn for<'c> Fn(&'c Client) -> bool + Send + Sync>,
80}
81
82fn create_global_with_filter<D, F>(display: &DisplayHandle, filter: F) -> GlobalId
83where
84    D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData> + 'static,
85    F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
86{
87    let data = VirtualKeyboardManagerGlobalData {
88        filter: Box::new(filter),
89    };
90
91    display.create_global::<D, ZwpVirtualKeyboardManagerV1, _>(MANAGER_VERSION, data)
92}
93
94impl VirtualKeyboardManagerState {
95    /// Initialize a virtual keyboard manager global.
96    pub fn new<D, F>(display: &DisplayHandle, filter: F) -> Self
97    where
98        D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData>,
99        D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
100        D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
101        D: SeatHandler,
102        D: 'static,
103        F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
104    {
105        let global = create_global_with_filter::<D, F>(display, filter);
106
107        Self { global }
108    }
109
110    /// Get the id of ZwpVirtualKeyboardManagerV1 global
111    pub fn global(&self) -> GlobalId {
112        self.global.clone()
113    }
114}
115
116impl<D> GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData, D>
117    for VirtualKeyboardManagerState
118where
119    D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData>,
120    D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
121    D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
122    D: SeatHandler,
123    D: 'static,
124{
125    fn bind(
126        _: &mut D,
127        _: &DisplayHandle,
128        _: &Client,
129        resource: New<ZwpVirtualKeyboardManagerV1>,
130        _: &VirtualKeyboardManagerGlobalData,
131        data_init: &mut DataInit<'_, D>,
132    ) {
133        data_init.init(resource, ());
134    }
135
136    fn can_view(client: Client, global_data: &VirtualKeyboardManagerGlobalData) -> bool {
137        (global_data.filter)(&client)
138    }
139}
140
141impl<D> Dispatch<ZwpVirtualKeyboardManagerV1, (), D> for VirtualKeyboardManagerState
142where
143    D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
144    D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
145    D: SeatHandler,
146    D: 'static,
147{
148    fn request(
149        _state: &mut D,
150        _client: &Client,
151        _resource: &ZwpVirtualKeyboardManagerV1,
152        request: zwp_virtual_keyboard_manager_v1::Request,
153        _data: &(),
154        _handle: &DisplayHandle,
155        data_init: &mut DataInit<'_, D>,
156    ) {
157        match request {
158            zwp_virtual_keyboard_manager_v1::Request::CreateVirtualKeyboard { seat, id } => {
159                let seat = Seat::<D>::from_resource(&seat).unwrap();
160                let user_data = seat.user_data();
161                user_data.insert_if_missing(VirtualKeyboardHandle::default);
162                let virtual_keyboard_handle = user_data.get::<VirtualKeyboardHandle>().unwrap();
163                data_init.init(
164                    id,
165                    VirtualKeyboardUserData {
166                        handle: virtual_keyboard_handle.clone(),
167                        seat: seat.clone(),
168                    },
169                );
170            }
171            _ => unreachable!(),
172        }
173    }
174}
175
176#[allow(missing_docs)] //TODO
177#[macro_export]
178macro_rules! delegate_virtual_keyboard_manager {
179    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
180        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
181            $crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1: $crate::wayland::virtual_keyboard::VirtualKeyboardManagerGlobalData
182        ] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);
183
184        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
185            $crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1: ()
186        ] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);
187
188        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
189            $crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1: $crate::wayland::virtual_keyboard::VirtualKeyboardUserData<Self>
190        ] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);
191    };
192}