core: layout: separate layout file parsing into new struct
Some fields in the layout can be abandoned when parsing is complete. The code for opening and parsing a file is partially duplicated for the main layout and bottom row. Separate the parsing into a new struct to make the individual results easier to work with.
This commit is contained in:
parent
81aae23fe7
commit
253575febd
1 changed files with 103 additions and 75 deletions
|
|
@ -25,7 +25,7 @@ unsafe extern "C" fn start_elem(data: *mut c_void,
|
|||
c_name: *const expat::XML_Char,
|
||||
c_attrs: *mut *const expat::XML_Char)
|
||||
{
|
||||
let layout = &mut *(data as *mut Layout);
|
||||
let layout = &mut *(data as *mut LayoutFile);
|
||||
let name = CStr::from_ptr(c_name)
|
||||
.to_str().expect("layout: XML element name must be UTF-8");
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ unsafe extern "C" fn start_elem(data: *mut c_void,
|
|||
|
||||
unsafe extern "C" fn end_elem(data: *mut c_void, c_name: *const expat::XML_Char)
|
||||
{
|
||||
let layout = &mut *(data as *mut Layout);
|
||||
let layout = &mut *(data as *mut LayoutFile);
|
||||
let name = CStr::from_ptr(c_name)
|
||||
.to_str().expect("layout: XML element name must be UTF-8");
|
||||
|
||||
|
|
@ -493,16 +493,6 @@ impl Key {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
rows: Vec<Vec<Key>>,
|
||||
width: f64,
|
||||
height: f64,
|
||||
row_width: f64,
|
||||
in_row: u32,
|
||||
|
||||
text_supp: bool,
|
||||
}
|
||||
|
||||
const KEYSYMS: [(&str, Keysym, &str); 21] = [
|
||||
("\\#", Keysym::numbersign, "#"),
|
||||
("\\?", Keysym::question, "?"),
|
||||
|
|
@ -527,48 +517,15 @@ const KEYSYMS: [(&str, Keysym, &str); 21] = [
|
|||
("up", Keysym::Up, "↑"),
|
||||
];
|
||||
|
||||
impl Layout {
|
||||
pub fn is_keysym_modifier(modifier: usize) -> bool
|
||||
{
|
||||
match modifier {
|
||||
MOD_FN => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the modifier can be emitted as a key event.
|
||||
*
|
||||
* Modifiers that modify the key values (e.g. the Fn key and any accents)
|
||||
* should usually not be emitted as key events to applications, and their
|
||||
* only purpose is to modify the key values. The Meta modifier should also
|
||||
* be inhibited from emitting a key event, because its purpose is to make
|
||||
* every key value emit a key press.
|
||||
*/
|
||||
pub fn is_pressable_modifier(modifier: usize) -> bool
|
||||
{
|
||||
!Self::is_keysym_modifier(modifier) && modifier != MOD_META
|
||||
}
|
||||
|
||||
pub fn is_label_modifier(modifier: usize) -> bool
|
||||
{
|
||||
// Shift does not change the keysym used for input, but changes the
|
||||
// rendered keysym.
|
||||
Self::is_keysym_modifier(modifier) || modifier == MOD_SHIFT
|
||||
}
|
||||
|
||||
pub fn modifier_keysym(modifier: usize) -> Keysym
|
||||
{
|
||||
match modifier {
|
||||
MOD_SHIFT => Keysym::Shift_L,
|
||||
MOD_CTRL => Keysym::Control_L,
|
||||
MOD_ALT => Keysym::Alt_L,
|
||||
MOD_FN => Keysym::XF86_Fn,
|
||||
MOD_META => Keysym::Meta_L,
|
||||
_ => Keysym::NoSymbol,
|
||||
}
|
||||
struct LayoutFile {
|
||||
rows: Vec<Vec<Key>>,
|
||||
width: f64,
|
||||
height: f64,
|
||||
row_width: f64,
|
||||
in_row: u32,
|
||||
}
|
||||
|
||||
impl LayoutFile {
|
||||
fn get_keysym_by_name(name: &str) -> KeyValue
|
||||
{
|
||||
if let Ok(idx) = KEYSYMS.binary_search_by_key(&name, |&(k, _, _)| k) {
|
||||
|
|
@ -651,29 +608,20 @@ impl Layout {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load(cfg: &Configuration) -> Result<Self, Error>
|
||||
fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error>
|
||||
{
|
||||
let mut layout = Layout {
|
||||
let mut layout = LayoutFile {
|
||||
rows: Vec::new(),
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
row_width: 0.0,
|
||||
in_row: 0,
|
||||
text_supp: false,
|
||||
};
|
||||
|
||||
let dir = Path::new("/usr/share/unfettered-keyboard/layouts");
|
||||
|
||||
let mut vec = Vec::new();
|
||||
let path = dir.join(cfg.layout());
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_end(&mut vec)?;
|
||||
|
||||
let mut vec2 = Vec::new();
|
||||
let path = dir.join("bottom_row.xml");
|
||||
let mut file = File::open(path)?;
|
||||
file.read_to_end(&mut vec2)?;
|
||||
|
||||
unsafe {
|
||||
let parser = expat::XML_ParserCreate(ptr::null());
|
||||
if ptr::eq(parser, ptr::null_mut()) {
|
||||
|
|
@ -681,7 +629,7 @@ impl Layout {
|
|||
}
|
||||
|
||||
expat::XML_SetElementHandler(parser, Some(start_elem), Some(end_elem));
|
||||
expat::XML_SetUserData(parser, &mut layout as *mut Layout as *mut c_void);
|
||||
expat::XML_SetUserData(parser, &mut layout as *mut Self as *mut c_void);
|
||||
|
||||
let status = expat::XML_Parse(parser, vec.as_ptr() as *const c_char,
|
||||
vec.len() as i32, 1);
|
||||
|
|
@ -689,21 +637,101 @@ impl Layout {
|
|||
return Err(Error::new(ErrorKind::InvalidData, "Could not parse XML"));
|
||||
}
|
||||
|
||||
expat::XML_ParserReset(parser, ptr::null());
|
||||
expat::XML_SetElementHandler(parser, Some(start_elem), Some(end_elem));
|
||||
expat::XML_SetUserData(parser, &mut layout as *mut Layout as *mut c_void);
|
||||
|
||||
let status = expat::XML_Parse(parser, vec2.as_ptr() as *const c_char,
|
||||
vec2.len() as i32, 1);
|
||||
if status != expat::XML_Status_XML_STATUS_OK {
|
||||
return Err(Error::new(ErrorKind::InvalidData, "Could not parse XML"));
|
||||
}
|
||||
|
||||
expat::XML_ParserFree(parser);
|
||||
};
|
||||
|
||||
Ok(layout)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Layout {
|
||||
rows: Vec<Vec<Key>>,
|
||||
width: f64,
|
||||
height: f64,
|
||||
text_supp: bool,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn is_keysym_modifier(modifier: usize) -> bool
|
||||
{
|
||||
match modifier {
|
||||
MOD_FN => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the modifier can be emitted as a key event.
|
||||
*
|
||||
* Modifiers that modify the key values (e.g. the Fn key and any accents)
|
||||
* should usually not be emitted as key events to applications, and their
|
||||
* only purpose is to modify the key values. The Meta modifier should also
|
||||
* be inhibited from emitting a key event, because its purpose is to make
|
||||
* every key value emit a key press.
|
||||
*/
|
||||
pub fn is_pressable_modifier(modifier: usize) -> bool
|
||||
{
|
||||
!Self::is_keysym_modifier(modifier) && modifier != MOD_META
|
||||
}
|
||||
|
||||
pub fn is_label_modifier(modifier: usize) -> bool
|
||||
{
|
||||
// Shift does not change the keysym used for input, but changes the
|
||||
// rendered keysym.
|
||||
Self::is_keysym_modifier(modifier) || modifier == MOD_SHIFT
|
||||
}
|
||||
|
||||
pub fn modifier_keysym(modifier: usize) -> Keysym
|
||||
{
|
||||
match modifier {
|
||||
MOD_SHIFT => Keysym::Shift_L,
|
||||
MOD_CTRL => Keysym::Control_L,
|
||||
MOD_ALT => Keysym::Alt_L,
|
||||
MOD_FN => Keysym::XF86_Fn,
|
||||
MOD_META => Keysym::Meta_L,
|
||||
_ => Keysym::NoSymbol,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(cfg: &Configuration) -> Result<Self, Error>
|
||||
{
|
||||
let dir = Path::new("/usr/share/unfettered-keyboard/layouts");
|
||||
|
||||
let path = dir.join(cfg.layout());
|
||||
let main_layout = LayoutFile::load(path)?;
|
||||
|
||||
let mut layout = Layout {
|
||||
rows: main_layout.rows,
|
||||
width: main_layout.width,
|
||||
height: main_layout.height,
|
||||
text_supp: false,
|
||||
};
|
||||
|
||||
let path = dir.join("bottom_row.xml");
|
||||
let bottom_row = LayoutFile::load(path)?;
|
||||
|
||||
let old_height = layout.height;
|
||||
layout.height += bottom_row.height;
|
||||
|
||||
layout.rows.reserve(bottom_row.rows.len());
|
||||
for row in bottom_row.rows {
|
||||
let mut new_row = Vec::with_capacity(row.len());
|
||||
|
||||
for key in row {
|
||||
new_row.push(Key {
|
||||
parts: key.parts,
|
||||
x1: key.x1,
|
||||
y1: old_height + key.y1,
|
||||
x2: key.x2,
|
||||
y2: old_height + key.y2,
|
||||
});
|
||||
}
|
||||
|
||||
layout.rows.push(new_row);
|
||||
}
|
||||
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn width(&self) -> f64
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue