add option to block poses when using keyboard (OpenXR only)

This commit is contained in:
Sapphire
2026-02-04 13:03:34 -06:00
committed by galister
parent d398e6fb5a
commit d713302d0d
7 changed files with 60 additions and 25 deletions

View File

@@ -36,6 +36,8 @@
"BLOCK_GAME_INPUT_HELP": "Blocks all input when an overlay is hovered",
"BLOCK_GAME_INPUT_IGNORE_WATCH": "Ignore watch when blocking input",
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Do not block input when watch is hovered",
"BLOCK_POSES_ON_KBD_INTERACTION": "Block poses when interacting with keyboard",
"BLOCK_POSES_ON_KBD_INTERACTION_HELP": "Blocks the game from receiving poses when the keyboard is hovered and 'Block game input' is enabled",
"CAPTURE_METHOD": "Wayland screen capture",
"CAPTURE_METHOD_HELP": "Try changing this if you are\nexperiencing black or glitchy screens",
"CLEAR_PIPEWIRE_TOKENS": "Clear PipeWire tokens",

View File

@@ -227,6 +227,7 @@ enum SettingType {
LeftHandedMouse,
BlockGameInput,
BlockGameInputIgnoreWatch,
BlockPosesOnKbdInteraction,
SpaceDragMultiplier,
UseSkybox,
UsePassthrough,
@@ -260,6 +261,7 @@ impl SettingType {
Self::LeftHandedMouse => &mut config.left_handed_mouse,
Self::BlockGameInput => &mut config.block_game_input,
Self::BlockGameInputIgnoreWatch => &mut config.block_game_input_ignore_watch,
Self::BlockPosesOnKbdInteraction => &mut config.block_poses_on_kbd_interaction,
Self::UseSkybox => &mut config.use_skybox,
Self::UsePassthrough => &mut config.use_passthrough,
Self::ScreenRenderDown => &mut config.screen_render_down,
@@ -363,6 +365,7 @@ impl SettingType {
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
Self::BlockPosesOnKbdInteraction => Ok("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION"),
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
@@ -390,6 +393,7 @@ impl SettingType {
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
Self::BlockPosesOnKbdInteraction => Some("APP_SETTINGS.BLOCK_POSES_ON_KBD_INTERACTION_HELP"),
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
@@ -726,6 +730,7 @@ impl<T> TabSettings<T> {
slider_f32!(mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5);
checkbox!(mp, c, SettingType::BlockGameInput);
checkbox!(mp, c, SettingType::BlockGameInputIgnoreWatch);
checkbox!(mp, c, SettingType::BlockPosesOnKbdInteraction);
}
TabNameEnum::Controls => {
let c = category!(mp, root, "APP_SETTINGS.CONTROLS", "dashboard/controller.svg")?;

View File

@@ -13,6 +13,7 @@ use wlx_common::windowing::{OverlayWindowState, Positioning};
use crate::backend::task::{InputTask, OverlayTask};
use crate::overlays::anchor::{ANCHOR_NAME, GRAB_HELP_NAME};
use crate::overlays::keyboard::KEYBOARD_NAME;
use crate::overlays::watch::WATCH_NAME;
use crate::state::{AppSession, AppState};
use crate::subsystem::hid::WheelDelta;
@@ -210,6 +211,7 @@ pub struct InteractionState {
pub next_push: Instant,
pub haptics: Option<f32>,
pub should_block_input: bool,
pub should_block_poses: bool,
}
impl Default for InteractionState {
@@ -222,6 +224,7 @@ impl Default for InteractionState {
next_push: Instant::now(),
haptics: None,
should_block_input: false,
should_block_poses: false,
}
}
}
@@ -473,13 +476,18 @@ 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);
if let Some(state) = hovered.config.active_state.as_ref() {
pointer.interaction.should_block_input = state.block_input
&& (hovered.config.name.as_ref() != WATCH_NAME
|| !app.session.config.block_game_input_ignore_watch);
pointer.interaction.should_block_poses = state.block_input
&& app.session.config.block_poses_on_kbd_interaction
&& hovered.config.name.as_ref() == KEYBOARD_NAME;
} else {
pointer.interaction.should_block_input = false;
pointer.interaction.should_block_poses = false;
}
#[cfg(debug_assertions)]
log::trace!("Hit: {} {:?}", hovered.config.name, hit);
@@ -556,6 +564,7 @@ fn handle_no_hit<O>(
let pointer = &mut app.input_state.pointers[pointer_idx];
pointer.interaction.should_block_input = false;
pointer.interaction.should_block_poses = false;
// in case click released while not aiming at anything
// send release event to overlay that was originally clicked

View File

@@ -5,14 +5,16 @@ use crate::state::AppState;
pub(super) struct InputBlocker {
use_io_blocks: bool,
blocked_last_frame: bool,
inputs_blocked_last_frame: bool,
poses_blocked_last_frame: bool,
}
impl InputBlocker {
pub fn new(monado: &Monado) -> Self {
Self {
use_io_blocks: monado.get_api_version() >= Version::new(1, 6, 0),
blocked_last_frame: false,
inputs_blocked_last_frame: false,
poses_blocked_last_frame: false,
}
}
@@ -21,29 +23,36 @@ impl InputBlocker {
return; // monado not available
};
let should_block = app
let should_block_inputs = 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) => {
let should_block_poses = app
.input_state
.pointers
.iter()
.any(|p| p.interaction.should_block_poses)
&& app.session.config.block_poses_on_kbd_interaction;
if should_block_inputs != self.inputs_blocked_last_frame
|| should_block_poses != self.poses_blocked_last_frame
{
if should_block_inputs {
trace!("Blocking input");
self.block_inputs(monado, true);
}
(false, true) => {
} else {
trace!("Unblocking input");
self.block_inputs(monado, false);
}
_ => {}
self.block_inputs(monado, should_block_inputs, should_block_poses);
}
self.blocked_last_frame = should_block;
self.inputs_blocked_last_frame = should_block_inputs;
self.poses_blocked_last_frame = should_block_poses;
}
fn block_inputs(&self, monado: &mut Monado, block: bool) {
fn block_inputs(&self, monado: &mut Monado, block_inputs: bool, block_poses: bool) {
match monado.clients() {
Ok(clients) => {
for mut client in clients {
@@ -69,13 +78,14 @@ impl InputBlocker {
if state.contains(ClientState::ClientSessionVisible) {
let r = if self.use_io_blocks {
client.set_io_blocks(if block {
BlockFlags::BlockInputs.into()
} else {
BlockFlags::None.into()
})
let flags = match (block_inputs, block_poses) {
(true, true) => BlockFlags::BlockPoses | BlockFlags::BlockInputs,
(true, false) => BlockFlags::BlockInputs.into(),
(false, _) => BlockFlags::None.into(),
};
client.set_io_blocks(flags)
} else {
client.set_io_active(!block)
client.set_io_active(!block_inputs)
};
if let Err(e) = r {
warn!("Failed to set io active for client: {e}");

View File

@@ -126,6 +126,7 @@ pub struct AutoSettings {
pub left_handed_mouse: bool,
pub block_game_input: bool,
pub block_game_input_ignore_watch: bool,
pub block_poses_on_kbd_interaction: bool,
pub space_drag_multiplier: f32,
pub use_skybox: bool,
pub use_passthrough: bool,
@@ -174,6 +175,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
left_handed_mouse: config.left_handed_mouse,
block_game_input: config.block_game_input,
block_game_input_ignore_watch: config.block_game_input_ignore_watch,
block_poses_on_kbd_interaction: config.block_poses_on_kbd_interaction,
space_drag_multiplier: config.space_drag_multiplier,
use_skybox: config.use_skybox,
use_passthrough: config.use_passthrough,

View File

@@ -102,6 +102,10 @@
## Do not block input when the watch is hovered.
#block_game_input_ignore_watch: true
## Monado/WiVRn only. Do not send hand poses when interacting with the
## keyboard.
#block_poses_on_kbd_interaction: true
## How fast to drag when the space drag feature is activated
#space_drag_multiplier: 1.0

View File

@@ -251,6 +251,9 @@ pub struct GeneralConfig {
#[serde(default = "def_true")]
pub block_game_input_ignore_watch: bool,
#[serde(default = "def_true")]
pub block_poses_on_kbd_interaction: bool,
#[serde(default = "def_one")]
pub space_drag_multiplier: f32,