diff --git a/Cargo.lock b/Cargo.lock index 35c967ec..0958d1c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,11 @@ name = "dtoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "linked-hash-map" version = "0.5.2" @@ -20,6 +25,15 @@ name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "1.0.2" @@ -44,6 +58,7 @@ dependencies = [ "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", + "xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -90,6 +105,34 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xkbcommon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "yaml-rust" version = "0.4.3" @@ -101,8 +144,10 @@ dependencies = [ [metadata] "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" @@ -110,4 +155,8 @@ dependencies = [ "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum xkbcommon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fda0ea5f7ddabd51deeeda7799bee06274112f577da7dd3d954b8eda731b2fce" "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/Cargo.toml b/Cargo.toml index 61276cc6..be13ac0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ bitflags = "1.1" maplit = "1.0" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" +xkbcommon = { version = "0.4", features = ["wayland"] } [lib] name = "rs" diff --git a/src/data.rs b/src/data.rs index 6546bfbc..926206b2 100644 --- a/src/data.rs +++ b/src/data.rs @@ -11,6 +11,8 @@ use std::path::PathBuf; use std::rc::Rc; use std::vec::Vec; +use xkbcommon::xkb; + use ::keyboard::{ KeyState, generate_keymap, generate_keycodes, FormattingError @@ -358,6 +360,39 @@ fn create_symbol( } } + fn keysym_valid(name: &str) -> bool { + xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) != xkb::KEY_NoSymbol + } + + let keysym = match &symbol_meta.action { + Some(_) => None, + None => Some(match &symbol_meta.keysym { + Some(keysym) => match keysym_valid(keysym.as_str()) { + true => keysym.clone(), + false => { + eprintln!("Keysym name invalid: {}", keysym); + "space".into() // placeholder + }, + }, + None => match keysym_valid(name) { + true => String::from(name), + false => match name.chars().count() { + 1 => format!("U{:04X}", name.chars().next().unwrap() as u32), + // If the name is longer than 1 char, + // then it's not a single Unicode char, + // but was trying to be an identifier + _ => { + eprintln!( + "Could not derive a valid keysym for key {}", + name + ); + "space".into() // placeholder + } + }, + }, + }), + }; + match &symbol_meta.action { Some(Action::SetView(view_name)) => ::symbol::Symbol { action: ::symbol::Action::SetLevel( @@ -374,11 +409,18 @@ fn create_symbol( ), }, }, - _ => ::symbol::Symbol { + Some(Action::ShowPrefs) => ::symbol::Symbol { action: ::symbol::Action::Submit { text: None, - // TODO: derive keysym name & value from button name - keys: vec!(), + keys: Vec::new(), + }, + }, + None => ::symbol::Symbol { + action: ::symbol::Action::Submit { + text: None, + keys: vec!( + ::symbol::KeySym(keysym.unwrap()), + ), }, }, } @@ -523,6 +565,36 @@ mod tests { } } + #[test] + fn test_layout_punctuation() { + let out = Layout::from_yaml_stream(PathBuf::from("tests/layout_key1.yaml")) + .unwrap() + .build() + .unwrap(); + assert_eq!( + out.views["base"] + .rows[0] + .buttons[0] + .label, + ::layout::Label::Text(CString::new("test").unwrap()) + ); + } + + #[test] + fn test_layout_unicode() { + let out = Layout::from_yaml_stream(PathBuf::from("tests/layout_key2.yaml")) + .unwrap() + .build() + .unwrap(); + assert_eq!( + out.views["base"] + .rows[0] + .buttons[0] + .label, + ::layout::Label::Text(CString::new("test").unwrap()) + ); + } + #[test] fn parsing_fallback() { assert!(load_layout_from_resource(FALLBACK_LAYOUT_NAME) @@ -530,4 +602,39 @@ mod tests { .is_ok() ); } + + #[test] + fn unicode_keysym() { + let keysym = xkb::keysym_from_name( + format!("U{:X}", "å".chars().next().unwrap() as u32).as_str(), + xkb::KEYSYM_NO_FLAGS, + ); + let keysym = xkb::keysym_to_utf8(keysym); + assert_eq!(keysym, "å\0"); + } + + #[test] + fn test_key_unicode() { + assert_eq!( + create_symbol( + &hashmap!{ + ".".into() => ButtonMeta { + icon: None, + keysym: None, + action: None, + label: Some("test".into()), + outline: None, + } + }, + ".", + Vec::new() + ), + ::symbol::Symbol { + action: ::symbol::Action::Submit { + text: None, + keys: vec!(::symbol::KeySym("U002E".into())), + }, + } + ); + } } diff --git a/src/keyboard.rs b/src/keyboard.rs index 8f9b2093..89369ea0 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -177,7 +177,6 @@ impl From for FormattingError { } /// Generates a de-facto single level keymap. TODO: actually drop second level -/// TODO: take in keysym->keycode mapping pub fn generate_keymap( keystates: &HashMap::>> ) -> Result { @@ -192,14 +191,24 @@ pub fn generate_keymap( )?; for (name, state) in keystates.iter() { - if let Some(keycode) = state.borrow().keycode { - write!( - buf, - " + let state = state.borrow(); + if let ::symbol::Action::Submit { text: _, keys } = &state.symbol.action { + match keys.len() { + 0 => eprintln!("Key {} has no keysyms", name), + a => { + // TODO: don't ignore any keysyms + if a > 1 { + eprintln!("Key {} multiple keysyms", name); + } + write!( + buf, + " <{}> = {};", - name, - keycode - )?; + keys[0].0, + state.keycode.unwrap() + )?; + }, + }; } } @@ -215,13 +224,15 @@ pub fn generate_keymap( )?; for (name, state) in keystates.iter() { - if let Some(_) = state.borrow().keycode { - write!( - buf, - " + if let ::symbol::Action::Submit { text: _, keys } = &state.borrow().symbol.action { + if let Some(keysym) = keys.iter().next() { + write!( + buf, + " key <{}> {{ [ {0} ] }};", - name, - )?; + keysym.0, + )?; + } } } writeln!( diff --git a/src/layout.rs b/src/layout.rs index 796f453a..318e557c 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -546,7 +546,7 @@ pub struct Size { pub height: f64, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Label { /// Text used to display the symbol Text(CString), diff --git a/src/lib.rs b/src/lib.rs index 3973ea51..9be4dc89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ extern crate bitflags; #[macro_use] extern crate maplit; extern crate serde; +extern crate xkbcommon; mod data; pub mod float_ord; diff --git a/src/symbol.rs b/src/symbol.rs index e2388f29..e2262a66 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -2,37 +2,22 @@ use std::ffi::CString; -/// Just defines some int->identifier mappings for convenience -#[derive(Debug, Clone)] -pub enum KeySym { - Unknown = 0, - Shift = 0xffe1, -} - -impl KeySym { - pub fn from_u32(num: u32) -> KeySym { - match num { - 0xffe1 => KeySym::Shift, - _ => KeySym::Unknown, - } - } -} - -#[derive(Debug, Clone)] -pub struct XKeySym(pub u32); +/// Name of the keysym +#[derive(Debug, Clone, PartialEq)] +pub struct KeySym(pub String); /// Use to switch layouts type Level = String; /// Use to send modified keypresses -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Modifier { Control, Alt, } /// Action to perform on the keypress and, in reverse, on keyrelease -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Action { /// Switch to this view SetLevel(Level), @@ -49,12 +34,12 @@ pub enum Action { /// Text to submit with input-method text: Option, /// The key events this symbol submits when submitting text is not possible - keys: Vec, + keys: Vec, }, } /// Contains a static description of a particular key's actions -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Symbol { /// The action that this key performs pub action: Action, diff --git a/tests/layout_key1.yaml b/tests/layout_key1.yaml new file mode 100644 index 00000000..cad7f65b --- /dev/null +++ b/tests/layout_key1.yaml @@ -0,0 +1,18 @@ +--- +# punctuation +bounds: + x: 0 + y: 0 + width: 0 + height: 0 +views: + base: + - "." +outlines: + default: + corner_radius: 1 + bounds: { x: 0, y: 0, width: 0, height: 0 } + +buttons: + ".": + label: "test" diff --git a/tests/layout_key2.yaml b/tests/layout_key2.yaml new file mode 100644 index 00000000..0581531e --- /dev/null +++ b/tests/layout_key2.yaml @@ -0,0 +1,18 @@ +--- +# punctuation +bounds: + x: 0 + y: 0 + width: 0 + height: 0 +views: + base: + - "å" +outlines: + default: + corner_radius: 1 + bounds: { x: 0, y: 0, width: 0, height: 0 } + +buttons: + å: + label: "test" diff --git a/tests/test-keymap-generation.c b/tests/test-keymap-generation.c index 4aadf8e5..f5d3d7b4 100644 --- a/tests/test-keymap-generation.c +++ b/tests/test-keymap-generation.c @@ -46,6 +46,7 @@ test_check_xkb (void) xkb_context_unref(context); if (!keymap) { + printf("%s", keymap_str); g_error("Bad keymap"); }