use std::{
env, fs,
io::{BufWriter, Write},
path::Path,
};
use serde::Deserialize;
#[derive(Deserialize)]
struct KeyCode {
pub usage_id: String,
pub key_code: String,
pub lang_code: Option<String>,
pub visual: String,
pub prefix: String,
pub key_type: String,
}
impl KeyCode {
pub fn prefix_as_pascal(&self) -> String {
let p = self.prefix.to_lowercase();
let parts = p.split("_");
parts
.map(|v| {
let mut c = v.chars();
let f = c.next().unwrap();
f.to_uppercase().collect::<String>() + c.as_str()
})
.collect::<Vec<_>>()
.join("")
}
}
fn main() {
println!("cargo::rerun-if-changed=src/key_codes.json");
let mut rdr = fs::File::open("src/key_codes.json").unwrap();
let key_codes: Vec<KeyCode> = serde_json::from_reader(&mut rdr).unwrap();
let keycodes_us = key_codes
.iter()
.filter(|v| {
if let Some(code) = &v.lang_code {
return code == "US";
}
true
})
.collect::<Vec<_>>();
let keycodes_uk = key_codes
.iter()
.filter(|v| {
if let Some(code) = &v.lang_code {
return code == "UK";
}
true
})
.collect::<Vec<_>>();
let mappings_path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
let mut mappings_fs = BufWriter::new(fs::File::create(mappings_path).unwrap());
writeln!(
&mut mappings_fs,
"/// Keyboard keys as enum values, with usage-id representation."
)
.unwrap();
writeln!(&mut mappings_fs, "#[repr(u8)]").unwrap();
write!(
&mut mappings_fs,
"#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = \"serde\", derive(Serialize, Deserialize))]\n"
)
.unwrap();
writeln!(&mut mappings_fs, "pub enum Keys {{").unwrap();
for key_code in &key_codes {
writeln!(
&mut mappings_fs,
" {} = {},",
key_code.prefix_as_pascal(),
key_code.usage_id
)
.unwrap();
}
writeln!(&mut mappings_fs, "}}").unwrap();
write!(
&mut mappings_fs,
"impl TryFrom<u8> for Keys {{
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {{
match value {{\n"
)
.unwrap();
for key in &key_codes {
writeln!(
&mut mappings_fs,
"x if x == Self::{0} as u8 => Ok(Self::{0}),",
key.prefix_as_pascal()
)
.unwrap();
}
write!(
&mut mappings_fs,
"_ => Err(()),
}}}}}}",
)
.unwrap();
let mut builder = phf_codegen::Map::new();
for key in &key_codes {
let usage_id = hex::decode(key.usage_id.strip_prefix("0x").unwrap()).unwrap()[0];
builder.entry(
usage_id,
format!(
"MappedKey{{
usage_id: {},
dom_key: \"{}\",
prefix: \"{}\",
visual: r#\"{}\"#,
key_type: MappedKeyType::{},
}}",
key.usage_id, key.key_code, key.prefix, key.visual, key.key_type,
),
);
}
writeln!(&mut mappings_fs, "/// usage-id to mapped key info.").unwrap();
write!(
&mut mappings_fs,
"pub static MAPPED_KEYS: phf::Map<u8, MappedKey> = \n{};\n",
builder.build(),
)
.unwrap();
let mut builder = phf_codegen::Map::new();
for key_code in &keycodes_us {
builder.entry(&key_code.key_code, &key_code.usage_id);
}
writeln!(
&mut mappings_fs,
"/// DOM key to usage-id map for the US layout."
)
.unwrap();
write!(
&mut mappings_fs,
"pub static DOM_KEYS_US: phf::Map<&'static str, u8> = \n{};\n",
builder.build(),
)
.unwrap();
let mut builder = phf_codegen::Map::new();
for key_code in &keycodes_uk {
builder.entry(&key_code.key_code, &key_code.usage_id);
}
writeln!(
&mut mappings_fs,
"/// DOM key to usage-id map for the UK layout."
)
.unwrap();
write!(
&mut mappings_fs,
"pub static DOM_KEYS_UK: phf::Map<&'static str, u8> = \n{};\n",
builder.build(),
)
.unwrap();
}