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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
},
|
||||
};
|
||||
use cosmic_config::{ConfigGet, CosmicConfigEntry};
|
||||
use cosmic_settings_config::{shortcuts, Shortcuts};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smithay::wayland::xdg_activation::XdgActivationState;
|
||||
pub use smithay::{
|
||||
|
|
@ -25,66 +26,33 @@ pub use smithay::{
|
|||
};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
collections::{BTreeMap, HashMap},
|
||||
fs::OpenOptions,
|
||||
path::PathBuf,
|
||||
sync::{atomic::AtomicBool, Arc, RwLock},
|
||||
};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{error, warn};
|
||||
|
||||
mod input_config;
|
||||
mod key_bindings;
|
||||
pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern};
|
||||
pub mod key_bindings;
|
||||
pub use key_bindings::{Action, PrivateAction};
|
||||
mod types;
|
||||
pub use self::types::*;
|
||||
use cosmic_comp_config::{
|
||||
input::InputConfig,
|
||||
workspace::{WorkspaceConfig, WorkspaceLayout},
|
||||
CosmicCompConfig, TileBehavior, XkbConfig,
|
||||
input::InputConfig, workspace::WorkspaceConfig, CosmicCompConfig, TileBehavior, XkbConfig,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
pub static_conf: StaticConfig,
|
||||
pub dynamic_conf: DynamicConfig,
|
||||
pub cosmic_helper: cosmic_config::Config,
|
||||
pub cosmic_conf: CosmicCompConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StaticConfig {
|
||||
pub key_bindings: HashMap<key_bindings::KeyPattern, key_bindings::Action>,
|
||||
pub data_control_enabled: bool,
|
||||
}
|
||||
|
||||
impl StaticConfig {
|
||||
pub fn get_shortcut_for_action(&self, action: &Action) -> Option<String> {
|
||||
let possible_variants = self
|
||||
.key_bindings
|
||||
.iter()
|
||||
.filter(|(_, a)| *a == action)
|
||||
.map(|(b, _)| b)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
possible_variants
|
||||
.iter()
|
||||
.find(|b| b.key.is_none()) // prefer short bindings
|
||||
.or_else(|| {
|
||||
possible_variants
|
||||
.iter() // prefer bindings containing arrow keys
|
||||
.find(|b| {
|
||||
matches!(
|
||||
b.key,
|
||||
Some(Keysym::Down)
|
||||
| Some(Keysym::Up)
|
||||
| Some(Keysym::Left)
|
||||
| Some(Keysym::Right)
|
||||
)
|
||||
})
|
||||
})
|
||||
.or_else(|| possible_variants.first()) // take the first one
|
||||
.map(|binding| binding.to_string())
|
||||
}
|
||||
/// cosmic-config context for `com.system76.CosmicSettings.Shortcuts`
|
||||
pub settings_context: cosmic_config::Config,
|
||||
/// Key bindings from `com.system76.CosmicSettings.Shortcuts`
|
||||
pub shortcuts: Shortcuts,
|
||||
/// System actions from `com.system76.CosmicSettings.Shortcuts`
|
||||
pub system_actions: BTreeMap<shortcuts::action::System, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -185,6 +153,7 @@ impl Config {
|
|||
.expect("Failed to add cosmic-config to the event loop");
|
||||
let xdg = xdg::BaseDirectories::new().ok();
|
||||
let workspace = get_config::<WorkspaceConfig>(&config, "workspaces");
|
||||
|
||||
let cosmic_comp_config =
|
||||
CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| {
|
||||
for err in errs {
|
||||
|
|
@ -192,72 +161,48 @@ impl Config {
|
|||
}
|
||||
c
|
||||
});
|
||||
Config {
|
||||
static_conf: Self::load_static(xdg.as_ref(), workspace.workspace_layout),
|
||||
dynamic_conf: Self::load_dynamic(xdg.as_ref()),
|
||||
cosmic_conf: cosmic_comp_config,
|
||||
cosmic_helper: config,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_static(
|
||||
xdg: Option<&xdg::BaseDirectories>,
|
||||
workspace_layout: WorkspaceLayout,
|
||||
) -> StaticConfig {
|
||||
let mut locations = if let Some(base) = xdg {
|
||||
vec![
|
||||
base.get_config_file("cosmic-comp.ron"),
|
||||
base.get_config_file("cosmic-comp/config.ron"),
|
||||
]
|
||||
} else {
|
||||
Vec::with_capacity(3)
|
||||
};
|
||||
if cfg!(debug_assertions) {
|
||||
if let Ok(mut cwd) = std::env::current_dir() {
|
||||
cwd.push("config.ron");
|
||||
locations.push(cwd);
|
||||
}
|
||||
}
|
||||
locations.push(PathBuf::from("/etc/cosmic-comp/config.ron"));
|
||||
locations.push(PathBuf::from("/etc/cosmic-comp.ron"));
|
||||
// Source key bindings from com.system76.CosmicSettings.Shortcuts
|
||||
let settings_context = shortcuts::context().unwrap();
|
||||
let system_actions = shortcuts::system_actions(&config);
|
||||
let mut shortcuts = shortcuts::shortcuts(&settings_context);
|
||||
|
||||
for path in locations {
|
||||
debug!("Trying config location: {}", path.display());
|
||||
if path.exists() {
|
||||
info!("Using config at {}", path.display());
|
||||
let Ok(file) = OpenOptions::new().read(true).open(path) else {
|
||||
error!("Failed to open config file.");
|
||||
continue;
|
||||
};
|
||||
match ron::de::from_reader::<_, StaticConfig>(file) {
|
||||
Ok(mut config) => {
|
||||
key_bindings::add_default_bindings(
|
||||
&mut config.key_bindings,
|
||||
workspace_layout,
|
||||
);
|
||||
return config;
|
||||
// Add any missing default shortcuts recommended by the compositor.
|
||||
key_bindings::add_default_bindings(&mut shortcuts, workspace.workspace_layout);
|
||||
|
||||
// Listen for updates to the keybindings config.
|
||||
let source = cosmic_config::calloop::ConfigWatchSource::new(&settings_context).expect(
|
||||
"failed to create config watch source for com.system76.CosmicSettings.Shortcuts",
|
||||
);
|
||||
_ = loop_handle.insert_source(source, |(config, keys), (), state| {
|
||||
for key in keys {
|
||||
match key.as_str() {
|
||||
// Reload the keyboard shortcuts config.
|
||||
"custom" | "defaults" => {
|
||||
let mut shortcuts = shortcuts::shortcuts(&config);
|
||||
let layout =
|
||||
get_config::<WorkspaceConfig>(&config, "workspaces").workspace_layout;
|
||||
key_bindings::add_default_bindings(&mut shortcuts, layout);
|
||||
state.common.config.shortcuts = shortcuts;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Malformed config file (skipping): {}", err);
|
||||
continue;
|
||||
|
||||
"system_actions" => {
|
||||
state.common.config.system_actions = shortcuts::system_actions(&config);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("No config found, consider installing a config file. Using default mapping.");
|
||||
|
||||
let mut config = ron::from_str(include_str!("../../config.ron")).unwrap_or_else(|err| {
|
||||
debug!("Failed to load internal default config: {}", err);
|
||||
StaticConfig {
|
||||
// Small useful keybindings by default
|
||||
key_bindings: HashMap::new(),
|
||||
data_control_enabled: false,
|
||||
}
|
||||
});
|
||||
|
||||
key_bindings::add_default_bindings(&mut config.key_bindings, workspace_layout);
|
||||
config
|
||||
Config {
|
||||
dynamic_conf: Self::load_dynamic(xdg.as_ref()),
|
||||
cosmic_conf: cosmic_comp_config,
|
||||
cosmic_helper: config,
|
||||
settings_context,
|
||||
shortcuts,
|
||||
system_actions,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_dynamic(xdg: Option<&xdg::BaseDirectories>) -> DynamicConfig {
|
||||
|
|
@ -314,6 +259,10 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn shortcut_for_action(&self, action: &shortcuts::Action) -> Option<String> {
|
||||
self.shortcuts.shortcut_for_action(action)
|
||||
}
|
||||
|
||||
pub fn read_outputs(
|
||||
&mut self,
|
||||
output_state: &mut OutputConfigurationState<State>,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use super::{KeyModifier, KeyModifiers};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smithay::reexports::x11rb::NO_SYMBOL;
|
||||
pub use smithay::{
|
||||
input::keyboard::{Keysym, XkbConfig as WlXkbConfig},
|
||||
utils::Transform,
|
||||
};
|
||||
use tracing::warn;
|
||||
use xkbcommon::xkb;
|
||||
pub use smithay::{input::keyboard::XkbConfig as WlXkbConfig, utils::Transform};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "Transform")]
|
||||
|
|
@ -23,62 +16,3 @@ pub enum TransformDef {
|
|||
Flipped180,
|
||||
Flipped270,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct KeyModifiersDef(Vec<KeyModifier>);
|
||||
|
||||
impl From<KeyModifiersDef> for KeyModifiers {
|
||||
fn from(src: KeyModifiersDef) -> Self {
|
||||
src.0.into_iter().fold(
|
||||
KeyModifiers {
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
shift: false,
|
||||
logo: false,
|
||||
},
|
||||
|mut modis, modi: KeyModifier| {
|
||||
modis += modi;
|
||||
modis
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn deserialize_KeyModifiers<'de, D>(deserializer: D) -> Result<KeyModifiers, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
KeyModifiersDef::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result<Option<Keysym>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
use serde::de::{Error, Unexpected};
|
||||
|
||||
let name = String::deserialize(deserializer)?;
|
||||
//let name = format!("KEY_{}", code);
|
||||
match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) {
|
||||
x if x.raw() == NO_SYMBOL => {
|
||||
match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) {
|
||||
x if x.raw() == NO_SYMBOL => Err(<D::Error as Error>::invalid_value(
|
||||
Unexpected::Str(&name),
|
||||
&"One of the keysym names of xkbcommon.h without the 'KEY_' prefix",
|
||||
)),
|
||||
x => {
|
||||
warn!(
|
||||
"Key-Binding '{}' only matched case insensitive for {:?}",
|
||||
name,
|
||||
xkb::keysym_get_name(x)
|
||||
);
|
||||
Ok(Some(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
x => Ok(Some(x)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue