diff --git a/inlyne.default.toml b/inlyne.default.toml index 15e6a370..0fe7949a 100644 --- a/inlyne.default.toml +++ b/inlyne.default.toml @@ -101,6 +101,7 @@ code-highlighter = "github" # ] # Possible Keys: [ # "a"-"z", +# "A"-"Z", # "0"-"9", # "`", "@", "*", "-", "=", "+", "[", "]", "\\", ";", ":", "'", ",", ".", # "/", diff --git a/src/keybindings/serialization.rs b/src/keybindings/serialization.rs index 801477a4..e9c97208 100644 --- a/src/keybindings/serialization.rs +++ b/src/keybindings/serialization.rs @@ -6,7 +6,7 @@ use super::action::{Action, VertDirection, Zoom}; use super::{Key, KeyCombo, ModifiedKey}; use serde::{de, Deserialize, Deserializer}; -use winit::event::ModifiersState; +use winit::event::{ModifiersState, VirtualKeyCode as VirtKey}; impl<'de> Deserialize<'de> for Action { fn deserialize(deserializer: D) -> Result @@ -69,6 +69,71 @@ impl<'de> Deserialize<'de> for Key { } } +struct ShortKey { + key: Key, + shift: bool, +} + +impl<'de> Deserialize<'de> for ShortKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum StringOrNum { + Str(String), + Num(u32), + } + + let shifted_key = |virt_key| { + Ok(Self { + key: Key::Resolved(virt_key), + shift: true, + }) + }; + + match StringOrNum::deserialize(deserializer)? { + StringOrNum::Str(s) => match &*s { + "A" => shifted_key(VirtKey::A), + "B" => shifted_key(VirtKey::B), + "C" => shifted_key(VirtKey::C), + "D" => shifted_key(VirtKey::D), + "E" => shifted_key(VirtKey::E), + "F" => shifted_key(VirtKey::F), + "G" => shifted_key(VirtKey::G), + "H" => shifted_key(VirtKey::H), + "I" => shifted_key(VirtKey::I), + "J" => shifted_key(VirtKey::J), + "K" => shifted_key(VirtKey::K), + "L" => shifted_key(VirtKey::L), + "M" => shifted_key(VirtKey::M), + "N" => shifted_key(VirtKey::N), + "O" => shifted_key(VirtKey::O), + "P" => shifted_key(VirtKey::P), + "Q" => shifted_key(VirtKey::Q), + "R" => shifted_key(VirtKey::R), + "S" => shifted_key(VirtKey::S), + "T" => shifted_key(VirtKey::T), + "U" => shifted_key(VirtKey::U), + "V" => shifted_key(VirtKey::V), + "W" => shifted_key(VirtKey::W), + "X" => shifted_key(VirtKey::X), + "Y" => shifted_key(VirtKey::Y), + "Z" => shifted_key(VirtKey::Z), + other => match Key::from_str(other) { + Ok(key) => Ok(Self { key, shift: false }), + Err(err) => Err(de::Error::custom(err)), + }, + }, + StringOrNum::Num(num) => Ok(Self { + key: Key::ScanCode(num), + shift: false, + }), + } + } +} + impl<'de> Deserialize<'de> for ModifiedKey { fn deserialize(deserializer: D) -> Result where @@ -82,24 +147,45 @@ impl<'de> Deserialize<'de> for ModifiedKey { Shift, } + #[derive(Deserialize)] + #[serde(untagged)] + enum ModOrMods { + Mod(ModifierType), + Mods(Vec), + } + #[derive(Deserialize)] struct Inner { - key: Key, - r#mod: Vec, + key: ShortKey, + #[serde(rename = "mod")] + mod_: ModOrMods, } #[derive(Deserialize)] #[serde(untagged)] enum KeyOrModifiedKey { - Key(Key), + Key(ShortKey), ModifiedKey(Inner), } Ok(match KeyOrModifiedKey::deserialize(deserializer)? { - KeyOrModifiedKey::Key(key) => ModifiedKey(key, ModifiersState::empty()), - KeyOrModifiedKey::ModifiedKey(Inner { key, r#mod }) => { + KeyOrModifiedKey::Key(ShortKey { key, shift }) => { + let mut mods = ModifiersState::empty(); + if shift { + mods |= ModifiersState::SHIFT; + } + ModifiedKey(key, mods) + } + KeyOrModifiedKey::ModifiedKey(Inner { + key: ShortKey { key, shift }, + mod_, + }) => { let mut modifiers = ModifiersState::empty(); - for ty in r#mod { + let mod_ = match mod_ { + ModOrMods::Mod(m) => vec![m], + ModOrMods::Mods(mods) => mods, + }; + for ty in mod_ { modifiers |= match ty { ModifierType::Alt => ModifiersState::ALT, ModifierType::Ctrl => ModifiersState::CTRL, @@ -107,6 +193,9 @@ impl<'de> Deserialize<'de> for ModifiedKey { ModifierType::Shift => ModifiersState::SHIFT, }; } + if shift { + modifiers |= ModifiersState::SHIFT; + } ModifiedKey(key, modifiers) } diff --git a/src/keybindings/tests.rs b/src/keybindings/tests.rs index a2d4ff8d..8ee3541e 100644 --- a/src/keybindings/tests.rs +++ b/src/keybindings/tests.rs @@ -49,16 +49,15 @@ base = [ // make things less verbose // TODO(cosmic): Consider switching the casing away from PascalCase? Maybe keep it inline with the // rest of the config file and use kebab-case instead? -// TODO(cosmic): Allow for passing a single string for `mod` const DEFAULTS_TEMPLATE: &str = r#" [keybindings] base = [ # Regular - ["Copy", { key = "c", mod = ["CTRL_OR_CMD"] }], - ["ZoomIn", { key = "=", mod = ["CTRL_OR_CMD"] }], - ["ZoomOut", { key = "-", mod = ["CTRL_OR_CMD"] }], - ["HistoryNext", { key = "Right", mod = ["Alt"] }], - ["HistoryPrevious", { key = "Left", mod = ["Alt"] }], + ["Copy", { key = "c", mod = "CTRL_OR_CMD" }], + ["ZoomIn", { key = "=", mod = "CTRL_OR_CMD" }], + ["ZoomOut", { key = "-", mod = "CTRL_OR_CMD" }], + ["HistoryNext", { key = "Right", mod = "Alt" }], + ["HistoryPrevious", { key = "Left", mod = "Alt" }], ["ScrollUp", "Up"], ["ScrollDown", "Down"], ["PageUp", "PageUp"], @@ -71,10 +70,10 @@ base = [ ["ScrollUp", "k"], ["ScrollDown", "j"], ["ToTop", ["g", "g"]], - ["ToBottom", { key = "g", mod = ["Shift"] }], + ["ToBottom", "G"], ["Quit", "q"], - ["Quit", [{ key = "z", mod = ["Shift"] }, { key = "z", mod = ["Shift"] }]], - ["Quit", [{ key = "z", mod = ["Shift"] }, { key = "q", mod = ["Shift"] }]], + ["Quit", ["Z", "Z"]], + ["Quit", ["Z", "Q"]], ["HistoryNext", ["b", "n"]], ["HistoryPrevious", ["b", "p"]], ]