diff --git a/src/backend/input.rs b/src/backend/input.rs index a5d8a5a..17f1dfc 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -198,6 +198,7 @@ pub struct PointerState { pub space_rotate: bool, pub click_modifier_right: bool, pub click_modifier_middle: bool, + pub move_mouse: bool, } #[derive(Debug, Clone, Copy, Default)] diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs index eeef579..37bcbc0 100644 --- a/src/backend/openvr/input.rs +++ b/src/backend/openvr/input.rs @@ -39,6 +39,7 @@ const PATH_SPACE_DRAG: &str = "/actions/default/in/SpaceDrag"; const PATH_SPACE_ROTATE: &str = "/actions/default/in/SpaceRotate"; const PATH_CLICK_MODIFIER_RIGHT: &str = "/actions/default/in/ClickModifierRight"; const PATH_CLICK_MODIFIER_MIDDLE: &str = "/actions/default/in/ClickModifierMiddle"; +const PATH_MOVE_MOUSE: &str = "/actions/default/in/MoveMouse"; const INPUT_ANY: InputValueHandle = InputValueHandle(ovr_overlay::sys::k_ulInvalidInputValueHandle); @@ -54,6 +55,7 @@ pub(super) struct OpenVrInputSource { space_rotate_hnd: ActionHandle, click_modifier_right_hnd: ActionHandle, click_modifier_middle_hnd: ActionHandle, + move_mouse_hnd: ActionHandle, } pub(super) struct OpenVrHandSource { @@ -77,6 +79,7 @@ impl OpenVrInputSource { let space_rotate_hnd = input.get_action_handle(PATH_SPACE_ROTATE)?; let click_modifier_right_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_RIGHT)?; let click_modifier_middle_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_MIDDLE)?; + let move_mouse_hnd = input.get_action_handle(PATH_MOVE_MOUSE)?; let input_hnd: Vec = INPUT_SOURCES .iter() @@ -112,6 +115,7 @@ impl OpenVrInputSource { space_rotate_hnd, click_modifier_right_hnd, click_modifier_middle_hnd, + move_mouse_hnd, hands, }) } @@ -212,6 +216,11 @@ impl OpenVrInputSource { .map(|x| x.0.bState) .unwrap_or(false); + app_hand.now.move_mouse = input + .get_digital_action_data(self.move_mouse_hnd, hand.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + app_hand.now.scroll = input .get_analog_action_data(self.scroll_hnd, hand.input_hnd) .map(|x| x.0.y) diff --git a/src/backend/openxr/input.rs b/src/backend/openxr/input.rs index 6bc0e35..e452036 100644 --- a/src/backend/openxr/input.rs +++ b/src/backend/openxr/input.rs @@ -53,6 +53,7 @@ pub(super) struct OpenXrHandSource { action_show_hide: xr::Action, action_click_modifier_right: xr::Action, action_click_modifier_middle: xr::Action, + action_move_mouse: xr::Action, action_haptics: xr::Action, } @@ -194,6 +195,12 @@ impl OpenXrHand { .state(&xr.session, xr::Path::NULL)? .current_state; + pointer.now.move_mouse = self + .source + .action_move_mouse + .state(&xr.session, xr::Path::NULL)? + .current_state; + Ok(()) } } @@ -242,6 +249,11 @@ impl OpenXrHandSource { &format!("{} hand middle click modifier", side), &[], )?; + let action_move_mouse = action_set.create_action::( + &format!("{}_move_mouse", side), + &format!("{} hand mouse move", side), + &[], + )?; let action_haptics = action_set.create_action::( &format!("{}_haptics", side), &format!("{} hand haptics", side), @@ -257,6 +269,7 @@ impl OpenXrHandSource { action_show_hide, action_click_modifier_right, action_click_modifier_middle, + action_move_mouse, action_haptics, }) } @@ -359,6 +372,14 @@ fn suggest_bindings( &hands[1].action_click_modifier_middle, instance.string_to_path("/user/hand/right/input/a/touch")?, ), + xr::Binding::new( + &hands[0].action_move_mouse, + instance.string_to_path("/user/hand/left/input/trigger/touch")?, + ), + xr::Binding::new( + &hands[1].action_move_mouse, + instance.string_to_path("/user/hand/right/input/trigger/touch")?, + ), xr::Binding::new( &hands[0].action_haptics, instance.string_to_path("/user/hand/left/output/haptic")?, @@ -434,6 +455,14 @@ fn suggest_bindings( &hands[1].action_click_modifier_middle, instance.string_to_path("/user/hand/right/input/a/touch")?, ), + xr::Binding::new( + &hands[0].action_move_mouse, + instance.string_to_path("/user/hand/left/input/trigger/touch")?, + ), + xr::Binding::new( + &hands[1].action_move_mouse, + instance.string_to_path("/user/hand/right/input/trigger/touch")?, + ), xr::Binding::new( &hands[0].action_haptics, instance.string_to_path("/user/hand/left/output/haptic")?, diff --git a/src/config.rs b/src/config.rs index 2116da7..392bf78 100644 --- a/src/config.rs +++ b/src/config.rs @@ -223,6 +223,9 @@ pub struct GeneralConfig { #[serde(default = "def_true")] pub realign_on_showhide: bool, + + #[serde(default = "def_false")] + pub focus_follows_mouse_mode: bool, } impl GeneralConfig { diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index bafd911..4602828 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -90,7 +90,9 @@ impl InteractionHandler for ScreenInteractionHandler { fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option { #[cfg(debug_assertions)] log::trace!("Hover: {:?}", hit.uv); - if self.next_move < Instant::now() { + if self.next_move < Instant::now() && + (!app.session.config.focus_follows_mouse_mode + || app.input_state.pointers[hit.pointer].now.move_mouse) { let pos = self.mouse_transform.transform_point2(hit.uv); app.hid_provider.mouse_move(pos); } @@ -112,6 +114,7 @@ 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() { diff --git a/src/res/actions.json b/src/res/actions.json index 64ee4ae..8fd0c4c 100644 --- a/src/res/actions.json +++ b/src/res/actions.json @@ -35,6 +35,11 @@ "type": "boolean", "requirement": "optional" }, + { + "name": "/actions/default/in/MoveMouse", + "type": "boolean", + "requirement": "optional" + }, { "name": "/actions/default/in/SpaceDrag", "type": "boolean", diff --git a/src/res/actions_binding_knuckles.json b/src/res/actions_binding_knuckles.json index df896e7..d77595b 100644 --- a/src/res/actions_binding_knuckles.json +++ b/src/res/actions_binding_knuckles.json @@ -67,6 +67,9 @@ "inputs" : { "click" : { "output" : "/actions/default/in/click" + }, + "touch": { + "output": "/actions/default/in/movemouse" } }, "mode" : "button", @@ -80,6 +83,9 @@ "inputs" : { "click" : { "output" : "/actions/default/in/click" + }, + "touch": { + "output": "/actions/default/in/movemouse" } }, "mode" : "button", diff --git a/src/res/actions_binding_oculus.json b/src/res/actions_binding_oculus.json index 5f25202..2602932 100644 --- a/src/res/actions_binding_oculus.json +++ b/src/res/actions_binding_oculus.json @@ -67,6 +67,9 @@ "inputs" : { "click" : { "output" : "/actions/default/in/click" + }, + "touch": { + "output": "/actions/default/in/movemouse" } }, "mode": "button", @@ -76,6 +79,9 @@ "inputs" : { "click" : { "output" : "/actions/default/in/click" + }, + "touch": { + "output": "/actions/default/in/movemouse" } }, "mode": "button", diff --git a/src/res/config.yaml b/src/res/config.yaml index 52bf9bb..4d5f544 100644 --- a/src/res/config.yaml +++ b/src/res/config.yaml @@ -19,3 +19,9 @@ allow_sliding: true # Enable / disable realigning the working set windows when they are shown/hidden # Default: true realign_on_showhide: true + +# When enabled, the mouse pointer will not be moved on the screen, unless the trigger is touched +# allowing for moving both pointers off the screens to the keyboard, while keeping the cursor position +# unchanged, for when the desktop is configured to move the focus with the mouse cursor +# Default: false +focus_follows_mouse_mode: false