keymap: Generate from symbol map, not layout
Includes changes to the keymap string without which Xwayland won't work.
This commit is contained in:
17
src/data.rs
17
src/data.rs
@ -382,7 +382,7 @@ impl Layout {
|
||||
)
|
||||
)}).collect();
|
||||
|
||||
let keymap: HashMap<String, u32> = generate_keycodes(
|
||||
let symbolmap: HashMap<String, u32> = 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,
|
||||
};
|
||||
|
||||
106
src/keyboard.rs
106
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<io::Error> 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::<String, KeyState>
|
||||
symbolmap: HashMap::<String, KeyCode>,
|
||||
) -> Result<String, FormattingError> {
|
||||
let mut buf: Vec<u8> = 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) {
|
||||
// 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,
|
||||
"
|
||||
<{}> = {};",
|
||||
named_keysym.0,
|
||||
<I{}> = {0};",
|
||||
keycode,
|
||||
)?;
|
||||
}
|
||||
},
|
||||
Action::Erase => {
|
||||
let mut keycodes = state.keycodes.iter();
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
<BackSpace> = {};",
|
||||
keycodes.next().expect("Erase key has no keycode"),
|
||||
)?;
|
||||
if let Some(_) = keycodes.next() {
|
||||
log_print!(
|
||||
logging::Level::Bug,
|
||||
"Erase key has multiple keycodes",
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"
|
||||
indicator 1 = \"Caps Lock\"; // Xwayland won't accept without it.
|
||||
}};
|
||||
|
||||
xkb_symbols \"squeekboard\" {{
|
||||
|
||||
name[Group1] = \"Letters\";
|
||||
name[Group2] = \"Numbers/Symbols\";
|
||||
|
||||
key <BackSpace> {{ [ BackSpace ] }};"
|
||||
"
|
||||
)?;
|
||||
|
||||
for (_name, state) in keystates.iter() {
|
||||
if let Action::Submit { text: _, keys } = &state.action {
|
||||
for keysym in keys.iter() {
|
||||
for (name, keycode) in symbolmap.iter() {
|
||||
write!(
|
||||
buf,
|
||||
"
|
||||
key <{}> {{ [ {0} ] }};",
|
||||
keysym.0,
|
||||
key <I{}> {{ [ {} ] }};",
|
||||
keycode,
|
||||
name,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"
|
||||
}};
|
||||
|
||||
xkb_types \"squeekboard\" {{
|
||||
virtual_modifiers Squeekboard; // No modifiers! Needed for Xorg for some reason.
|
||||
|
||||
type \"TWO_LEVEL\" {{
|
||||
modifiers = Shift;
|
||||
map[Shift] = Level2;
|
||||
level_name[Level1] = \"Base\";
|
||||
level_name[Level2] = \"Shift\";
|
||||
// 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\";
|
||||
}};
|
||||
|
||||
}};
|
||||
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user