mirror of https://github.com/k0kubun/xremap
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
3.5 KiB
Rust
106 lines
3.5 KiB
Rust
use crate::config::application::deserialize_string_or_vec;
|
|
use crate::config::application::Application;
|
|
use crate::config::key_press::KeyPress;
|
|
use crate::config::keymap_action::{Actions, KeymapAction};
|
|
use evdev::Key;
|
|
use serde::{Deserialize, Deserializer};
|
|
use std::collections::HashMap;
|
|
|
|
use super::device::Device;
|
|
use super::key_press::Modifier;
|
|
|
|
// Config interface
|
|
#[derive(Debug, Deserialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct Keymap {
|
|
#[serde(default = "String::new")]
|
|
pub name: String,
|
|
#[serde(deserialize_with = "deserialize_remap")]
|
|
pub remap: HashMap<KeyPress, Vec<KeymapAction>>,
|
|
pub application: Option<Application>,
|
|
pub device: Option<Device>,
|
|
#[serde(default, deserialize_with = "deserialize_string_or_vec")]
|
|
pub mode: Option<Vec<String>>,
|
|
#[serde(default)]
|
|
pub exact_match: bool,
|
|
}
|
|
|
|
fn deserialize_remap<'de, D>(deserializer: D) -> Result<HashMap<KeyPress, Vec<KeymapAction>>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let remap = HashMap::<KeyPress, Actions>::deserialize(deserializer)?;
|
|
Ok(remap
|
|
.into_iter()
|
|
.map(|(key_press, actions)| (key_press, actions.into_vec()))
|
|
.collect())
|
|
}
|
|
|
|
// Internals for efficient keymap lookup
|
|
#[derive(Clone, Debug)]
|
|
pub struct KeymapEntry {
|
|
pub actions: Vec<KeymapAction>,
|
|
pub modifiers: Vec<Modifier>,
|
|
pub application: Option<Application>,
|
|
pub device: Option<Device>,
|
|
pub mode: Option<Vec<String>>,
|
|
pub exact_match: bool,
|
|
}
|
|
|
|
// Convert an array of keymaps to a single hashmap whose key is a triggering key.
|
|
//
|
|
// For each key, Vec<KeymapEntry> is scanned once, matching the exact modifiers,
|
|
// and then it's scanned again, allowing extra modifiers.
|
|
//
|
|
// First matching KeymapEntry wins at each iteration.
|
|
pub fn build_keymap_table(keymaps: &Vec<Keymap>) -> HashMap<Key, Vec<KeymapEntry>> {
|
|
let mut table: HashMap<Key, Vec<KeymapEntry>> = HashMap::new();
|
|
for keymap in keymaps {
|
|
for (key_press, actions) in keymap.remap.iter() {
|
|
let mut entries: Vec<KeymapEntry> = match table.get(&key_press.key) {
|
|
Some(entries) => entries.to_vec(),
|
|
None => vec![],
|
|
};
|
|
entries.push(KeymapEntry {
|
|
actions: actions.to_vec(),
|
|
modifiers: key_press.modifiers.clone(),
|
|
application: keymap.application.clone(),
|
|
device: keymap.device.clone(),
|
|
mode: keymap.mode.clone(),
|
|
exact_match: keymap.exact_match,
|
|
});
|
|
table.insert(key_press.key, entries);
|
|
}
|
|
}
|
|
return table;
|
|
}
|
|
|
|
// Subset of KeymapEntry for override_remap
|
|
#[derive(Clone)]
|
|
pub struct OverrideEntry {
|
|
pub actions: Vec<KeymapAction>,
|
|
pub modifiers: Vec<Modifier>,
|
|
pub exact_match: bool,
|
|
}
|
|
|
|
// This is executed on runtime unlike build_keymap_table, but hopefully not called so often.
|
|
pub fn build_override_table(
|
|
remap: &HashMap<KeyPress, Vec<KeymapAction>>,
|
|
exact_match: bool,
|
|
) -> HashMap<Key, Vec<OverrideEntry>> {
|
|
let mut table: HashMap<Key, Vec<OverrideEntry>> = HashMap::new();
|
|
for (key_press, actions) in remap.iter() {
|
|
let mut entries: Vec<OverrideEntry> = match table.get(&key_press.key) {
|
|
Some(entries) => entries.to_vec(),
|
|
None => vec![],
|
|
};
|
|
entries.push(OverrideEntry {
|
|
actions: actions.to_vec(),
|
|
modifiers: key_press.modifiers.clone(),
|
|
exact_match,
|
|
});
|
|
table.insert(key_press.key, entries);
|
|
}
|
|
return table;
|
|
}
|