mirror of https://github.com/wayvr-org/wayvr.git
alt-tabbing and stuff
This commit is contained in:
parent
4cd238e487
commit
7efcb3cc84
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue