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:
Richard Acayan 2024-09-26 17:19:43 -04:00
parent 81aae23fe7
commit 253575febd

View file

@ -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