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" >
|
||||
<CheckBox id="align_box" translation="EDIT_MODE.ALIGN_TO_HMD" tooltip_side="bottom" />
|
||||
</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="block_input_box" translation="EDIT_MODE.BLOCK_INPUT" tooltip_side="bottom" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"MOVE_PRESS_AND_DRAG": "Verschieben (drücken & ziehen)",
|
||||
"OPACITY": "Undurchsichtigkeit",
|
||||
"POSITIONING": "Positionierung",
|
||||
"BLOCK_GAME_INPUT": "Spieleingabe blockieren",
|
||||
"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_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.",
|
||||
"POSITIONING": "Positioning",
|
||||
"GLOBAL": "Always visible",
|
||||
"BLOCK_INPUT": "Block game input",
|
||||
"RESIZE_PRESS_AND_DRAG": "Resize (press & drag)",
|
||||
"STEREO_3D_MODE": {
|
||||
"ADJUST_MOUSE": "Adjust mouse",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"MOVE_PRESS_AND_DRAG": "Mover (presionar y arrastrar)",
|
||||
"OPACITY": "Opacidad",
|
||||
"POSITIONING": "Posicionamiento",
|
||||
"BLOCK_GAME_INPUT": "Bloquear entrada del juego",
|
||||
"RESIZE_PRESS_AND_DRAG": "Redimensionar (presionar y arrastrar)",
|
||||
"POS_STATIC": "Estático: Permanece en su lugar y nunca se recentra.",
|
||||
"POS_ANCHORED": "Anclado: Se mueve junto con el resto del conjunto. Predeterminado.",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"POS_HMD": "Segui l'HMD.",
|
||||
"POS_STATIC": "Statico: non fa parte di alcun set, senza recentratura.",
|
||||
"POSITIONING": "Posizionamento",
|
||||
"BLOCK_GAME_INPUT": "Blocca l'input di gioco",
|
||||
"RESIZE_PRESS_AND_DRAG": "Ridimensiona (premi e trascina)",
|
||||
"STEREO_3D_MODE": {
|
||||
"SPLIT_BOTTOM_TOP": "DAL BASSO→IN ALTO",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"MOVE_PRESS_AND_DRAG": "移動(押してドラッグ)",
|
||||
"OPACITY": "不透明度",
|
||||
"POSITIONING": "位置付け",
|
||||
"BLOCK_GAME_INPUT": "ゲームの入力をブロック",
|
||||
"RESIZE_PRESS_AND_DRAG": "サイズ変更(押してドラッグ)",
|
||||
"POS_STATIC": "固定:置かれた場所に留まり、再センタリングされません。",
|
||||
"POS_ANCHORED": "アンカー:セット内の他のウィンドウと共に移動します。デフォルト。",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"MOVE_PRESS_AND_DRAG": "Przesuń (naciśnij i przeciągnij)",
|
||||
"OPACITY": "Przezroczystość",
|
||||
"POSITIONING": "Pozycjonowanie",
|
||||
"BLOCK_INPUT": "Blokuj input z gry",
|
||||
"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_ANCHORED": "Zakotwiczone: Porusza się razem z resztą zestawu. Domyślne.",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"POS_HMD": "跟随头显 (HMD)。",
|
||||
"POS_STATIC": "静态:不属于任何集合,不重新居中。",
|
||||
"POSITIONING": "定位",
|
||||
"BLOCK_GAME_INPUT": "屏蔽游戏输入",
|
||||
"RESIZE_PRESS_AND_DRAG": "调整大小 (按住并拖拽)",
|
||||
"STEREO_3D_MODE": {
|
||||
"SPLIT_BOTTOM_TOP": "下→上",
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::process::{Child, Command};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use glam::{Affine3A, Mat3A, Vec2, Vec3, Vec3A, Vec3Swizzles};
|
||||
use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
|
||||
|
||||
use idmap_derive::IntegerId;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
@@ -209,6 +209,7 @@ pub struct InteractionState {
|
||||
pub hovered_id: Option<OverlayID>,
|
||||
pub next_push: Instant,
|
||||
pub haptics: Option<f32>,
|
||||
pub should_block_input: bool,
|
||||
}
|
||||
|
||||
impl Default for InteractionState {
|
||||
@@ -220,6 +221,7 @@ impl Default for InteractionState {
|
||||
hovered_id: None,
|
||||
next_push: Instant::now(),
|
||||
haptics: None,
|
||||
should_block_input: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,7 +395,7 @@ where
|
||||
for (idx, hit) in hits.iter().enumerate() {
|
||||
populate_lines(
|
||||
lines,
|
||||
&mut app.input_state.pointers[idx],
|
||||
&app.input_state.pointers[idx],
|
||||
hit.0,
|
||||
&app.input_state.hmd,
|
||||
);
|
||||
@@ -471,6 +473,14 @@ where
|
||||
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)]
|
||||
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
|
||||
// send release event to overlay that was originally clicked
|
||||
let pointer = &mut app.input_state.pointers[pointer_idx];
|
||||
if !pointer.now.click
|
||||
&& pointer.before.click
|
||||
&& let Some(clicked_id) = pointer.interaction.clicked_id.take()
|
||||
|
||||
@@ -15,7 +15,6 @@ use wlx_common::config_io;
|
||||
use crate::{
|
||||
backend::input::{Haptics, TrackedDevice, TrackedDeviceRole},
|
||||
state::AppState,
|
||||
windowing::OverlayID,
|
||||
};
|
||||
|
||||
use super::helpers::{Affine3AConvert, OVRError};
|
||||
@@ -143,26 +142,41 @@ impl OpenVrInputSource {
|
||||
input: &mut InputManager,
|
||||
system: &mut SystemManager,
|
||||
app: &mut AppState,
|
||||
watch_id: OverlayID,
|
||||
) {
|
||||
let should_block_input = app.input_state.pointers.iter().any(|p| {
|
||||
p.interaction.hovered_id.is_some_and(|id| {
|
||||
id != watch_id || !app.session.config.block_game_input_ignore_watch
|
||||
})
|
||||
}) && app.session.config.block_game_input;
|
||||
let should_block_input_left = app.input_state.pointers[0].interaction.should_block_input
|
||||
&& 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,
|
||||
ulRestrictedToDevice: 0,
|
||||
ulRestrictedToDevice: self.hands[0].input_hnd.0,
|
||||
ulSecondaryActionSet: 0,
|
||||
unPadding: 0,
|
||||
// the range between 0x01000000 and 0x01FFFFFF overrides game action sets as long as
|
||||
// global input from overlays is enabled in SteamVR developer settings
|
||||
// (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);
|
||||
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();
|
||||
|
||||
app.input_state.pre_update();
|
||||
input_source.update(
|
||||
universe.clone(),
|
||||
&mut input_mgr,
|
||||
&mut system_mgr,
|
||||
&mut app,
|
||||
watch_id,
|
||||
);
|
||||
input_source.update(universe.clone(), &mut input_mgr, &mut system_mgr, &mut app);
|
||||
app.input_state.post_update(&app.session);
|
||||
|
||||
if app
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use libmonado::{ClientState, Monado};
|
||||
use log::{trace, warn};
|
||||
|
||||
use crate::{state::AppState, windowing::OverlayID};
|
||||
use crate::state::AppState;
|
||||
|
||||
pub(super) struct InputBlocker {
|
||||
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 {
|
||||
return; // monado not available
|
||||
};
|
||||
|
||||
let should_block = app.input_state.pointers.iter().any(|p| {
|
||||
p.interaction.hovered_id.is_some_and(|id| {
|
||||
id != watch_id || !app.session.config.block_game_input_ignore_watch
|
||||
})
|
||||
}) && app.session.config.block_game_input;
|
||||
let should_block = app
|
||||
.input_state
|
||||
.pointers
|
||||
.iter()
|
||||
.any(|p| p.interaction.should_block_input)
|
||||
&& app.session.config.block_game_input;
|
||||
|
||||
match (should_block, self.blocked_last_frame) {
|
||||
(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);
|
||||
|
||||
if let Some(ref mut blocker) = blocker {
|
||||
blocker.update(&mut app, watch_id);
|
||||
blocker.update(&mut 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, "align_box", cb_assign_align)?;
|
||||
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(
|
||||
&mut panel,
|
||||
"stereo_full_frame_box",
|
||||
@@ -498,6 +499,11 @@ fn reset_panel(
|
||||
.fetch_component_as::<ComponentCheckbox>("global_box")?;
|
||||
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
|
||||
.state
|
||||
.pos
|
||||
@@ -601,6 +607,14 @@ const fn cb_assign_global(_app: &mut AppState, owc: &mut OverlayWindowConfig, gl
|
||||
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(
|
||||
_app: &mut AppState,
|
||||
owc: &mut OverlayWindowConfig,
|
||||
|
||||
@@ -76,6 +76,7 @@ pub struct OverlayWindowState {
|
||||
pub curvature: Option<f32>,
|
||||
pub additive: bool,
|
||||
pub saved_transform: Option<Affine3A>,
|
||||
pub block_input: bool,
|
||||
}
|
||||
|
||||
impl Default for OverlayWindowState {
|
||||
@@ -89,6 +90,7 @@ impl Default for OverlayWindowState {
|
||||
transform: Affine3A::IDENTITY,
|
||||
additive: false,
|
||||
saved_transform: None,
|
||||
block_input: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user