Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wayland/virtual keyboard #720

Merged
merged 33 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4149557
wayland/virtual keyboard
Aug 21, 2022
ebefb0e
Added keyboard handling
Aug 21, 2022
9350f09
Redirecting keyboard input straight into keyboard handler
Aug 23, 2022
034cf7c
Fail using handle
Aug 24, 2022
84192bb
Merge branch 'master' into wayland/virtual_keyboard
Aug 24, 2022
b51a9c3
Working virtual keyboard with keymap changing
Aug 25, 2022
876bec0
Added filter for trusted clients
Aug 26, 2022
3973a07
Merge branch 'Smithay:master' into wayland/virtual_keyboard
Aug 26, 2022
8cff03b
Added documentation
Aug 26, 2022
b23b27a
removing patch crates
Aug 26, 2022
fc4ee2c
Merge branch 'master' into wayland/virtual_keyboard
Aug 27, 2022
1d63f63
Merge branch 'Smithay:master' into wayland/virtual_keyboard
Aug 31, 2022
560ac77
Updated wayland crates in cargo.toml
Aug 31, 2022
577fef6
Updated wlcs_anvil cargo.toml
Aug 31, 2022
27576e4
Update to beta.9
Aug 31, 2022
db13137
Merge branch 'wayland/virtual_keyboard' of me.github.com:rano-oss/smi…
Sep 5, 2022
a7554dd
removed unnecessary internal reference
Sep 10, 2022
ae6584f
Merge branch 'master' into wayland/virtual_keyboard
Sep 10, 2022
be8efbd
fixes after merging with master
Sep 10, 2022
8b45a50
Added extra comment
Sep 10, 2022
85ac5dd
Make it pub crate
Sep 17, 2022
a38ba4a
Merge branch 'master' into wayland/virtual_keyboard
Sep 21, 2022
9bf3462
convert OwnedFd to raw for xkbcommon
Sep 21, 2022
fbecbe6
Merge branch 'master' into wayland/virtual_keyboard
Oct 19, 2022
b9ed4b3
working keymap switching
Oct 22, 2022
ccfd754
format...
Oct 22, 2022
dccae17
clippy
Oct 22, 2022
08441d7
Change keymap is a wayland frontend feature
Oct 22, 2022
8f26898
All keymap change functions movced to frontend
Oct 22, 2022
5953712
Merge branch 'master' into wayland/virtual_keyboard
Oct 29, 2022
401bf7d
refactor how keyboard is changed
Oct 30, 2022
8f3f583
logging level set to warning instead of debug when changing keymap on…
Oct 31, 2022
f0c84e3
move use inside function
Oct 31, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ wayland-sys = { version = "=0.30.0-beta.12", optional = true }
wayland-backend = { version = "=0.1.0-beta.12", optional = true }
winit = { version = "0.27.1", default-features = false, features = ["wayland", "wayland-dlopen", "x11"], optional = true }
x11rb = { version = "0.10.0", optional = true }
xkbcommon = "0.5.0"
xkbcommon = { version = "0.5.0", features = ["wayland"]}
scan_fmt = { version = "0.2.3", default-features = false }
io-lifetimes = "=1.0.0-rc1"

Expand Down
6 changes: 5 additions & 1 deletion anvil/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use smithay::{
delegate_compositor, delegate_data_device, delegate_input_method_manager,
delegate_keyboard_shortcuts_inhibit, delegate_layer_shell, delegate_output, delegate_primary_selection,
delegate_seat, delegate_shm, delegate_tablet_manager, delegate_text_input_manager, delegate_viewporter,
delegate_xdg_activation, delegate_xdg_decoration, delegate_xdg_shell,
delegate_virtual_keyboard_manager, delegate_xdg_activation, delegate_xdg_decoration, delegate_xdg_shell,
desktop::{
utils::{surface_primary_scanout_output, update_surface_primary_scanout_output},
PopupManager, Space, Window,
Expand Down Expand Up @@ -54,6 +54,7 @@ use smithay::{
tablet_manager::TabletSeatTrait,
text_input::TextInputManagerState,
viewporter::ViewporterState,
virtual_keyboard::VirtualKeyboardManagerState,
xdg_activation::{
XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData,
},
Expand Down Expand Up @@ -206,6 +207,8 @@ impl<BackendData> KeyboardShortcutsInhibitHandler for AnvilState<BackendData> {

delegate_keyboard_shortcuts_inhibit!(@<BackendData: 'static> AnvilState<BackendData>);

delegate_virtual_keyboard_manager!(@<BackendData: 'static> AnvilState<BackendData>);

delegate_viewporter!(@<BackendData: 'static> AnvilState<BackendData>);

impl<BackendData> XdgActivationHandler for AnvilState<BackendData> {
Expand Down Expand Up @@ -320,6 +323,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
let xdg_shell_state = XdgShellState::new::<Self, _>(&dh, log.clone());
TextInputManagerState::new::<Self>(&dh);
InputMethodManagerState::new::<Self>(&dh);
VirtualKeyboardManagerState::new::<Self, _>(&dh, |_client| true);

// init input
let seat_name = backend_data.seat_name();
Expand Down
18 changes: 18 additions & 0 deletions src/input/keyboard/keymap_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,24 @@ impl KeymapFile {
}
}

#[cfg(feature = "wayland_frontend")]
pub(crate) fn change_keymap<L>(&mut self, keymap: String, logger: L)
where
L: Into<Option<slog::Logger>>,
{
let logger = crate::slog_or_fallback(logger);
let name = CString::new("smithay-keymap-file").unwrap();
let sealed = SealedFile::new(name, CString::new(keymap.clone()).unwrap());

if let Err(err) = sealed.as_ref() {
error!(logger, "Error when creating sealed keymap file: {}", err);
}

self.sealed = sealed.ok();
self.keymap = keymap;
}

#[cfg(feature = "wayland_frontend")]
/// Run a closure with the file descriptor to ensure safety
pub fn with_fd<F>(&self, supports_sealed: bool, cb: F) -> Result<(), std::io::Error>
where
Expand Down
29 changes: 26 additions & 3 deletions src/input/keyboard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub(crate) struct KbdInternal<D: SeatHandler> {
pending_focus: Option<<D as SeatHandler>::KeyboardFocus>,
pub(crate) pressed_keys: HashSet<u32>,
pub(crate) mods_state: ModifiersState,
keymap: xkb::Keymap,
pub(crate) keymap: xkb::Keymap,
pub(crate) state: xkb::State,
pub(crate) repeat_rate: i32,
pub(crate) repeat_delay: i32,
Expand Down Expand Up @@ -215,7 +215,7 @@ pub enum Error {
pub(crate) struct KbdRc<D: SeatHandler> {
pub(crate) internal: Mutex<KbdInternal<D>>,
#[cfg(feature = "wayland_frontend")]
pub(crate) keymap: KeymapFile,
pub(crate) keymap: Mutex<KeymapFile>,
pub(crate) logger: ::slog::Logger,
#[cfg(feature = "wayland_frontend")]
pub(crate) known_kbds: Mutex<Vec<wayland_server::protocol::wl_keyboard::WlKeyboard>>,
Expand Down Expand Up @@ -427,7 +427,7 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
Ok(Self {
arc: Arc::new(KbdRc {
#[cfg(feature = "wayland_frontend")]
keymap: KeymapFile::new(&internal.keymap, log.clone()),
keymap: Mutex::new(KeymapFile::new(&internal.keymap, log.clone())),
internal: Mutex::new(internal),
logger: log,
#[cfg(feature = "wayland_frontend")]
Expand All @@ -436,6 +436,29 @@ impl<D: SeatHandler + 'static> KeyboardHandle<D> {
})
}

#[cfg(feature = "wayland_frontend")]
pub(crate) fn change_keymap(&self, keymap: xkb::Keymap) {
let keymap = keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
let logger = &self.arc.logger;
let mut keymap_file = self.arc.keymap.lock().unwrap();
keymap_file.change_keymap(keymap, logger.clone());

use std::os::unix::io::AsRawFd;
use wayland_server::{protocol::wl_keyboard::KeymapFormat, Resource};
let known_kbds = &self.arc.known_kbds;
for kbd in &*known_kbds.lock().unwrap() {
let res = keymap_file.with_fd(kbd.version() >= 7, |fd, size| {
kbd.keymap(KeymapFormat::XkbV1, fd.as_raw_fd(), size as u32)
});
if let Err(e) = res {
debug!(logger,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should rather be a warning

Copy link
Contributor Author

@rano-oss rano-oss Oct 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I change this, or merge and create a new shorter pr? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Figured I might as well 😸

"Failed to send keymap to client";
"err" => format!("{:?}", e)
);
}
}
}

/// Change the current grab on this keyboard to the provided grab
///
/// Overwrites any current grab.
Expand Down
1 change: 1 addition & 0 deletions src/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ pub mod socket;
pub mod tablet_manager;
pub mod text_input;
pub mod viewporter;
pub mod virtual_keyboard;
pub mod xdg_activation;
5 changes: 3 additions & 2 deletions src/wayland/seat/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ where
trace!(self.arc.logger, "Sending keymap to client");

// prepare a tempfile with the keymap, to send it to the client
let ret = self.arc.keymap.send(&kbd);
let keymap_file = self.arc.keymap.lock().unwrap();
let ret = keymap_file.send(&kbd);

if let Err(e) = ret {
warn!(self.arc.logger,
Expand Down Expand Up @@ -122,7 +123,7 @@ where
}
}

fn for_each_focused_kbds<D: SeatHandler + 'static>(
pub(crate) fn for_each_focused_kbds<D: SeatHandler + 'static>(
seat: &Seat<D>,
surface: &WlSurface,
mut f: impl FnMut(WlKeyboard),
Expand Down
184 changes: 184 additions & 0 deletions src/wayland/virtual_keyboard/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
//! Utilities for virtual keyboard support
//!
//! This module provides you with utilities to handle virtual keyboard instances.
//! It can be used standalone to implement virtual keyboards or together with
//! an input method to pass through keys from the keyboard.
//!
//! ```
//! use smithay::{
//! delegate_seat, delegate_virtual_keyboard_manager,
//! };
//! use smithay::input::{Seat, SeatState, SeatHandler, pointer::CursorImageStatus};
//! use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState;
//! use smithay::reexports::wayland_server::{Display, protocol::wl_surface::WlSurface};
//!
//! # struct State { seat_state: SeatState<Self> };
//!
//! delegate_seat!(State);
//! // Delegate virtual keyboard handling for State to VirtualKeyboardManagerState.
//! delegate_virtual_keyboard_manager!(State);
//!
//! # let mut display = Display::<State>::new().unwrap();
//! # let display_handle = display.handle();
//!
//! let seat_state = SeatState::<State>::new();
//!
//! // implement the required traits
//! impl SeatHandler for State {
//! type KeyboardFocus = WlSurface;
//! type PointerFocus = WlSurface;
//! fn seat_state(&mut self) -> &mut SeatState<Self> {
//! &mut self.seat_state
//! }
//! fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) { unimplemented!() }
//! fn cursor_image(&mut self, seat: &Seat<Self>, image: CursorImageStatus) { unimplemented!() }
//! }
//!
//! // Add the seat state to your state, create manager global and add client filter
//! // to avoid untrusted clients requesting a new keyboard
//! VirtualKeyboardManagerState::new::<State, _>(&display_handle, |_client| true);
//!
//! ```
//!

use wayland_protocols_misc::zwp_virtual_keyboard_v1::server::{
zwp_virtual_keyboard_manager_v1::{self, ZwpVirtualKeyboardManagerV1},
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
};
use wayland_server::{backend::GlobalId, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New};

use crate::input::{Seat, SeatHandler};

use self::virtual_keyboard_handle::VirtualKeyboardHandle;

const MANAGER_VERSION: u32 = 1;

mod virtual_keyboard_handle;

pub use virtual_keyboard_handle::VirtualKeyboardUserData;

/// State of wp misc virtual keyboard protocol
#[derive(Debug)]
pub struct VirtualKeyboardManagerState {
global: GlobalId,
}

/// Data associated with a VirtualKeyboardManager global.
#[allow(missing_debug_implementations)]
pub struct VirtualKeyboardManagerGlobalData {
filter: Box<dyn for<'c> Fn(&'c Client) -> bool + Send + Sync>,
}

fn create_global_with_filter<D, F>(display: &DisplayHandle, filter: F) -> GlobalId
where
D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData> + 'static,
F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
{
let data = VirtualKeyboardManagerGlobalData {
filter: Box::new(filter),
};

display.create_global::<D, ZwpVirtualKeyboardManagerV1, _>(MANAGER_VERSION, data)
}

impl VirtualKeyboardManagerState {
/// Initialize a virtual keyboard manager global.
pub fn new<D, F>(display: &DisplayHandle, filter: F) -> Self
where
D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData>,
D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
D: SeatHandler,
D: 'static,
F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
{
let global = create_global_with_filter::<D, F>(display, filter);

Self { global }
}

/// Get the id of ZwpVirtualKeyboardManagerV1 global
pub fn global(&self) -> GlobalId {
self.global.clone()
}
}

impl<D> GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData, D>
for VirtualKeyboardManagerState
where
D: GlobalDispatch<ZwpVirtualKeyboardManagerV1, VirtualKeyboardManagerGlobalData>,
D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
D: SeatHandler,
D: 'static,
{
fn bind(
_: &mut D,
_: &DisplayHandle,
_: &Client,
resource: New<ZwpVirtualKeyboardManagerV1>,
_: &VirtualKeyboardManagerGlobalData,
data_init: &mut DataInit<'_, D>,
) {
data_init.init(resource, ());
}

fn can_view(client: Client, global_data: &VirtualKeyboardManagerGlobalData) -> bool {
(global_data.filter)(&client)
}
}

impl<D> Dispatch<ZwpVirtualKeyboardManagerV1, (), D> for VirtualKeyboardManagerState
where
D: Dispatch<ZwpVirtualKeyboardManagerV1, ()>,
D: Dispatch<ZwpVirtualKeyboardV1, VirtualKeyboardUserData<D>>,
D: SeatHandler,
D: 'static,
{
fn request(
_state: &mut D,
_client: &Client,
_resource: &ZwpVirtualKeyboardManagerV1,
request: zwp_virtual_keyboard_manager_v1::Request,
_data: &(),
_handle: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
zwp_virtual_keyboard_manager_v1::Request::CreateVirtualKeyboard { seat, id } => {
let seat = Seat::<D>::from_resource(&seat).unwrap();
let user_data = seat.user_data();
user_data.insert_if_missing(VirtualKeyboardHandle::default);
let virtual_keyboard_handle = user_data.get::<VirtualKeyboardHandle>().unwrap();
data_init.init(
id,
VirtualKeyboardUserData {
handle: virtual_keyboard_handle.clone(),
seat: seat.clone(),
},
);

virtual_keyboard_handle.count_instance();
}
_ => unreachable!(),
}
}
}

#[allow(missing_docs)] //TODO
#[macro_export]
macro_rules! delegate_virtual_keyboard_manager {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
$crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1: $crate::wayland::virtual_keyboard::VirtualKeyboardManagerGlobalData
] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);

$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1: ()
] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);

$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols_misc::zwp_virtual_keyboard_v1::server::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1: $crate::wayland::virtual_keyboard::VirtualKeyboardUserData<Self>
] => $crate::wayland::virtual_keyboard::VirtualKeyboardManagerState);
};
}
Loading