keystate: Wrap in refconuter
This commit is contained in:
108
src/keyboard.rs
108
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,6 +169,13 @@ pub mod c {
|
|||||||
None
|
None
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
key.borrow_mut(|key| {
|
||||||
|
if let Some(_) = key.symbol {
|
||||||
|
eprintln!("Key {:?} already has a symbol defined", text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
key.symbol = Some(match element.to_bytes() {
|
key.symbol = Some(match element.to_bytes() {
|
||||||
b"symbol" => Symbol {
|
b"symbol" => Symbol {
|
||||||
action: Action::Submit {
|
action: Action::Submit {
|
||||||
@ -158,31 +187,34 @@ pub mod c {
|
|||||||
},
|
},
|
||||||
_ => panic!("unsupported element type {:?}", element),
|
_ => 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 {
|
||||||
|
/// This pointer stays after the function exits,
|
||||||
|
/// so it must reference borrowed data and not any copy
|
||||||
Some(ref symbol) => symbol as *const symbol::Symbol,
|
Some(ref symbol) => symbol as *const symbol::Symbol,
|
||||||
None => ptr::null(),
|
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