kms: Add key repetition for shortcuts
This commit is contained in:
parent
99f29187af
commit
235248d445
6 changed files with 86 additions and 43 deletions
|
|
@ -155,7 +155,7 @@ pub fn init_backend(
|
||||||
if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event {
|
if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event {
|
||||||
data.state.common.config.read_device(device);
|
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() {
|
for output in data.state.common.shell.outputs() {
|
||||||
if let Err(err) = data.state.backend.kms().schedule_render(
|
if let Err(err) = data.state.backend.kms().schedule_render(
|
||||||
&data.state.common.event_loop_handle,
|
&data.state.common.event_loop_handle,
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,7 @@ impl State {
|
||||||
render_ping.ping();
|
render_ping.ping();
|
||||||
}
|
}
|
||||||
WinitEvent::Refresh => 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),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,7 @@ impl State {
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.process_input_event(event);
|
self.process_input_event(event, false);
|
||||||
// TODO actually figure out the output
|
// TODO actually figure out the output
|
||||||
for output in self.common.shell.outputs() {
|
for output in self.common.shell.outputs() {
|
||||||
self.backend.x11().schedule_render(output, None);
|
self.backend.x11().schedule_render(output, None);
|
||||||
|
|
|
||||||
105
src/input/mod.rs
105
src/input/mod.rs
|
|
@ -15,6 +15,7 @@ use crate::{
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session},
|
wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session},
|
||||||
};
|
};
|
||||||
|
use calloop::{timer::Timer, RegistrationToken};
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::{
|
backend::input::{
|
||||||
|
|
@ -40,7 +41,11 @@ use smithay::{
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing::{error, trace, warn};
|
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;
|
use xkbcommon::xkb::KEY_XF86Switch_VT_12;
|
||||||
|
|
||||||
crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS);
|
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 SeatId(pub usize);
|
||||||
pub struct ActiveOutput(pub RefCell<Output>);
|
pub struct ActiveOutput(pub RefCell<Output>);
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SupressedKeys(RefCell<Vec<u32>>);
|
pub struct SupressedKeys(RefCell<Vec<(u32, Option<RegistrationToken>)>>);
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Devices(RefCell<HashMap<String, Vec<DeviceCapability>>>);
|
pub struct Devices(RefCell<HashMap<String, Vec<DeviceCapability>>>);
|
||||||
|
|
||||||
|
|
@ -66,17 +71,26 @@ impl Drop for SeatId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupressedKeys {
|
impl SupressedKeys {
|
||||||
fn add(&self, keysym: &KeysymHandle) {
|
fn add(&self, keysym: &KeysymHandle, token: impl Into<Option<RegistrationToken>>) {
|
||||||
self.0.borrow_mut().push(keysym.raw_code());
|
self.0.borrow_mut().push((keysym.raw_code(), token.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&self, keysym: &KeysymHandle) -> bool {
|
fn filter(&self, keysym: &KeysymHandle) -> Option<Vec<RegistrationToken>> {
|
||||||
let mut keys = self.0.borrow_mut();
|
let mut keys = self.0.borrow_mut();
|
||||||
if let Some(i) = keys.iter().position(|x| *x == keysym.raw_code()) {
|
let (removed, remaining) = keys
|
||||||
keys.remove(i);
|
.drain(..)
|
||||||
true
|
.partition(|(key, _)| *key == keysym.raw_code());
|
||||||
|
*keys = remaining;
|
||||||
|
|
||||||
|
let removed = removed
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, token)| token)
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if removed.is_empty() {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
false
|
Some(removed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +168,11 @@ pub fn add_seat(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
|
pub fn process_input_event<B: InputBackend>(
|
||||||
|
&mut self,
|
||||||
|
event: InputEvent<B>,
|
||||||
|
needs_key_repetition: bool,
|
||||||
|
) {
|
||||||
use smithay::backend::input::Event;
|
use smithay::backend::input::Event;
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
|
@ -195,7 +213,9 @@ impl State {
|
||||||
InputEvent::Keyboard { event, .. } => {
|
InputEvent::Keyboard { event, .. } => {
|
||||||
use smithay::backend::input::KeyboardKeyEvent;
|
use smithay::backend::input::KeyboardKeyEvent;
|
||||||
|
|
||||||
|
let loop_handle = self.common.event_loop_handle.clone();
|
||||||
let device = event.device();
|
let device = event.device();
|
||||||
|
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
let workspace = self.common.shell.active_space_mut(¤t_output);
|
let workspace = self.common.shell.active_space_mut(¤t_output);
|
||||||
|
|
@ -251,7 +271,6 @@ impl State {
|
||||||
&& handle.raw_syms().contains(&action_pattern.key)
|
&& handle.raw_syms().contains(&action_pattern.key)
|
||||||
{
|
{
|
||||||
data.common.shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone());
|
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 {
|
} else if action_pattern.modifiers != *modifiers {
|
||||||
let mut new_pattern = action_pattern.clone();
|
let mut new_pattern = action_pattern.clone();
|
||||||
new_pattern.modifiers = modifiers.clone().into();
|
new_pattern.modifiers = modifiers.clone().into();
|
||||||
|
|
@ -280,10 +299,10 @@ impl State {
|
||||||
data.common.shell.resize_mode()
|
data.common.shell.resize_mode()
|
||||||
{
|
{
|
||||||
let resize_edge = match handle.modified_sym() {
|
let resize_edge = match handle.modified_sym() {
|
||||||
keysyms::KEY_Left | keysyms::KEY_H => Some(ResizeEdge::LEFT),
|
keysyms::KEY_Left | keysyms::KEY_h | keysyms::KEY_H => Some(ResizeEdge::LEFT),
|
||||||
keysyms::KEY_Down | keysyms::KEY_J => Some(ResizeEdge::BOTTOM),
|
keysyms::KEY_Down | keysyms::KEY_j | keysyms::KEY_J => Some(ResizeEdge::BOTTOM),
|
||||||
keysyms::KEY_Up | keysyms::KEY_K => Some(ResizeEdge::TOP),
|
keysyms::KEY_Up | keysyms::KEY_k | keysyms::KEY_K => Some(ResizeEdge::TOP),
|
||||||
keysyms::KEY_Right | keysyms::KEY_L => Some(ResizeEdge::RIGHT),
|
keysyms::KEY_Right | keysyms::KEY_l | keysyms::KEY_L => Some(ResizeEdge::RIGHT),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -291,21 +310,51 @@ impl State {
|
||||||
if direction == ResizeDirection::Inwards {
|
if direction == ResizeDirection::Inwards {
|
||||||
edge.flip_direction();
|
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::<SupressedKeys>().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::<SupressedKeys>()
|
||||||
|
.unwrap()
|
||||||
|
.add(&handle, token);
|
||||||
|
}
|
||||||
return FilterResult::Intercept(Some((
|
return FilterResult::Intercept(Some((
|
||||||
Action::_ResizingInternal(direction, edge, state),
|
action,
|
||||||
KeyPattern {
|
key_pattern
|
||||||
modifiers: modifiers.clone().into(),
|
|
||||||
key: handle.raw_code(),
|
|
||||||
},
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip released events for initially surpressed keys
|
// Skip released events for initially surpressed keys
|
||||||
if state == KeyState::Released
|
if state == KeyState::Released {
|
||||||
&& userdata.get::<SupressedKeys>().unwrap().filter(&handle)
|
if let Some(tokens) = userdata.get::<SupressedKeys>().unwrap().filter(&handle) {
|
||||||
{
|
for token in tokens {
|
||||||
return FilterResult::Intercept(None);
|
loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
return FilterResult::Intercept(None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass keys to debug interface, if it has focus
|
// Pass keys to debug interface, if it has focus
|
||||||
|
|
@ -341,7 +390,7 @@ impl State {
|
||||||
) {
|
) {
|
||||||
error!(?err, "Failed switching virtual terminal.");
|
error!(?err, "Failed switching virtual terminal.");
|
||||||
}
|
}
|
||||||
userdata.get::<SupressedKeys>().unwrap().add(&handle);
|
userdata.get::<SupressedKeys>().unwrap().add(&handle, None);
|
||||||
return FilterResult::Intercept(None);
|
return FilterResult::Intercept(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,7 +406,7 @@ impl State {
|
||||||
userdata
|
userdata
|
||||||
.get::<SupressedKeys>()
|
.get::<SupressedKeys>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(&handle);
|
.add(&handle, None);
|
||||||
return FilterResult::Intercept(Some((
|
return FilterResult::Intercept(Some((
|
||||||
action.clone(),
|
action.clone(),
|
||||||
binding.clone(),
|
binding.clone(),
|
||||||
|
|
@ -1188,9 +1237,9 @@ impl State {
|
||||||
),
|
),
|
||||||
Action::_ResizingInternal(direction, edge, state) => {
|
Action::_ResizingInternal(direction, edge, state) => {
|
||||||
if state == KeyState::Pressed {
|
if state == KeyState::Pressed {
|
||||||
self.common.shell.start_resize(seat, direction, edge);
|
self.common.shell.resize(seat, direction, edge);
|
||||||
} else {
|
} else {
|
||||||
self.common.shell.stop_resize(seat, direction, edge);
|
self.common.shell.finish_resize(direction, edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::ToggleOrientation => {
|
Action::ToggleOrientation => {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ impl CosmicStack {
|
||||||
for window in &windows {
|
for window in &windows {
|
||||||
window.try_force_undecorated(true);
|
window.try_force_undecorated(true);
|
||||||
window.set_tiled(true);
|
window.set_tiled(true);
|
||||||
|
window.send_configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
let width = windows[0].geometry().size.w;
|
let width = windows[0].geometry().size.w;
|
||||||
|
|
|
||||||
|
|
@ -1249,6 +1249,9 @@ impl Shell {
|
||||||
} else {
|
} else {
|
||||||
if let ResizeMode::Started(_, _, direction) = &self.resize_mode {
|
if let ResizeMode::Started(_, _, direction) = &self.resize_mode {
|
||||||
self.resize_mode = ResizeMode::Ended(Instant::now(), *direction);
|
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(
|
pub fn resize(&mut self, seat: &Seat<State>, direction: ResizeDirection, edge: ResizeEdge) {
|
||||||
&mut self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
direction: ResizeDirection,
|
|
||||||
edge: ResizeEdge,
|
|
||||||
) {
|
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let (_, idx) = self.workspaces.active_num(&output);
|
let (_, idx) = self.workspaces.active_num(&output);
|
||||||
let Some(focused) = seat.get_keyboard().unwrap().current_focus() else { return };
|
let Some(focused) = seat.get_keyboard().unwrap().current_focus() else { return };
|
||||||
|
|
@ -1615,12 +1613,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_resize(
|
pub fn finish_resize(&mut self, direction: ResizeDirection, edge: ResizeEdge) {
|
||||||
&mut self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
direction: ResizeDirection,
|
|
||||||
edge: ResizeEdge,
|
|
||||||
) {
|
|
||||||
if let Some((old_focused, old_direction, old_edge, _, idx, output)) =
|
if let Some((old_focused, old_direction, old_edge, _, idx, output)) =
|
||||||
self.resize_state.take()
|
self.resize_state.take()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue