alt-tabbing and stuff

This commit is contained in:
galister 2026-07-16 00:52:57 +09:00
parent 4cd238e487
commit 7efcb3cc84
10 changed files with 211 additions and 53 deletions

View File

@ -7,7 +7,7 @@ use glam::{Affine3A, Vec2, Vec3A, Vec3Swizzles};
use idmap_derive::IntegerId; use idmap_derive::IntegerId;
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use strum::AsRefStr; use strum::{AsRefStr, EnumIs};
use wayvr_ipc::packet_client::{HandsfreeAction, HandsfreeParams}; use wayvr_ipc::packet_client::{HandsfreeAction, HandsfreeParams};
use wlx_common::common::LeftRight; use wlx_common::common::LeftRight;
use wlx_common::windowing::{OverlayWindowState, Positioning}; use wlx_common::windowing::{OverlayWindowState, Positioning};
@ -58,13 +58,22 @@ pub enum TrackedDeviceRole {
Tracker, Tracker,
} }
#[derive(Debug, Clone, Copy, EnumIs)]
pub enum FocusPickState {
None,
/// aiming to pick the focus
Aiming,
/// picking the focus. this will be consumed on valid on_hover
Picking,
}
pub struct InputState { pub struct InputState {
pub hmd: Affine3A, pub hmd: Affine3A,
pub ipd: f32, pub ipd: f32,
pub pointers: [Pointer; 2], pub pointers: [Pointer; 2],
pub devices: Vec<TrackedDevice>, pub devices: Vec<TrackedDevice>,
pub handsfree_state: PointerState, pub handsfree_state: PointerState,
pub picking_focus: bool, pub picking_focus: FocusPickState,
processes: Vec<Child>, processes: Vec<Child>,
} }
@ -77,7 +86,7 @@ impl InputState {
devices: Vec::new(), devices: Vec::new(),
processes: Vec::new(), processes: Vec::new(),
handsfree_state: PointerState::default(), handsfree_state: PointerState::default(),
picking_focus: false, picking_focus: FocusPickState::None,
} }
} }
@ -210,6 +219,9 @@ fn debug_print_hand(hand: &Pointer) {
if hand.now.grab != hand.before.grab { if hand.now.grab != hand.before.grab {
log::debug!("Hand {}: grab {}", hand.idx, hand.now.grab); log::debug!("Hand {}: grab {}", hand.idx, hand.now.grab);
} }
if hand.now.grab_float != hand.before.grab_float {
log::debug!("Hand {}: grab {}", hand.idx, hand.now.grab);
}
if hand.now.alt_click != hand.before.alt_click { if hand.now.alt_click != hand.before.alt_click {
log::debug!("Hand {}: alt_click {}", hand.idx, hand.now.alt_click); log::debug!("Hand {}: alt_click {}", hand.idx, hand.now.alt_click);
} }
@ -316,6 +328,7 @@ pub struct PointerState {
pub scroll_y: f32, pub scroll_y: f32,
pub click: bool, pub click: bool,
pub grab: bool, pub grab: bool,
pub grab_float: bool,
pub alt_click: bool, pub alt_click: bool,
pub show_hide: bool, pub show_hide: bool,
pub toggle_dashboard: bool, pub toggle_dashboard: bool,
@ -411,6 +424,7 @@ fn populate_lines(
fn update_focus(app: &mut AppState, overlay_input_focus: Option<InputFocus>) { fn update_focus(app: &mut AppState, overlay_input_focus: Option<InputFocus>) {
if let Some(f) = &overlay_input_focus if let Some(f) = &overlay_input_focus
&& app.input_state.picking_focus.is_none()
&& app && app
.hid_provider .hid_provider
.set_input_focus(app.wvr_server.as_mut(), *f) .set_input_focus(app.wvr_server.as_mut(), *f)
@ -538,8 +552,11 @@ where
let hovered_state = hovered.config.active_state.as_mut().unwrap(); let hovered_state = hovered.config.active_state.as_mut().unwrap();
let grab_float = pointer.now.grab_float;
let grab_start = pointer.now.grab && !pointer.before.grab;
// grab // grab
if pointer.now.grab && !pointer.before.grab && hovered_state.grabbable { if grab_start && hovered_state.grabbable {
update_focus(app, hovered.config.input_focus); update_focus(app, hovered.config.input_focus);
start_grab( start_grab(
idx, idx,
@ -549,6 +566,7 @@ where
hovered_state, hovered_state,
app, app,
edit_mode, edit_mode,
grab_float,
); );
log::debug!("Hand {}: grabbed {}", hit.pointer, hovered.config.name); log::debug!("Hand {}: grabbed {}", hit.pointer, hovered.config.name);
return ( return (
@ -762,15 +780,19 @@ fn start_grab(
state: &mut OverlayWindowState, state: &mut OverlayWindowState,
app: &mut AppState, app: &mut AppState,
edit_mode: bool, edit_mode: bool,
grab_float: bool,
) { ) {
let pointer = &mut app.input_state.pointers[idx]; let pointer = &mut app.input_state.pointers[idx];
// Grab anchor if: // Grab anchor if:
// - grabbed overlay is Anchored // - grabbed overlay is Anchored
// - not in editmode // - not in editmode
// - not using grab_float
// - grabbing with one hand. (grabbing with the 2nd hand will grab the individual overlay instead) // - grabbing with one hand. (grabbing with the 2nd hand will grab the individual overlay instead)
let grab_anchor = let grab_anchor = !edit_mode
!edit_mode && !app.anchor_grabbed && matches!(state.positioning, Positioning::Anchored); && !grab_float
&& !app.anchor_grabbed
&& matches!(state.positioning, Positioning::Anchored);
let relative_grab_transform = if grab_anchor { let relative_grab_transform = if grab_anchor {
app.anchor app.anchor

View File

@ -219,6 +219,9 @@ pub fn openvr_run(args: &Args) -> Result<(), BackendError> {
while let Some(task) = due_tasks.pop_front() { while let Some(task) = due_tasks.pop_front() {
match task { match task {
TaskType::Global(task) => {
task(&mut app);
}
TaskType::Input(task) => { TaskType::Input(task) => {
app.input_state.handle_task(task); app.input_state.handle_task(task);
} }

View File

@ -4,7 +4,7 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use glam::{Affine3A, Quat, Vec3, bool}; use glam::{Affine3A, FloatExt, Quat, Vec3, bool};
use libmonado::{self as mnd, DeviceLogic}; use libmonado::{self as mnd, DeviceLogic};
use openxr::{self as xr, Quaternionf, Vector2f, Vector3f}; use openxr::{self as xr, Quaternionf, Vector2f, Vector3f};
use wlx_common::{ use wlx_common::{
@ -238,13 +238,18 @@ impl OpenXrInputSource {
let mut any_tracked = false; let mut any_tracked = false;
let old_handsfree = app.session.config.handsfree_pointer; let old_handsfree = app.session.config.handsfree_pointer;
if app.input_state.picking_focus { if !app.input_state.picking_focus.is_none() {
app.session.config.handsfree_pointer = app.session.config.handsfree_alt_tab.into(); app.session.config.handsfree_pointer = app.session.config.handsfree_alt_tab.into();
app.input_state.handsfree_state.scroll_x =
app.input_state.handsfree_state.scroll_x.lerp(0.0, 0.7);
app.input_state.handsfree_state.scroll_y =
app.input_state.handsfree_state.scroll_y.lerp(0.0, 0.7);
let ptr1 = &mut app.input_state.pointers[1]; let ptr1 = &mut app.input_state.pointers[1];
ptr1.before = ptr1.now; ptr1.before = ptr1.now;
ptr1.now = PointerState::default(); ptr1.now = PointerState::default();
ptr1.tracked = false ptr1.tracked = false;
} else { } else {
for i in 0..2 { for i in 0..2 {
let pointer = &mut app.input_state.pointers[i]; let pointer = &mut app.input_state.pointers[i];
@ -399,6 +404,7 @@ impl OpenXrPointer {
// input from wayvrctl // input from wayvrctl
pointer.now.click = handsfree_state.click; pointer.now.click = handsfree_state.click;
pointer.now.grab = handsfree_state.grab; pointer.now.grab = handsfree_state.grab;
pointer.now.grab_float = handsfree_state.grab_float;
pointer.now.click_modifier_right = handsfree_state.click_modifier_right; pointer.now.click_modifier_right = handsfree_state.click_modifier_right;
pointer.now.click_modifier_middle = handsfree_state.click_modifier_middle; pointer.now.click_modifier_middle = handsfree_state.click_modifier_middle;
pointer.now.scroll_y = handsfree_state.scroll_y; pointer.now.scroll_y = handsfree_state.scroll_y;

View File

@ -473,6 +473,9 @@ pub fn openxr_run(args: &Args) -> Result<(), BackendError> {
app.tasks.retrieve_due(&mut due_tasks); app.tasks.retrieve_due(&mut due_tasks);
while let Some(task) = due_tasks.pop_front() { while let Some(task) = due_tasks.pop_front() {
match task { match task {
TaskType::Global(task) => {
task(&mut app);
}
TaskType::Input(task) => { TaskType::Input(task) => {
app.input_state.handle_task(task); app.input_state.handle_task(task);
} }

View File

@ -128,8 +128,11 @@ pub enum OverlayTask {
Drop(OverlaySelector), Drop(OverlaySelector),
} }
pub type GlobalTask = dyn FnOnce(&mut AppState) + Send;
#[allow(dead_code)] #[allow(dead_code)]
pub enum TaskType { pub enum TaskType {
Global(Box<GlobalTask>),
Input(InputTask), Input(InputTask),
Overlay(OverlayTask), Overlay(OverlayTask),
Playspace(PlayspaceTask), Playspace(PlayspaceTask),

View File

@ -34,9 +34,8 @@ pub enum KeyCombo {
Super2, Super2,
Super3, Super3,
Super4, Super4,
SuperTab,
AltF4, AltF4,
AltTab,
AltShiftTab,
/// Always consumed by InputCapture internally /// Always consumed by InputCapture internally
CtrlAltDel, CtrlAltDel,
} }
@ -61,7 +60,8 @@ pub enum CapturedEvent {
horizontal_v120: i32, horizontal_v120: i32,
vertical_v120: i32, vertical_v120: i32,
}, },
UngrabbedAll, Grabbed,
Ungrabbed,
KeyCombo { KeyCombo {
combo: KeyCombo, combo: KeyCombo,
pressed: bool, pressed: bool,
@ -326,6 +326,7 @@ fn worker_main(
} }
let mut grabbed = false; let mut grabbed = false;
let mut pending_grab = false;
let mut watchdog = Instant::now() + WATCHDOG_TIMEOUT; let mut watchdog = Instant::now() + WATCHDOG_TIMEOUT;
let mut emergency_ungrab = false; let mut emergency_ungrab = false;
let mut pointer_accel = PointerAccelConfig::default(); let mut pointer_accel = PointerAccelConfig::default();
@ -336,6 +337,8 @@ fn worker_main(
loop { loop {
match command_rx.try_recv() { match command_rx.try_recv() {
Ok(Command::SetGrabbed(requested)) => { Ok(Command::SetGrabbed(requested)) => {
pending_grab = false;
let _ = if requested { let _ = if requested {
match restricted_state.borrow_mut().set_grabbed(true) { match restricted_state.borrow_mut().set_grabbed(true) {
Ok(()) => { Ok(()) => {
@ -409,9 +412,10 @@ fn worker_main(
&event_tx, &event_tx,
); );
grabbed = false; grabbed = false;
pending_grab = false;
emergency_ungrab = false; emergency_ungrab = false;
if event_tx.send(CapturedEvent::UngrabbedAll).is_err() { if event_tx.send(CapturedEvent::Ungrabbed).is_err() {
break 'worker; break 'worker;
} }
continue; continue;
@ -459,6 +463,8 @@ fn worker_main(
match process_libinput_event( match process_libinput_event(
event, event,
grabbed, grabbed,
true,
&mut pending_grab,
&event_tx, &event_tx,
&mut runtime_devices, &mut runtime_devices,
&mut pointer_devices, &mut pointer_devices,
@ -473,6 +479,27 @@ fn worker_main(
} }
} }
if !grabbed && pending_grab && all_keyboard_keys_released(&runtime_devices) {
pending_grab = false;
match restricted_state.borrow_mut().set_grabbed(true) {
Ok(()) => {
grabbed = true;
watchdog = Instant::now() + WATCHDOG_TIMEOUT;
// should not be needed but sanity
clear_transient_state(&mut runtime_devices);
if event_tx.send(CapturedEvent::Grabbed).is_err() {
break 'worker;
}
}
Err(error) => {
log::warn!("Could not grab input devices after Super+Tab: {error}");
}
}
}
if emergency_ungrab { if emergency_ungrab {
force_emergency_ungrab( force_emergency_ungrab(
&mut libinput, &mut libinput,
@ -485,7 +512,7 @@ fn worker_main(
grabbed = false; grabbed = false;
emergency_ungrab = false; emergency_ungrab = false;
if event_tx.send(CapturedEvent::UngrabbedAll).is_err() { if event_tx.send(CapturedEvent::Ungrabbed).is_err() {
break 'worker; break 'worker;
} }
} }
@ -494,7 +521,9 @@ fn worker_main(
fn process_libinput_event( fn process_libinput_event(
event: Event, event: Event,
emit: bool, grabbed: bool,
allow_deferred_grab: bool,
pending_grab: &mut bool,
event_tx: &Sender<CapturedEvent>, event_tx: &Sender<CapturedEvent>,
runtime_devices: &mut HashMap<LibinputDevice, RuntimeDeviceState>, runtime_devices: &mut HashMap<LibinputDevice, RuntimeDeviceState>,
pointer_devices: &mut HashSet<LibinputDevice>, pointer_devices: &mut HashSet<LibinputDevice>,
@ -504,7 +533,7 @@ fn process_libinput_event(
Event::Device(event) => { Event::Device(event) => {
handle_device_event(event, runtime_devices, pointer_devices, pointer_accel); handle_device_event(event, runtime_devices, pointer_devices, pointer_accel);
} }
Event::Keyboard(KeyboardEvent::Key(event)) if emit => { Event::Keyboard(KeyboardEvent::Key(event)) => {
let code_u32 = event.key(); let code_u32 = event.key();
let Ok(code) = u16::try_from(code_u32) else { let Ok(code) = u16::try_from(code_u32) else {
log::warn!("Ignoring out-of-range Linux key code {code_u32}"); log::warn!("Ignoring out-of-range Linux key code {code_u32}");
@ -521,16 +550,26 @@ fn process_libinput_event(
state.pressed_keys.remove(&code); state.pressed_keys.remove(&code);
} }
if !grabbed {
// while ungrabbed, SuperTab will arm an automatic grab
if allow_deferred_grab
&& key_combo_is_pressed(KeyCombo::SuperTab, &state.pressed_keys)
{
*pending_grab = true;
}
return ProcessResult::Continue;
}
if pressed && key_combo_is_pressed(KeyCombo::CtrlAltDel, &state.pressed_keys) { if pressed && key_combo_is_pressed(KeyCombo::CtrlAltDel, &state.pressed_keys) {
log::info!("Ctrl+Alt+Del pressed, ungrabbing all input devices"); log::info!("Ctrl+Alt+Del pressed, ungrabbing all input devices");
return ProcessResult::EmergencyUngrab; return ProcessResult::EmergencyUngrab;
} }
// emit press/release whenever a combo's complete state changes. // while grabbed, these combos get emitted as normal
for combo in [ for combo in [
KeyCombo::SuperTab,
KeyCombo::AltF4, KeyCombo::AltF4,
KeyCombo::AltShiftTab,
KeyCombo::AltTab,
KeyCombo::Super1, KeyCombo::Super1,
KeyCombo::Super2, KeyCombo::Super2,
KeyCombo::Super3, KeyCombo::Super3,
@ -564,7 +603,7 @@ fn process_libinput_event(
return ProcessResult::ReceiverGone; return ProcessResult::ReceiverGone;
} }
} }
Event::Pointer(PointerEvent::Motion(event)) if emit => { Event::Pointer(PointerEvent::Motion(event)) if grabbed => {
let dx = event.dx(); let dx = event.dx();
let dy = event.dy(); let dy = event.dy();
let dx_raw = event.dx_unaccelerated(); let dx_raw = event.dx_unaccelerated();
@ -582,7 +621,7 @@ fn process_libinput_event(
return ProcessResult::ReceiverGone; return ProcessResult::ReceiverGone;
} }
} }
Event::Pointer(PointerEvent::Button(event)) if emit => { Event::Pointer(PointerEvent::Button(event)) if grabbed => {
let pressed = event.button_state() == ButtonState::Pressed; let pressed = event.button_state() == ButtonState::Pressed;
if event_tx if event_tx
.send(CapturedEvent::PointerButton { .send(CapturedEvent::PointerButton {
@ -594,7 +633,7 @@ fn process_libinput_event(
return ProcessResult::ReceiverGone; return ProcessResult::ReceiverGone;
} }
} }
Event::Pointer(PointerEvent::ScrollWheel(event)) if emit => { Event::Pointer(PointerEvent::ScrollWheel(event)) if grabbed => {
let horizontal = if event.has_axis(Axis::Horizontal) { let horizontal = if event.has_axis(Axis::Horizontal) {
event.scroll_value_v120(Axis::Horizontal) event.scroll_value_v120(Axis::Horizontal)
} else { } else {
@ -680,10 +719,14 @@ fn drain_pending_libinput_events(
event_tx: &Sender<CapturedEvent>, event_tx: &Sender<CapturedEvent>,
) { ) {
let _ = libinput.dispatch(); let _ = libinput.dispatch();
let mut ignored = false;
for event in libinput { for event in libinput {
let _ = process_libinput_event( let _ = process_libinput_event(
event, event,
false, false,
false,
&mut ignored,
event_tx, event_tx,
runtime_devices, runtime_devices,
pointer_devices, pointer_devices,
@ -836,14 +879,10 @@ fn key_combo_is_pressed(combo: KeyCombo, pressed: &HashSet<u16>) -> bool {
let meta = let meta =
pressed.contains(&KeyCode::KEY_LEFTMETA.0) || pressed.contains(&KeyCode::KEY_RIGHTMETA.0); pressed.contains(&KeyCode::KEY_LEFTMETA.0) || pressed.contains(&KeyCode::KEY_RIGHTMETA.0);
let shift =
pressed.contains(&KeyCode::KEY_LEFTSHIFT.0) || pressed.contains(&KeyCode::KEY_RIGHTSHIFT.0);
match combo { match combo {
KeyCombo::AltF4 => alt && pressed.contains(&KeyCode::KEY_F4.0), KeyCombo::AltF4 => alt && pressed.contains(&KeyCode::KEY_F4.0),
KeyCombo::AltShiftTab => alt && shift && pressed.contains(&KeyCode::KEY_TAB.0),
KeyCombo::AltTab => alt && pressed.contains(&KeyCode::KEY_TAB.0),
KeyCombo::CtrlAltDel => ctrl && alt && pressed.contains(&KeyCode::KEY_DELETE.0), KeyCombo::CtrlAltDel => ctrl && alt && pressed.contains(&KeyCode::KEY_DELETE.0),
KeyCombo::SuperTab => meta && pressed.contains(&KeyCode::KEY_TAB.0),
KeyCombo::Super1 => meta && pressed.contains(&KeyCode::KEY_1.0), KeyCombo::Super1 => meta && pressed.contains(&KeyCode::KEY_1.0),
KeyCombo::Super2 => meta && pressed.contains(&KeyCode::KEY_2.0), KeyCombo::Super2 => meta && pressed.contains(&KeyCode::KEY_2.0),
KeyCombo::Super3 => meta && pressed.contains(&KeyCode::KEY_3.0), KeyCombo::Super3 => meta && pressed.contains(&KeyCode::KEY_3.0),
@ -861,3 +900,11 @@ fn with_device_context(action: &str, path: &Path, error: io::Error) -> io::Error
format!("failed to {action} {}: {error}", path.display()), format!("failed to {action} {}: {error}", path.display()),
) )
} }
fn all_keyboard_keys_released(
runtime_devices: &HashMap<LibinputDevice, RuntimeDeviceState>,
) -> bool {
runtime_devices
.values()
.all(|state| state.pressed_keys.is_empty())
}

View File

@ -77,12 +77,13 @@ use crate::{
state::AppState, state::AppState,
subsystem::{ subsystem::{
dbus::DbusConnector, dbus::DbusConnector,
hid::{MODS_TO_KEYS, WheelDelta}, hid::{self, MODS_TO_KEYS, WheelDelta},
input::{HidWrapper, InputFocus},
}, },
windowing::{OverlayID, OverlaySelector, backend::OverlayEventData}, windowing::{OverlayID, OverlaySelector, backend::OverlayEventData},
}; };
pub use hit_test::{WvrHitContext, WvrHitTarget, build_hit_context}; pub use hit_test::{WvrHitTarget, build_hit_context};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct WaylandEnv { pub struct WaylandEnv {
@ -322,6 +323,7 @@ impl WvrServerState {
input_state: &app.input_state, input_state: &app.input_state,
tasks: &mut tasks, tasks: &mut tasks,
signals: &app.wayvr_signals, signals: &app.wayvr_signals,
hid_wrapper: &mut app.hid_provider,
}); });
// Tick all child processes // Tick all child processes
@ -637,7 +639,11 @@ impl WvrServerState {
wvr_server.manager.cleanup_handles(); wvr_server.manager.cleanup_handles();
} }
wvr_server.process_input_capture(&mut app.input_state, &mut app.tasks); wvr_server.process_input_capture(
&mut app.input_state,
&mut app.tasks,
&mut app.hid_provider,
);
wvr_server.ticks += 1; wvr_server.ticks += 1;
@ -752,10 +758,8 @@ impl WvrServerState {
&mut self, &mut self,
input_state: &mut InputState, input_state: &mut InputState,
tasks: &mut TaskContainer, tasks: &mut TaskContainer,
hid_wrapper: &mut HidWrapper,
) { ) {
if !self.has_input_focus {
return;
}
let Some(input_capture) = self.input_capture.as_mut() else { let Some(input_capture) = self.input_capture.as_mut() else {
return; return;
}; };
@ -766,13 +770,47 @@ impl WvrServerState {
for ev in input_capture.drain_events() { for ev in input_capture.drain_events() {
match ev { match ev {
input_capture::CapturedEvent::Key { code, pressed } => { input_capture::CapturedEvent::Key { code, pressed } => {
self.manager.send_key((code as u32) + 8, pressed); let vk = (code as u32) + 8;
if input_state.picking_focus.is_aiming() {
if (hid::VirtualKey::Q as u32) == vk {
input_state.handsfree_state.grab = pressed;
input_state.handsfree_state.grab_float = pressed;
}
if (hid::VirtualKey::A as u32) == vk {
input_state.handsfree_state.grab = pressed;
}
if (hid::VirtualKey::W as u32) == vk {
input_state.handsfree_state.click = pressed;
}
if (hid::VirtualKey::E as u32) == vk && pressed {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleEditMode));
}
if (hid::VirtualKey::D as u32) == vk && pressed {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleDashboard));
}
} else {
self.manager.send_key(vk, pressed);
}
} }
input_capture::CapturedEvent::PointerButton { button, pressed } => { input_capture::CapturedEvent::PointerButton { button, pressed } => {
let Some(mouse_index) = Self::button_to_mouse_index(button) else { let Some(mouse_index) = Self::button_to_mouse_index(button) else {
continue; continue;
}; };
self.manager.send_pointer_button(mouse_index, pressed); if input_state.picking_focus.is_aiming() {
match mouse_index {
MouseIndex::Left => input_state.handsfree_state.click = pressed,
MouseIndex::Right => {
input_state.handsfree_state.click = pressed;
input_state.handsfree_state.click_modifier_right = pressed;
}
MouseIndex::Center if pressed => {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleEditMode));
}
_ => {}
}
} else {
self.manager.send_pointer_button(mouse_index, pressed);
}
} }
input_capture::CapturedEvent::PointerMotion { input_capture::CapturedEvent::PointerMotion {
dx, dx,
@ -794,9 +832,16 @@ impl WvrServerState {
x: horizontal_v120 as f32, x: horizontal_v120 as f32,
y: vertical_v120 as f32, y: vertical_v120 as f32,
}; };
self.manager.send_pointer_axis_wheel_raw(delta); if input_state.picking_focus.is_aiming() {
input_state.handsfree_state.scroll_y = (vertical_v120 as f32) * -0.12;
} else {
self.manager.send_pointer_axis_wheel_raw(delta);
}
} }
input_capture::CapturedEvent::UngrabbedAll => { input_capture::CapturedEvent::Grabbed => {
hid_wrapper.set_input_focus(Some(self), InputFocus::WayVR);
}
input_capture::CapturedEvent::Ungrabbed => {
self.manager.release_all_keys(); self.manager.release_all_keys();
self.has_input_focus = false; self.has_input_focus = false;
self.wm.keyboard_focus = None; self.wm.keyboard_focus = None;
@ -808,20 +853,33 @@ impl WvrServerState {
self.close_window(window_handle); self.close_window(window_handle);
} }
} }
input_capture::KeyCombo::AltTab => input_state.picking_focus = pressed, input_capture::KeyCombo::SuperTab => {
input_capture::KeyCombo::AltShiftTab => { if pressed {
input_state.handsfree_state.grab = pressed input_state.picking_focus = super::input::FocusPickState::Aiming;
} else {
input_state.picking_focus = super::input::FocusPickState::Picking;
tasks.enqueue_at(
TaskType::Global(Box::new(|app| {
app.input_state.picking_focus =
super::input::FocusPickState::None;
let _ = std::mem::take(&mut app.input_state.handsfree_state);
})),
Instant::now() + Duration::from_millis(33),
);
}
} }
input_capture::KeyCombo::Super1 => { input_capture::KeyCombo::Super1 if pressed => {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(0))) tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(0)))
} }
input_capture::KeyCombo::Super2 => { input_capture::KeyCombo::Super2 if pressed => {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(1))) tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(1)))
} }
input_capture::KeyCombo::Super3 => { input_capture::KeyCombo::Super3 if pressed => {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(2))) tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(2)))
} }
input_capture::KeyCombo::Super4 => { input_capture::KeyCombo::Super4 if pressed => {
tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(3))) tasks.enqueue(TaskType::Overlay(OverlayTask::ToggleSet(3)))
} }
_ => {} _ => {}
@ -881,6 +939,7 @@ impl WvrServerState {
} }
} }
/// Use HidWrapper::set_input_focus instead!!!
pub fn set_input_focus(&mut self, has_focus: bool) { pub fn set_input_focus(&mut self, has_focus: bool) {
let Some(input_capture) = self.input_capture.as_mut() else { let Some(input_capture) = self.input_capture.as_mut() else {
return; return;
@ -982,7 +1041,7 @@ impl WvrServerState {
target: PointerFocusTarget, target: PointerFocusTarget,
global_pos: Vec2, global_pos: Vec2,
hover_window: window::WindowHandle, hover_window: window::WindowHandle,
force_focus: bool, picking_focus: bool,
) { ) {
if self.mouse_freeze > Instant::now() { if self.mouse_freeze > Instant::now() {
return; return;
@ -990,7 +1049,7 @@ impl WvrServerState {
let global_pos = DVec2::from(global_pos); let global_pos = DVec2::from(global_pos);
let (focus, focus_keyboard) = self.get_mouse_focus(target, hover_window, force_focus); let (focus, focus_keyboard) = self.get_mouse_focus(target, hover_window, picking_focus);
if focus_keyboard.is_some() { if focus_keyboard.is_some() {
self.manager.seat_keyboard.set_focus( self.manager.seat_keyboard.set_focus(
&mut self.manager.state, &mut self.manager.state,

View File

@ -1,5 +1,6 @@
use crate::backend::wayvr::{self, WvrServerState}; use crate::backend::wayvr::{self, WvrServerState};
use crate::subsystem::input::{HidWrapper, InputFocus};
use crate::{ use crate::{
backend::input::InputState, backend::input::InputState,
ipc::{event_queue::SyncEventQueue, signal::WayVRSignal}, ipc::{event_queue::SyncEventQueue, signal::WayVRSignal},
@ -86,6 +87,7 @@ pub struct TickParams<'a> {
pub tasks: &'a mut Vec<wayvr::TickTask>, pub tasks: &'a mut Vec<wayvr::TickTask>,
pub signals: &'a SyncEventQueue<WayVRSignal>, pub signals: &'a SyncEventQueue<WayVRSignal>,
pub input_state: &'a InputState, pub input_state: &'a InputState,
pub hid_wrapper: &'a mut HidWrapper,
} }
pub fn gen_args_vec(input: &str) -> Vec<&str> { pub fn gen_args_vec(input: &str) -> Vec<&str> {
@ -335,7 +337,14 @@ impl Connection {
} }
fn handle_wvr_input_capture(params: &mut TickParams, grab: bool) { fn handle_wvr_input_capture(params: &mut TickParams, grab: bool) {
params.wvr_server.set_input_focus(grab); let val = if grab {
InputFocus::WayVR
} else {
InputFocus::PhysicalScreen
};
params
.hid_wrapper
.set_input_focus(Some(params.wvr_server), val);
} }
fn handle_wlx_device_haptics( fn handle_wlx_device_haptics(

View File

@ -9,7 +9,7 @@ use wlx_capture::{WlxCapture, frame::Transform};
use crate::{ use crate::{
backend::{ backend::{
XrBackend, XrBackend,
input::{HoverResult, PointerHit, PointerMode}, input::{self, HoverResult, PointerHit, PointerMode},
}, },
overlays::screen::capture::MyFirstDmaExporter, overlays::screen::capture::MyFirstDmaExporter,
state::AppState, state::AppState,
@ -302,7 +302,9 @@ impl OverlayBackend for ScreenBackend {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("Hover: {:?}", hit.uv); log::trace!("Hover: {:?}", hit.uv);
if app.input_state.picking_focus { let pick_now = app.input_state.picking_focus.is_picking();
if pick_now {
app.input_state.picking_focus = input::FocusPickState::None;
app.hid_provider app.hid_provider
.set_input_focus(app.wvr_server.as_mut(), InputFocus::PhysicalScreen); .set_input_focus(app.wvr_server.as_mut(), InputFocus::PhysicalScreen);
} }

View File

@ -845,7 +845,9 @@ impl OverlayBackend for WvrWindowBackend {
self.panel_hovered = false; self.panel_hovered = false;
} }
if app.input_state.picking_focus { let pick_now = app.input_state.picking_focus.is_picking();
if pick_now {
app.input_state.picking_focus = input::FocusPickState::None;
app.hid_provider app.hid_provider
.set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR); .set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR);
} }
@ -855,7 +857,7 @@ impl OverlayBackend for WvrWindowBackend {
PointerFocusTarget::Surface { surface, origin }, PointerFocusTarget::Surface { surface, origin },
global_pos, global_pos,
self.window, self.window,
app.input_state.picking_focus, pick_now,
); );
HoverResult::consume() HoverResult::consume()
@ -866,7 +868,9 @@ impl OverlayBackend for WvrWindowBackend {
self.panel_hovered = false; self.panel_hovered = false;
} }
if app.input_state.picking_focus { let pick_now = app.input_state.picking_focus.is_picking();
if pick_now {
app.input_state.picking_focus = input::FocusPickState::None;
app.hid_provider app.hid_provider
.set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR); .set_input_focus(app.wvr_server.as_mut(), InputFocus::WayVR);
} }
@ -876,7 +880,7 @@ impl OverlayBackend for WvrWindowBackend {
PointerFocusTarget::Toplevel, PointerFocusTarget::Toplevel,
pos, pos,
self.window, self.window,
app.input_state.picking_focus, pick_now,
); );
HoverResult::consume() HoverResult::consume()