mouse wheel handling & wl_virtual modifiers

This commit is contained in:
galister 2026-07-23 16:41:22 +09:00
parent 590980e560
commit 6a6264347b
8 changed files with 62 additions and 49 deletions

View File

@ -121,16 +121,6 @@ impl InputCapture {
self.event_rx.try_iter().collect()
}
/// Exclusively grabs every currently detected keyboard and mouse.
/// Newly connected matching devices are grabbed automatically.
pub fn set_grabbed(&self, grabbed: bool) -> anyhow::Result<()> {
self.command_tx
.try_send(Command::SetGrabbed(grabbed))
.map_err(|error| anyhow::anyhow!("worker thread unreachable: {error}"))?;
Ok(())
}
/// Set acceleration profile for current and future mice
pub fn set_pointer_accel(&self, accel: bool, speed: f32) -> anyhow::Result<()> {
if !speed.is_finite() || !(-1.0..=1.0).contains(&speed) {
@ -156,8 +146,12 @@ impl Drop for InputCapture {
enum Command {
ResetWatchdog,
SetGrabbed(bool),
SetPointerAccel { accel: bool, speed: f32 },
#[allow(dead_code)]
SetGrabbed(bool), // might need later?
SetPointerAccel {
accel: bool,
speed: f32,
},
Shutdown,
}

View File

@ -85,7 +85,7 @@ use crate::{
subsystem::{
dbus::DbusConnector,
hid::{self, MODS_TO_KEYS, WheelDelta},
input::{HidWrapper, InputFocus},
input::HidWrapper,
},
windowing::{OverlayID, OverlaySelector, backend::OverlayEventData},
};
@ -897,7 +897,6 @@ impl WvrServerState {
}
}
input_capture::CapturedEvent::Grabbed => {
hid_wrapper.set_input_focus(Some(self), InputFocus::WayVR);
audio_sample_player.play_sample(audio_system, "input_grab");
if !self.grab_toast_sent {
self.grab_toast_sent = true;

View File

@ -352,7 +352,10 @@ impl OverlayBackend for ScreenBackend {
.mouse_move(DVec2::new(pos.x as _, pos.y as _));
}
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta: WheelDelta) {
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, mut delta: WheelDelta) {
// convert to v120 value; maximum deflect scrolls at half speed
delta.x *= 60.0;
delta.y *= 60.0;
app.hid_provider.inner.wheel(delta);
}

View File

@ -13,7 +13,7 @@ impl HidProvider for DummyProvider {
fn set_desktop_extent(&mut self, _extent: DVec2) {}
fn set_desktop_origin(&mut self, _origin: DVec2) {}
fn set_modifiers(&mut self, _modifiers: u8) {}
fn send_key(&self, _key: VirtualKey, _down: bool) {}
fn send_key(&mut self, _key: VirtualKey, _down: bool) {}
fn set_keymap(&mut self, _keymap: &XkbKeymap) {}

View File

@ -16,7 +16,7 @@ pub trait HidProvider: Sync + Send {
// Keyboard Functions
fn set_modifiers(&mut self, mods: u8);
fn send_key(&self, key: VirtualKey, down: bool);
fn send_key(&mut self, key: VirtualKey, down: bool);
fn set_keymap(&mut self, keymap: &XkbKeymap);
// Common Functions

View File

@ -135,18 +135,14 @@ impl UInputProvider {
}
fn wheel_internal(&self, delta: WheelDelta) {
let multiplier = 64.0; /* cherry-picked value, overall scrolling speed can be altered via `scroll_speed` in the config */
let delta_x = (delta.x * multiplier) as i32;
let delta_y = (delta.y * multiplier) as i32;
let time = get_time();
let events = [
new_event(time, EV_REL, RelativeAxis::WheelHiRes as _, delta_y),
new_event(time, EV_REL, RelativeAxis::WheelHiRes as _, delta.y as _),
new_event(
time,
EV_REL,
RelativeAxis::HorizontalWheelHiRes as _,
delta_x,
delta.x as _,
),
new_event(time, EV_SYN, 0, 0),
];
@ -206,7 +202,7 @@ impl HidProvider for UInputProvider {
self.cur_modifiers = modifiers;
}
fn send_key(&self, key: VirtualKey, down: bool) {
fn send_key(&mut self, key: VirtualKey, down: bool) {
#[cfg(debug_assertions)]
log::trace!("send_key: {key:?} {down}");

View File

@ -2,7 +2,7 @@ use std::io::Write;
use std::os::fd::AsFd;
use std::time::{SystemTime, UNIX_EPOCH};
use anyhow::Context as _;
use glam::{DVec2};
use glam::{Vec2, DVec2};
use input_linux::sys::{*};
use smithay::reexports::rustix::fs::{memfd_create, MemfdFlags};
use smithay::reexports::wayland_protocols_wlr::virtual_pointer::v1::client::zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1;
@ -21,6 +21,8 @@ use crate::overlays::toast::Toast;
use crate::subsystem::hid::provider::HidProvider;
use crate::subsystem::hid::{VirtualKey, WheelDelta, *};
const LOCKED: u8 = CAPS_LOCK | NUM_LOCK;
pub struct WlVirtualProvider {
_connection: wayland_client::Connection,
queue: wayland_client::EventQueue<KbState>,
@ -35,6 +37,7 @@ pub struct WlVirtualProvider {
keyboard_mods_state: u8,
last_pointer_position: DVec2,
wheel_accum: Vec2,
}
struct KbState;
@ -84,28 +87,30 @@ impl HidProvider for WlVirtualProvider {
self.virtual_pointer.frame();
}
fn wheel(&mut self, delta: WheelDelta) {
fn wheel(&mut self, mut delta: WheelDelta) {
#[cfg(debug_assertions)]
log::trace!("Scroll Axis: {delta:?}");
// no clue; a value of 10 seems to equal a v120 value of 120
delta.x /= 12.0;
delta.y /= 12.0;
self.virtual_pointer.axis_source(AxisSource::Wheel);
if delta.y != 0.0 {
let steps = -delta.y.round() as i32;
self.virtual_pointer.axis_discrete(
Self::now_ms(),
Axis::VerticalScroll,
steps as f64 * 15.0,
steps,
-delta.y as _,
accumulate_discrete_scroll(&mut self.wheel_accum.y, -delta.y),
);
}
if delta.x != 0.0 {
let steps = delta.x.round() as i32;
self.virtual_pointer.axis_discrete(
Self::now_ms(),
Axis::HorizontalScroll,
steps as f64 * 15.0,
steps,
delta.x as _,
accumulate_discrete_scroll(&mut self.wheel_accum.x, delta.x),
);
}
@ -122,15 +127,13 @@ impl HidProvider for WlVirtualProvider {
}
fn set_modifiers(&mut self, mods: u8) {
const LOCKED: u8 = CAPS_LOCK | NUM_LOCK;
let changed = (self.keyboard_mods_state ^ mods) & !LOCKED;
for bit in [SHIFT, CTRL, ALT, SUPER] {
if changed & bit != 0 {
let down = mods & bit != 0;
if let Some(kc) = Self::modifier_keycode(bit) {
if let Some(kc) = MODS_TO_KEYS.get(bit) {
self.virtual_keyboard
.key(Self::now_ms(), kc - 8, down as u32);
.key(Self::now_ms(), kc[0] as u32 - 8, down as u32);
}
}
}
@ -143,7 +146,7 @@ impl HidProvider for WlVirtualProvider {
self._connection.flush().unwrap();
}
fn send_key(&self, key: VirtualKey, down: bool) {
fn send_key(&mut self, key: VirtualKey, down: bool) {
#[cfg(debug_assertions)]
log::trace!("Keyboard key: {key:?} ({}), down: {down}", key as u16);
@ -156,6 +159,20 @@ impl HidProvider for WlVirtualProvider {
},
);
// sending a mod key → also have to update mod state
if let Some(m) = KEYS_TO_MODS.get(key) {
match (down, m & LOCKED != 0) {
(true, true) => self.keyboard_mods_state ^= m,
(true, false) => self.keyboard_mods_state |= m,
(false, false) => self.keyboard_mods_state &= !m,
(false, true) => {}
}
let depressed = (self.keyboard_mods_state & !LOCKED) as u32;
let locked = (self.keyboard_mods_state & LOCKED) as u32;
self.virtual_keyboard.modifiers(depressed, 0, locked, 0);
}
self._connection.flush().unwrap();
}
@ -222,6 +239,7 @@ impl WlVirtualProvider {
desktop_origin: DVec2::ZERO,
keyboard_mods_state: 0,
last_pointer_position: DVec2::ZERO,
wheel_accum: Vec2::ZERO,
};
result.set_keymap(&XkbKeymap {
@ -245,17 +263,6 @@ impl WlVirtualProvider {
.expect("Failed to compile XKB keymap")
}
fn modifier_keycode(bit: u8) -> Option<u32> {
let evdev = match bit {
b if b == SHIFT => KEY_LEFTSHIFT,
b if b == CTRL => KEY_LEFTCTRL,
b if b == ALT => KEY_LEFTALT,
b if b == SUPER => KEY_LEFTMETA,
_ => return None,
};
Some(evdev as u32 + 8)
}
fn now_ms() -> u32 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
@ -292,3 +299,17 @@ pub fn initialize_wl_virtual() -> anyhow::Result<Box<dyn HidProvider>, Toast> {
})?;
Ok(Box::new(provider))
}
fn accumulate_discrete_scroll(acc: &mut f32, delta: f32) -> i32 {
const WHEEL_DETENT: f32 = 10.0;
*acc += delta;
let steps = (*acc / WHEEL_DETENT).trunc() as i32;
if steps != 0 {
*acc -= steps as f32 * WHEEL_DETENT;
if acc.abs() < 0.001 {
*acc = 0.0;
}
}
steps
}

View File

@ -63,7 +63,7 @@ impl HidWrapper {
}
pub fn send_key_routed(
&self,
&mut self,
wvr_server: Option<&mut WvrServerState>,
key: VirtualKey,
down: bool,