diff --git a/res/com.system76.CosmicTerm.Shortcuts/v1/defaults b/res/com.system76.CosmicTerm.Shortcuts/v1/defaults deleted file mode 100644 index 1eb6d74..0000000 --- a/res/com.system76.CosmicTerm.Shortcuts/v1/defaults +++ /dev/null @@ -1,50 +0,0 @@ -{ - (modifiers: [Ctrl, Shift], key: "A"): SelectAll, - (modifiers: [Ctrl, Shift], key: "C"): Copy, - (modifiers: [], key: "Copy"): Copy, - (modifiers: [Ctrl], key: "c"): CopyOrSigint, - (modifiers: [Ctrl, Shift], key: "F"): Find, - (modifiers: [Ctrl, Shift], key: "N"): WindowNew, - (modifiers: [Ctrl, Shift], key: "Q"): WindowClose, - (modifiers: [Ctrl, Shift], key: "T"): TabNew, - (modifiers: [Ctrl, Shift], key: "V"): Paste, - (modifiers: [], key: "Paste"): Paste, - (modifiers: [Shift], key: "Insert"): PastePrimary, - (modifiers: [Ctrl, Shift], key: "W"): TabClose, - (modifiers: [Ctrl], key: ","): Settings, - (modifiers: [], key: "F11"): ToggleFullscreen, - - (modifiers: [Ctrl, Alt], key: "d"): PaneSplitHorizontal, - (modifiers: [Ctrl, Alt], key: "r"): PaneSplitVertical, - (modifiers: [Ctrl, Shift], key: "X"): PaneToggleMaximized, - (modifiers: [Ctrl, Alt], key: "p"): PasswordManager, - - (modifiers: [Ctrl], key: "Tab"): TabNext, - (modifiers: [Ctrl, Shift], key: "Tab"): TabPrev, - - (modifiers: [Ctrl, Shift], key: "1"): TabActivate0, - (modifiers: [Ctrl, Shift], key: "2"): TabActivate1, - (modifiers: [Ctrl, Shift], key: "3"): TabActivate2, - (modifiers: [Ctrl, Shift], key: "4"): TabActivate3, - (modifiers: [Ctrl, Shift], key: "5"): TabActivate4, - (modifiers: [Ctrl, Shift], key: "6"): TabActivate5, - (modifiers: [Ctrl, Shift], key: "7"): TabActivate6, - (modifiers: [Ctrl, Shift], key: "8"): TabActivate7, - (modifiers: [Ctrl, Shift], key: "9"): TabActivate8, - - (modifiers: [Ctrl], key: "0"): ZoomReset, - (modifiers: [Ctrl], key: "-"): ZoomOut, - (modifiers: [Ctrl], key: "="): ZoomIn, - (modifiers: [Ctrl], key: "+"): ZoomIn, - - (modifiers: [Ctrl, Shift], key: "ArrowLeft"): PaneFocusLeft, - (modifiers: [Ctrl, Shift], key: "H"): PaneFocusLeft, - (modifiers: [Ctrl, Shift], key: "ArrowDown"): PaneFocusDown, - (modifiers: [Ctrl, Shift], key: "J"): PaneFocusDown, - (modifiers: [Ctrl, Shift], key: "ArrowUp"): PaneFocusUp, - (modifiers: [Ctrl, Shift], key: "K"): PaneFocusUp, - (modifiers: [Ctrl, Shift], key: "ArrowRight"): PaneFocusRight, - (modifiers: [Ctrl, Shift], key: "L"): PaneFocusRight, - - (modifiers: [Ctrl, Alt], key: "L"): ClearScrollback, -} diff --git a/src/key_bind.rs b/src/key_bind.rs index 1114426..86f3d39 100644 --- a/src/key_bind.rs +++ b/src/key_bind.rs @@ -1,96 +1,9 @@ -use cosmic::widget::menu::key_bind::{KeyBind, Modifier}; -use cosmic::{iced::keyboard::Key, iced_core::keyboard::key::Named}; +use cosmic::widget::menu::key_bind::KeyBind; use std::collections::HashMap; use crate::Action; use crate::shortcuts::ShortcutsConfig; pub fn key_binds(shortcuts: &ShortcutsConfig) -> HashMap { - let key_binds = shortcuts.key_binds(); - if key_binds.is_empty() { - fallback_key_binds() - } else { - key_binds - } -} - -fn fallback_key_binds() -> HashMap { - let mut key_binds = HashMap::new(); - - macro_rules! bind { - ([$($modifier:ident),* $(,)?], $key:expr, $action:ident) => {{ - key_binds.insert( - KeyBind { - modifiers: vec![$(Modifier::$modifier),*], - key: $key, - }, - Action::$action, - ); - }}; - } - - // Standard key bindings - bind!([Ctrl, Shift], Key::Character("A".into()), SelectAll); - bind!([Ctrl, Shift], Key::Character("C".into()), Copy); - bind!([], Key::Named(Named::Copy), Copy); - bind!([Ctrl], Key::Character("c".into()), CopyOrSigint); - bind!([Ctrl, Shift], Key::Character("F".into()), Find); - bind!([Ctrl, Shift], Key::Character("N".into()), WindowNew); - bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose); - bind!([Ctrl, Shift], Key::Character("T".into()), TabNew); - bind!([Ctrl, Shift], Key::Character("V".into()), Paste); - bind!([], Key::Named(Named::Paste), Paste); - bind!([Shift], Key::Named(Named::Insert), PastePrimary); - bind!([Ctrl, Shift], Key::Character("W".into()), TabClose); - bind!([Ctrl], Key::Character(",".into()), Settings); - bind!([], Key::Named(Named::F11), ToggleFullscreen); - - // Ctrl+Alt+D splits horizontally, Ctrl+Alt+R splits vertically, Ctrl+Shift+X maximizes split - //TODO: Adjust bindings as desired by UX - bind!([Ctrl, Alt], Key::Character("d".into()), PaneSplitHorizontal); - bind!([Ctrl, Alt], Key::Character("r".into()), PaneSplitVertical); - bind!( - [Ctrl, Shift], - Key::Character("X".into()), - PaneToggleMaximized - ); - #[cfg(feature = "password_manager")] - bind!([Ctrl, Alt], Key::Character("p".into()), PasswordManager); - - // Ctrl+Tab and Ctrl+Shift+Tab cycle through tabs - // Ctrl+Tab is not a special key for terminals and is free to use - bind!([Ctrl], Key::Named(Named::Tab), TabNext); - bind!([Ctrl, Shift], Key::Named(Named::Tab), TabPrev); - - // Ctrl+Shift+# activates tabs by index - bind!([Ctrl, Shift], Key::Character("1".into()), TabActivate0); - bind!([Ctrl, Shift], Key::Character("2".into()), TabActivate1); - bind!([Ctrl, Shift], Key::Character("3".into()), TabActivate2); - bind!([Ctrl, Shift], Key::Character("4".into()), TabActivate3); - bind!([Ctrl, Shift], Key::Character("5".into()), TabActivate4); - bind!([Ctrl, Shift], Key::Character("6".into()), TabActivate5); - bind!([Ctrl, Shift], Key::Character("7".into()), TabActivate6); - bind!([Ctrl, Shift], Key::Character("8".into()), TabActivate7); - bind!([Ctrl, Shift], Key::Character("9".into()), TabActivate8); - - // Ctrl+0, Ctrl+-, and Ctrl+= are not special keys for terminals and are free to use - bind!([Ctrl], Key::Character("0".into()), ZoomReset); - bind!([Ctrl], Key::Character("-".into()), ZoomOut); - bind!([Ctrl], Key::Character("=".into()), ZoomIn); - bind!([Ctrl], Key::Character("+".into()), ZoomIn); - - // Ctrl+Arrows and Ctrl+HJKL move between splits - bind!([Ctrl, Shift], Key::Named(Named::ArrowLeft), PaneFocusLeft); - bind!([Ctrl, Shift], Key::Character("H".into()), PaneFocusLeft); - bind!([Ctrl, Shift], Key::Named(Named::ArrowDown), PaneFocusDown); - bind!([Ctrl, Shift], Key::Character("J".into()), PaneFocusDown); - bind!([Ctrl, Shift], Key::Named(Named::ArrowUp), PaneFocusUp); - bind!([Ctrl, Shift], Key::Character("K".into()), PaneFocusUp); - bind!([Ctrl, Shift], Key::Named(Named::ArrowRight), PaneFocusRight); - bind!([Ctrl, Shift], Key::Character("L".into()), PaneFocusRight); - - // CTRL+Alt+L clears the scrollback. - bind!([Ctrl, Alt], Key::Character("L".into()), ClearScrollback); - - key_binds + shortcuts.key_binds() } diff --git a/src/shortcuts.rs b/src/shortcuts.rs index 247afea..024a0f5 100644 --- a/src/shortcuts.rs +++ b/src/shortcuts.rs @@ -176,15 +176,17 @@ pub struct ShortcutsConfig { impl ShortcutsConfig { pub fn key_binds(&self) -> HashMap { let mut binds = HashMap::new(); - insert_shortcuts(&self.defaults, &mut binds, false); + let defaults = self.defaults_or_fallback(); + insert_shortcuts(&defaults, &mut binds, false); insert_shortcuts(&self.custom, &mut binds, true); binds } pub fn bindings_for_action(&self, action: KeyBindAction) -> Vec { let mut bindings = Vec::new(); + let defaults = self.defaults_or_fallback(); - for (binding, default_action) in &self.defaults.0 { + for (binding, default_action) in &defaults.0 { if *default_action != action { continue; } @@ -219,6 +221,14 @@ impl ShortcutsConfig { bindings } + + fn defaults_or_fallback(&self) -> Shortcuts { + if self.defaults.0.is_empty() { + fallback_shortcuts() + } else { + self.defaults.clone() + } + } } pub fn load() -> (Option, ShortcutsConfig) { @@ -412,6 +422,83 @@ fn insert_shortcuts( } } +fn fallback_shortcuts() -> Shortcuts { + let mut shortcuts = BTreeMap::new(); + + macro_rules! bind { + ([$($modifier:ident),* $(,)?], $key:expr, $action:ident) => {{ + shortcuts.insert( + Binding { + modifiers: vec![$(ModifierName::$modifier),*], + key: $key.to_string(), + }, + KeyBindAction::$action, + ); + }}; + } + + // Standard key bindings + bind!([Ctrl, Shift], "A", SelectAll); + bind!([Ctrl, Shift], "C", Copy); + bind!([], "Copy", Copy); + bind!([Ctrl], "c", CopyOrSigint); + bind!([Ctrl, Shift], "F", Find); + bind!([Ctrl, Shift], "N", WindowNew); + bind!([Ctrl, Shift], "Q", WindowClose); + bind!([Ctrl, Shift], "T", TabNew); + bind!([Ctrl, Shift], "V", Paste); + bind!([], "Paste", Paste); + bind!([Shift], "Insert", PastePrimary); + bind!([Ctrl, Shift], "W", TabClose); + bind!([Ctrl], ",", Settings); + bind!([], "F11", ToggleFullscreen); + + // Ctrl+Alt+D splits horizontally, Ctrl+Alt+R splits vertically, Ctrl+Shift+X maximizes split + //TODO: Adjust bindings as desired by UX + bind!([Ctrl, Alt], "d", PaneSplitHorizontal); + bind!([Ctrl, Alt], "r", PaneSplitVertical); + bind!([Ctrl, Shift], "X", PaneToggleMaximized); + #[cfg(feature = "password_manager")] + bind!([Ctrl, Alt], "p", PasswordManager); + + // Ctrl+Tab and Ctrl+Shift+Tab cycle through tabs + // Ctrl+Tab is not a special key for terminals and is free to use + bind!([Ctrl], "Tab", TabNext); + bind!([Ctrl, Shift], "Tab", TabPrev); + + // Ctrl+Shift+# activates tabs by index + bind!([Ctrl, Shift], "1", TabActivate0); + bind!([Ctrl, Shift], "2", TabActivate1); + bind!([Ctrl, Shift], "3", TabActivate2); + bind!([Ctrl, Shift], "4", TabActivate3); + bind!([Ctrl, Shift], "5", TabActivate4); + bind!([Ctrl, Shift], "6", TabActivate5); + bind!([Ctrl, Shift], "7", TabActivate6); + bind!([Ctrl, Shift], "8", TabActivate7); + bind!([Ctrl, Shift], "9", TabActivate8); + + // Ctrl+0, Ctrl+-, and Ctrl+= are not special keys for terminals and are free to use + bind!([Ctrl], "0", ZoomReset); + bind!([Ctrl], "-", ZoomOut); + bind!([Ctrl], "=", ZoomIn); + bind!([Ctrl], "+", ZoomIn); + + // Ctrl+Arrows and Ctrl+HJKL move between splits + bind!([Ctrl, Shift], "ArrowLeft", PaneFocusLeft); + bind!([Ctrl, Shift], "H", PaneFocusLeft); + bind!([Ctrl, Shift], "ArrowDown", PaneFocusDown); + bind!([Ctrl, Shift], "J", PaneFocusDown); + bind!([Ctrl, Shift], "ArrowUp", PaneFocusUp); + bind!([Ctrl, Shift], "K", PaneFocusUp); + bind!([Ctrl, Shift], "ArrowRight", PaneFocusRight); + bind!([Ctrl, Shift], "L", PaneFocusRight); + + // CTRL+Alt+L clears the scrollback. + bind!([Ctrl, Alt], "L", ClearScrollback); + + Shortcuts(shortcuts) +} + fn key_from_string(value: &str) -> Option { match value { "Copy" => Some(Key::Named(Named::Copy)),