diff --git a/src/backend/input.rs b/src/backend/input.rs index 8383c9c..1306eb5 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -217,7 +217,8 @@ impl Pointer { #[derive(Clone, Copy, Default)] pub struct PointerState { - pub scroll: f32, + pub scroll_x: f32, + pub scroll_y: f32, pub click: bool, pub grab: bool, pub alt_click: bool, @@ -252,7 +253,7 @@ pub trait InteractionHandler { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option; fn on_left(&mut self, app: &mut AppState, pointer: usize); 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; @@ -263,7 +264,7 @@ impl InteractionHandler for DummyInteractionHandler { None } 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)] @@ -419,8 +420,9 @@ where pointer = &mut app.input_state.pointers[idx]; - if pointer.now.scroll.abs() > 0.1 { - let scroll = pointer.now.scroll; + if pointer.now.scroll_x.abs() > 0.1 || pointer.now.scroll_y.abs() > 0.1 { + let scroll_x = pointer.now.scroll_x; + let scroll_y = pointer.now.scroll_y; if app.input_state.pointers[1 - idx] .interaction .grabbed @@ -432,7 +434,7 @@ where if can_curve { 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 { hovered.state.curvature = None; } else { @@ -442,7 +444,7 @@ where hovered.state.curvature = None; } } 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]; } @@ -560,10 +562,10 @@ impl Pointer { if self.now.click { self.interaction.mode = PointerMode::Special; 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; } - if cur_scale > 20. && self.now.scroll < 0.0 { + if cur_scale > 20. && self.now.scroll_y < 0.0 { return; } @@ -571,9 +573,9 @@ impl Pointer { .state .transform .matrix3 - .mul_scalar(1.0 - 0.025 * self.now.scroll); - } else if config.allow_sliding && self.now.scroll.is_finite() { - grab_data.offset.z -= self.now.scroll * 0.05; + .mul_scalar(1.0 - 0.025 * self.now.scroll_y); + } else if config.allow_sliding && self.now.scroll_y.is_finite() { + grab_data.offset.z -= self.now.scroll_y * 0.05; } overlay.state.transform.translation = self.pose.transform_point3a(grab_data.offset); overlay.state.realign(hmd); diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs index bebcb6f..c803ea4 100644 --- a/src/backend/openvr/input.rs +++ b/src/backend/openvr/input.rs @@ -230,10 +230,12 @@ impl OpenVrInputSource { .map(|x| x.0.bState) .unwrap_or(false); - app_hand.now.scroll = input + let scroll = input .get_analog_action_data(self.scroll_hnd, hand.input_hnd) - .map(|x| x.0.y) - .unwrap_or(0.0); + .map(|x| (x.0.x, x.0.y)) + .unwrap_or((0.0, 0.0)); + app_hand.now.scroll_x = scroll.0; + app_hand.now.scroll_y = scroll.1; } } diff --git a/src/backend/openxr/input.rs b/src/backend/openxr/input.rs index a6f12a3..a1d1871 100644 --- a/src/backend/openxr/input.rs +++ b/src/backend/openxr/input.rs @@ -6,7 +6,7 @@ use std::{ use glam::{bool, Affine3A, Quat, Vec3}; use libmonado as mnd; -use openxr::{self as xr, Quaternionf, Vector3f}; +use openxr::{self as xr, Quaternionf, Vector2f, Vector3f}; use serde::{Deserialize, Serialize}; use crate::{ @@ -161,7 +161,7 @@ pub(super) struct OpenXrHandSource { action_modifier_right: CustomClickAction, action_modifier_middle: CustomClickAction, action_move_mouse: CustomClickAction, - action_scroll: xr::Action, + action_scroll: xr::Action, action_haptics: xr::Action, } @@ -350,12 +350,15 @@ impl OpenXrHand { .action_grab .state(pointer.before.grab, xr, session)?; - pointer.now.scroll = self + let scroll = self .source .action_scroll .state(&xr.session, xr::Path::NULL)? .current_state; + pointer.now.scroll_x = scroll.x; + pointer.now.scroll_y = scroll.y; + pointer.now.alt_click = self.source .action_alt_click @@ -417,7 +420,7 @@ impl OpenXrHandSource { &[], )?; - let action_scroll = action_set.create_action::( + let action_scroll = action_set.create_action::( &format!("{}_scroll", side), &format!("{} hand scroll", side), &[], diff --git a/src/backend/openxr/openxr_actions.json5 b/src/backend/openxr/openxr_actions.json5 index 432b98b..ac3e026 100644 --- a/src/backend/openxr/openxr_actions.json5 +++ b/src/backend/openxr/openxr_actions.json5 @@ -81,6 +81,10 @@ left: "/user/hand/left/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: { double_click: true, left: "/user/hand/left/input/y/click", @@ -129,6 +133,10 @@ scroll: { left: "/user/hand/left/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: { double_click: false, @@ -180,6 +188,10 @@ left: "/user/hand/left/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: { left: "/user/hand/left/input/menu/click", }, @@ -215,6 +227,10 @@ left: "/user/hand/left/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: { left: "/user/hand/left/input/menu/click", }, @@ -246,6 +262,10 @@ left: "/user/hand/left/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: { left: "/user/hand/left/input/menu/click", }, diff --git a/src/backend/overlay.rs b/src/backend/overlay.rs index 0a7097e..a9516e5 100644 --- a/src/backend/overlay.rs +++ b/src/backend/overlay.rs @@ -365,8 +365,8 @@ impl InteractionHandler for SplitOverlayBackend { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option { self.interaction.on_hover(app, hit) } - fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { - self.interaction.on_scroll(app, hit, delta); + fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) { + self.interaction.on_scroll(app, hit, delta_y, delta_x); } fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { self.interaction.on_pointer(app, hit, pressed); diff --git a/src/backend/wayvr/display.rs b/src/backend/wayvr/display.rs index 7f52a5e..d1f5892 100644 --- a/src/backend/wayvr/display.rs +++ b/src/backend/wayvr/display.rs @@ -479,7 +479,7 @@ impl Display { 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( &mut manager.state, input::pointer::AxisFrame { @@ -489,8 +489,8 @@ impl Display { smithay::backend::input::AxisRelativeDirection::Identical, ), time: 0, - axis: (0.0, -delta as f64), - v120: Some((0, (delta * -120.0) as i32)), + axis: (delta_x as f64, -delta_y as f64), + v120: Some((0, (delta_y * -120.0) as i32)), stop: (false, false), }, ); diff --git a/src/backend/wayvr/mod.rs b/src/backend/wayvr/mod.rs index ecb0556..74b9d4d 100644 --- a/src/backend/wayvr/mod.rs +++ b/src/backend/wayvr/mod.rs @@ -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) { - display.send_mouse_scroll(&mut self.manager, delta); + display.send_mouse_scroll(&mut self.manager, delta_y, delta_x); } } diff --git a/src/gui/canvas/control.rs b/src/gui/canvas/control.rs index b6c09fb..137e41b 100644 --- a/src/gui/canvas/control.rs +++ b/src/gui/canvas/control.rs @@ -35,7 +35,7 @@ pub(crate) struct Control { pub on_update: Option, pub on_press: Option, pub on_release: Option, - pub on_scroll: Option, + pub on_scroll: Option, pub test_highlight: Option Option>, pub(super) on_render_bg: Option>, diff --git a/src/gui/canvas/mod.rs b/src/gui/canvas/mod.rs index bfc94d0..e23f1d9 100644 --- a/src/gui/canvas/mod.rs +++ b/src/gui/canvas/mod.rs @@ -267,13 +267,13 @@ impl InteractionHandler for Canvas { } } } - 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]; if let Some(idx) = idx { let c = &mut self.controls[idx]; 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); } } } diff --git a/src/gui/modular/button.rs b/src/gui/modular/button.rs index 4066913..1215024 100644 --- a/src/gui/modular/button.rs +++ b/src/gui/modular/button.rs @@ -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 let ModularData::Button(data) = button.state.as_mut().unwrap() else { 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() } else { data.scroll_up.as_ref() diff --git a/src/hid/mod.rs b/src/hid/mod.rs index 4104e69..219b2fe 100644 --- a/src/hid/mod.rs +++ b/src/hid/mod.rs @@ -1,4 +1,4 @@ -use glam::Vec2; +use glam::{IVec2, Vec2}; use idmap::{idmap, IdMap}; use idmap_derive::IntegerId; use input_linux::{ @@ -46,7 +46,7 @@ pub fn initialize() -> Box { pub trait HidProvider { fn mouse_move(&mut self, pos: Vec2); 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 send_key(&self, key: VirtualKey, down: bool); fn set_desktop_extent(&mut self, extent: Vec2); @@ -64,7 +64,7 @@ struct MouseAction { last_requested_pos: Option, pos: Option, button: Option, - scroll: Option, + scroll: Option, } pub struct UInputProvider { @@ -149,7 +149,8 @@ impl UInputProvider { mouse_handle.set_evbit(EventKind::Relative).ok()?; mouse_handle.set_absbit(AbsoluteAxis::X).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()?; for btn in MOUSE_LEFT..=MOUSE_MIDDLE { @@ -193,10 +194,11 @@ impl UInputProvider { 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 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), ]; 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; } } - fn wheel(&mut self, delta: i32) { + fn wheel(&mut self, delta_y: i32, delta_x: i32) { 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 // (allows scrolling on all Chromium-based applications) self.current_action.pos = None; @@ -263,7 +265,7 @@ impl HidProvider for UInputProvider { self.send_button_internal(button.button, button.down); } 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 { fn mouse_move(&mut self, _pos: Vec2) {} 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 send_key(&self, _key: VirtualKey, _down: bool) {} fn set_desktop_extent(&mut self, _extent: Vec2) {} diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index a691dbe..4fb3612 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -516,9 +516,10 @@ impl InteractionHandler for KeyboardBackend { &mut self, app: &mut AppState, 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) { self.canvas.on_left(app, pointer) diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index e4a6c3d..dba6212 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -88,7 +88,6 @@ fn set_next_move(millis_from_now: u64) { } pub struct ScreenInteractionHandler { - next_scroll: Instant, mouse_transform: Affine2, } impl ScreenInteractionHandler { @@ -113,7 +112,6 @@ impl ScreenInteractionHandler { }; ScreenInteractionHandler { - next_scroll: Instant::now(), mouse_transform: transform, } } @@ -152,19 +150,8 @@ impl InteractionHandler for ScreenInteractionHandler { let pos = self.mouse_transform.transform_point2(hit.uv); app.hid_provider.mouse_move(pos); } - fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { - if self.next_scroll > Instant::now() { - 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_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta_y: f32, delta_x: f32) { + app.hid_provider.wheel((delta_y*64.) as i32, (delta_x*64.) as i32) } fn on_left(&mut self, _app: &mut AppState, _hand: usize) {} } diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index ad083ff..95395d9 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -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(); ctx.wayvr .borrow_mut() .data .state - .send_mouse_scroll(ctx.display, delta); + .send_mouse_scroll(ctx.display, delta_y, delta_x); } }