From 235248d44510417e1d6913c8cf8cac2a0a864498 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 6 Jul 2023 18:20:10 +0200 Subject: [PATCH] kms: Add key repetition for shortcuts --- src/backend/kms/mod.rs | 2 +- src/backend/winit.rs | 2 +- src/backend/x11.rs | 2 +- src/input/mod.rs | 105 +++++++++++++++++++++++++++---------- src/shell/element/stack.rs | 1 + src/shell/mod.rs | 17 ++---- 6 files changed, 86 insertions(+), 43 deletions(-) diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 09b6c607..783fe394 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -155,7 +155,7 @@ pub fn init_backend( if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event { data.state.common.config.read_device(device); } - data.state.process_input_event(event); + data.state.process_input_event(event, true); for output in data.state.common.shell.outputs() { if let Err(err) = data.state.backend.kms().schedule_render( &data.state.common.event_loop_handle, diff --git a/src/backend/winit.rs b/src/backend/winit.rs index f94339a5..f1988b5b 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -360,7 +360,7 @@ impl State { render_ping.ping(); } WinitEvent::Refresh => render_ping.ping(), - WinitEvent::Input(event) => self.process_input_event(event), + WinitEvent::Input(event) => self.process_input_event(event, false), _ => {} }; } diff --git a/src/backend/x11.rs b/src/backend/x11.rs index e27fefc7..103a48a4 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -535,7 +535,7 @@ impl State { _ => {} }; - self.process_input_event(event); + self.process_input_event(event, false); // TODO actually figure out the output for output in self.common.shell.outputs() { self.backend.x11().schedule_render(output, None); diff --git a/src/input/mod.rs b/src/input/mod.rs index ac228548..8108805d 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -15,6 +15,7 @@ use crate::{ utils::prelude::*, wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, }; +use calloop::{timer::Timer, RegistrationToken}; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; use smithay::{ backend::input::{ @@ -40,7 +41,11 @@ use smithay::{ use tracing::info; use tracing::{error, trace, warn}; -use std::{cell::RefCell, collections::HashMap}; +use std::{ + cell::RefCell, + collections::HashMap, + time::{Duration, Instant}, +}; use xkbcommon::xkb::KEY_XF86Switch_VT_12; crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS); @@ -49,7 +54,7 @@ crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS); pub struct SeatId(pub usize); pub struct ActiveOutput(pub RefCell); #[derive(Default)] -pub struct SupressedKeys(RefCell>); +pub struct SupressedKeys(RefCell)>>); #[derive(Default)] pub struct Devices(RefCell>>); @@ -66,17 +71,26 @@ impl Drop for SeatId { } impl SupressedKeys { - fn add(&self, keysym: &KeysymHandle) { - self.0.borrow_mut().push(keysym.raw_code()); + fn add(&self, keysym: &KeysymHandle, token: impl Into>) { + self.0.borrow_mut().push((keysym.raw_code(), token.into())); } - fn filter(&self, keysym: &KeysymHandle) -> bool { + fn filter(&self, keysym: &KeysymHandle) -> Option> { let mut keys = self.0.borrow_mut(); - if let Some(i) = keys.iter().position(|x| *x == keysym.raw_code()) { - keys.remove(i); - true + let (removed, remaining) = keys + .drain(..) + .partition(|(key, _)| *key == keysym.raw_code()); + *keys = remaining; + + let removed = removed + .into_iter() + .map(|(_, token)| token) + .flatten() + .collect::>(); + if removed.is_empty() { + None } else { - false + Some(removed) } } } @@ -154,7 +168,11 @@ pub fn add_seat( } impl State { - pub fn process_input_event(&mut self, event: InputEvent) { + pub fn process_input_event( + &mut self, + event: InputEvent, + needs_key_repetition: bool, + ) { use smithay::backend::input::Event; match event { @@ -195,7 +213,9 @@ impl State { InputEvent::Keyboard { event, .. } => { use smithay::backend::input::KeyboardKeyEvent; + let loop_handle = self.common.event_loop_handle.clone(); let device = event.device(); + for seat in self.common.seats().cloned().collect::>().iter() { let current_output = seat.active_output(); let workspace = self.common.shell.active_space_mut(¤t_output); @@ -251,7 +271,6 @@ impl State { && handle.raw_syms().contains(&action_pattern.key) { data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone()); - return FilterResult::Intercept(None); } else if action_pattern.modifiers != *modifiers { let mut new_pattern = action_pattern.clone(); new_pattern.modifiers = modifiers.clone().into(); @@ -280,10 +299,10 @@ impl State { data.common.shell.resize_mode() { let resize_edge = match handle.modified_sym() { - keysyms::KEY_Left | keysyms::KEY_H => Some(ResizeEdge::LEFT), - keysyms::KEY_Down | keysyms::KEY_J => Some(ResizeEdge::BOTTOM), - keysyms::KEY_Up | keysyms::KEY_K => Some(ResizeEdge::TOP), - keysyms::KEY_Right | keysyms::KEY_L => Some(ResizeEdge::RIGHT), + keysyms::KEY_Left | keysyms::KEY_h | keysyms::KEY_H => Some(ResizeEdge::LEFT), + keysyms::KEY_Down | keysyms::KEY_j | keysyms::KEY_J => Some(ResizeEdge::BOTTOM), + keysyms::KEY_Up | keysyms::KEY_k | keysyms::KEY_K => Some(ResizeEdge::TOP), + keysyms::KEY_Right | keysyms::KEY_l | keysyms::KEY_L => Some(ResizeEdge::RIGHT), _ => None, }; @@ -291,21 +310,51 @@ impl State { if direction == ResizeDirection::Inwards { edge.flip_direction(); } + let action = Action::_ResizingInternal(direction, edge, state); + let key_pattern = KeyPattern { + modifiers: modifiers.clone().into(), + key: handle.raw_code(), + }; + + if state == KeyState::Released { + if let Some(tokens) = userdata.get::().unwrap().filter(&handle) { + for token in tokens { + loop_handle.remove(token); + } + } + } else { + let token = if needs_key_repetition { + let seat_clone = seat.clone(); + let action_clone = action.clone(); + let key_pattern_clone = key_pattern.clone(); + let start = Instant::now(); + loop_handle.insert_source(Timer::from_duration(Duration::from_millis(200)), move |current, _, data| { + let duration = current.duration_since(start).as_millis(); + data.state.handle_action(action_clone.clone(), &seat_clone, serial, time.overflowing_add(duration as u32).0, key_pattern_clone.clone(), None); + calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25)) + }).ok() + } else { None }; + + userdata + .get::() + .unwrap() + .add(&handle, token); + } return FilterResult::Intercept(Some(( - Action::_ResizingInternal(direction, edge, state), - KeyPattern { - modifiers: modifiers.clone().into(), - key: handle.raw_code(), - }, + action, + key_pattern ))); } } // Skip released events for initially surpressed keys - if state == KeyState::Released - && userdata.get::().unwrap().filter(&handle) - { - return FilterResult::Intercept(None); + if state == KeyState::Released { + if let Some(tokens) = userdata.get::().unwrap().filter(&handle) { + for token in tokens { + loop_handle.remove(token); + } + return FilterResult::Intercept(None); + } } // Pass keys to debug interface, if it has focus @@ -341,7 +390,7 @@ impl State { ) { error!(?err, "Failed switching virtual terminal."); } - userdata.get::().unwrap().add(&handle); + userdata.get::().unwrap().add(&handle, None); return FilterResult::Intercept(None); } @@ -357,7 +406,7 @@ impl State { userdata .get::() .unwrap() - .add(&handle); + .add(&handle, None); return FilterResult::Intercept(Some(( action.clone(), binding.clone(), @@ -1188,9 +1237,9 @@ impl State { ), Action::_ResizingInternal(direction, edge, state) => { if state == KeyState::Pressed { - self.common.shell.start_resize(seat, direction, edge); + self.common.shell.resize(seat, direction, edge); } else { - self.common.shell.stop_resize(seat, direction, edge); + self.common.shell.finish_resize(direction, edge); } } Action::ToggleOrientation => { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 74c95599..88f702c9 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -129,6 +129,7 @@ impl CosmicStack { for window in &windows { window.try_force_undecorated(true); window.set_tiled(true); + window.send_configure(); } let width = windows[0].geometry().size.w; diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 17aa4aca..72659ec3 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1249,6 +1249,9 @@ impl Shell { } else { if let ResizeMode::Started(_, _, direction) = &self.resize_mode { self.resize_mode = ResizeMode::Ended(Instant::now(), *direction); + if let Some((_, direction, edge, _, _, _)) = self.resize_state.as_ref() { + self.finish_resize(*direction, *edge); + } } } } @@ -1591,12 +1594,7 @@ impl Shell { } } - pub fn start_resize( - &mut self, - seat: &Seat, - direction: ResizeDirection, - edge: ResizeEdge, - ) { + pub fn resize(&mut self, seat: &Seat, direction: ResizeDirection, edge: ResizeEdge) { let output = seat.active_output(); let (_, idx) = self.workspaces.active_num(&output); let Some(focused) = seat.get_keyboard().unwrap().current_focus() else { return }; @@ -1615,12 +1613,7 @@ impl Shell { } } - pub fn stop_resize( - &mut self, - _seat: &Seat, - direction: ResizeDirection, - edge: ResizeEdge, - ) { + pub fn finish_resize(&mut self, direction: ResizeDirection, edge: ResizeEdge) { if let Some((old_focused, old_direction, old_edge, _, idx, output)) = self.resize_state.take() {