keystate: Wrap in refconuter
This commit is contained in:
		
							
								
								
									
										134
									
								
								src/keyboard.rs
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/keyboard.rs
									
									
									
									
									
								
							@ -7,9 +7,16 @@ pub mod c {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use ::util::c::{ as_cstr, into_cstring };
 | 
					    use ::util::c::{ as_cstr, into_cstring };
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    use std::cell::RefCell;
 | 
				
			||||||
    use std::ffi::CString;
 | 
					    use std::ffi::CString;
 | 
				
			||||||
    use std::os::raw::c_char;
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
    use std::ptr;
 | 
					    use std::ptr;
 | 
				
			||||||
 | 
					    use std::rc::Rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // traits
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    use std::borrow::ToOwned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // The following defined in C
 | 
					    // The following defined in C
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
@ -17,6 +24,33 @@ pub mod c {
 | 
				
			|||||||
        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
					        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The wrapped structure for KeyState suitable for handling in C
 | 
				
			||||||
 | 
					    /// Since C doesn't respect borrowing rules,
 | 
				
			||||||
 | 
					    /// RefCell will enforce them dynamically (only 1 writer/many readers)
 | 
				
			||||||
 | 
					    /// Rc is implied and will ensure timely dropping
 | 
				
			||||||
 | 
					    pub struct CKeyState(*const RefCell<KeyState>);
 | 
				
			||||||
 | 
					    impl CKeyState {
 | 
				
			||||||
 | 
					        fn unwrap(self) -> Rc<RefCell<KeyState>> {
 | 
				
			||||||
 | 
					            unsafe { Rc::from_raw(self.0) }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fn to_owned(self) -> KeyState {
 | 
				
			||||||
 | 
					            let rc = self.unwrap();
 | 
				
			||||||
 | 
					            let state = rc.borrow().to_owned();
 | 
				
			||||||
 | 
					            Rc::into_raw(rc); // Prevent dropping
 | 
				
			||||||
 | 
					            state
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fn borrow_mut<F, T>(self, f: F) -> T where F: FnOnce(&mut KeyState) -> T {
 | 
				
			||||||
 | 
					            let rc = self.unwrap();
 | 
				
			||||||
 | 
					            let ret = {
 | 
				
			||||||
 | 
					                let mut state = rc.borrow_mut();
 | 
				
			||||||
 | 
					                f(&mut state)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            Rc::into_raw(rc); // Prevent dropping
 | 
				
			||||||
 | 
					            ret
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: unwrapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
					    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -24,63 +58,59 @@ pub mod c {
 | 
				
			|||||||
    // so it should handle garbled strings in the future
 | 
					    // so it should handle garbled strings in the future
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_new(keycode: u32) -> *mut KeyState {
 | 
					    fn squeek_key_new(keycode: u32) -> CKeyState {
 | 
				
			||||||
        Box::into_raw(Box::new(
 | 
					        let state: Rc<RefCell<KeyState>> = Rc::new(RefCell::new(
 | 
				
			||||||
            KeyState {
 | 
					            KeyState {
 | 
				
			||||||
                pressed: false,
 | 
					                pressed: false,
 | 
				
			||||||
                locked: false,
 | 
					                locked: false,
 | 
				
			||||||
                keycode: keycode,
 | 
					                keycode: keycode,
 | 
				
			||||||
                symbol: None,
 | 
					                symbol: None,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        ))
 | 
					        ));
 | 
				
			||||||
 | 
					        CKeyState(Rc::into_raw(state))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_free(key: *mut KeyState) {
 | 
					    fn squeek_key_free(key: CKeyState) {
 | 
				
			||||||
        unsafe { Box::from_raw(key) }; // gets dropped
 | 
					        key.unwrap(); // reference dropped
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_is_pressed(key: *const KeyState) -> u32 {
 | 
					    fn squeek_key_is_pressed(key: CKeyState) -> u32 {
 | 
				
			||||||
        let key = unsafe { &*key };
 | 
					        //let key = unsafe { Rc::from_raw(key.0) };
 | 
				
			||||||
        return key.pressed as u32;
 | 
					        return key.to_owned().pressed as u32;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_set_pressed(key: *mut KeyState, pressed: u32) {
 | 
					    fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
 | 
				
			||||||
        let key = unsafe { &mut *key };
 | 
					        key.borrow_mut(|key| key.pressed = pressed != 0);
 | 
				
			||||||
        key.pressed = pressed != 0;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_is_locked(key: *const KeyState) -> u32 {
 | 
					    fn squeek_key_is_locked(key: CKeyState) -> u32 {
 | 
				
			||||||
        let key = unsafe { &*key };
 | 
					        return key.to_owned().locked as u32;
 | 
				
			||||||
        return key.locked as u32;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_set_locked(key: *mut KeyState, locked: u32) {
 | 
					    fn squeek_key_set_locked(key: CKeyState, locked: u32) {
 | 
				
			||||||
        let key = unsafe { &mut *key };
 | 
					        key.borrow_mut(|key| key.locked = locked != 0);
 | 
				
			||||||
        key.locked = locked != 0;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_get_keycode(key: *const KeyState) -> u32 {
 | 
					    fn squeek_key_get_keycode(key: CKeyState) -> u32 {
 | 
				
			||||||
        let key = unsafe { &*key };
 | 
					        return key.to_owned().keycode as u32;
 | 
				
			||||||
        return key.keycode as u32;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_set_keycode(key: *mut KeyState, code: u32) {
 | 
					    fn squeek_key_set_keycode(key: CKeyState, code: u32) {
 | 
				
			||||||
        let key = unsafe { &mut *key };
 | 
					        key.borrow_mut(|key| key.keycode = code);
 | 
				
			||||||
        key.keycode = code;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // TODO: this will receive data from the filesystem,
 | 
					    // TODO: this will receive data from the filesystem,
 | 
				
			||||||
@ -88,7 +118,7 @@ pub mod c {
 | 
				
			|||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_add_symbol(
 | 
					    fn squeek_key_add_symbol(
 | 
				
			||||||
        key: *mut KeyState,
 | 
					        key: CKeyState,
 | 
				
			||||||
        element: *const c_char,
 | 
					        element: *const c_char,
 | 
				
			||||||
        text_raw: *const c_char, keyval: u32,
 | 
					        text_raw: *const c_char, keyval: u32,
 | 
				
			||||||
        label: *const c_char, icon: *const c_char,
 | 
					        label: *const c_char, icon: *const c_char,
 | 
				
			||||||
@ -110,14 +140,6 @@ pub mod c {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let key = unsafe { &mut *key };
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        if let Some(_) = key.symbol {
 | 
					 | 
				
			||||||
            eprintln!("Key {:?} already has a symbol defined", text);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let icon = into_cstring(icon)
 | 
					        let icon = into_cstring(icon)
 | 
				
			||||||
            .unwrap_or_else(|e| {
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
                eprintln!("Icon name unreadable: {}", e);
 | 
					                eprintln!("Icon name unreadable: {}", e);
 | 
				
			||||||
@ -147,42 +169,52 @@ pub mod c {
 | 
				
			|||||||
                None
 | 
					                None
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        key.symbol = Some(match element.to_bytes() {
 | 
					
 | 
				
			||||||
            b"symbol" => Symbol {
 | 
					        key.borrow_mut(|key| {
 | 
				
			||||||
                action: Action::Submit {
 | 
					            if let Some(_) = key.symbol {
 | 
				
			||||||
                    text: text,
 | 
					                eprintln!("Key {:?} already has a symbol defined", text);
 | 
				
			||||||
                    keys: Vec::new(),
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            key.symbol = Some(match element.to_bytes() {
 | 
				
			||||||
 | 
					                b"symbol" => Symbol {
 | 
				
			||||||
 | 
					                    action: Action::Submit {
 | 
				
			||||||
 | 
					                        text: text,
 | 
				
			||||||
 | 
					                        keys: Vec::new(),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    label: label,
 | 
				
			||||||
 | 
					                    tooltip: tooltip,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                label: label,
 | 
					                _ => panic!("unsupported element type {:?}", element),
 | 
				
			||||||
                tooltip: tooltip,
 | 
					            });
 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            _ => panic!("unsupported element type {:?}", element),
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_get_symbol(key: *const KeyState) -> *const symbol::Symbol {
 | 
					    fn squeek_key_get_symbol(key: CKeyState) -> *const symbol::Symbol {
 | 
				
			||||||
        let key = unsafe { &*key };
 | 
					        key.borrow_mut(|key| {
 | 
				
			||||||
        match key.symbol {
 | 
					            match key.symbol {
 | 
				
			||||||
            Some(ref symbol) => symbol as *const symbol::Symbol,
 | 
					                /// This pointer stays after the function exits,
 | 
				
			||||||
            None => ptr::null(),
 | 
					                /// so it must reference borrowed data and not any copy
 | 
				
			||||||
        }
 | 
					                Some(ref symbol) => symbol as *const symbol::Symbol,
 | 
				
			||||||
 | 
					                None => ptr::null(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_key_to_keymap_entry(
 | 
					    fn squeek_key_to_keymap_entry(
 | 
				
			||||||
        key_name: *const c_char,
 | 
					        key_name: *const c_char,
 | 
				
			||||||
        key: *const KeyState,
 | 
					        key: CKeyState,
 | 
				
			||||||
    ) -> *const c_char {
 | 
					    ) -> *const c_char {
 | 
				
			||||||
        let key_name = as_cstr(&key_name)
 | 
					        let key_name = as_cstr(&key_name)
 | 
				
			||||||
            .expect("Missing key name")
 | 
					            .expect("Missing key name")
 | 
				
			||||||
            .to_str()
 | 
					            .to_str()
 | 
				
			||||||
            .expect("Bad key name");
 | 
					            .expect("Bad key name");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let key = unsafe { &*key };
 | 
					        let symbol_name = match key.to_owned().symbol {
 | 
				
			||||||
        let symbol_name = match key.symbol {
 | 
					 | 
				
			||||||
            Some(ref symbol) => match &symbol.action {
 | 
					            Some(ref symbol) => match &symbol.action {
 | 
				
			||||||
                symbol::Action::Submit { text: Some(text), .. } => {
 | 
					                symbol::Action::Submit { text: Some(text), .. } => {
 | 
				
			||||||
                    Some(
 | 
					                    Some(
 | 
				
			||||||
@ -209,7 +241,7 @@ pub mod c {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct KeyState {
 | 
					pub struct KeyState {
 | 
				
			||||||
    pressed: bool,
 | 
					    pressed: bool,
 | 
				
			||||||
    locked: bool,
 | 
					    locked: bool,
 | 
				
			||||||
 | 
				
			|||||||
@ -74,7 +74,7 @@ pub mod c {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Just defines some int->identifier mappings for convenience
 | 
					/// Just defines some int->identifier mappings for convenience
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub enum KeySym {
 | 
					pub enum KeySym {
 | 
				
			||||||
    Unknown = 0,
 | 
					    Unknown = 0,
 | 
				
			||||||
    Shift = 0xffe1,
 | 
					    Shift = 0xffe1,
 | 
				
			||||||
@ -89,10 +89,10 @@ impl KeySym {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct XKeySym(pub u32);
 | 
					pub struct XKeySym(pub u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub enum Label {
 | 
					pub enum Label {
 | 
				
			||||||
    /// Text used to display the symbol
 | 
					    /// Text used to display the symbol
 | 
				
			||||||
    Text(CString),
 | 
					    Text(CString),
 | 
				
			||||||
@ -104,14 +104,14 @@ pub enum Label {
 | 
				
			|||||||
type Level = u8;
 | 
					type Level = u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Use to send modified keypresses
 | 
					/// Use to send modified keypresses
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub enum Modifier {
 | 
					pub enum Modifier {
 | 
				
			||||||
    Control,
 | 
					    Control,
 | 
				
			||||||
    Alt,
 | 
					    Alt,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Action to perform on the keypress and, in reverse, on keyrelease
 | 
					/// Action to perform on the keypress and, in reverse, on keyrelease
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub enum Action {
 | 
					pub enum Action {
 | 
				
			||||||
    /// Switch to this level TODO: reverse?
 | 
					    /// Switch to this level TODO: reverse?
 | 
				
			||||||
    SetLevel(Level),
 | 
					    SetLevel(Level),
 | 
				
			||||||
@ -127,7 +127,7 @@ pub enum Action {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Contains a static description of a particular key's actions
 | 
					/// Contains a static description of a particular key's actions
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct Symbol {
 | 
					pub struct Symbol {
 | 
				
			||||||
    /// The action that this key performs
 | 
					    /// The action that this key performs
 | 
				
			||||||
    pub action: Action,
 | 
					    pub action: Action,
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user