use crate::map_builder::Replace::{CustomChar, CustomString};
use crate::map_builder::Replace::{MapChar, MapString};
use crate::Keymap;
use evdev_rs::enums::EventType;
use evdev_rs::util::event_code_to_int;
use evdev_rs::EventCodeIterator;
use std::collections::{BTreeMap, HashMap};
use std::marker::PhantomData;
pub enum SymbolType {
KeyName,
Unicode,
SymbolName,
UnicodeSymbol,
SymbolDisplay,
}
pub enum Fill {
None,
Evdev(bool),
EvdevCustom(fn(String) -> String),
}
#[derive(Clone)]
enum Replace {
MapString(BTreeMap<String, String>),
MapChar(HashMap<char, char>),
CustomString(fn(String) -> String),
CustomChar(fn(char) -> char),
}
enum CodeType {
EvDev,
XKB,
XKBHwKey,
}
#[doc(hidden)]
pub struct CodeUnknown;
#[doc(hidden)]
pub struct CodeEvdev;
#[doc(hidden)]
pub struct CodeXkb;
#[doc(hidden)]
pub struct CodeXkbHw;
#[doc(hidden)]
pub struct SymbolUnknown;
#[doc(hidden)]
pub struct SymbolUnicode;
#[doc(hidden)]
pub struct SymbolString(SymbolType);
#[doc(hidden)]
pub struct SymbolCodes;
#[doc(hidden)]
pub struct Fixed;
#[doc(hidden)]
pub struct Open;
pub struct MapBuilder<C, S, F> {
code: PhantomData<C>,
symbol: S,
fill: Fill,
replace: Vec<Replace>,
_marker: PhantomData<F>,
}
impl Default for MapBuilder<CodeUnknown, SymbolUnknown, Open> {
fn default() -> MapBuilder<CodeUnknown, SymbolUnknown, Open> {
MapBuilder {
code: PhantomData,
symbol: SymbolUnknown,
fill: Fill::None,
replace: Vec::new(),
_marker: PhantomData,
}
}
}
impl<C, S> MapBuilder<C, S, Open> {
pub fn code_evdev(self) -> MapBuilder<CodeEvdev, S, Open> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
pub fn code_xkb(self) -> MapBuilder<CodeXkb, S, Open> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
pub fn code_xkb_hw(self) -> MapBuilder<CodeXkbHw, S, Open> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
pub fn symbol_unicode(self) -> MapBuilder<C, SymbolUnicode, Open> {
MapBuilder {
code: PhantomData,
symbol: SymbolUnicode,
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
pub fn symbol(self, symbol: SymbolType) -> MapBuilder<C, SymbolString, Open> {
MapBuilder {
code: PhantomData,
symbol: SymbolString(symbol),
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
pub fn symbol_codes(self) -> MapBuilder<C, SymbolCodes, Open> {
MapBuilder {
code: PhantomData,
symbol: SymbolCodes,
fill: self.fill,
replace: self.replace,
_marker: PhantomData,
}
}
}
impl<F> MapBuilder<CodeEvdev, SymbolString, F> {
pub fn fill(self, fill: Fill) -> MapBuilder<CodeEvdev, SymbolString, Fixed> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill,
replace: self.replace,
_marker: PhantomData,
}
}
}
impl<C, F> MapBuilder<C, SymbolString, F> {
pub fn replace_symbol_by_map(self, replace: BTreeMap<String, String>) -> MapBuilder<C, SymbolString, Fixed> {
let mut r = self.replace.clone();
r.push(MapString(replace));
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: r,
_marker: PhantomData,
}
}
pub fn replace_symbol_by_function(self, replace: fn(String) -> String) -> MapBuilder<C, SymbolString, Fixed> {
let mut r = self.replace.clone();
r.push(CustomString(replace));
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: r,
_marker: PhantomData,
}
}
pub fn reset_replace(self) -> MapBuilder<C, SymbolString, Fixed> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: Vec::new(),
_marker: PhantomData,
}
}
fn replace_str(&self, mut s: String) -> String {
for r in &self.replace {
match r {
CustomString(f) => s = f(s),
MapString(map) => {
if let Some(replacement) = map.get(&s) {
s = replacement.clone();
}
}
MapChar(_) | CustomChar(_) => unreachable!()
}
}
s
}
}
impl<C, F> MapBuilder<C, SymbolUnicode, F> {
pub fn replace_symbol_by_map(self, replace: HashMap<char, char>) -> MapBuilder<C, SymbolUnicode, Fixed> {
let mut r = self.replace.clone();
r.push(MapChar(replace));
MapBuilder {
code: PhantomData,
symbol: SymbolUnicode,
fill: self.fill,
replace: r,
_marker: PhantomData,
}
}
pub fn replace_symbol_by_function(self, replace: fn(char) -> char) -> MapBuilder<C, SymbolUnicode, Fixed> {
let mut r = self.replace.clone();
r.push(CustomChar(replace));
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: r,
_marker: PhantomData,
}
}
pub fn reset_replace(self) -> MapBuilder<C, SymbolUnicode, Fixed> {
MapBuilder {
code: PhantomData,
symbol: self.symbol,
fill: self.fill,
replace: Vec::new(),
_marker: PhantomData,
}
}
fn replace_char(&self, mut c: char) -> char {
for r in &self.replace {
match r {
CustomChar(f) => c = f(c),
MapChar(map) => {
if let Some(replacement) = map.get(&c) {
c = replacement.clone();
}
}
MapString(_) | CustomString(_) => unreachable!()
}
}
c
}
}
pub enum BuildMaps {
CodeToSymbol,
SymbolToCode,
Both,
}
impl<F> MapBuilder<CodeEvdev, SymbolString, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u16, String>, BTreeMap<String, u16>) {
let mut map = HashMap::new();
let mut reverse = BTreeMap::new();
for k in &keymap.keys {
let symbol = match self.symbol.0 {
SymbolType::KeyName => Some(k.keyname.clone()),
SymbolType::Unicode => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else {
None
}
}
SymbolType::SymbolName => {
if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
}
SymbolType::UnicodeSymbol => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
},
SymbolType::SymbolDisplay => {
Some(k.display())
}
};
if let Some(symbol) = symbol {
let symbol = self.replace_str(symbol);
match out {
BuildMaps::CodeToSymbol => {
map.insert(k.evdev_code(), symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, k.evdev_code());
}
BuildMaps::Both => {
map.insert(k.evdev_code(), symbol.clone());
reverse.insert(symbol, k.evdev_code());
}
};
}
}
match &self.fill {
Fill::None => {}
fill => {
for ev in EventCodeIterator::new(&EventType::EV_KEY) {
let code = event_code_to_int(&ev).1 as u16;
if !map.contains_key(&code) {
let symbol = {
let en = format!("{ev:?}");
match fill {
Fill::None => {
panic!("")
}
Fill::Evdev(true) => {
en[7..en.len() - 1].to_string()
}
Fill::Evdev(false) => en,
Fill::EvdevCustom(reformat) => reformat(en),
}
};
let symbol = self.replace_str(symbol);
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol.clone());
reverse.insert(symbol, code);
}
};
}
}
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeEvdev, SymbolUnicode, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u16, char>, HashMap<char, u16>) {
let mut map = HashMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
if let Some(u) = k.visible_unicode() {
let symbol = self.replace_char(u);
let code = k.evdev_code();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol);
reverse.insert(symbol, code);
}
};
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeEvdev, SymbolCodes, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u16, Vec<u32>>, HashMap<Vec<u32>, u16>) {
let mut map = HashMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
let code = k.evdev_code();
let symbol = k.keysyms().clone();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol.clone());
reverse.insert(symbol, code);
}
};
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkb, SymbolString, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u32, String>, BTreeMap<String, u32>) {
let mut map = HashMap::new();
let mut reverse = BTreeMap::new();
for k in &keymap.keys {
let symbol = match self.symbol.0 {
SymbolType::KeyName => Some(k.keyname.clone()),
SymbolType::Unicode => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else {
None
}
}
SymbolType::SymbolName => {
if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
}
SymbolType::UnicodeSymbol => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
},
SymbolType::SymbolDisplay => {
Some(k.display())
}
};
if let Some(symbol) = symbol {
let code = k.keycode;
let symbol = self.replace_str(symbol);
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol.clone());
reverse.insert(symbol, code);
}
};
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkb, SymbolUnicode, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u32, char>, HashMap<char, u32>) {
let mut map = HashMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
if let Some(u) = k.visible_unicode() {
let symbol = self.replace_char(u);
let code = k.keycode;
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol);
reverse.insert(symbol, code);
}
};
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkb, SymbolCodes, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (HashMap<u32, Vec<u32>>, HashMap<Vec<u32>, u32>) {
let mut map = HashMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
let code = k.keycode;
let symbol = k.keysyms().clone();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code, symbol.clone());
reverse.insert(symbol, code);
}
};
map.insert(k.keycode, k.keysyms().clone());
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkbHw, SymbolString, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (BTreeMap<String, String>, BTreeMap<String, String>) {
let mut map = BTreeMap::new();
let mut reverse = BTreeMap::new();
for k in &keymap.keys {
let symbol = match self.symbol.0 {
SymbolType::KeyName => Some(k.keyname.clone()),
SymbolType::Unicode => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else {
None
}
}
SymbolType::SymbolName => {
if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
}
SymbolType::UnicodeSymbol => {
if let Some(u) = k.visible_unicode() {
Some(String::from(u))
} else if let Some(ref s) = k.symbol_name() {
Some(s.clone())
} else {
None
}
},
SymbolType::SymbolDisplay => {
Some(k.display())
}
};
if let Some(symbol) = symbol {
let symbol = self.replace_str(symbol);
let code = k.keyname.clone();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code.clone(), symbol.clone());
reverse.insert(symbol, code);
}
};
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkbHw, SymbolUnicode, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (BTreeMap<String, char>, HashMap<char, String>) {
let mut map = BTreeMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
if let Some(u) = k.visible_unicode() {
let symbol = self.replace_char(u);
let code = k.keyname.clone();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code.clone(), symbol);
reverse.insert(symbol, code);
}
};
}
}
(map, reverse)
}
}
impl<F> MapBuilder<CodeXkbHw, SymbolCodes, F> {
pub fn build(
&self,
keymap: &Keymap,
out: BuildMaps,
) -> (BTreeMap<String, Vec<u32>>, HashMap<Vec<u32>, String>) {
let mut map = BTreeMap::new();
let mut reverse = HashMap::new();
for k in &keymap.keys {
let code = k.keyname.clone();
let symbol = k.keysyms().clone();
match out {
BuildMaps::CodeToSymbol => {
map.insert(code, symbol);
}
BuildMaps::SymbolToCode => {
reverse.insert(symbol, code);
}
BuildMaps::Both => {
map.insert(code.clone(), symbol.clone());
reverse.insert(symbol, code);
}
};
}
(map, reverse)
}
}
#[cfg(test)]
mod test {
use crate::map_builder::{BuildMaps, Fill, MapBuilder, SymbolType};
use crate::Keymap;
use std::collections::BTreeMap;
#[test]
fn test_builder_evdev() {
let keymap =
Keymap::from_rmlvo(Some("evdev"), Some("pc105"), Some("us"), Some("dvp"), None, false)
.unwrap();
let mut replace: BTreeMap<String, String> = BTreeMap::new();
replace.insert("&".to_string(), "\\ampersand".to_string());
let builder_str = MapBuilder::default()
.code_evdev()
.symbol(SymbolType::UnicodeSymbol)
.fill(Fill::Evdev(true))
.replace_symbol_by_map(replace);
let (to, from) = builder_str.build(&keymap, BuildMaps::Both);
assert_eq!(to[&5], "}"); assert_eq!(to[&23], "c"); assert_eq!(to[&2], "\\ampersand"); assert_eq!(to[&1], "Escape"); assert_eq!(to[&0x161], "KEY_SELECT");
assert_eq!(to[&74], "-");
assert_eq!(from[&"}".to_string()], 5); assert_eq!(from[&"c".to_string()], 23); assert_eq!(from[&"\\ampersand".to_string()], 2); assert_eq!(from[&"Escape".to_string()], 1); assert_eq!(from[&"KEY_SELECT".to_string()], 0x161);
let (to, from) = builder_str
.fill(Fill::EvdevCustom(|s: String| {
s[11..s.len() - 1].to_lowercase()
}))
.replace_symbol_by_function(|s| s.to_lowercase())
.build(&keymap, BuildMaps::Both);
assert_eq!(to[&1], "escape"); assert_eq!(to[&2], "\\ampersand"); assert_eq!(to[&0x13a], "select"); assert_eq!(to[&0x161], "select"); assert_eq!(from[&"select".to_string()], 0x161);
let builder_display = MapBuilder::default()
.code_evdev()
.symbol(SymbolType::SymbolDisplay)
.fill(Fill::Evdev(true));
let (to, from) = builder_display.build(&keymap, BuildMaps::Both);
assert_eq!(to[&5], "}"); assert_eq!(to[&23], "c"); assert_eq!(to[&2], "&"); assert_eq!(to[&1], "Escape"); assert_eq!(to[&0x161], "KEY_SELECT");
assert_eq!(to[&74], "KP_Subtract");
assert_eq!(from[&"}".to_string()], 5); assert_eq!(from[&"c".to_string()], 23); assert_eq!(from[&"&".to_string()], 2); assert_eq!(from[&"Escape".to_string()], 1); assert_eq!(from[&"KEY_SELECT".to_string()], 0x161); let builder_char = MapBuilder::default()
.code_evdev()
.symbol_unicode();
let (to, from) = builder_char.build(&keymap, BuildMaps::Both);
assert_eq!(to.get(&1), None); assert_eq!(to[&2], '&'); assert_eq!(from[&'b'], 49);
let builder_symbols = MapBuilder::default()
.code_evdev()
.symbol_codes();
let (to, from) = builder_symbols.build(&keymap, BuildMaps::Both);
assert_eq!(to[&1], vec![65307]); assert_eq!(to[&2], vec![38]); assert_eq!(from[&vec![98]], 49); }
#[test]
fn test_builder_xkb() {
let keymap =
Keymap::from_rmlvo(Some("evdev"), Some("pc105"), Some("us"), Some("dvp"), None, false)
.unwrap();
let mut replace: BTreeMap<String, String> = BTreeMap::new();
replace.insert("&".to_string(), "\\ampersand".to_string());
let builder_str = MapBuilder::default()
.code_xkb()
.symbol(SymbolType::Unicode)
.replace_symbol_by_map(replace);
let (to, from) = builder_str.build(&keymap, BuildMaps::Both);
assert_eq!(to[&13], "}"); assert_eq!(to[&31], "c"); assert_eq!(to[&10], "\\ampersand"); assert_eq!(to.get(&9), None); assert_eq!(to.get(&0x161), None);
assert_eq!(from[&"}".to_string()], 13); assert_eq!(from[&"c".to_string()], 31); assert_eq!(from[&"\\ampersand".to_string()], 10); assert_eq!(from.get(&"KEY_SELECT".to_string()), None);
let (to, from) = builder_str
.reset_replace()
.replace_symbol_by_function(|s| s.to_lowercase())
.build(&keymap, BuildMaps::Both);
assert_eq!(to.get(&9), None); assert_eq!(to[&10], "&"); assert_eq!(from[&"b".to_string()], 57);
let builder_char = MapBuilder::default()
.code_xkb()
.symbol_unicode();
let (to, from) = builder_char.build(&keymap, BuildMaps::Both);
assert_eq!(to.get(&9), None); assert_eq!(to[&10], '&'); assert_eq!(from[&'b'], 57);
let builder_symbols = MapBuilder::default()
.code_xkb()
.symbol_codes();
let (to, from) = builder_symbols.build(&keymap, BuildMaps::Both);
assert_eq!(to.get(&1), None); assert_eq!(to[&10], vec![38]); assert_eq!(from[&vec![98]], 57); }
#[test]
fn test_builder_xkb_hw() {
let keymap =
Keymap::from_rmlvo(Some("evdev"), Some("pc105"), Some("us"), Some("dvp"), None, false)
.unwrap();
let builder_str = MapBuilder::default()
.code_xkb_hw()
.symbol(SymbolType::SymbolName)
.replace_symbol_by_function(|s| s.to_uppercase());
let (to, from) = builder_str.build(&keymap, BuildMaps::Both);
assert_eq!(to["AE04"], "BRACERIGHT"); assert_eq!(to["AD08"], "C"); assert_eq!(to["AE01"], "AMPERSAND"); assert_eq!(to["ESC"], "ESCAPE"); assert_eq!(to.get("SUPR"), None);
assert_eq!(from["BRACERIGHT"], "AE04"); assert_eq!(from["C"], "AD08"); assert_eq!(from["AMPERSAND"], "AE01"); assert_eq!(from.get("not_a_key"), None);
let builder_char = MapBuilder::default()
.code_xkb_hw()
.symbol_unicode();
let (to, from) = builder_char.build(&keymap, BuildMaps::Both);
assert_eq!(to.get("ESC"), None); assert_eq!(to["AE01"], '&'); assert_eq!(from[&'b'], "AB06");
let builder_symbols = MapBuilder::default()
.code_xkb_hw()
.symbol_codes();
let (to, from) = builder_symbols.build(&keymap, BuildMaps::Both);
assert_eq!(to.get("ESC"), Some(vec![65307]).as_ref()); assert_eq!(to["AE01"], vec![38]); assert_eq!(from[&vec![98]], "AB06"); }
}