feat: runtime configurable keybindings
This commit is contained in:
parent
62afa4cf61
commit
553c49b42b
25 changed files with 674 additions and 829 deletions
|
|
@ -1,221 +1,29 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::shell::{focus::FocusDirection, grabs::ResizeEdge, Direction, ResizeDirection};
|
||||
use cosmic_comp_config::workspace::WorkspaceLayout;
|
||||
use serde::Deserialize;
|
||||
use smithay::{
|
||||
backend::input::KeyState,
|
||||
input::keyboard::{xkb::keysym_get_name, ModifiersState},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use cosmic_settings_config::shortcuts::State as KeyState;
|
||||
use cosmic_settings_config::shortcuts::{self, Modifiers, Shortcuts};
|
||||
use smithay::input::keyboard::ModifiersState;
|
||||
use xkbcommon::xkb;
|
||||
|
||||
use super::types::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||
pub enum KeyModifier {
|
||||
Ctrl,
|
||||
Alt,
|
||||
Shift,
|
||||
Super,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||
pub struct KeyModifiers {
|
||||
pub ctrl: bool,
|
||||
pub alt: bool,
|
||||
pub shift: bool,
|
||||
pub logo: bool,
|
||||
}
|
||||
|
||||
impl PartialEq<ModifiersState> for KeyModifiers {
|
||||
fn eq(&self, other: &ModifiersState) -> bool {
|
||||
self.ctrl == other.ctrl
|
||||
&& self.alt == other.alt
|
||||
&& self.shift == other.shift
|
||||
&& self.logo == other.logo
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<KeyModifiers> for ModifiersState {
|
||||
fn into(self) -> KeyModifiers {
|
||||
KeyModifiers {
|
||||
ctrl: self.ctrl,
|
||||
alt: self.alt,
|
||||
shift: self.shift,
|
||||
logo: self.logo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign<KeyModifier> for KeyModifiers {
|
||||
fn add_assign(&mut self, rhs: KeyModifier) {
|
||||
match rhs {
|
||||
KeyModifier::Ctrl => self.ctrl = true,
|
||||
KeyModifier::Alt => self.alt = true,
|
||||
KeyModifier::Shift => self.shift = true,
|
||||
KeyModifier::Super => self.logo = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for KeyModifier {
|
||||
type Output = KeyModifiers;
|
||||
|
||||
fn bitor(self, rhs: KeyModifier) -> Self::Output {
|
||||
let mut modifiers = self.into();
|
||||
modifiers += rhs;
|
||||
modifiers
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<KeyModifiers> for KeyModifier {
|
||||
fn into(self) -> KeyModifiers {
|
||||
let mut modifiers = KeyModifiers {
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
shift: false,
|
||||
logo: false,
|
||||
};
|
||||
modifiers += self;
|
||||
modifiers
|
||||
}
|
||||
}
|
||||
|
||||
/// Describtion of a key combination that might be
|
||||
/// handled by the compositor.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct KeyPattern {
|
||||
/// What modifiers are expected to be pressed alongside the key
|
||||
#[serde(deserialize_with = "deserialize_KeyModifiers")]
|
||||
pub modifiers: KeyModifiers,
|
||||
/// The actual key, that was pressed
|
||||
#[serde(deserialize_with = "deserialize_Keysym", default)]
|
||||
pub key: Option<Keysym>,
|
||||
}
|
||||
|
||||
impl KeyPattern {
|
||||
pub fn new(modifiers: impl Into<KeyModifiers>, key: Option<Keysym>) -> KeyPattern {
|
||||
KeyPattern {
|
||||
modifiers: modifiers.into(),
|
||||
key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inferred_direction(&self) -> Option<Direction> {
|
||||
match self.key? {
|
||||
Keysym::Left | Keysym::h | Keysym::H => Some(Direction::Left),
|
||||
Keysym::Down | Keysym::j | Keysym::J => Some(Direction::Down),
|
||||
Keysym::Up | Keysym::k | Keysym::K => Some(Direction::Up),
|
||||
Keysym::Right | Keysym::l | Keysym::L => Some(Direction::Right),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for KeyPattern {
|
||||
fn to_string(&self) -> String {
|
||||
let mut result = String::new();
|
||||
if self.modifiers.logo {
|
||||
result += "Super+";
|
||||
}
|
||||
if self.modifiers.ctrl {
|
||||
result += "Ctrl+";
|
||||
}
|
||||
if self.modifiers.alt {
|
||||
result += "Alt+";
|
||||
}
|
||||
if self.modifiers.shift {
|
||||
result += "Shift+";
|
||||
}
|
||||
|
||||
if let Some(key) = self.key {
|
||||
result += &keysym_get_name(key);
|
||||
} else {
|
||||
result.remove(result.len() - 1);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Action {
|
||||
Terminate,
|
||||
Debug,
|
||||
Close,
|
||||
#[serde(skip)]
|
||||
/// Behaviors managed internally by cosmic-comp.
|
||||
Private(PrivateAction),
|
||||
/// Behaviors managed via cosmic-settings.
|
||||
Shortcut(shortcuts::Action),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
// Behaviors which are internally defined and emitted.
|
||||
pub enum PrivateAction {
|
||||
Escape,
|
||||
|
||||
Workspace(u8),
|
||||
NextWorkspace,
|
||||
PreviousWorkspace,
|
||||
LastWorkspace,
|
||||
MoveToWorkspace(u8),
|
||||
MoveToNextWorkspace,
|
||||
MoveToPreviousWorkspace,
|
||||
MoveToLastWorkspace,
|
||||
SendToWorkspace(u8),
|
||||
SendToNextWorkspace,
|
||||
SendToPreviousWorkspace,
|
||||
SendToLastWorkspace,
|
||||
|
||||
NextOutput,
|
||||
PreviousOutput,
|
||||
MoveToNextOutput,
|
||||
MoveToPreviousOutput,
|
||||
SendToNextOutput,
|
||||
SendToPreviousOutput,
|
||||
SwitchOutput(Direction),
|
||||
MoveToOutput(Direction),
|
||||
SendToOutput(Direction),
|
||||
|
||||
MigrateWorkspaceToNextOutput,
|
||||
MigrateWorkspaceToPreviousOutput,
|
||||
MigrateWorkspaceToOutput(Direction),
|
||||
|
||||
Focus(FocusDirection),
|
||||
Move(Direction),
|
||||
|
||||
ToggleOrientation,
|
||||
Orientation(crate::shell::layout::Orientation),
|
||||
|
||||
ToggleStacking,
|
||||
ToggleTiling,
|
||||
ToggleWindowFloating,
|
||||
ToggleSticky,
|
||||
SwapWindow,
|
||||
|
||||
Resizing(ResizeDirection),
|
||||
#[serde(skip)]
|
||||
_ResizingInternal(ResizeDirection, ResizeEdge, KeyState),
|
||||
Minimize,
|
||||
Maximize,
|
||||
Spawn(String),
|
||||
Resizing(
|
||||
shortcuts::action::ResizeDirection,
|
||||
shortcuts::action::ResizeEdge,
|
||||
shortcuts::State,
|
||||
),
|
||||
}
|
||||
|
||||
fn insert_binding(
|
||||
key_bindings: &mut HashMap<KeyPattern, Action>,
|
||||
modifiers: KeyModifiers,
|
||||
keys: impl Iterator<Item = Keysym>,
|
||||
action: Action,
|
||||
) {
|
||||
if !key_bindings.values().any(|a| a == &action) {
|
||||
for key in keys {
|
||||
let pattern = KeyPattern {
|
||||
modifiers: modifiers.clone(),
|
||||
key: Some(key),
|
||||
};
|
||||
if !key_bindings.contains_key(&pattern) {
|
||||
key_bindings.insert(pattern, action.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_default_bindings(
|
||||
key_bindings: &mut HashMap<KeyPattern, Action>,
|
||||
workspace_layout: WorkspaceLayout,
|
||||
) {
|
||||
pub fn add_default_bindings(shortcuts: &mut Shortcuts, workspace_layout: WorkspaceLayout) {
|
||||
let (
|
||||
workspace_previous,
|
||||
workspace_next,
|
||||
|
|
@ -223,102 +31,110 @@ pub fn add_default_bindings(
|
|||
(output_next, output_next_dir),
|
||||
) = match workspace_layout {
|
||||
WorkspaceLayout::Horizontal => (
|
||||
[Keysym::Left, Keysym::h],
|
||||
[Keysym::Right, Keysym::l],
|
||||
([Keysym::Up, Keysym::k], Direction::Up),
|
||||
([Keysym::Down, Keysym::j], Direction::Down),
|
||||
[xkb::Keysym::Left, xkb::Keysym::h],
|
||||
[xkb::Keysym::Right, xkb::Keysym::l],
|
||||
(
|
||||
[xkb::Keysym::Up, xkb::Keysym::k],
|
||||
shortcuts::action::Direction::Up,
|
||||
),
|
||||
(
|
||||
[xkb::Keysym::Down, xkb::Keysym::j],
|
||||
shortcuts::action::Direction::Down,
|
||||
),
|
||||
),
|
||||
WorkspaceLayout::Vertical => (
|
||||
[Keysym::Up, Keysym::k],
|
||||
[Keysym::Down, Keysym::j],
|
||||
([Keysym::Left, Keysym::h], Direction::Left),
|
||||
([Keysym::Right, Keysym::l], Direction::Right),
|
||||
[xkb::Keysym::Up, xkb::Keysym::k],
|
||||
[xkb::Keysym::Down, xkb::Keysym::j],
|
||||
(
|
||||
[xkb::Keysym::Left, xkb::Keysym::h],
|
||||
shortcuts::action::Direction::Left,
|
||||
),
|
||||
(
|
||||
[xkb::Keysym::Right, xkb::Keysym::l],
|
||||
shortcuts::action::Direction::Right,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
..Default::default()
|
||||
},
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl(),
|
||||
workspace_previous.iter().copied(),
|
||||
Action::PreviousWorkspace,
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
..Default::default()
|
||||
},
|
||||
workspace_next.iter().copied(),
|
||||
Action::NextWorkspace,
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
shift: true,
|
||||
..Default::default()
|
||||
},
|
||||
workspace_previous.iter().copied(),
|
||||
Action::MoveToPreviousWorkspace,
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
shift: true,
|
||||
..Default::default()
|
||||
},
|
||||
workspace_next.iter().copied(),
|
||||
Action::MoveToNextWorkspace,
|
||||
shortcuts::Action::PreviousWorkspace,
|
||||
);
|
||||
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
..Default::default()
|
||||
},
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl(),
|
||||
workspace_next.iter().copied(),
|
||||
shortcuts::Action::NextWorkspace,
|
||||
);
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl().shift(),
|
||||
workspace_previous.iter().copied(),
|
||||
shortcuts::Action::MoveToPreviousWorkspace,
|
||||
);
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl().shift(),
|
||||
workspace_next.iter().copied(),
|
||||
shortcuts::Action::MoveToNextWorkspace,
|
||||
);
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl(),
|
||||
output_previous.iter().copied(),
|
||||
Action::SwitchOutput(output_previous_dir),
|
||||
shortcuts::Action::SwitchOutput(output_previous_dir),
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl(),
|
||||
output_next.iter().copied(),
|
||||
Action::SwitchOutput(output_next_dir),
|
||||
shortcuts::Action::SwitchOutput(output_next_dir),
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
shift: true,
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl().shift(),
|
||||
output_previous.iter().copied(),
|
||||
Action::MoveToOutput(output_previous_dir),
|
||||
shortcuts::Action::MoveToOutput(output_previous_dir),
|
||||
);
|
||||
insert_binding(
|
||||
key_bindings,
|
||||
KeyModifiers {
|
||||
logo: true,
|
||||
ctrl: true,
|
||||
shift: true,
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
shortcuts.insert_default_binding(
|
||||
Modifiers::new().logo().ctrl().shift(),
|
||||
output_next.iter().copied(),
|
||||
Action::MoveToOutput(output_next_dir),
|
||||
shortcuts::Action::MoveToOutput(output_next_dir),
|
||||
);
|
||||
}
|
||||
|
||||
/// Convert `cosmic_settings_config::shortcuts::State` to `smithay::backend::input::KeyState`.
|
||||
pub fn cosmic_keystate_to_smithay(value: KeyState) -> smithay::backend::input::KeyState {
|
||||
match value {
|
||||
KeyState::Pressed => smithay::backend::input::KeyState::Pressed,
|
||||
KeyState::Released => smithay::backend::input::KeyState::Released,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `smithay::backend::input::KeyState` to `cosmic_settings_config::shortcuts::State`.
|
||||
pub fn cosmic_keystate_from_smithay(value: smithay::backend::input::KeyState) -> KeyState {
|
||||
match value {
|
||||
smithay::backend::input::KeyState::Pressed => KeyState::Pressed,
|
||||
smithay::backend::input::KeyState::Released => KeyState::Released,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare `cosmic_settings_config::shortcuts::Modifiers` to `smithay::input::keyboard::ModifiersState`.
|
||||
pub fn cosmic_modifiers_eq_smithay(this: &Modifiers, other: &ModifiersState) -> bool {
|
||||
this.ctrl == other.ctrl
|
||||
&& this.alt == other.alt
|
||||
&& this.shift == other.shift
|
||||
&& this.logo == other.logo
|
||||
}
|
||||
|
||||
/// Convert `smithay::input::keyboard::ModifiersState` to `cosmic_settings_config::shortcuts::Modifiers`
|
||||
pub fn cosmic_modifiers_from_smithay(value: ModifiersState) -> Modifiers {
|
||||
Modifiers {
|
||||
ctrl: value.ctrl,
|
||||
alt: value.alt,
|
||||
shift: value.shift,
|
||||
logo: value.logo,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue