diff --git a/src/backend/openxr/blocker.rs b/src/backend/openxr/blocker.rs new file mode 100644 index 0000000..8631b2d --- /dev/null +++ b/src/backend/openxr/blocker.rs @@ -0,0 +1,73 @@ +use libmonado::{ClientState, Monado}; +use log::{info, warn}; + +use crate::{backend::overlay::OverlayID, state::AppState}; + +pub(super) struct InputBlocker { + hovered_last_frame: bool, +} + +impl InputBlocker { + pub const fn new() -> Self { + Self { + hovered_last_frame: false, + } + } + + pub fn update(&mut self, state: &AppState, watch_id: OverlayID, monado: &mut Monado) { + if !state.session.config.block_game_input { + return; + } + + let any_hovered = state.input_state.pointers.iter().any(|p| { + p.interaction.hovered_id.is_some_and(|id| { + id != watch_id || !state.session.config.block_game_input_ignore_watch + }) + }); + + match (any_hovered, self.hovered_last_frame) { + (true, false) => { + info!("Blocking input"); + set_clients_io_active(monado, false); + } + (false, true) => { + info!("Unblocking input"); + set_clients_io_active(monado, true); + } + _ => {} + } + + self.hovered_last_frame = any_hovered; + } +} + +fn set_clients_io_active(monado: &mut Monado, active: bool) { + match monado.clients() { + Ok(clients) => { + for mut client in clients { + let name = match client.name() { + Ok(n) => n, + Err(e) => { + warn!("Failed to get client name: {e}"); + continue; + } + }; + + let state = match client.state() { + Ok(s) => s, + Err(e) => { + warn!("Failed to get client state: {e}"); + continue; + } + }; + + if name != "wlx-overlay-s" && state.contains(ClientState::ClientSessionVisible) { + if let Err(e) = client.set_io_active(active) { + warn!("Failed to set io active for client: {e}"); + } + } + } + } + Err(e) => warn!("Failed to get clients from Monado: {e}"), + } +} diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index e224d74..759c7fc 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -35,6 +35,7 @@ use crate::{ #[cfg(feature = "wayvr")] use crate::{gui::modular::button::WayVRAction, overlays::wayvr::wayvr_action}; +mod blocker; mod helpers; mod input; mod lines; @@ -108,6 +109,8 @@ pub fn openxr_run(running: Arc, show_by_default: bool) -> Result<(), .ok() }); + let mut blocker = monado.is_some().then(blocker::InputBlocker::new); + let (session, mut frame_wait, mut frame_stream) = unsafe { let raw_session = helpers::create_overlay_session( &xr_instance, @@ -268,6 +271,14 @@ pub fn openxr_run(running: Arc, show_by_default: bool) -> Result<(), input_source.update(&xr_state, &mut app)?; app.input_state.post_update(&app.session); + if let Some(ref mut blocker) = blocker { + blocker.update( + &app, + watch_id, + monado.as_mut().unwrap(), // safe + ); + } + if app .input_state .pointers diff --git a/src/config.rs b/src/config.rs index bedf4c2..b1d5de2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -273,6 +273,12 @@ pub struct GeneralConfig { #[serde(default = "def_false")] pub focus_follows_mouse_mode: bool, + #[serde(default = "def_false")] + pub block_game_input: bool, + + #[serde(default = "def_true")] + pub block_game_input_ignore_watch: bool, + #[serde(default = "def_font")] pub primary_font: Arc,