keysyms: Derive from Unicode labels
This commit is contained in:
113
src/data.rs
113
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())),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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!(
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -3,6 +3,7 @@ extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate maplit;
|
||||
extern crate serde;
|
||||
extern crate xkbcommon;
|
||||
|
||||
mod data;
|
||||
pub mod float_ord;
|
||||
|
||||
@ -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,
|
||||
|
||||
Reference in New Issue
Block a user