eekkey: Moved state to KeyState
This commit is contained in:
		
							
								
								
									
										19
									
								
								src/keyboard.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/keyboard.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#ifndef __KEYBOARD_H
 | 
			
		||||
#define __KYBOARD_H
 | 
			
		||||
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
#include "inttypes.h"
 | 
			
		||||
 | 
			
		||||
struct squeek_key;
 | 
			
		||||
 | 
			
		||||
struct squeek_key *squeek_key_new(uint32_t keycode);
 | 
			
		||||
void squeek_key_free(struct squeek_key *key);
 | 
			
		||||
void squeek_key_add_symbol(struct squeek_key* key,
 | 
			
		||||
                           const char *element_name,
 | 
			
		||||
                           const char *text, uint32_t keyval,
 | 
			
		||||
                           const char *label, const char *icon,
 | 
			
		||||
                           const char *tooltip);
 | 
			
		||||
uint32_t squeek_key_is_pressed(struct squeek_key *key);
 | 
			
		||||
void squeek_key_set_pressed(struct squeek_key *key, uint32_t pressed);
 | 
			
		||||
struct squeek_symbol *squeek_key_get_symbol(struct squeek_key* key, uint32_t level);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										216
									
								
								src/keyboard.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/keyboard.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,216 @@
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
 | 
			
		||||
use super::symbol;
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use ::util::c::{ as_cstr, into_cstring };
 | 
			
		||||
    
 | 
			
		||||
    use std::ffi::CString;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
			
		||||
    
 | 
			
		||||
    // TODO: this will receive data from the filesystem,
 | 
			
		||||
    // so it should handle garbled strings in the future
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_new(keycode: u32) -> *mut KeyState {
 | 
			
		||||
        Box::into_raw(Box::new(
 | 
			
		||||
            KeyState {
 | 
			
		||||
                pressed: false,
 | 
			
		||||
                keycode: keycode,
 | 
			
		||||
                symbols: Vec::new(),
 | 
			
		||||
            }
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_free(key: *mut KeyState) {
 | 
			
		||||
        unsafe { Box::from_raw(key) }; // gets dropped
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_is_pressed(key: *const KeyState) -> u32{
 | 
			
		||||
        let key = unsafe { &*key };
 | 
			
		||||
        return key.pressed as u32;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_set_pressed(key: *mut KeyState, pressed: u32) {
 | 
			
		||||
        let key = unsafe { &mut *key };
 | 
			
		||||
        key.pressed = pressed != 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // TODO: this will receive data from the filesystem,
 | 
			
		||||
    // so it should handle garbled strings in the future
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_add_symbol(
 | 
			
		||||
        key: *mut KeyState,
 | 
			
		||||
        element: *const c_char,
 | 
			
		||||
        text_raw: *const c_char, keyval: u32,
 | 
			
		||||
        label: *const c_char, icon: *const c_char,
 | 
			
		||||
        tooltip: *const c_char,
 | 
			
		||||
    ) {
 | 
			
		||||
        let element = as_cstr(&element)
 | 
			
		||||
            .expect("Missing element name");
 | 
			
		||||
 | 
			
		||||
        let text = into_cstring(text_raw)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Text unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            })
 | 
			
		||||
            .and_then(|text| {
 | 
			
		||||
                if text.as_bytes() == b"" {
 | 
			
		||||
                    None
 | 
			
		||||
                } else {
 | 
			
		||||
                    Some(text)
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        let icon = into_cstring(icon)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Icon name unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        use symbol::*;
 | 
			
		||||
        // Only read label if there's no icon
 | 
			
		||||
        let label = match icon {
 | 
			
		||||
            Some(icon) => Label::IconName(icon),
 | 
			
		||||
            None => Label::Text(
 | 
			
		||||
                into_cstring(label)
 | 
			
		||||
                    .unwrap_or_else(|e| {
 | 
			
		||||
                        eprintln!("Label unreadable: {}", e);
 | 
			
		||||
                        Some(CString::new(" ").unwrap())
 | 
			
		||||
                    })
 | 
			
		||||
                    .unwrap_or_else(|| {
 | 
			
		||||
                        eprintln!("Label missing");
 | 
			
		||||
                        CString::new(" ").unwrap()
 | 
			
		||||
                    })
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let tooltip = into_cstring(tooltip)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Tooltip unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
        let symbol = match element.to_bytes() {
 | 
			
		||||
            b"symbol" => Symbol {
 | 
			
		||||
                action: Action::Submit {
 | 
			
		||||
                    text: text,
 | 
			
		||||
                    keys: Vec::new(),
 | 
			
		||||
                },
 | 
			
		||||
                label: label,
 | 
			
		||||
                tooltip: tooltip,
 | 
			
		||||
            },
 | 
			
		||||
            b"keysym" => {
 | 
			
		||||
                let keysym = XKeySym(
 | 
			
		||||
                    if keyval == 0 {
 | 
			
		||||
                        unsafe { eek_keysym_from_name(text_raw) }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        keyval
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                Symbol {
 | 
			
		||||
                    action: match KeySym::from_u32(keysym.0) {
 | 
			
		||||
                        KeySym::Shift => Action::SetLevel(1),
 | 
			
		||||
                        _ => Action::Submit {
 | 
			
		||||
                            text: text,
 | 
			
		||||
                            keys: vec![keysym],
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    label: label,
 | 
			
		||||
                    tooltip: tooltip,
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            _ => panic!("unsupported element type {:?}", element),
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        let key = unsafe { &mut *key };
 | 
			
		||||
        key.symbols.push(symbol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_get_symbol(
 | 
			
		||||
        key: *const KeyState, index: u32
 | 
			
		||||
    ) -> *const symbol::Symbol {
 | 
			
		||||
        let key = unsafe { &*key };
 | 
			
		||||
        let index = index as usize;
 | 
			
		||||
        &key.symbols[
 | 
			
		||||
            if index < key.symbols.len() { index } else { 0 }
 | 
			
		||||
        ] as *const symbol::Symbol
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_to_keymap_entry(
 | 
			
		||||
        key_name: *const c_char,
 | 
			
		||||
        key: *const KeyState,
 | 
			
		||||
    ) -> *const c_char {
 | 
			
		||||
        let key_name = as_cstr(&key_name)
 | 
			
		||||
            .expect("Missing key name")
 | 
			
		||||
            .to_str()
 | 
			
		||||
            .expect("Bad key name");
 | 
			
		||||
 | 
			
		||||
        let key = unsafe { &*key };
 | 
			
		||||
        let symbol_names = key.symbols.iter()
 | 
			
		||||
            .map(|symbol| {
 | 
			
		||||
                match &symbol.action {
 | 
			
		||||
                    symbol::Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                        Some(
 | 
			
		||||
                            text.clone()
 | 
			
		||||
                                .into_string().expect("Bad symbol")
 | 
			
		||||
                        )
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => None
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
        let inner = match symbol_names.len() {
 | 
			
		||||
            1 => match &symbol_names[0] {
 | 
			
		||||
                Some(name) => format!("[ {} ]", name),
 | 
			
		||||
                _ => format!("[ ]"),
 | 
			
		||||
            },
 | 
			
		||||
            4 => {
 | 
			
		||||
                let first = match (&symbol_names[0], &symbol_names[1]) {
 | 
			
		||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
			
		||||
                    _ => format!(""),
 | 
			
		||||
                };
 | 
			
		||||
                let second = match (&symbol_names[2], &symbol_names[3]) {
 | 
			
		||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
			
		||||
                    _ => format!(""),
 | 
			
		||||
                };
 | 
			
		||||
                format!("[ {} ], [ {} ]", first, second)
 | 
			
		||||
            },
 | 
			
		||||
            _ => panic!("Unsupported number of symbols"),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        CString::new(format!("        key <{}> {{ {} }};\n", key_name, inner))
 | 
			
		||||
            .expect("Couldn't convert string")
 | 
			
		||||
            .into_raw()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct KeyState {
 | 
			
		||||
    pressed: bool,
 | 
			
		||||
    keycode: u32,
 | 
			
		||||
    symbols: Vec<symbol::Symbol>,
 | 
			
		||||
}
 | 
			
		||||
@ -2,4 +2,6 @@
 | 
			
		||||
mod bitflags;
 | 
			
		||||
 | 
			
		||||
mod imservice;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
mod symbol;
 | 
			
		||||
mod util;
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,5 @@ uint32_t squeek_symbol_get_modifier_mask(struct squeek_symbol* symbol);
 | 
			
		||||
 | 
			
		||||
void squeek_symbol_print(struct squeek_symbol* symbol);
 | 
			
		||||
 | 
			
		||||
struct squeek_symbols* squeek_symbols_new();
 | 
			
		||||
void squeek_symbols_free(struct squeek_symbols*);
 | 
			
		||||
struct squeek_symbol *squeek_symbols_get(struct squeek_symbols*, uint32_t level);
 | 
			
		||||
 | 
			
		||||
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_symbols *symbols);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										228
									
								
								src/symbol.rs
									
									
									
									
									
								
							
							
						
						
									
										228
									
								
								src/symbol.rs
									
									
									
									
									
								
							@ -1,67 +1,16 @@
 | 
			
		||||
use std::boxed::Box;
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    use std::ptr;
 | 
			
		||||
    use std::str::Utf8Error;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        } else {
 | 
			
		||||
            unsafe {CStr::from_ptr(*s)}
 | 
			
		||||
                .to_str()
 | 
			
		||||
                .map(Some)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fn as_cstr(s: &*const c_char) -> Option<&CStr> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            None
 | 
			
		||||
        } else {
 | 
			
		||||
            Some(unsafe {CStr::from_ptr(*s)})
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        } else {
 | 
			
		||||
            CString::new(
 | 
			
		||||
                unsafe {CStr::from_ptr(s)}.to_bytes()
 | 
			
		||||
            ).map(Some)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[cfg(test)]
 | 
			
		||||
    mod tests {
 | 
			
		||||
        use super::*;
 | 
			
		||||
        
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_null_cstring() {
 | 
			
		||||
            assert_eq!(into_cstring(ptr::null()), Ok(None))
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_null_str() {
 | 
			
		||||
            assert_eq!(as_str(&ptr::null()), Ok(None))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // The following defined in C
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    extern "C" {
 | 
			
		||||
        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Legacy; Will never be used in Rust as a bit field
 | 
			
		||||
    enum ModifierMask {
 | 
			
		||||
        Nothing = 0,
 | 
			
		||||
@ -72,98 +21,6 @@ pub mod c {
 | 
			
		||||
    
 | 
			
		||||
    // TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
			
		||||
    // Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
 | 
			
		||||
    
 | 
			
		||||
    // TODO: this will receive data from the filesystem,
 | 
			
		||||
    // so it should handle garbled strings in the future
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbols_add(
 | 
			
		||||
        v: *mut Vec<Symbol>,
 | 
			
		||||
        element: *const c_char,
 | 
			
		||||
        text_raw: *const c_char, keyval: u32,
 | 
			
		||||
        label: *const c_char, icon: *const c_char,
 | 
			
		||||
        tooltip: *const c_char,
 | 
			
		||||
    ) {
 | 
			
		||||
        let element = as_cstr(&element)
 | 
			
		||||
            .expect("Missing element name");
 | 
			
		||||
 | 
			
		||||
        let text = into_cstring(text_raw)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Text unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            })
 | 
			
		||||
            .and_then(|text| {
 | 
			
		||||
                if text.as_bytes() == b"" {
 | 
			
		||||
                    None
 | 
			
		||||
                } else {
 | 
			
		||||
                    Some(text)
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        let icon = into_cstring(icon)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Icon name unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        // Only read label if there's no icon
 | 
			
		||||
        let label = match icon {
 | 
			
		||||
            Some(icon) => Label::IconName(icon),
 | 
			
		||||
            None => Label::Text(
 | 
			
		||||
                into_cstring(label)
 | 
			
		||||
                    .unwrap_or_else(|e| {
 | 
			
		||||
                        eprintln!("Label unreadable: {}", e);
 | 
			
		||||
                        Some(CString::new(" ").unwrap())
 | 
			
		||||
                    })
 | 
			
		||||
                    .unwrap_or_else(|| {
 | 
			
		||||
                        eprintln!("Label missing");
 | 
			
		||||
                        CString::new(" ").unwrap()
 | 
			
		||||
                    })
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let tooltip = into_cstring(tooltip)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                eprintln!("Tooltip unreadable: {}", e);
 | 
			
		||||
                None
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
        let symbol = match element.to_bytes() {
 | 
			
		||||
            b"symbol" => Symbol {
 | 
			
		||||
                action: Action::Submit {
 | 
			
		||||
                    text: text,
 | 
			
		||||
                    keys: Vec::new(),
 | 
			
		||||
                },
 | 
			
		||||
                label: label,
 | 
			
		||||
                tooltip: tooltip,
 | 
			
		||||
            },
 | 
			
		||||
            b"keysym" => {
 | 
			
		||||
                let keysym = XKeySym(
 | 
			
		||||
                    if keyval == 0 {
 | 
			
		||||
                        unsafe { eek_keysym_from_name(text_raw) }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        keyval
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
                Symbol {
 | 
			
		||||
                    action: match KeySym::from_u32(keysym.0) {
 | 
			
		||||
                        KeySym::Shift => Action::SetLevel(1),
 | 
			
		||||
                        _ => Action::Submit {
 | 
			
		||||
                            text: text,
 | 
			
		||||
                            keys: vec![keysym],
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    label: label,
 | 
			
		||||
                    tooltip: tooltip,
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            _ => panic!("unsupported element type {:?}", element),
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        let v = unsafe { &mut *v };
 | 
			
		||||
        v.push(symbol);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
@ -214,88 +71,17 @@ pub mod c {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        println!("{:?}", symbol);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbols_new() -> *const Vec<Symbol> {
 | 
			
		||||
        Box::into_raw(Box::new(Vec::new()))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbols_get(v: *mut Vec<Symbol>, index: u32) -> *const Symbol {
 | 
			
		||||
        let v = unsafe { &mut *v };
 | 
			
		||||
        let index = index as usize;
 | 
			
		||||
        &v[
 | 
			
		||||
            if index < v.len() { index } else { 0 }
 | 
			
		||||
        ] as *const Symbol
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbols_free(symbols: *mut Vec<Symbol>) {
 | 
			
		||||
        unsafe { Box::from_raw(symbols) }; // Will just get dropped, together with the contents
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_key_to_keymap_entry(
 | 
			
		||||
        key_name: *const c_char,
 | 
			
		||||
        symbols: *const Vec<Symbol>,
 | 
			
		||||
    ) -> *const c_char {
 | 
			
		||||
        let key_name = as_cstr(&key_name)
 | 
			
		||||
            .expect("Missing key name")
 | 
			
		||||
            .to_str()
 | 
			
		||||
            .expect("Bad key name");
 | 
			
		||||
        let symbols = unsafe { &*symbols };
 | 
			
		||||
        let symbol_names = symbols.iter()
 | 
			
		||||
            .map(|symbol| {
 | 
			
		||||
                match &symbol.action {
 | 
			
		||||
                    Action::Submit { text: Some(text), .. } => {
 | 
			
		||||
                        Some(
 | 
			
		||||
                            text.clone()
 | 
			
		||||
                                .into_string().expect("Bad symbol")
 | 
			
		||||
                        )
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => None
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
        let inner = match symbol_names.len() {
 | 
			
		||||
            1 => match &symbol_names[0] {
 | 
			
		||||
                Some(name) => format!("[ {} ]", name),
 | 
			
		||||
                _ => format!("[ ]"),
 | 
			
		||||
            },
 | 
			
		||||
            4 => {
 | 
			
		||||
                let first = match (&symbol_names[0], &symbol_names[1]) {
 | 
			
		||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
			
		||||
                    _ => format!(""),
 | 
			
		||||
                };
 | 
			
		||||
                let second = match (&symbol_names[2], &symbol_names[3]) {
 | 
			
		||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
			
		||||
                    _ => format!(""),
 | 
			
		||||
                };
 | 
			
		||||
                format!("[ {} ], [ {} ]", first, second)
 | 
			
		||||
            },
 | 
			
		||||
            _ => panic!("Unsupported number of symbols"),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        CString::new(format!("        key <{}> {{ {} }};\n", key_name, inner))
 | 
			
		||||
            .expect("Couldn't convert string")
 | 
			
		||||
            .into_raw()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Just defines some int->identifier mappings for convenience
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum KeySym {
 | 
			
		||||
pub enum KeySym {
 | 
			
		||||
    Unknown = 0,
 | 
			
		||||
    Shift = 0xffe1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KeySym {
 | 
			
		||||
    fn from_u32(num: u32) -> KeySym {
 | 
			
		||||
    pub fn from_u32(num: u32) -> KeySym {
 | 
			
		||||
        match num {
 | 
			
		||||
            0xffe1 => KeySym::Shift,
 | 
			
		||||
            _ => KeySym::Unknown,
 | 
			
		||||
@ -304,7 +90,7 @@ impl KeySym {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct XKeySym(u32);
 | 
			
		||||
pub struct XKeySym(pub u32);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Label {
 | 
			
		||||
@ -344,9 +130,9 @@ pub enum Action {
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Symbol {
 | 
			
		||||
    /// The action that this key performs
 | 
			
		||||
    action: Action,
 | 
			
		||||
    pub action: Action,
 | 
			
		||||
    /// Label to display to the user
 | 
			
		||||
    label: Label,
 | 
			
		||||
    pub label: Label,
 | 
			
		||||
    // FIXME: is it used?
 | 
			
		||||
    tooltip: Option<CString>,
 | 
			
		||||
    pub tooltip: Option<CString>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use std::ffi::{ CStr, CString };
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    use std::str::Utf8Error;
 | 
			
		||||
    
 | 
			
		||||
    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        } else {
 | 
			
		||||
            unsafe {CStr::from_ptr(*s)}
 | 
			
		||||
                .to_str()
 | 
			
		||||
                .map(Some)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    pub fn as_cstr(s: &*const c_char) -> Option<&CStr> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            None
 | 
			
		||||
        } else {
 | 
			
		||||
            Some(unsafe {CStr::from_ptr(*s)})
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
 | 
			
		||||
        if s.is_null() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        } else {
 | 
			
		||||
            CString::new(
 | 
			
		||||
                unsafe {CStr::from_ptr(s)}.to_bytes()
 | 
			
		||||
            ).map(Some)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[cfg(test)]
 | 
			
		||||
    mod tests {
 | 
			
		||||
        use super::*;
 | 
			
		||||
        use std::ptr;
 | 
			
		||||
        
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_null_cstring() {
 | 
			
		||||
            assert_eq!(into_cstring(ptr::null()), Ok(None))
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_null_str() {
 | 
			
		||||
            assert_eq!(as_str(&ptr::null()), Ok(None))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user