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_name: *const expat::XML_Char,
|
||||||
c_attrs: *mut *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)
|
let name = CStr::from_ptr(c_name)
|
||||||
.to_str().expect("layout: XML element name must be UTF-8");
|
.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)
|
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)
|
let name = CStr::from_ptr(c_name)
|
||||||
.to_str().expect("layout: XML element name must be UTF-8");
|
.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] = [
|
const KEYSYMS: [(&str, Keysym, &str); 21] = [
|
||||||
("\\#", Keysym::numbersign, "#"),
|
("\\#", Keysym::numbersign, "#"),
|
||||||
("\\?", Keysym::question, "?"),
|
("\\?", Keysym::question, "?"),
|
||||||
|
|
@ -527,48 +517,15 @@ const KEYSYMS: [(&str, Keysym, &str); 21] = [
|
||||||
("up", Keysym::Up, "↑"),
|
("up", Keysym::Up, "↑"),
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Layout {
|
struct LayoutFile {
|
||||||
pub fn is_keysym_modifier(modifier: usize) -> bool
|
rows: Vec<Vec<Key>>,
|
||||||
{
|
width: f64,
|
||||||
match modifier {
|
height: f64,
|
||||||
MOD_FN => true,
|
row_width: f64,
|
||||||
_ => false,
|
in_row: u32,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LayoutFile {
|
||||||
fn get_keysym_by_name(name: &str) -> KeyValue
|
fn get_keysym_by_name(name: &str) -> KeyValue
|
||||||
{
|
{
|
||||||
if let Ok(idx) = KEYSYMS.binary_search_by_key(&name, |&(k, _, _)| k) {
|
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(),
|
rows: Vec::new(),
|
||||||
width: 0.0,
|
width: 0.0,
|
||||||
height: 0.0,
|
height: 0.0,
|
||||||
row_width: 0.0,
|
row_width: 0.0,
|
||||||
in_row: 0,
|
in_row: 0,
|
||||||
text_supp: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let dir = Path::new("/usr/share/unfettered-keyboard/layouts");
|
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
let path = dir.join(cfg.layout());
|
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path)?;
|
||||||
file.read_to_end(&mut vec)?;
|
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 {
|
unsafe {
|
||||||
let parser = expat::XML_ParserCreate(ptr::null());
|
let parser = expat::XML_ParserCreate(ptr::null());
|
||||||
if ptr::eq(parser, ptr::null_mut()) {
|
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_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,
|
let status = expat::XML_Parse(parser, vec.as_ptr() as *const c_char,
|
||||||
vec.len() as i32, 1);
|
vec.len() as i32, 1);
|
||||||
|
|
@ -689,21 +637,101 @@ impl Layout {
|
||||||
return Err(Error::new(ErrorKind::InvalidData, "Could not parse XML"));
|
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);
|
expat::XML_ParserFree(parser);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(layout)
|
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)]
|
#[inline(always)]
|
||||||
pub fn width(&self) -> f64
|
pub fn width(&self) -> f64
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue