input blocking improvements (#399)
* move input blocking hover logic into InteractionState * add per-window input blocking setting * OpenVR: per-hand input blocking * move block_input setting into OverlayWindowState
This commit is contained in:
@@ -72,8 +72,9 @@
|
|||||||
<div id="pos_align_to_hmd" >
|
<div id="pos_align_to_hmd" >
|
||||||
<CheckBox id="align_box" translation="EDIT_MODE.ALIGN_TO_HMD" tooltip_side="bottom" />
|
<CheckBox id="align_box" translation="EDIT_MODE.ALIGN_TO_HMD" tooltip_side="bottom" />
|
||||||
</div>
|
</div>
|
||||||
<div id="pos_global">
|
<div id="pos_global" gap="16" justify_content="center" align_items="center">
|
||||||
<CheckBox id="global_box" translation="EDIT_MODE.GLOBAL" tooltip_side="bottom" />
|
<CheckBox id="global_box" translation="EDIT_MODE.GLOBAL" tooltip_side="bottom" />
|
||||||
|
<CheckBox id="block_input_box" translation="EDIT_MODE.BLOCK_INPUT" tooltip_side="bottom" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"MOVE_PRESS_AND_DRAG": "Verschieben (drücken & ziehen)",
|
"MOVE_PRESS_AND_DRAG": "Verschieben (drücken & ziehen)",
|
||||||
"OPACITY": "Undurchsichtigkeit",
|
"OPACITY": "Undurchsichtigkeit",
|
||||||
"POSITIONING": "Positionierung",
|
"POSITIONING": "Positionierung",
|
||||||
|
"BLOCK_GAME_INPUT": "Spieleingabe blockieren",
|
||||||
"RESIZE_PRESS_AND_DRAG": "Größe ändern (gedrückt halten & ziehen)",
|
"RESIZE_PRESS_AND_DRAG": "Größe ändern (gedrückt halten & ziehen)",
|
||||||
"POS_STATIC": "Statisch: Bleibt an Ort und Stelle und wird niemals neu zentriert.",
|
"POS_STATIC": "Statisch: Bleibt an Ort und Stelle und wird niemals neu zentriert.",
|
||||||
"POS_ANCHORED": "Verankert: Bewegt sich zusammen mit dem Rest des Sets. Standard.",
|
"POS_ANCHORED": "Verankert: Bewegt sich zusammen mit dem Rest des Sets. Standard.",
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
"POS_STATIC": "Static: Not part of any set, no recenter.",
|
"POS_STATIC": "Static: Not part of any set, no recenter.",
|
||||||
"POSITIONING": "Positioning",
|
"POSITIONING": "Positioning",
|
||||||
"GLOBAL": "Always visible",
|
"GLOBAL": "Always visible",
|
||||||
|
"BLOCK_INPUT": "Block game input",
|
||||||
"RESIZE_PRESS_AND_DRAG": "Resize (press & drag)",
|
"RESIZE_PRESS_AND_DRAG": "Resize (press & drag)",
|
||||||
"STEREO_3D_MODE": {
|
"STEREO_3D_MODE": {
|
||||||
"ADJUST_MOUSE": "Adjust mouse",
|
"ADJUST_MOUSE": "Adjust mouse",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"MOVE_PRESS_AND_DRAG": "Mover (presionar y arrastrar)",
|
"MOVE_PRESS_AND_DRAG": "Mover (presionar y arrastrar)",
|
||||||
"OPACITY": "Opacidad",
|
"OPACITY": "Opacidad",
|
||||||
"POSITIONING": "Posicionamiento",
|
"POSITIONING": "Posicionamiento",
|
||||||
|
"BLOCK_GAME_INPUT": "Bloquear entrada del juego",
|
||||||
"RESIZE_PRESS_AND_DRAG": "Redimensionar (presionar y arrastrar)",
|
"RESIZE_PRESS_AND_DRAG": "Redimensionar (presionar y arrastrar)",
|
||||||
"POS_STATIC": "Estático: Permanece en su lugar y nunca se recentra.",
|
"POS_STATIC": "Estático: Permanece en su lugar y nunca se recentra.",
|
||||||
"POS_ANCHORED": "Anclado: Se mueve junto con el resto del conjunto. Predeterminado.",
|
"POS_ANCHORED": "Anclado: Se mueve junto con el resto del conjunto. Predeterminado.",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"POS_HMD": "Segui l'HMD.",
|
"POS_HMD": "Segui l'HMD.",
|
||||||
"POS_STATIC": "Statico: non fa parte di alcun set, senza recentratura.",
|
"POS_STATIC": "Statico: non fa parte di alcun set, senza recentratura.",
|
||||||
"POSITIONING": "Posizionamento",
|
"POSITIONING": "Posizionamento",
|
||||||
|
"BLOCK_GAME_INPUT": "Blocca l'input di gioco",
|
||||||
"RESIZE_PRESS_AND_DRAG": "Ridimensiona (premi e trascina)",
|
"RESIZE_PRESS_AND_DRAG": "Ridimensiona (premi e trascina)",
|
||||||
"STEREO_3D_MODE": {
|
"STEREO_3D_MODE": {
|
||||||
"SPLIT_BOTTOM_TOP": "DAL BASSO→IN ALTO",
|
"SPLIT_BOTTOM_TOP": "DAL BASSO→IN ALTO",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"MOVE_PRESS_AND_DRAG": "移動(押してドラッグ)",
|
"MOVE_PRESS_AND_DRAG": "移動(押してドラッグ)",
|
||||||
"OPACITY": "不透明度",
|
"OPACITY": "不透明度",
|
||||||
"POSITIONING": "位置付け",
|
"POSITIONING": "位置付け",
|
||||||
|
"BLOCK_GAME_INPUT": "ゲームの入力をブロック",
|
||||||
"RESIZE_PRESS_AND_DRAG": "サイズ変更(押してドラッグ)",
|
"RESIZE_PRESS_AND_DRAG": "サイズ変更(押してドラッグ)",
|
||||||
"POS_STATIC": "固定:置かれた場所に留まり、再センタリングされません。",
|
"POS_STATIC": "固定:置かれた場所に留まり、再センタリングされません。",
|
||||||
"POS_ANCHORED": "アンカー:セット内の他のウィンドウと共に移動します。デフォルト。",
|
"POS_ANCHORED": "アンカー:セット内の他のウィンドウと共に移動します。デフォルト。",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"MOVE_PRESS_AND_DRAG": "Przesuń (naciśnij i przeciągnij)",
|
"MOVE_PRESS_AND_DRAG": "Przesuń (naciśnij i przeciągnij)",
|
||||||
"OPACITY": "Przezroczystość",
|
"OPACITY": "Przezroczystość",
|
||||||
"POSITIONING": "Pozycjonowanie",
|
"POSITIONING": "Pozycjonowanie",
|
||||||
|
"BLOCK_INPUT": "Blokuj input z gry",
|
||||||
"RESIZE_PRESS_AND_DRAG": "Zmień rozmiar (naciśnij i przeciągnij)",
|
"RESIZE_PRESS_AND_DRAG": "Zmień rozmiar (naciśnij i przeciągnij)",
|
||||||
"POS_STATIC": "Statyczne: Pozostaje w miejscu i nigdy nie jest ponownie wyśrodkowywane.",
|
"POS_STATIC": "Statyczne: Pozostaje w miejscu i nigdy nie jest ponownie wyśrodkowywane.",
|
||||||
"POS_ANCHORED": "Zakotwiczone: Porusza się razem z resztą zestawu. Domyślne.",
|
"POS_ANCHORED": "Zakotwiczone: Porusza się razem z resztą zestawu. Domyślne.",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
"POS_HMD": "跟随头显 (HMD)。",
|
"POS_HMD": "跟随头显 (HMD)。",
|
||||||
"POS_STATIC": "静态:不属于任何集合,不重新居中。",
|
"POS_STATIC": "静态:不属于任何集合,不重新居中。",
|
||||||
"POSITIONING": "定位",
|
"POSITIONING": "定位",
|
||||||
|
"BLOCK_GAME_INPUT": "屏蔽游戏输入",
|
||||||
"RESIZE_PRESS_AND_DRAG": "调整大小 (按住并拖拽)",
|
"RESIZE_PRESS_AND_DRAG": "调整大小 (按住并拖拽)",
|
||||||
"STEREO_3D_MODE": {
|
"STEREO_3D_MODE": {
|
||||||
"SPLIT_BOTTOM_TOP": "下→上",
|
"SPLIT_BOTTOM_TOP": "下→上",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::process::{Child, Command};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use glam::{Affine3A, Mat3A, Vec2, Vec3, Vec3A, Vec3Swizzles};
|
use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
||||||
|
|
||||||
use idmap_derive::IntegerId;
|
use idmap_derive::IntegerId;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
@@ -209,6 +209,7 @@ pub struct InteractionState {
|
|||||||
pub hovered_id: Option<OverlayID>,
|
pub hovered_id: Option<OverlayID>,
|
||||||
pub next_push: Instant,
|
pub next_push: Instant,
|
||||||
pub haptics: Option<f32>,
|
pub haptics: Option<f32>,
|
||||||
|
pub should_block_input: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for InteractionState {
|
impl Default for InteractionState {
|
||||||
@@ -220,6 +221,7 @@ impl Default for InteractionState {
|
|||||||
hovered_id: None,
|
hovered_id: None,
|
||||||
next_push: Instant::now(),
|
next_push: Instant::now(),
|
||||||
haptics: None,
|
haptics: None,
|
||||||
|
should_block_input: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +395,7 @@ where
|
|||||||
for (idx, hit) in hits.iter().enumerate() {
|
for (idx, hit) in hits.iter().enumerate() {
|
||||||
populate_lines(
|
populate_lines(
|
||||||
lines,
|
lines,
|
||||||
&mut app.input_state.pointers[idx],
|
&app.input_state.pointers[idx],
|
||||||
hit.0,
|
hit.0,
|
||||||
&app.input_state.hmd,
|
&app.input_state.hmd,
|
||||||
);
|
);
|
||||||
@@ -471,6 +473,14 @@ where
|
|||||||
hit.primary = true;
|
hit.primary = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pointer.interaction.should_block_input = hovered
|
||||||
|
.config
|
||||||
|
.active_state
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |state| state.block_input)
|
||||||
|
&& (hovered.config.name.as_ref() != WATCH_NAME
|
||||||
|
|| !app.session.config.block_game_input_ignore_watch);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("Hit: {} {:?}", hovered.config.name, hit);
|
log::trace!("Hit: {} {:?}", hovered.config.name, hit);
|
||||||
|
|
||||||
@@ -544,9 +554,11 @@ fn handle_no_hit<O>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pointer = &mut app.input_state.pointers[pointer_idx];
|
||||||
|
pointer.interaction.should_block_input = false;
|
||||||
|
|
||||||
// in case click released while not aiming at anything
|
// in case click released while not aiming at anything
|
||||||
// send release event to overlay that was originally clicked
|
// send release event to overlay that was originally clicked
|
||||||
let pointer = &mut app.input_state.pointers[pointer_idx];
|
|
||||||
if !pointer.now.click
|
if !pointer.now.click
|
||||||
&& pointer.before.click
|
&& pointer.before.click
|
||||||
&& let Some(clicked_id) = pointer.interaction.clicked_id.take()
|
&& let Some(clicked_id) = pointer.interaction.clicked_id.take()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use wlx_common::config_io;
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::input::{Haptics, TrackedDevice, TrackedDeviceRole},
|
backend::input::{Haptics, TrackedDevice, TrackedDeviceRole},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::OverlayID,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::helpers::{Affine3AConvert, OVRError};
|
use super::helpers::{Affine3AConvert, OVRError};
|
||||||
@@ -143,26 +142,41 @@ impl OpenVrInputSource {
|
|||||||
input: &mut InputManager,
|
input: &mut InputManager,
|
||||||
system: &mut SystemManager,
|
system: &mut SystemManager,
|
||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
watch_id: OverlayID,
|
|
||||||
) {
|
) {
|
||||||
let should_block_input = app.input_state.pointers.iter().any(|p| {
|
let should_block_input_left = app.input_state.pointers[0].interaction.should_block_input
|
||||||
p.interaction.hovered_id.is_some_and(|id| {
|
&& app.session.config.block_game_input;
|
||||||
id != watch_id || !app.session.config.block_game_input_ignore_watch
|
|
||||||
})
|
|
||||||
}) && app.session.config.block_game_input;
|
|
||||||
|
|
||||||
let aas = ActiveActionSet(ovr_overlay::sys::VRActiveActionSet_t {
|
let should_block_input_right = app.input_state.pointers[1].interaction.should_block_input
|
||||||
|
&& app.session.config.block_game_input;
|
||||||
|
|
||||||
|
let aas_left = ActiveActionSet(ovr_overlay::sys::VRActiveActionSet_t {
|
||||||
ulActionSet: self.set_hnd.0,
|
ulActionSet: self.set_hnd.0,
|
||||||
ulRestrictedToDevice: 0,
|
ulRestrictedToDevice: self.hands[0].input_hnd.0,
|
||||||
ulSecondaryActionSet: 0,
|
ulSecondaryActionSet: 0,
|
||||||
unPadding: 0,
|
unPadding: 0,
|
||||||
// the range between 0x01000000 and 0x01FFFFFF overrides game action sets as long as
|
// the range between 0x01000000 and 0x01FFFFFF overrides game action sets as long as
|
||||||
// global input from overlays is enabled in SteamVR developer settings
|
// global input from overlays is enabled in SteamVR developer settings
|
||||||
// (taken from https://github.com/ValveSoftware/openvr/issues/1236)
|
// (taken from https://github.com/ValveSoftware/openvr/issues/1236)
|
||||||
nPriority: if should_block_input { 0x01000000 } else { 0x0 },
|
nPriority: if should_block_input_left {
|
||||||
|
0x01000000
|
||||||
|
} else {
|
||||||
|
0x0
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = input.update_actions(&mut [aas]);
|
let aas_right = ActiveActionSet(ovr_overlay::sys::VRActiveActionSet_t {
|
||||||
|
ulActionSet: self.set_hnd.0,
|
||||||
|
ulRestrictedToDevice: self.hands[1].input_hnd.0,
|
||||||
|
ulSecondaryActionSet: 0,
|
||||||
|
unPadding: 0,
|
||||||
|
nPriority: if should_block_input_right {
|
||||||
|
0x01000000
|
||||||
|
} else {
|
||||||
|
0x0
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = input.update_actions(&mut [aas_left, aas_right]);
|
||||||
|
|
||||||
let devices = system.get_device_to_absolute_tracking_pose(universe.clone(), 0.005);
|
let devices = system.get_device_to_absolute_tracking_pose(universe.clone(), 0.005);
|
||||||
app.input_state.hmd = devices[0].mDeviceToAbsoluteTracking.to_affine();
|
app.input_state.hmd = devices[0].mDeviceToAbsoluteTracking.to_affine();
|
||||||
|
|||||||
@@ -241,13 +241,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
let universe = playspace.get_universe();
|
let universe = playspace.get_universe();
|
||||||
|
|
||||||
app.input_state.pre_update();
|
app.input_state.pre_update();
|
||||||
input_source.update(
|
input_source.update(universe.clone(), &mut input_mgr, &mut system_mgr, &mut app);
|
||||||
universe.clone(),
|
|
||||||
&mut input_mgr,
|
|
||||||
&mut system_mgr,
|
|
||||||
&mut app,
|
|
||||||
watch_id,
|
|
||||||
);
|
|
||||||
app.input_state.post_update(&app.session);
|
app.input_state.post_update(&app.session);
|
||||||
|
|
||||||
if app
|
if app
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use libmonado::{ClientState, Monado};
|
use libmonado::{ClientState, Monado};
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
|
|
||||||
use crate::{state::AppState, windowing::OverlayID};
|
use crate::state::AppState;
|
||||||
|
|
||||||
pub(super) struct InputBlocker {
|
pub(super) struct InputBlocker {
|
||||||
blocked_last_frame: bool,
|
blocked_last_frame: bool,
|
||||||
@@ -14,16 +14,17 @@ impl InputBlocker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, app: &mut AppState, watch_id: OverlayID) {
|
pub fn update(&mut self, app: &mut AppState) {
|
||||||
let Some(monado) = &mut app.monado else {
|
let Some(monado) = &mut app.monado else {
|
||||||
return; // monado not available
|
return; // monado not available
|
||||||
};
|
};
|
||||||
|
|
||||||
let should_block = app.input_state.pointers.iter().any(|p| {
|
let should_block = app
|
||||||
p.interaction.hovered_id.is_some_and(|id| {
|
.input_state
|
||||||
id != watch_id || !app.session.config.block_game_input_ignore_watch
|
.pointers
|
||||||
})
|
.iter()
|
||||||
}) && app.session.config.block_game_input;
|
.any(|p| p.interaction.should_block_input)
|
||||||
|
&& app.session.config.block_game_input;
|
||||||
|
|
||||||
match (should_block, self.blocked_last_frame) {
|
match (should_block, self.blocked_last_frame) {
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
app.input_state.post_update(&app.session);
|
app.input_state.post_update(&app.session);
|
||||||
|
|
||||||
if let Some(ref mut blocker) = blocker {
|
if let Some(ref mut blocker) = blocker {
|
||||||
blocker.update(&mut app, watch_id);
|
blocker.update(&mut app);
|
||||||
}
|
}
|
||||||
|
|
||||||
if app
|
if app
|
||||||
|
|||||||
@@ -432,6 +432,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
|||||||
set_up_checkbox(&mut panel, "additive_box", cb_assign_additive)?;
|
set_up_checkbox(&mut panel, "additive_box", cb_assign_additive)?;
|
||||||
set_up_checkbox(&mut panel, "align_box", cb_assign_align)?;
|
set_up_checkbox(&mut panel, "align_box", cb_assign_align)?;
|
||||||
set_up_checkbox(&mut panel, "global_box", cb_assign_global)?;
|
set_up_checkbox(&mut panel, "global_box", cb_assign_global)?;
|
||||||
|
set_up_checkbox(&mut panel, "block_input_box", cb_assign_block_input)?;
|
||||||
set_up_checkbox(
|
set_up_checkbox(
|
||||||
&mut panel,
|
&mut panel,
|
||||||
"stereo_full_frame_box",
|
"stereo_full_frame_box",
|
||||||
@@ -498,6 +499,11 @@ fn reset_panel(
|
|||||||
.fetch_component_as::<ComponentCheckbox>("global_box")?;
|
.fetch_component_as::<ComponentCheckbox>("global_box")?;
|
||||||
c.set_checked(&mut common, owc.global);
|
c.set_checked(&mut common, owc.global);
|
||||||
|
|
||||||
|
let c = panel
|
||||||
|
.parser_state
|
||||||
|
.fetch_component_as::<ComponentCheckbox>("block_input_box")?;
|
||||||
|
c.set_checked(&mut common, state.block_input);
|
||||||
|
|
||||||
panel
|
panel
|
||||||
.state
|
.state
|
||||||
.pos
|
.pos
|
||||||
@@ -601,6 +607,14 @@ const fn cb_assign_global(_app: &mut AppState, owc: &mut OverlayWindowConfig, gl
|
|||||||
owc.global = global;
|
owc.global = global;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn cb_assign_block_input(
|
||||||
|
_app: &mut AppState,
|
||||||
|
owc: &mut OverlayWindowConfig,
|
||||||
|
block_input: bool,
|
||||||
|
) {
|
||||||
|
owc.active_state.as_mut().unwrap().block_input = block_input;
|
||||||
|
}
|
||||||
|
|
||||||
fn cb_assign_stereo_full_frame(
|
fn cb_assign_stereo_full_frame(
|
||||||
_app: &mut AppState,
|
_app: &mut AppState,
|
||||||
owc: &mut OverlayWindowConfig,
|
owc: &mut OverlayWindowConfig,
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ pub struct OverlayWindowState {
|
|||||||
pub curvature: Option<f32>,
|
pub curvature: Option<f32>,
|
||||||
pub additive: bool,
|
pub additive: bool,
|
||||||
pub saved_transform: Option<Affine3A>,
|
pub saved_transform: Option<Affine3A>,
|
||||||
|
pub block_input: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OverlayWindowState {
|
impl Default for OverlayWindowState {
|
||||||
@@ -89,6 +90,7 @@ impl Default for OverlayWindowState {
|
|||||||
transform: Affine3A::IDENTITY,
|
transform: Affine3A::IDENTITY,
|
||||||
additive: false,
|
additive: false,
|
||||||
saved_transform: None,
|
saved_transform: None,
|
||||||
|
block_input: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user