eekkey: Moved state to KeyState
This commit is contained in:
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "eek-section.h"
|
#include "eek-section.h"
|
||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
|
#include "src/keyboard.h"
|
||||||
#include "src/symbol.h"
|
#include "src/symbol.h"
|
||||||
|
|
||||||
#include "eek-key.h"
|
#include "eek-key.h"
|
||||||
@ -53,9 +54,8 @@ static guint signals[LAST_SIGNAL] = { 0, };
|
|||||||
typedef struct _EekKeyPrivate
|
typedef struct _EekKeyPrivate
|
||||||
{
|
{
|
||||||
guint keycode;
|
guint keycode;
|
||||||
struct squeek_symbols *symbols;
|
|
||||||
gulong oref; // UI outline reference
|
gulong oref; // UI outline reference
|
||||||
gboolean is_pressed;
|
struct squeek_key *state;
|
||||||
gboolean is_locked;
|
gboolean is_locked;
|
||||||
} EekKeyPrivate;
|
} EekKeyPrivate;
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ eek_key_finalize (GObject *object)
|
|||||||
EekKey *self = EEK_KEY (object);
|
EekKey *self = EEK_KEY (object);
|
||||||
EekKeyPrivate *priv = eek_key_get_instance_private (self);
|
EekKeyPrivate *priv = eek_key_get_instance_private (self);
|
||||||
|
|
||||||
squeek_symbols_free (priv->symbols);
|
squeek_key_free (priv->state);
|
||||||
|
|
||||||
G_OBJECT_CLASS (eek_key_parent_class)->finalize (object);
|
G_OBJECT_CLASS (eek_key_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ static void
|
|||||||
eek_key_init (EekKey *self)
|
eek_key_init (EekKey *self)
|
||||||
{
|
{
|
||||||
EekKeyPrivate *priv = eek_key_get_instance_private (self);
|
EekKeyPrivate *priv = eek_key_get_instance_private (self);
|
||||||
priv->symbols = squeek_symbols_new ();
|
priv->state = squeek_key_new (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,23 +253,6 @@ eek_key_get_keycode (EekKey *key)
|
|||||||
return priv->keycode;
|
return priv->keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* eek_key_get_symbol_matrix:
|
|
||||||
* @key: an #EekKey
|
|
||||||
*
|
|
||||||
* Get the symbol matrix of @key.
|
|
||||||
* Returns: (transfer none): #EekSymbolMatrix or %NULL
|
|
||||||
*/
|
|
||||||
struct squeek_symbols *
|
|
||||||
eek_key_get_symbol_matrix (EekKey *key)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (EEK_IS_KEY(key), NULL);
|
|
||||||
|
|
||||||
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
|
||||||
|
|
||||||
return priv->symbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* eek_key_get_symbol_at_index:
|
* eek_key_get_symbol_at_index:
|
||||||
* @key: an #EekKey
|
* @key: an #EekKey
|
||||||
@ -286,8 +269,8 @@ eek_key_get_symbol_at_index (EekKey *key,
|
|||||||
gint group,
|
gint group,
|
||||||
guint level)
|
guint level)
|
||||||
{
|
{
|
||||||
struct squeek_symbols *symbols = eek_key_get_symbol_matrix(key);
|
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
||||||
return squeek_symbols_get(symbols, level);
|
return squeek_key_get_symbol(priv->state, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -341,7 +324,7 @@ eek_key_is_pressed (EekKey *key)
|
|||||||
|
|
||||||
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
||||||
|
|
||||||
return priv->is_pressed;
|
return (bool)squeek_key_is_pressed(priv->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -366,5 +349,10 @@ void eek_key_set_pressed(EekKey *key, gboolean value)
|
|||||||
|
|
||||||
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
||||||
|
|
||||||
priv->is_pressed = value;
|
squeek_key_set_pressed(priv->state, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct squeek_key *eek_key_get_state(EekKey *key) {
|
||||||
|
EekKeyPrivate *priv = eek_key_get_instance_private (key);
|
||||||
|
return priv->state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,8 +58,7 @@ GType eek_key_get_type (void) G_GNUC_CONST;
|
|||||||
void eek_key_set_keycode (EekKey *key,
|
void eek_key_set_keycode (EekKey *key,
|
||||||
guint keycode);
|
guint keycode);
|
||||||
guint eek_key_get_keycode (EekKey *key);
|
guint eek_key_get_keycode (EekKey *key);
|
||||||
struct squeek_symbols *
|
struct squeek_key *eek_key_get_state(EekKey *key);
|
||||||
eek_key_get_symbol_matrix (EekKey *key);
|
|
||||||
struct squeek_symbol *eek_key_get_symbol_at_index (EekKey *key,
|
struct squeek_symbol *eek_key_get_symbol_at_index (EekKey *key,
|
||||||
gint group,
|
gint group,
|
||||||
guint level);
|
guint level);
|
||||||
|
|||||||
@ -763,7 +763,7 @@ eek_keyboard_get_keymap(EekKeyboard *keyboard)
|
|||||||
// FIXME: free
|
// FIXME: free
|
||||||
const char *key_str = squeek_key_to_keymap_entry(
|
const char *key_str = squeek_key_to_keymap_entry(
|
||||||
(char*)key_name,
|
(char*)key_name,
|
||||||
eek_key_get_symbol_matrix(key)
|
eek_key_get_state(key)
|
||||||
);
|
);
|
||||||
current = symbols;
|
current = symbols;
|
||||||
symbols = g_strconcat(current, key_str, NULL);
|
symbols = g_strconcat(current, key_str, NULL);
|
||||||
|
|||||||
@ -86,10 +86,6 @@ static void render_key (EekRenderer *self,
|
|||||||
cairo_t *cr,
|
cairo_t *cr,
|
||||||
EekKey *key, guint level,
|
EekKey *key, guint level,
|
||||||
gboolean active);
|
gboolean active);
|
||||||
static void on_symbol_index_changed (EekKeyboard *keyboard,
|
|
||||||
gint group,
|
|
||||||
gint level,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
struct _CreateKeyboardSurfaceCallbackData {
|
struct _CreateKeyboardSurfaceCallbackData {
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
@ -715,16 +711,6 @@ invalidate (EekRenderer *renderer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
on_symbol_index_changed (EekKeyboard *keyboard,
|
|
||||||
gint group,
|
|
||||||
gint level,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
EekRenderer *renderer = user_data;
|
|
||||||
invalidate (renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
EekRenderer *
|
EekRenderer *
|
||||||
eek_renderer_new (EekKeyboard *keyboard,
|
eek_renderer_new (EekKeyboard *keyboard,
|
||||||
PangoContext *pcontext,
|
PangoContext *pcontext,
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
#include "eek-keyboard.h"
|
#include "eek-keyboard.h"
|
||||||
#include "eek-section.h"
|
#include "eek-section.h"
|
||||||
#include "eek-key.h"
|
#include "eek-key.h"
|
||||||
|
#include "src/keyboard.h"
|
||||||
#include "src/symbol.h"
|
#include "src/symbol.h"
|
||||||
|
|
||||||
#include "squeekboard-resources.h"
|
#include "squeekboard-resources.h"
|
||||||
@ -748,8 +749,8 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
|
|||||||
g_strcmp0 (element_name, "keysym") == 0 ||
|
g_strcmp0 (element_name, "keysym") == 0 ||
|
||||||
g_strcmp0 (element_name, "text") == 0) {
|
g_strcmp0 (element_name, "text") == 0) {
|
||||||
|
|
||||||
squeek_symbols_add(
|
squeek_key_add_symbol(
|
||||||
eek_key_get_symbol_matrix(data->key),
|
eek_key_get_state(data->key),
|
||||||
element_name,
|
element_name,
|
||||||
text,
|
text,
|
||||||
data->keyval,
|
data->keyval,
|
||||||
|
|||||||
19
src/keyboard.h
Normal file
19
src/keyboard.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef __KEYBOARD_H
|
||||||
|
#define __KYBOARD_H
|
||||||
|
|
||||||
|
#include "stdbool.h"
|
||||||
|
#include "inttypes.h"
|
||||||
|
|
||||||
|
struct squeek_key;
|
||||||
|
|
||||||
|
struct squeek_key *squeek_key_new(uint32_t keycode);
|
||||||
|
void squeek_key_free(struct squeek_key *key);
|
||||||
|
void squeek_key_add_symbol(struct squeek_key* key,
|
||||||
|
const char *element_name,
|
||||||
|
const char *text, uint32_t keyval,
|
||||||
|
const char *label, const char *icon,
|
||||||
|
const char *tooltip);
|
||||||
|
uint32_t squeek_key_is_pressed(struct squeek_key *key);
|
||||||
|
void squeek_key_set_pressed(struct squeek_key *key, uint32_t pressed);
|
||||||
|
struct squeek_symbol *squeek_key_get_symbol(struct squeek_key* key, uint32_t level);
|
||||||
|
#endif
|
||||||
216
src/keyboard.rs
Normal file
216
src/keyboard.rs
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
use super::symbol;
|
||||||
|
|
||||||
|
/// Gathers stuff defined in C or called by C
|
||||||
|
pub mod c {
|
||||||
|
use super::*;
|
||||||
|
use ::util::c::{ as_cstr, into_cstring };
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
// The following defined in C
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" {
|
||||||
|
fn eek_keysym_from_name(name: *const c_char) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||||
|
|
||||||
|
// TODO: this will receive data from the filesystem,
|
||||||
|
// so it should handle garbled strings in the future
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_new(keycode: u32) -> *mut KeyState {
|
||||||
|
Box::into_raw(Box::new(
|
||||||
|
KeyState {
|
||||||
|
pressed: false,
|
||||||
|
keycode: keycode,
|
||||||
|
symbols: Vec::new(),
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_free(key: *mut KeyState) {
|
||||||
|
unsafe { Box::from_raw(key) }; // gets dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_is_pressed(key: *const KeyState) -> u32{
|
||||||
|
let key = unsafe { &*key };
|
||||||
|
return key.pressed as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_set_pressed(key: *mut KeyState, pressed: u32) {
|
||||||
|
let key = unsafe { &mut *key };
|
||||||
|
key.pressed = pressed != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this will receive data from the filesystem,
|
||||||
|
// so it should handle garbled strings in the future
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_add_symbol(
|
||||||
|
key: *mut KeyState,
|
||||||
|
element: *const c_char,
|
||||||
|
text_raw: *const c_char, keyval: u32,
|
||||||
|
label: *const c_char, icon: *const c_char,
|
||||||
|
tooltip: *const c_char,
|
||||||
|
) {
|
||||||
|
let element = as_cstr(&element)
|
||||||
|
.expect("Missing element name");
|
||||||
|
|
||||||
|
let text = into_cstring(text_raw)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
eprintln!("Text unreadable: {}", e);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.and_then(|text| {
|
||||||
|
if text.as_bytes() == b"" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(text)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let icon = into_cstring(icon)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
eprintln!("Icon name unreadable: {}", e);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
use symbol::*;
|
||||||
|
// Only read label if there's no icon
|
||||||
|
let label = match icon {
|
||||||
|
Some(icon) => Label::IconName(icon),
|
||||||
|
None => Label::Text(
|
||||||
|
into_cstring(label)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
eprintln!("Label unreadable: {}", e);
|
||||||
|
Some(CString::new(" ").unwrap())
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
eprintln!("Label missing");
|
||||||
|
CString::new(" ").unwrap()
|
||||||
|
})
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let tooltip = into_cstring(tooltip)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
eprintln!("Tooltip unreadable: {}", e);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
let symbol = match element.to_bytes() {
|
||||||
|
b"symbol" => Symbol {
|
||||||
|
action: Action::Submit {
|
||||||
|
text: text,
|
||||||
|
keys: Vec::new(),
|
||||||
|
},
|
||||||
|
label: label,
|
||||||
|
tooltip: tooltip,
|
||||||
|
},
|
||||||
|
b"keysym" => {
|
||||||
|
let keysym = XKeySym(
|
||||||
|
if keyval == 0 {
|
||||||
|
unsafe { eek_keysym_from_name(text_raw) }
|
||||||
|
} else {
|
||||||
|
keyval
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Symbol {
|
||||||
|
action: match KeySym::from_u32(keysym.0) {
|
||||||
|
KeySym::Shift => Action::SetLevel(1),
|
||||||
|
_ => Action::Submit {
|
||||||
|
text: text,
|
||||||
|
keys: vec![keysym],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: label,
|
||||||
|
tooltip: tooltip,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!("unsupported element type {:?}", element),
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = unsafe { &mut *key };
|
||||||
|
key.symbols.push(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_get_symbol(
|
||||||
|
key: *const KeyState, index: u32
|
||||||
|
) -> *const symbol::Symbol {
|
||||||
|
let key = unsafe { &*key };
|
||||||
|
let index = index as usize;
|
||||||
|
&key.symbols[
|
||||||
|
if index < key.symbols.len() { index } else { 0 }
|
||||||
|
] as *const symbol::Symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_key_to_keymap_entry(
|
||||||
|
key_name: *const c_char,
|
||||||
|
key: *const KeyState,
|
||||||
|
) -> *const c_char {
|
||||||
|
let key_name = as_cstr(&key_name)
|
||||||
|
.expect("Missing key name")
|
||||||
|
.to_str()
|
||||||
|
.expect("Bad key name");
|
||||||
|
|
||||||
|
let key = unsafe { &*key };
|
||||||
|
let symbol_names = key.symbols.iter()
|
||||||
|
.map(|symbol| {
|
||||||
|
match &symbol.action {
|
||||||
|
symbol::Action::Submit { text: Some(text), .. } => {
|
||||||
|
Some(
|
||||||
|
text.clone()
|
||||||
|
.into_string().expect("Bad symbol")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let inner = match symbol_names.len() {
|
||||||
|
1 => match &symbol_names[0] {
|
||||||
|
Some(name) => format!("[ {} ]", name),
|
||||||
|
_ => format!("[ ]"),
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
let first = match (&symbol_names[0], &symbol_names[1]) {
|
||||||
|
(Some(left), Some(right)) => format!("{}, {}", left, right),
|
||||||
|
_ => format!(""),
|
||||||
|
};
|
||||||
|
let second = match (&symbol_names[2], &symbol_names[3]) {
|
||||||
|
(Some(left), Some(right)) => format!("{}, {}", left, right),
|
||||||
|
_ => format!(""),
|
||||||
|
};
|
||||||
|
format!("[ {} ], [ {} ]", first, second)
|
||||||
|
},
|
||||||
|
_ => panic!("Unsupported number of symbols"),
|
||||||
|
};
|
||||||
|
|
||||||
|
CString::new(format!(" key <{}> {{ {} }};\n", key_name, inner))
|
||||||
|
.expect("Couldn't convert string")
|
||||||
|
.into_raw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyState {
|
||||||
|
pressed: bool,
|
||||||
|
keycode: u32,
|
||||||
|
symbols: Vec<symbol::Symbol>,
|
||||||
|
}
|
||||||
@ -2,4 +2,6 @@
|
|||||||
mod bitflags;
|
mod bitflags;
|
||||||
|
|
||||||
mod imservice;
|
mod imservice;
|
||||||
|
mod keyboard;
|
||||||
mod symbol;
|
mod symbol;
|
||||||
|
mod util;
|
||||||
|
|||||||
@ -22,9 +22,5 @@ uint32_t squeek_symbol_get_modifier_mask(struct squeek_symbol* symbol);
|
|||||||
|
|
||||||
void squeek_symbol_print(struct squeek_symbol* symbol);
|
void squeek_symbol_print(struct squeek_symbol* symbol);
|
||||||
|
|
||||||
struct squeek_symbols* squeek_symbols_new();
|
|
||||||
void squeek_symbols_free(struct squeek_symbols*);
|
|
||||||
struct squeek_symbol *squeek_symbols_get(struct squeek_symbols*, uint32_t level);
|
|
||||||
|
|
||||||
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_symbols *symbols);
|
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_symbols *symbols);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
226
src/symbol.rs
226
src/symbol.rs
@ -1,4 +1,3 @@
|
|||||||
use std::boxed::Box;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
|
||||||
@ -9,59 +8,9 @@ pub mod c {
|
|||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str::Utf8Error;
|
|
||||||
|
|
||||||
|
|
||||||
fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
|
|
||||||
if s.is_null() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
unsafe {CStr::from_ptr(*s)}
|
|
||||||
.to_str()
|
|
||||||
.map(Some)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_cstr(s: &*const c_char) -> Option<&CStr> {
|
|
||||||
if s.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(unsafe {CStr::from_ptr(*s)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
|
|
||||||
if s.is_null() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
CString::new(
|
|
||||||
unsafe {CStr::from_ptr(s)}.to_bytes()
|
|
||||||
).map(Some)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_null_cstring() {
|
|
||||||
assert_eq!(into_cstring(ptr::null()), Ok(None))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_null_str() {
|
|
||||||
assert_eq!(as_str(&ptr::null()), Ok(None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following defined in C
|
// The following defined in C
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
extern "C" {
|
|
||||||
fn eek_keysym_from_name(name: *const c_char) -> u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legacy; Will never be used in Rust as a bit field
|
// Legacy; Will never be used in Rust as a bit field
|
||||||
enum ModifierMask {
|
enum ModifierMask {
|
||||||
Nothing = 0,
|
Nothing = 0,
|
||||||
@ -72,98 +21,6 @@ pub mod c {
|
|||||||
|
|
||||||
// TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
// TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
|
||||||
// Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
|
// Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
|
||||||
|
|
||||||
// TODO: this will receive data from the filesystem,
|
|
||||||
// so it should handle garbled strings in the future
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_symbols_add(
|
|
||||||
v: *mut Vec<Symbol>,
|
|
||||||
element: *const c_char,
|
|
||||||
text_raw: *const c_char, keyval: u32,
|
|
||||||
label: *const c_char, icon: *const c_char,
|
|
||||||
tooltip: *const c_char,
|
|
||||||
) {
|
|
||||||
let element = as_cstr(&element)
|
|
||||||
.expect("Missing element name");
|
|
||||||
|
|
||||||
let text = into_cstring(text_raw)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
eprintln!("Text unreadable: {}", e);
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.and_then(|text| {
|
|
||||||
if text.as_bytes() == b"" {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(text)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let icon = into_cstring(icon)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
eprintln!("Icon name unreadable: {}", e);
|
|
||||||
None
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only read label if there's no icon
|
|
||||||
let label = match icon {
|
|
||||||
Some(icon) => Label::IconName(icon),
|
|
||||||
None => Label::Text(
|
|
||||||
into_cstring(label)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
eprintln!("Label unreadable: {}", e);
|
|
||||||
Some(CString::new(" ").unwrap())
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
eprintln!("Label missing");
|
|
||||||
CString::new(" ").unwrap()
|
|
||||||
})
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let tooltip = into_cstring(tooltip)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
eprintln!("Tooltip unreadable: {}", e);
|
|
||||||
None
|
|
||||||
});
|
|
||||||
|
|
||||||
let symbol = match element.to_bytes() {
|
|
||||||
b"symbol" => Symbol {
|
|
||||||
action: Action::Submit {
|
|
||||||
text: text,
|
|
||||||
keys: Vec::new(),
|
|
||||||
},
|
|
||||||
label: label,
|
|
||||||
tooltip: tooltip,
|
|
||||||
},
|
|
||||||
b"keysym" => {
|
|
||||||
let keysym = XKeySym(
|
|
||||||
if keyval == 0 {
|
|
||||||
unsafe { eek_keysym_from_name(text_raw) }
|
|
||||||
} else {
|
|
||||||
keyval
|
|
||||||
}
|
|
||||||
);
|
|
||||||
Symbol {
|
|
||||||
action: match KeySym::from_u32(keysym.0) {
|
|
||||||
KeySym::Shift => Action::SetLevel(1),
|
|
||||||
_ => Action::Submit {
|
|
||||||
text: text,
|
|
||||||
keys: vec![keysym],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label: label,
|
|
||||||
tooltip: tooltip,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("unsupported element type {:?}", element),
|
|
||||||
};
|
|
||||||
|
|
||||||
let v = unsafe { &mut *v };
|
|
||||||
v.push(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
|
fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
|
||||||
@ -214,88 +71,17 @@ pub mod c {
|
|||||||
let symbol = unsafe { &*symbol };
|
let symbol = unsafe { &*symbol };
|
||||||
println!("{:?}", symbol);
|
println!("{:?}", symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_symbols_new() -> *const Vec<Symbol> {
|
|
||||||
Box::into_raw(Box::new(Vec::new()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_symbols_get(v: *mut Vec<Symbol>, index: u32) -> *const Symbol {
|
|
||||||
let v = unsafe { &mut *v };
|
|
||||||
let index = index as usize;
|
|
||||||
&v[
|
|
||||||
if index < v.len() { index } else { 0 }
|
|
||||||
] as *const Symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_symbols_free(symbols: *mut Vec<Symbol>) {
|
|
||||||
unsafe { Box::from_raw(symbols) }; // Will just get dropped, together with the contents
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_key_to_keymap_entry(
|
|
||||||
key_name: *const c_char,
|
|
||||||
symbols: *const Vec<Symbol>,
|
|
||||||
) -> *const c_char {
|
|
||||||
let key_name = as_cstr(&key_name)
|
|
||||||
.expect("Missing key name")
|
|
||||||
.to_str()
|
|
||||||
.expect("Bad key name");
|
|
||||||
let symbols = unsafe { &*symbols };
|
|
||||||
let symbol_names = symbols.iter()
|
|
||||||
.map(|symbol| {
|
|
||||||
match &symbol.action {
|
|
||||||
Action::Submit { text: Some(text), .. } => {
|
|
||||||
Some(
|
|
||||||
text.clone()
|
|
||||||
.into_string().expect("Bad symbol")
|
|
||||||
)
|
|
||||||
},
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let inner = match symbol_names.len() {
|
|
||||||
1 => match &symbol_names[0] {
|
|
||||||
Some(name) => format!("[ {} ]", name),
|
|
||||||
_ => format!("[ ]"),
|
|
||||||
},
|
|
||||||
4 => {
|
|
||||||
let first = match (&symbol_names[0], &symbol_names[1]) {
|
|
||||||
(Some(left), Some(right)) => format!("{}, {}", left, right),
|
|
||||||
_ => format!(""),
|
|
||||||
};
|
|
||||||
let second = match (&symbol_names[2], &symbol_names[3]) {
|
|
||||||
(Some(left), Some(right)) => format!("{}, {}", left, right),
|
|
||||||
_ => format!(""),
|
|
||||||
};
|
|
||||||
format!("[ {} ], [ {} ]", first, second)
|
|
||||||
},
|
|
||||||
_ => panic!("Unsupported number of symbols"),
|
|
||||||
};
|
|
||||||
|
|
||||||
CString::new(format!(" key <{}> {{ {} }};\n", key_name, inner))
|
|
||||||
.expect("Couldn't convert string")
|
|
||||||
.into_raw()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just defines some int->identifier mappings for convenience
|
/// Just defines some int->identifier mappings for convenience
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum KeySym {
|
pub enum KeySym {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Shift = 0xffe1,
|
Shift = 0xffe1,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeySym {
|
impl KeySym {
|
||||||
fn from_u32(num: u32) -> KeySym {
|
pub fn from_u32(num: u32) -> KeySym {
|
||||||
match num {
|
match num {
|
||||||
0xffe1 => KeySym::Shift,
|
0xffe1 => KeySym::Shift,
|
||||||
_ => KeySym::Unknown,
|
_ => KeySym::Unknown,
|
||||||
@ -304,7 +90,7 @@ impl KeySym {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct XKeySym(u32);
|
pub struct XKeySym(pub u32);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Label {
|
pub enum Label {
|
||||||
@ -344,9 +130,9 @@ pub enum Action {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
/// The action that this key performs
|
/// The action that this key performs
|
||||||
action: Action,
|
pub action: Action,
|
||||||
/// Label to display to the user
|
/// Label to display to the user
|
||||||
label: Label,
|
pub label: Label,
|
||||||
// FIXME: is it used?
|
// FIXME: is it used?
|
||||||
tooltip: Option<CString>,
|
pub tooltip: Option<CString>,
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/util.rs
Normal file
49
src/util.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
pub mod c {
|
||||||
|
use std::ffi::{ CStr, CString };
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
|
pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
|
||||||
|
if s.is_null() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
unsafe {CStr::from_ptr(*s)}
|
||||||
|
.to_str()
|
||||||
|
.map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_cstr(s: &*const c_char) -> Option<&CStr> {
|
||||||
|
if s.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(unsafe {CStr::from_ptr(*s)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
|
||||||
|
if s.is_null() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
CString::new(
|
||||||
|
unsafe {CStr::from_ptr(s)}.to_bytes()
|
||||||
|
).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_null_cstring() {
|
||||||
|
assert_eq!(into_cstring(ptr::null()), Ok(None))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_null_str() {
|
||||||
|
assert_eq!(as_str(&ptr::null()), Ok(None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user