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();
|
)}).collect();
|
||||||
|
|
||||||
let keymap: HashMap<String, u32> = generate_keycodes(
|
let symbolmap: HashMap<String, u32> = generate_keycodes(
|
||||||
button_actions.iter()
|
button_actions.iter()
|
||||||
.filter_map(|(_name, action)| {
|
.filter_map(|(_name, action)| {
|
||||||
match action {
|
match action {
|
||||||
@ -399,20 +399,20 @@ impl Layout {
|
|||||||
let button_states = button_actions.into_iter().map(|(name, action)| {
|
let button_states = button_actions.into_iter().map(|(name, action)| {
|
||||||
let keycodes = match &action {
|
let keycodes = match &action {
|
||||||
::action::Action::Submit { text: _, keys } => {
|
::action::Action::Submit { text: _, keys } => {
|
||||||
keys.iter().map(|named_keycode| {
|
keys.iter().map(|named_keysym| {
|
||||||
*keymap.get(named_keycode.0.as_str())
|
*symbolmap.get(named_keysym.0.as_str())
|
||||||
.expect(
|
.expect(
|
||||||
format!(
|
format!(
|
||||||
"keycode {} in key {} missing from keymap",
|
"keysym {} in key {} missing from symbol map",
|
||||||
named_keycode.0,
|
named_keysym.0,
|
||||||
name
|
name
|
||||||
).as_str()
|
).as_str()
|
||||||
)
|
)
|
||||||
}).collect()
|
}).collect()
|
||||||
},
|
},
|
||||||
action::Action::Erase => vec![
|
action::Action::Erase => vec![
|
||||||
*keymap.get("BackSpace")
|
*symbolmap.get("BackSpace")
|
||||||
.expect(&format!("BackSpace missing from keymap")),
|
.expect(&format!("BackSpace missing from symbol map")),
|
||||||
],
|
],
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
};
|
};
|
||||||
@ -430,8 +430,7 @@ impl Layout {
|
|||||||
button_states
|
button_states
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: generate from symbols
|
let keymap_str = match generate_keymap(symbolmap) {
|
||||||
let keymap_str = match generate_keymap(&button_states) {
|
|
||||||
Err(e) => { return (Err(e), warning_handler) },
|
Err(e) => { return (Err(e), warning_handler) },
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
|
|||||||
106
src/keyboard.rs
106
src/keyboard.rs
@ -9,7 +9,6 @@ use std::rc::Rc;
|
|||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
use ::action::Action;
|
use ::action::Action;
|
||||||
use ::logging;
|
|
||||||
|
|
||||||
// Traits
|
// Traits
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -125,11 +124,9 @@ impl From<io::Error> for FormattingError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a de-facto single level keymap.
|
/// Generates a de-facto single level keymap.
|
||||||
// TODO: don't rely on keys and their order,
|
/// Key codes must not repeat and should remain between 9 and 255.
|
||||||
// but rather on what keysyms and keycodes are in use.
|
|
||||||
// Iterating actions makes it hard to deduplicate keysyms.
|
|
||||||
pub fn generate_keymap(
|
pub fn generate_keymap(
|
||||||
keystates: &HashMap::<String, KeyState>
|
symbolmap: HashMap::<String, KeyCode>,
|
||||||
) -> Result<String, FormattingError> {
|
) -> Result<String, FormattingError> {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
writeln!(
|
writeln!(
|
||||||
@ -138,88 +135,75 @@ pub fn generate_keymap(
|
|||||||
|
|
||||||
xkb_keycodes \"squeekboard\" {{
|
xkb_keycodes \"squeekboard\" {{
|
||||||
minimum = 8;
|
minimum = 8;
|
||||||
maximum = 255;"
|
maximum = 999;"
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (name, state) in keystates.iter() {
|
// Xorg can only consume up to 255 keys, so this may not work in Xwayland.
|
||||||
match &state.action {
|
// Two possible solutions:
|
||||||
Action::Submit { text: _, keys } => {
|
// - use levels to cram multiple characters into one key
|
||||||
if let 0 = keys.len() {
|
// - swap layouts on key presses
|
||||||
log_print!(
|
for keycode in symbolmap.values() {
|
||||||
logging::Level::Warning,
|
|
||||||
"Key {} has no keysyms", name,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
|
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"
|
"
|
||||||
<{}> = {};",
|
<I{}> = {0};",
|
||||||
named_keysym.0,
|
|
||||||
keycode,
|
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!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
"
|
"
|
||||||
|
indicator 1 = \"Caps Lock\"; // Xwayland won't accept without it.
|
||||||
}};
|
}};
|
||||||
|
|
||||||
xkb_symbols \"squeekboard\" {{
|
xkb_symbols \"squeekboard\" {{
|
||||||
|
"
|
||||||
name[Group1] = \"Letters\";
|
|
||||||
name[Group2] = \"Numbers/Symbols\";
|
|
||||||
|
|
||||||
key <BackSpace> {{ [ BackSpace ] }};"
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (_name, state) in keystates.iter() {
|
for (name, keycode) in symbolmap.iter() {
|
||||||
if let Action::Submit { text: _, keys } = &state.action {
|
|
||||||
for keysym in keys.iter() {
|
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"
|
"
|
||||||
key <{}> {{ [ {0} ] }};",
|
key <I{}> {{ [ {} ] }};",
|
||||||
keysym.0,
|
keycode,
|
||||||
|
name,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
"
|
"
|
||||||
}};
|
}};
|
||||||
|
|
||||||
xkb_types \"squeekboard\" {{
|
xkb_types \"squeekboard\" {{
|
||||||
|
virtual_modifiers Squeekboard; // No modifiers! Needed for Xorg for some reason.
|
||||||
|
|
||||||
type \"TWO_LEVEL\" {{
|
// Those names are needed for Xwayland.
|
||||||
modifiers = Shift;
|
type \"ONE_LEVEL\" {{
|
||||||
map[Shift] = Level2;
|
modifiers= none;
|
||||||
level_name[Level1] = \"Base\";
|
level_name[Level1]= \"Any\";
|
||||||
level_name[Level2] = \"Shift\";
|
|
||||||
}};
|
}};
|
||||||
|
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\" {{
|
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 xkbcommon::xkb;
|
||||||
|
|
||||||
use ::action::KeySym;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keymap_multi() {
|
fn test_keymap_multi() {
|
||||||
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
|
||||||
|
|
||||||
let keymap_str = generate_keymap(&hashmap!{
|
let keymap_str = generate_keymap(hashmap!{
|
||||||
"ac".into() => KeyState {
|
"a".into() => 9,
|
||||||
action: Action::Submit {
|
"c".into() => 10,
|
||||||
text: None,
|
|
||||||
keys: vec!(KeySym("a".into()), KeySym("c".into())),
|
|
||||||
},
|
|
||||||
keycodes: vec!(9, 10),
|
|
||||||
pressed: PressType::Released,
|
|
||||||
},
|
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
let keymap = xkb::Keymap::new_from_string(
|
let keymap = xkb::Keymap::new_from_string(
|
||||||
|
|||||||
Reference in New Issue
Block a user