138 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
/*! Testing functionality */
 | 
						|
 | 
						|
use crate::data::parsing::Layout;
 | 
						|
use crate::logging;
 | 
						|
use xkbcommon::xkb;
 | 
						|
 | 
						|
 | 
						|
pub struct CountAndPrint(u32);
 | 
						|
 | 
						|
impl logging::Handler for CountAndPrint {
 | 
						|
    fn handle(&mut self, level: logging::Level, warning: &str) {
 | 
						|
        use crate::logging::Level::*;
 | 
						|
        match level {
 | 
						|
            Panic | Bug | Error | Warning | Surprise => {
 | 
						|
                self.0 += 1;
 | 
						|
            },
 | 
						|
            _ => {}
 | 
						|
        }
 | 
						|
        logging::Print{}.handle(level, warning)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl CountAndPrint {
 | 
						|
    fn new() -> CountAndPrint {
 | 
						|
        CountAndPrint(0)
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub fn check_builtin_layout(name: &str, missing_return: bool) {
 | 
						|
    check_layout(
 | 
						|
        Layout::from_resource(name).expect("Invalid layout data"),
 | 
						|
        missing_return,
 | 
						|
    )
 | 
						|
}
 | 
						|
 | 
						|
pub fn check_layout_file(path: &str) {
 | 
						|
    check_layout(
 | 
						|
        Layout::from_file(path.into()).expect("Invalid layout file"),
 | 
						|
        false,
 | 
						|
    )
 | 
						|
}
 | 
						|
 | 
						|
fn check_sym_in_keymap(state: &xkb::State, sym_name: &str) -> bool {
 | 
						|
    let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
 | 
						|
    if sym.raw() == xkb::keysyms::KEY_NoSymbol {
 | 
						|
        panic!("Entered invalid keysym: {}", sym_name);
 | 
						|
    }
 | 
						|
    let map = state.get_keymap();
 | 
						|
    let range = map.min_keycode().raw()..=map.max_keycode().raw();
 | 
						|
    range.flat_map(|code| state.key_get_syms(code.into()))
 | 
						|
        .find(|s| **s == sym)
 | 
						|
        .is_some()
 | 
						|
}
 | 
						|
 | 
						|
fn check_sym_presence(
 | 
						|
    states: &[xkb::State],
 | 
						|
    sym_name: &str,
 | 
						|
    handler: &mut dyn logging::Handler,
 | 
						|
) {
 | 
						|
    let found = states.iter()
 | 
						|
        .position(|state| {
 | 
						|
            check_sym_in_keymap(&state, sym_name)
 | 
						|
        });
 | 
						|
 | 
						|
    if let None = found {
 | 
						|
        handler.handle(
 | 
						|
            logging::Level::Surprise,
 | 
						|
            &format!("There's no way to input the keysym {} on this layout", sym_name),
 | 
						|
        )
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
fn check_layout(layout: Layout, allow_missing_return: bool) {
 | 
						|
    let handler = CountAndPrint::new();
 | 
						|
    let (layout, mut handler) = layout.build(handler);
 | 
						|
 | 
						|
    if handler.0 > 0 {
 | 
						|
        println!("{} problems while parsing layout", handler.0)
 | 
						|
    }
 | 
						|
 | 
						|
    let layout = layout.expect("layout broken");
 | 
						|
    
 | 
						|
    let xkb_states: Vec<xkb::State> = layout.keymaps.iter()
 | 
						|
        .map(|keymap_str| {
 | 
						|
            let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
 | 
						|
            let keymap_str = keymap_str
 | 
						|
                .clone()
 | 
						|
                .into_string().expect("Failed to decode keymap string");
 | 
						|
            let keymap = xkb::Keymap::new_from_string(
 | 
						|
                &context,
 | 
						|
                keymap_str.clone(),
 | 
						|
                xkb::KEYMAP_FORMAT_TEXT_V1,
 | 
						|
                xkb::KEYMAP_COMPILE_NO_FLAGS,
 | 
						|
            ).expect("Failed to create keymap");
 | 
						|
            xkb::State::new(&keymap)
 | 
						|
        })
 | 
						|
        .collect();
 | 
						|
 | 
						|
    check_sym_presence(&xkb_states, "BackSpace", &mut handler);
 | 
						|
    let mut printer = logging::Print;
 | 
						|
    check_sym_presence(
 | 
						|
        &xkb_states,
 | 
						|
        "Return",
 | 
						|
        if allow_missing_return { &mut printer }
 | 
						|
        else { &mut handler },
 | 
						|
    );
 | 
						|
 | 
						|
    // "Press" each button with keysyms
 | 
						|
    for (_pos, view) in layout.views.values() {
 | 
						|
        for (_y, row) in view.get_rows() {
 | 
						|
            for (_x, button) in row.get_buttons() {
 | 
						|
                for keycode in &button.keycodes {
 | 
						|
                    match xkb_states[keycode.keymap_idx].key_get_one_sym(keycode.code.into()).raw() {
 | 
						|
                        xkb::keysyms::KEY_NoSymbol => {
 | 
						|
                            eprintln!(
 | 
						|
                                "keymap {}: {}",
 | 
						|
                                keycode.keymap_idx,
 | 
						|
                                layout.keymaps[keycode.keymap_idx].to_str().unwrap(),
 | 
						|
                            );
 | 
						|
                            panic!(
 | 
						|
                                "Keysym for code {:?} on key {} ({:?}) can't be resolved",
 | 
						|
                                keycode,
 | 
						|
                                button.name.to_string_lossy(),
 | 
						|
                                button.name,
 | 
						|
                            );
 | 
						|
                        },
 | 
						|
                        _ => {},
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if handler.0 > 0 {
 | 
						|
        panic!("Layout contains mistakes");
 | 
						|
    }
 | 
						|
}
 |