From 16325040a561312322a1b8ab3bdf316a374c9c2d Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 15 Jul 2026 14:12:25 +0900 Subject: [PATCH] key combos --- wayvr/src/backend/wayvr/input_capture.rs | 48 +++++++++++++++++++----- wayvr/src/backend/wayvr/mod.rs | 16 +++++++- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/wayvr/src/backend/wayvr/input_capture.rs b/wayvr/src/backend/wayvr/input_capture.rs index deccd471..d8bdc976 100644 --- a/wayvr/src/backend/wayvr/input_capture.rs +++ b/wayvr/src/backend/wayvr/input_capture.rs @@ -24,12 +24,20 @@ use std::{ time::{Duration, Instant}, }; -pub const IGNORE_PREFIX: &str = "WayVR"; +pub const SEAT_NAME: &str = "wayvr"; -const SEAT_NAME: &str = "seat0"; +const IGNORE_PREFIX: &str = "WayVR"; const WATCHDOG_TIMEOUT: Duration = Duration::from_millis(5000); const POLL_TIMEOUT_MS: i32 = 20; +#[derive(Debug, Clone, Copy)] +pub enum KeyCombo { + AltF4, + AltTab, + /// Always consumed by InputCapture internally + CtrlAltDel, +} + #[derive(Debug, Clone)] pub enum CapturedEvent { Key { @@ -49,6 +57,7 @@ pub enum CapturedEvent { vertical_v120: i32, }, UngrabbedAll, + KeyCombo(KeyCombo), } #[derive(Debug, Clone, Copy)] @@ -519,9 +528,16 @@ fn process_libinput_event( if pressed { state.pressed_keys.insert(code); - if emergency_chord_active(&state.pressed_keys) { - log::info!("Ctrl+Alt+Del pressed, ungrabbing all input devices"); - return ProcessResult::EmergencyUngrab; + + match check_key_combo(&state.pressed_keys) { + Some(KeyCombo::CtrlAltDel) => { + log::info!("Ctrl+Alt+Del pressed, ungrabbing all input devices"); + return ProcessResult::EmergencyUngrab; + } + Some(key_combo) if emit => { + let _ = event_tx.send(CapturedEvent::KeyCombo(key_combo)); + } + _ => {} } } else { state.pressed_keys.remove(&code); @@ -785,14 +801,26 @@ fn mouse_buttons() -> [KeyCode; 8] { ] } -fn emergency_chord_active(pressed: &HashSet) -> bool { - let ctrl = - pressed.contains(&KeyCode::KEY_LEFTCTRL.0) || pressed.contains(&KeyCode::KEY_RIGHTCTRL.0); - +fn check_key_combo(pressed: &HashSet) -> Option { let alt = pressed.contains(&KeyCode::KEY_LEFTALT.0) || pressed.contains(&KeyCode::KEY_RIGHTALT.0); - ctrl && alt && pressed.contains(&KeyCode::KEY_DELETE.0) + if alt && pressed.contains(&KeyCode::KEY_F4.0) { + return Some(KeyCombo::AltF4); + } + + if alt && pressed.contains(&KeyCode::KEY_TAB.0) { + return Some(KeyCombo::AltTab); + } + + let ctrl = + pressed.contains(&KeyCode::KEY_LEFTCTRL.0) || pressed.contains(&KeyCode::KEY_RIGHTCTRL.0); + + if ctrl && alt && pressed.contains(&KeyCode::KEY_DELETE.0) { + return Some(KeyCombo::CtrlAltDel); + } + + None } fn io_errno(error: io::Error) -> i32 { diff --git a/wayvr/src/backend/wayvr/mod.rs b/wayvr/src/backend/wayvr/mod.rs index ad94520d..5cc3f193 100644 --- a/wayvr/src/backend/wayvr/mod.rs +++ b/wayvr/src/backend/wayvr/mod.rs @@ -65,7 +65,7 @@ use crate::{ task::{OverlayTask, SpawnPos, TaskContainer, TaskType, ToggleMode}, wayvr::{ image_importer::ImageImporter, - input_capture::InputCapture, + input_capture::{InputCapture, SEAT_NAME}, process::{KillSignal, Process}, }, }, @@ -178,7 +178,7 @@ impl WvrServerState { let shm = ShmState::new::(&dh, Vec::new()); let data_device = DataDeviceState::new::(&dh); let primary_selection_state = PrimarySelectionState::new::(&dh); - let mut seat = seat_state.new_wl_seat(&dh, "wayvr"); + let mut seat = seat_state.new_wl_seat(&dh, SEAT_NAME); let ext_data_control_state = selection_ext::DataControlState::new::( &dh, @@ -798,6 +798,18 @@ impl WvrServerState { self.manager.release_all_keys(); self.has_input_focus = false; } + input_capture::CapturedEvent::KeyCombo(key_combo) => { + match key_combo { + input_capture::KeyCombo::AltF4 => { + if let Some(hover) = self.wm.mouse.as_mut() { + let window_handle = hover.hover_window; + self.close_window(window_handle); + } + } + input_capture::KeyCombo::AltTab => {} + input_capture::KeyCombo::CtrlAltDel => { /* not exposed to us */ } + } + } } }