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