keysyms: Derive from Unicode labels

This commit is contained in:
Dorota Czaplejewicz
2019-09-10 17:55:09 +00:00
parent 015ba79f65
commit 8e654346a2
10 changed files with 231 additions and 40 deletions

View File

@ -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())),
},
}
);
}
}

View File

@ -177,7 +177,6 @@ impl From<io::Error> 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::<String, Rc<RefCell<KeyState>>>
) -> Result<String, FormattingError> {
@ -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!(

View File

@ -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),

View File

@ -3,6 +3,7 @@ extern crate bitflags;
#[macro_use]
extern crate maplit;
extern crate serde;
extern crate xkbcommon;
mod data;
pub mod float_ord;

View File

@ -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<CString>,
/// The key events this symbol submits when submitting text is not possible
keys: Vec<XKeySym>,
keys: Vec<KeySym>,
},
}
/// 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,