Skip to content

Commit

Permalink
refactor(config): Improve keybindings config definition ergonomics (#287
Browse files Browse the repository at this point in the history
)

* refactor(config): Allow for passing capital letters for keys

* refactor(config): Allow for passing a single modifier
  • Loading branch information
CosmicHorrorDev authored Mar 24, 2024
1 parent 8dd9b38 commit 55a477e
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 16 deletions.
1 change: 1 addition & 0 deletions inlyne.default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ code-highlighter = "github"
# ]
# Possible Keys: [
# "a"-"z",
# "A"-"Z",
# "0"-"9",
# "`", "@", "*", "-", "=", "+", "[", "]", "\\", ";", ":", "'", ",", ".",
# "/",
Expand Down
103 changes: 96 additions & 7 deletions src/keybindings/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<D>(deserializer: D) -> Result<Self, D::Error>
Expand Down Expand Up @@ -69,6 +69,71 @@ impl<'de> Deserialize<'de> for Key {
}
}

struct ShortKey {
key: Key,
shift: bool,
}

impl<'de> Deserialize<'de> for ShortKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand All @@ -82,31 +147,55 @@ impl<'de> Deserialize<'de> for ModifiedKey {
Shift,
}

#[derive(Deserialize)]
#[serde(untagged)]
enum ModOrMods {
Mod(ModifierType),
Mods(Vec<ModifierType>),
}

#[derive(Deserialize)]
struct Inner {
key: Key,
r#mod: Vec<ModifierType>,
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,
ModifierType::Os => ModifiersState::LOGO,
ModifierType::Shift => ModifiersState::SHIFT,
};
}
if shift {
modifiers |= ModifiersState::SHIFT;
}

ModifiedKey(key, modifiers)
}
Expand Down
17 changes: 8 additions & 9 deletions src/keybindings/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand All @@ -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"]],
]
Expand Down

0 comments on commit 55a477e

Please sign in to comment.