From 2219eb67e124dc2cbfc31cdda25214617d0646f5 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 28 Sep 2020 17:52:00 +0000 Subject: [PATCH] keymap: Generate from symbol map, not layout Includes changes to the keymap string without which Xwayland won't work. --- src/data.rs | 17 +++---- src/keyboard.rs | 128 ++++++++++++++++++++---------------------------- 2 files changed, 60 insertions(+), 85 deletions(-) diff --git a/src/data.rs b/src/data.rs index c3cf5345..a0fa2a20 100644 --- a/src/data.rs +++ b/src/data.rs @@ -382,7 +382,7 @@ impl Layout { ) )}).collect(); - let keymap: HashMap = generate_keycodes( + let symbolmap: HashMap = generate_keycodes( button_actions.iter() .filter_map(|(_name, action)| { match action { @@ -399,20 +399,20 @@ impl Layout { let button_states = button_actions.into_iter().map(|(name, action)| { let keycodes = match &action { ::action::Action::Submit { text: _, keys } => { - keys.iter().map(|named_keycode| { - *keymap.get(named_keycode.0.as_str()) + keys.iter().map(|named_keysym| { + *symbolmap.get(named_keysym.0.as_str()) .expect( format!( - "keycode {} in key {} missing from keymap", - named_keycode.0, + "keysym {} in key {} missing from symbol map", + named_keysym.0, name ).as_str() ) }).collect() }, action::Action::Erase => vec![ - *keymap.get("BackSpace") - .expect(&format!("BackSpace missing from keymap")), + *symbolmap.get("BackSpace") + .expect(&format!("BackSpace missing from symbol map")), ], _ => Vec::new(), }; @@ -430,8 +430,7 @@ impl Layout { button_states ); - // TODO: generate from symbols - let keymap_str = match generate_keymap(&button_states) { + let keymap_str = match generate_keymap(symbolmap) { Err(e) => { return (Err(e), warning_handler) }, Ok(v) => v, }; diff --git a/src/keyboard.rs b/src/keyboard.rs index 749d21ad..8418a98e 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -9,7 +9,6 @@ use std::rc::Rc; use std::string::FromUtf8Error; use ::action::Action; -use ::logging; // Traits use std::io::Write; @@ -125,11 +124,9 @@ impl From for FormattingError { } /// Generates a de-facto single level keymap. -// TODO: don't rely on keys and their order, -// but rather on what keysyms and keycodes are in use. -// Iterating actions makes it hard to deduplicate keysyms. +/// Key codes must not repeat and should remain between 9 and 255. pub fn generate_keymap( - keystates: &HashMap:: + symbolmap: HashMap::, ) -> Result { let mut buf: Vec = Vec::new(); writeln!( @@ -138,88 +135,75 @@ pub fn generate_keymap( xkb_keycodes \"squeekboard\" {{ minimum = 8; - maximum = 255;" + maximum = 999;" )?; - for (name, state) in keystates.iter() { - match &state.action { - Action::Submit { text: _, keys } => { - if let 0 = keys.len() { - log_print!( - logging::Level::Warning, - "Key {} has no keysyms", name, - ); - }; - for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) { - write!( - buf, - " - <{}> = {};", - named_keysym.0, - keycode, - )?; - } - }, - Action::Erase => { - let mut keycodes = state.keycodes.iter(); - write!( - buf, - " - = {};", - keycodes.next().expect("Erase key has no keycode"), - )?; - if let Some(_) = keycodes.next() { - log_print!( - logging::Level::Bug, - "Erase key has multiple keycodes", - ); - } - }, - _ => {}, - } + // Xorg can only consume up to 255 keys, so this may not work in Xwayland. + // Two possible solutions: + // - use levels to cram multiple characters into one key + // - swap layouts on key presses + for keycode in symbolmap.values() { + write!( + buf, + " + = {0};", + keycode, + )?; } - + writeln!( buf, " + indicator 1 = \"Caps Lock\"; // Xwayland won't accept without it. }}; xkb_symbols \"squeekboard\" {{ - - name[Group1] = \"Letters\"; - name[Group2] = \"Numbers/Symbols\"; - - key {{ [ BackSpace ] }};" +" )?; - for (_name, state) in keystates.iter() { - if let Action::Submit { text: _, keys } = &state.action { - for keysym in keys.iter() { - write!( - buf, - " - key <{}> {{ [ {0} ] }};", - keysym.0, - )?; - } - } + for (name, keycode) in symbolmap.iter() { + write!( + buf, + " +key {{ [ {} ] }};", + keycode, + name, + )?; } + writeln!( buf, " }}; xkb_types \"squeekboard\" {{ + virtual_modifiers Squeekboard; // No modifiers! Needed for Xorg for some reason. + + // Those names are needed for Xwayland. + type \"ONE_LEVEL\" {{ + modifiers= none; + level_name[Level1]= \"Any\"; + }}; + type \"TWO_LEVEL\" {{ + level_name[Level1]= \"Base\"; + }}; + type \"ALPHABETIC\" {{ + level_name[Level1]= \"Base\"; + }}; + type \"KEYPAD\" {{ + level_name[Level1]= \"Base\"; + }}; + type \"SHIFT+ALT\" {{ + level_name[Level1]= \"Base\"; + }}; - type \"TWO_LEVEL\" {{ - modifiers = Shift; - map[Shift] = Level2; - level_name[Level1] = \"Base\"; - level_name[Level2] = \"Shift\"; - }}; }}; xkb_compatibility \"squeekboard\" {{ + // Needed for Xwayland again. + interpret Any+AnyOf(all) {{ + action= SetMods(modifiers=modMapMods,clearLocks); + }}; }}; }};" )?; @@ -234,21 +218,13 @@ mod tests { use xkbcommon::xkb; - use ::action::KeySym; - #[test] fn test_keymap_multi() { let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); - let keymap_str = generate_keymap(&hashmap!{ - "ac".into() => KeyState { - action: Action::Submit { - text: None, - keys: vec!(KeySym("a".into()), KeySym("c".into())), - }, - keycodes: vec!(9, 10), - pressed: PressType::Released, - }, + let keymap_str = generate_keymap(hashmap!{ + "a".into() => 9, + "c".into() => 10, }).unwrap(); let keymap = xkb::Keymap::new_from_string(