diff --git a/input-emulation/Cargo.toml b/input-emulation/Cargo.toml index 042091c..76a841a 100644 --- a/input-emulation/Cargo.toml +++ b/input-emulation/Cargo.toml @@ -25,6 +25,7 @@ tokio = { version = "1.32.0", features = [ once_cell = "1.19.0" [target.'cfg(all(unix, not(target_os="macos")))'.dependencies] +bitflags = "2.6.0" wayland-client = { version = "0.31.1", optional = true } wayland-protocols = { version = "0.32.1", features = [ "client", @@ -42,6 +43,8 @@ ashpd = { version = "0.10", default-features = false, features = [ "tokio", ], optional = true } reis = { version = "0.4", features = ["tokio"], optional = true } +keycode = "0.4.0" + [target.'cfg(target_os="macos")'.dependencies] bitflags = "2.6.0" diff --git a/input-emulation/src/wlroots.rs b/input-emulation/src/wlroots.rs index df18ed1..56d5c21 100644 --- a/input-emulation/src/wlroots.rs +++ b/input-emulation/src/wlroots.rs @@ -2,9 +2,11 @@ use crate::error::EmulationError; use super::{error::WlrootsEmulationCreationError, Emulation}; use async_trait::async_trait; +use bitflags::bitflags; use std::collections::HashMap; use std::io; use std::os::fd::{AsFd, OwnedFd}; +use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; use wayland_client::backend::WaylandError; use wayland_client::WEnum; @@ -29,7 +31,7 @@ use wayland_client::{ Connection, Dispatch, EventQueue, QueueHandle, }; -use input_event::{Event, KeyboardEvent, PointerEvent}; +use input_event::{scancode, Event, KeyboardEvent, PointerEvent}; use super::error::WaylandBindError; use super::EmulationHandle; @@ -103,7 +105,11 @@ impl State { panic!("no keymap"); } - let vinput = VirtualInput { pointer, keyboard }; + let vinput = VirtualInput { + pointer, + keyboard, + modifiers: Arc::new(Mutex::new(XMods::empty())), + }; self.input_for_client.insert(client, vinput); } @@ -174,6 +180,7 @@ impl Emulation for WlrootsEmulation { struct VirtualInput { pointer: Vp, keyboard: Vk, + modifiers: Arc>, } impl VirtualInput { @@ -212,6 +219,13 @@ impl VirtualInput { Event::Keyboard(e) => match e { KeyboardEvent::Key { time, key, state } => { self.keyboard.key(time, key, state as u32); + if let Ok(mut mods) = self.modifiers.lock() { + if mods.from_key_event(key, state) { + log::trace!("Key triggers modifier change"); + log::trace!("Modifiers: {:?}", mods); + self.keyboard.modifiers(mods.bits(), 0, 0, 0); + } + } } KeyboardEvent::Modifiers { depressed: mods_depressed, @@ -279,3 +293,47 @@ impl Dispatch for State { } } } + +// From X11/X.h +bitflags! { + #[repr(C)] + #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] + struct XMods: u32 { + const ShiftMask = (1<<0); + const LockMask = (1<<1); + const ControlMask = (1<<2); + const Mod1Mask = (1<<3); + const Mod2Mask = (1<<4); + const Mod3Mask = (1<<5); + const Mod4Mask = (1<<6); + const Mod5Mask = (1<<7); + } +} + +impl XMods { + fn from_key_event(&mut self, key: u32, state: u8) -> bool { + if let Ok(key) = scancode::Linux::try_from(key) { + log::trace!("Attempting to process modifier from: {:#?}", key); + let mask = match key { + scancode::Linux::KeyLeftShift | scancode::Linux::KeyRightShift => XMods::ShiftMask, + scancode::Linux::KeyCapsLock => XMods::LockMask, + scancode::Linux::KeyLeftCtrl | scancode::Linux::KeyRightCtrl => XMods::ControlMask, + scancode::Linux::KeyLeftAlt | scancode::Linux::KeyRightalt => XMods::Mod1Mask, + scancode::Linux::KeyLeftMeta | scancode::Linux::KeyRightmeta => XMods::Mod4Mask, + _ => XMods::empty(), + }; + // unchanged + if mask.is_empty() { + log::trace!("{:#?} is not a modifier key", key); + return false; + } + match state { + 1 => self.insert(mask), + _ => self.remove(mask), + } + true + } else { + false + } + } +}