Switch to WheelHiRes. Add horizontal scrolling (#171)

* Switch to HiResScroll. Add horizontal scrolling

* Fix OpenVR compilation for horizontal scrolling

* fix OpenXR scroll using x axis for both scroll axes
This commit is contained in:
AdiMCS
2025-03-09 10:20:10 -07:00
committed by GitHub
parent 36074307b7
commit b0883e81bf
14 changed files with 77 additions and 60 deletions

View File

@@ -217,7 +217,8 @@ impl Pointer {
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct PointerState { pub struct PointerState {
pub scroll: f32, pub scroll_x: f32,
pub scroll_y: f32,
pub click: bool, pub click: bool,
pub grab: bool, pub grab: bool,
pub alt_click: bool, pub alt_click: bool,
@@ -252,7 +253,7 @@ pub trait InteractionHandler {
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>; fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>;
fn on_left(&mut self, app: &mut AppState, pointer: usize); fn on_left(&mut self, app: &mut AppState, pointer: usize);
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool); fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32); fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32);
} }
pub struct DummyInteractionHandler; pub struct DummyInteractionHandler;
@@ -263,7 +264,7 @@ impl InteractionHandler for DummyInteractionHandler {
None None
} }
fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {} fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {}
fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {} fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta_y: f32, _delta_x: f32) {}
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@@ -419,8 +420,9 @@ where
pointer = &mut app.input_state.pointers[idx]; pointer = &mut app.input_state.pointers[idx];
if pointer.now.scroll.abs() > 0.1 { if pointer.now.scroll_x.abs() > 0.1 || pointer.now.scroll_y.abs() > 0.1 {
let scroll = pointer.now.scroll; let scroll_x = pointer.now.scroll_x;
let scroll_y = pointer.now.scroll_y;
if app.input_state.pointers[1 - idx] if app.input_state.pointers[1 - idx]
.interaction .interaction
.grabbed .grabbed
@@ -432,7 +434,7 @@ where
if can_curve { if can_curve {
let cur = hovered.state.curvature.unwrap_or(0.0); let cur = hovered.state.curvature.unwrap_or(0.0);
let new = (cur - scroll * 0.01).min(0.5); let new = (cur - scroll_y * 0.01).min(0.5);
if new <= f32::EPSILON { if new <= f32::EPSILON {
hovered.state.curvature = None; hovered.state.curvature = None;
} else { } else {
@@ -442,7 +444,7 @@ where
hovered.state.curvature = None; hovered.state.curvature = None;
} }
} else { } else {
hovered.backend.on_scroll(app, &hit, scroll); hovered.backend.on_scroll(app, &hit, scroll_y, scroll_x);
} }
pointer = &mut app.input_state.pointers[idx]; pointer = &mut app.input_state.pointers[idx];
} }
@@ -560,10 +562,10 @@ impl Pointer {
if self.now.click { if self.now.click {
self.interaction.mode = PointerMode::Special; self.interaction.mode = PointerMode::Special;
let cur_scale = overlay.state.transform.x_axis.length(); let cur_scale = overlay.state.transform.x_axis.length();
if cur_scale < 0.1 && self.now.scroll > 0.0 { if cur_scale < 0.1 && self.now.scroll_y > 0.0 {
return; return;
} }
if cur_scale > 20. && self.now.scroll < 0.0 { if cur_scale > 20. && self.now.scroll_y < 0.0 {
return; return;
} }
@@ -571,9 +573,9 @@ impl Pointer {
.state .state
.transform .transform
.matrix3 .matrix3
.mul_scalar(1.0 - 0.025 * self.now.scroll); .mul_scalar(1.0 - 0.025 * self.now.scroll_y);
} else if config.allow_sliding && self.now.scroll.is_finite() { } else if config.allow_sliding && self.now.scroll_y.is_finite() {
grab_data.offset.z -= self.now.scroll * 0.05; grab_data.offset.z -= self.now.scroll_y * 0.05;
} }
overlay.state.transform.translation = self.pose.transform_point3a(grab_data.offset); overlay.state.transform.translation = self.pose.transform_point3a(grab_data.offset);
overlay.state.realign(hmd); overlay.state.realign(hmd);

View File

@@ -230,10 +230,12 @@ impl OpenVrInputSource {
.map(|x| x.0.bState) .map(|x| x.0.bState)
.unwrap_or(false); .unwrap_or(false);
app_hand.now.scroll = input let scroll = input
.get_analog_action_data(self.scroll_hnd, hand.input_hnd) .get_analog_action_data(self.scroll_hnd, hand.input_hnd)
.map(|x| x.0.y) .map(|x| (x.0.x, x.0.y))
.unwrap_or(0.0); .unwrap_or((0.0, 0.0));
app_hand.now.scroll_x = scroll.0;
app_hand.now.scroll_y = scroll.1;
} }
} }

View File

@@ -6,7 +6,7 @@ use std::{
use glam::{bool, Affine3A, Quat, Vec3}; use glam::{bool, Affine3A, Quat, Vec3};
use libmonado as mnd; use libmonado as mnd;
use openxr::{self as xr, Quaternionf, Vector3f}; use openxr::{self as xr, Quaternionf, Vector2f, Vector3f};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@@ -161,7 +161,7 @@ pub(super) struct OpenXrHandSource {
action_modifier_right: CustomClickAction, action_modifier_right: CustomClickAction,
action_modifier_middle: CustomClickAction, action_modifier_middle: CustomClickAction,
action_move_mouse: CustomClickAction, action_move_mouse: CustomClickAction,
action_scroll: xr::Action<f32>, action_scroll: xr::Action<Vector2f>,
action_haptics: xr::Action<xr::Haptic>, action_haptics: xr::Action<xr::Haptic>,
} }
@@ -350,12 +350,15 @@ impl OpenXrHand {
.action_grab .action_grab
.state(pointer.before.grab, xr, session)?; .state(pointer.before.grab, xr, session)?;
pointer.now.scroll = self let scroll = self
.source .source
.action_scroll .action_scroll
.state(&xr.session, xr::Path::NULL)? .state(&xr.session, xr::Path::NULL)?
.current_state; .current_state;
pointer.now.scroll_x = scroll.x;
pointer.now.scroll_y = scroll.y;
pointer.now.alt_click = pointer.now.alt_click =
self.source self.source
.action_alt_click .action_alt_click
@@ -417,7 +420,7 @@ impl OpenXrHandSource {
&[], &[],
)?; )?;
let action_scroll = action_set.create_action::<f32>( let action_scroll = action_set.create_action::<Vector2f>(
&format!("{}_scroll", side), &format!("{}_scroll", side),
&format!("{} hand scroll", side), &format!("{} hand scroll", side),
&[], &[],

View File

@@ -81,6 +81,10 @@
left: "/user/hand/left/input/thumbstick/y", left: "/user/hand/left/input/thumbstick/y",
right: "/user/hand/right/input/thumbstick/y" right: "/user/hand/right/input/thumbstick/y"
}, },
scroll_horizontal: {
left: "/user/hand/left/input/thumbstick/x",
right: "/user/hand/right/input/thumbstick/x"
},
show_hide: { show_hide: {
double_click: true, double_click: true,
left: "/user/hand/left/input/y/click", left: "/user/hand/left/input/y/click",
@@ -129,6 +133,10 @@
scroll: { scroll: {
left: "/user/hand/left/input/thumbstick/y", left: "/user/hand/left/input/thumbstick/y",
right: "/user/hand/right/input/thumbstick/y" right: "/user/hand/right/input/thumbstick/y"
},
scroll_horizontal: {
left: "/user/hand/left/input/thumbstick/x",
right: "/user/hand/right/input/thumbstick/x"
}, },
toggle_dashboard: { toggle_dashboard: {
double_click: false, double_click: false,
@@ -180,6 +188,10 @@
left: "/user/hand/left/input/trackpad/y", left: "/user/hand/left/input/trackpad/y",
right: "/user/hand/right/input/trackpad/y" right: "/user/hand/right/input/trackpad/y"
}, },
scroll_horizontal: {
left: "/user/hand/left/input/trackpad/x",
right: "/user/hand/right/input/trackpad/x"
},
show_hide: { show_hide: {
left: "/user/hand/left/input/menu/click", left: "/user/hand/left/input/menu/click",
}, },
@@ -215,6 +227,10 @@
left: "/user/hand/left/input/thumbstick/y", left: "/user/hand/left/input/thumbstick/y",
right: "/user/hand/right/input/thumbstick/y" right: "/user/hand/right/input/thumbstick/y"
}, },
scroll_horizontal: {
left: "/user/hand/left/input/thumbstick/x",
right: "/user/hand/right/input/thumbstick/x"
},
show_hide: { show_hide: {
left: "/user/hand/left/input/menu/click", left: "/user/hand/left/input/menu/click",
}, },
@@ -246,6 +262,10 @@
left: "/user/hand/left/input/thumbstick/y", left: "/user/hand/left/input/thumbstick/y",
right: "/user/hand/right/input/thumbstick/y" right: "/user/hand/right/input/thumbstick/y"
}, },
scroll_horizontal: {
left: "/user/hand/left/input/thumbstick/x",
right: "/user/hand/right/input/thumbstick/x"
},
show_hide: { show_hide: {
left: "/user/hand/left/input/menu/click", left: "/user/hand/left/input/menu/click",
}, },

View File

@@ -365,8 +365,8 @@ impl InteractionHandler for SplitOverlayBackend {
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
self.interaction.on_hover(app, hit) self.interaction.on_hover(app, hit)
} }
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) {
self.interaction.on_scroll(app, hit, delta); self.interaction.on_scroll(app, hit, delta_y, delta_x);
} }
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
self.interaction.on_pointer(app, hit, pressed); self.interaction.on_pointer(app, hit, pressed);

View File

@@ -479,7 +479,7 @@ impl Display {
manager.seat_pointer.frame(&mut manager.state); manager.seat_pointer.frame(&mut manager.state);
} }
pub fn send_mouse_scroll(&self, manager: &mut WayVRCompositor, delta: f32) { pub fn send_mouse_scroll(&self, manager: &mut WayVRCompositor, delta_y: f32, delta_x: f32) {
manager.seat_pointer.axis( manager.seat_pointer.axis(
&mut manager.state, &mut manager.state,
input::pointer::AxisFrame { input::pointer::AxisFrame {
@@ -489,8 +489,8 @@ impl Display {
smithay::backend::input::AxisRelativeDirection::Identical, smithay::backend::input::AxisRelativeDirection::Identical,
), ),
time: 0, time: 0,
axis: (0.0, -delta as f64), axis: (delta_x as f64, -delta_y as f64),
v120: Some((0, (delta * -120.0) as i32)), v120: Some((0, (delta_y * -120.0) as i32)),
stop: (false, false), stop: (false, false),
}, },
); );

View File

@@ -463,9 +463,9 @@ impl WayVRState {
} }
} }
pub fn send_mouse_scroll(&mut self, display: display::DisplayHandle, delta: f32) { pub fn send_mouse_scroll(&mut self, display: display::DisplayHandle, delta_y: f32, delta_x: f32) {
if let Some(display) = self.displays.get(&display) { if let Some(display) = self.displays.get(&display) {
display.send_mouse_scroll(&mut self.manager, delta); display.send_mouse_scroll(&mut self.manager, delta_y, delta_x);
} }
} }

View File

@@ -35,7 +35,7 @@ pub(crate) struct Control<D, S> {
pub on_update: Option<fn(&mut Self, &mut D, &mut AppState)>, pub on_update: Option<fn(&mut Self, &mut D, &mut AppState)>,
pub on_press: Option<fn(&mut Self, &mut D, &mut AppState, PointerMode)>, pub on_press: Option<fn(&mut Self, &mut D, &mut AppState, PointerMode)>,
pub on_release: Option<fn(&mut Self, &mut D, &mut AppState)>, pub on_release: Option<fn(&mut Self, &mut D, &mut AppState)>,
pub on_scroll: Option<fn(&mut Self, &mut D, &mut AppState, f32)>, pub on_scroll: Option<fn(&mut Self, &mut D, &mut AppState, f32, f32)>,
pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> Option<Vec4>>, pub test_highlight: Option<fn(&Self, &mut D, &mut AppState) -> Option<Vec4>>,
pub(super) on_render_bg: Option<ControlRenderer<D, S>>, pub(super) on_render_bg: Option<ControlRenderer<D, S>>,

View File

@@ -267,13 +267,13 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
} }
} }
} }
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) {
let idx = self.hover_controls[hit.pointer]; let idx = self.hover_controls[hit.pointer];
if let Some(idx) = idx { if let Some(idx) = idx {
let c = &mut self.controls[idx]; let c = &mut self.controls[idx];
if let Some(ref mut f) = c.on_scroll { if let Some(ref mut f) = c.on_scroll {
f(c, &mut self.canvas.data, app, delta); f(c, &mut self.canvas.data, app, delta_y, delta_x);
} }
} }
} }

View File

@@ -326,13 +326,13 @@ fn modular_button_up(button: &mut ModularControl, _: &mut (), app: &mut AppState
} }
} }
fn modular_button_scroll(button: &mut ModularControl, _: &mut (), app: &mut AppState, delta: f32) { fn modular_button_scroll(button: &mut ModularControl, _: &mut (), app: &mut AppState, delta_y: f32, delta_x: f32) {
// want panic // want panic
let ModularData::Button(data) = button.state.as_mut().unwrap() else { let ModularData::Button(data) = button.state.as_mut().unwrap() else {
panic!("modular_button_scroll: button state is not Button"); panic!("modular_button_scroll: button state is not Button");
}; };
let actions = if delta < 0.0 { let actions = if delta_y < 0.0 {
data.scroll_down.as_ref() data.scroll_down.as_ref()
} else { } else {
data.scroll_up.as_ref() data.scroll_up.as_ref()

View File

@@ -1,4 +1,4 @@
use glam::Vec2; use glam::{IVec2, Vec2};
use idmap::{idmap, IdMap}; use idmap::{idmap, IdMap};
use idmap_derive::IntegerId; use idmap_derive::IntegerId;
use input_linux::{ use input_linux::{
@@ -46,7 +46,7 @@ pub fn initialize() -> Box<dyn HidProvider> {
pub trait HidProvider { pub trait HidProvider {
fn mouse_move(&mut self, pos: Vec2); fn mouse_move(&mut self, pos: Vec2);
fn send_button(&mut self, button: u16, down: bool); fn send_button(&mut self, button: u16, down: bool);
fn wheel(&mut self, delta: i32); fn wheel(&mut self, delta_y: i32, delta_x: i32);
fn set_modifiers(&mut self, mods: u8); fn set_modifiers(&mut self, mods: u8);
fn send_key(&self, key: VirtualKey, down: bool); fn send_key(&self, key: VirtualKey, down: bool);
fn set_desktop_extent(&mut self, extent: Vec2); fn set_desktop_extent(&mut self, extent: Vec2);
@@ -64,7 +64,7 @@ struct MouseAction {
last_requested_pos: Option<Vec2>, last_requested_pos: Option<Vec2>,
pos: Option<Vec2>, pos: Option<Vec2>,
button: Option<MouseButtonAction>, button: Option<MouseButtonAction>,
scroll: Option<i32>, scroll: Option<IVec2>,
} }
pub struct UInputProvider { pub struct UInputProvider {
@@ -149,7 +149,8 @@ impl UInputProvider {
mouse_handle.set_evbit(EventKind::Relative).ok()?; mouse_handle.set_evbit(EventKind::Relative).ok()?;
mouse_handle.set_absbit(AbsoluteAxis::X).ok()?; mouse_handle.set_absbit(AbsoluteAxis::X).ok()?;
mouse_handle.set_absbit(AbsoluteAxis::Y).ok()?; mouse_handle.set_absbit(AbsoluteAxis::Y).ok()?;
mouse_handle.set_relbit(RelativeAxis::Wheel).ok()?; mouse_handle.set_relbit(RelativeAxis::WheelHiRes).ok()?;
mouse_handle.set_relbit(RelativeAxis::HorizontalWheelHiRes).ok()?;
mouse_handle.set_evbit(EventKind::Key).ok()?; mouse_handle.set_evbit(EventKind::Key).ok()?;
for btn in MOUSE_LEFT..=MOUSE_MIDDLE { for btn in MOUSE_LEFT..=MOUSE_MIDDLE {
@@ -193,10 +194,11 @@ impl UInputProvider {
log::error!("{}", res.to_string()); log::error!("{}", res.to_string());
} }
} }
fn wheel_internal(&self, delta: i32) { fn wheel_internal(&self, delta_y: i32, delta_x: i32) {
let time = get_time(); let time = get_time();
let events = [ let events = [
new_event(time, EV_REL, RelativeAxis::Wheel as _, delta), new_event(time, EV_REL, RelativeAxis::WheelHiRes as _, delta_y),
new_event(time, EV_REL, RelativeAxis::HorizontalWheelHiRes as _, delta_x),
new_event(time, EV_SYN, 0, 0), new_event(time, EV_SYN, 0, 0),
]; ];
if let Err(res) = self.mouse_handle.write(&events) { if let Err(res) = self.mouse_handle.write(&events) {
@@ -247,9 +249,9 @@ impl HidProvider for UInputProvider {
self.current_action.pos = self.current_action.last_requested_pos; self.current_action.pos = self.current_action.last_requested_pos;
} }
} }
fn wheel(&mut self, delta: i32) { fn wheel(&mut self, delta_y: i32, delta_x: i32) {
if self.current_action.scroll.is_none() { if self.current_action.scroll.is_none() {
self.current_action.scroll = Some(delta); self.current_action.scroll = Some(IVec2::new(delta_x, delta_y));
// Pass mouse motion events only if not scrolling // Pass mouse motion events only if not scrolling
// (allows scrolling on all Chromium-based applications) // (allows scrolling on all Chromium-based applications)
self.current_action.pos = None; self.current_action.pos = None;
@@ -263,7 +265,7 @@ impl HidProvider for UInputProvider {
self.send_button_internal(button.button, button.down); self.send_button_internal(button.button, button.down);
} }
if let Some(scroll) = self.current_action.scroll.take() { if let Some(scroll) = self.current_action.scroll.take() {
self.wheel_internal(scroll); self.wheel_internal(scroll.y, scroll.x);
} }
} }
} }
@@ -271,7 +273,7 @@ impl HidProvider for UInputProvider {
impl HidProvider for DummyProvider { impl HidProvider for DummyProvider {
fn mouse_move(&mut self, _pos: Vec2) {} fn mouse_move(&mut self, _pos: Vec2) {}
fn send_button(&mut self, _button: u16, _down: bool) {} fn send_button(&mut self, _button: u16, _down: bool) {}
fn wheel(&mut self, _delta: i32) {} fn wheel(&mut self, _delta_y: i32, _delta_x: i32) {}
fn set_modifiers(&mut self, _modifiers: u8) {} fn set_modifiers(&mut self, _modifiers: u8) {}
fn send_key(&self, _key: VirtualKey, _down: bool) {} fn send_key(&self, _key: VirtualKey, _down: bool) {}
fn set_desktop_extent(&mut self, _extent: Vec2) {} fn set_desktop_extent(&mut self, _extent: Vec2) {}

View File

@@ -516,9 +516,10 @@ impl InteractionHandler for KeyboardBackend {
&mut self, &mut self,
app: &mut AppState, app: &mut AppState,
hit: &crate::backend::input::PointerHit, hit: &crate::backend::input::PointerHit,
delta: f32, delta_y: f32,
delta_x: f32,
) { ) {
self.canvas.on_scroll(app, hit, delta) self.canvas.on_scroll(app, hit, delta_y, delta_x)
} }
fn on_left(&mut self, app: &mut AppState, pointer: usize) { fn on_left(&mut self, app: &mut AppState, pointer: usize) {
self.canvas.on_left(app, pointer) self.canvas.on_left(app, pointer)

View File

@@ -88,7 +88,6 @@ fn set_next_move(millis_from_now: u64) {
} }
pub struct ScreenInteractionHandler { pub struct ScreenInteractionHandler {
next_scroll: Instant,
mouse_transform: Affine2, mouse_transform: Affine2,
} }
impl ScreenInteractionHandler { impl ScreenInteractionHandler {
@@ -113,7 +112,6 @@ impl ScreenInteractionHandler {
}; };
ScreenInteractionHandler { ScreenInteractionHandler {
next_scroll: Instant::now(),
mouse_transform: transform, mouse_transform: transform,
} }
} }
@@ -152,19 +150,8 @@ impl InteractionHandler for ScreenInteractionHandler {
let pos = self.mouse_transform.transform_point2(hit.uv); let pos = self.mouse_transform.transform_point2(hit.uv);
app.hid_provider.mouse_move(pos); app.hid_provider.mouse_move(pos);
} }
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta_y: f32, delta_x: f32) {
if self.next_scroll > Instant::now() { app.hid_provider.wheel((delta_y*64.) as i32, (delta_x*64.) as i32)
return;
}
let max_millis = if matches!(hit.mode, PointerMode::Left) {
200.0
} else {
100.0
};
let millis = (1. - delta.abs()) * max_millis;
self.next_scroll = Instant::now().add(Duration::from_millis(millis as _));
app.hid_provider.wheel(if delta < 0. { -1 } else { 1 })
} }
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {} fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
} }

View File

@@ -153,13 +153,13 @@ impl InteractionHandler for WayVRInteractionHandler {
} }
} }
fn on_scroll(&mut self, _app: &mut state::AppState, _hit: &input::PointerHit, delta: f32) { fn on_scroll(&mut self, _app: &mut state::AppState, _hit: &input::PointerHit, delta_y: f32, delta_x: f32) {
let ctx = self.context.borrow(); let ctx = self.context.borrow();
ctx.wayvr ctx.wayvr
.borrow_mut() .borrow_mut()
.data .data
.state .state
.send_mouse_scroll(ctx.display, delta); .send_mouse_scroll(ctx.display, delta_y, delta_x);
} }
} }