views: Change based on layout file
This commit is contained in:
@ -40,7 +40,9 @@ views:
|
|||||||
buttons:
|
buttons:
|
||||||
Shift_L:
|
Shift_L:
|
||||||
action:
|
action:
|
||||||
set_view: "upper"
|
locking:
|
||||||
|
lock_view: "upper"
|
||||||
|
unlock_view: "base"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "key-shift"
|
icon: "key-shift"
|
||||||
BackSpace:
|
BackSpace:
|
||||||
|
|||||||
@ -49,66 +49,49 @@ eek_modifier_key_free (EekModifierKey *modkey)
|
|||||||
g_slice_free (EekModifierKey, modkey);
|
g_slice_free (EekModifierKey, modkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the state of locked keys based on the key that was activated
|
void
|
||||||
/// FIXME: make independent of what the key are named,
|
eek_keyboard_set_button_locked (LevelKeyboard *keyboard,
|
||||||
/// and instead refer to the contained symbols
|
struct squeek_button *button)
|
||||||
static guint
|
|
||||||
set_key_states (LevelKeyboard *keyboard,
|
|
||||||
struct squeek_button *button,
|
|
||||||
guint new_level)
|
|
||||||
{
|
{
|
||||||
// Keys locking rules hardcoded for the time being...
|
|
||||||
const gchar *name = squeek_button_get_name(button);
|
|
||||||
// Lock the shift whenever it's pressed on the baselevel
|
|
||||||
// TODO: need to lock shift on the destination level
|
|
||||||
if (g_strcmp0(name, "Shift_L") == 0 && squeek_layout_get_level(keyboard->layout) == 0) {
|
|
||||||
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
|
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
|
||||||
modifier_key->modifiers = 0;
|
modifier_key->modifiers = 0;
|
||||||
modifier_key->button = button;
|
modifier_key->button = button;
|
||||||
keyboard->locked_buttons =
|
keyboard->locked_buttons =
|
||||||
g_list_prepend (keyboard->locked_buttons, modifier_key);
|
g_list_prepend (keyboard->locked_buttons, modifier_key);
|
||||||
struct squeek_key *key = squeek_button_get_key(button);
|
|
||||||
squeek_key_set_locked(key, true);
|
|
||||||
}
|
}
|
||||||
if (squeek_layout_get_level(keyboard->layout) == 1) {
|
|
||||||
// Only shift is locked in this state, unlock on any key press
|
/// Unlock all locked keys.
|
||||||
|
/// All locked keys will unlock at the next keypress (should be called "stuck")
|
||||||
|
/// Returns the number of handled keys
|
||||||
|
/// TODO: may need to check key type in order to chain locks
|
||||||
|
/// before pressing an "emitting" key
|
||||||
|
static int unlock_keys(LevelKeyboard *keyboard) {
|
||||||
|
int handled = 0;
|
||||||
for (GList *head = keyboard->locked_buttons; head; ) {
|
for (GList *head = keyboard->locked_buttons; head; ) {
|
||||||
EekModifierKey *modifier_key = head->data;
|
EekModifierKey *modifier_key = head->data;
|
||||||
GList *next = g_list_next (head);
|
GList *next = g_list_next (head);
|
||||||
keyboard->locked_buttons =
|
keyboard->locked_buttons =
|
||||||
g_list_remove_link (keyboard->locked_buttons, head);
|
g_list_remove_link (keyboard->locked_buttons, head);
|
||||||
squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false);
|
//squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false);
|
||||||
|
|
||||||
|
squeek_layout_set_state_from_press(keyboard->layout, keyboard, modifier_key->button);
|
||||||
g_list_free1 (head);
|
g_list_free1 (head);
|
||||||
head = next;
|
head = next;
|
||||||
|
handled++;
|
||||||
}
|
}
|
||||||
return 0;
|
return handled;
|
||||||
}
|
|
||||||
return new_level;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: unhardcode, parse some user information as to which key triggers which view (level)
|
|
||||||
static void
|
static void
|
||||||
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
|
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
|
||||||
{
|
{
|
||||||
/* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
|
// If the currently locked key was already handled in the unlock phase,
|
||||||
guint level = squeek_layout_get_level(keyboard->layout);
|
// then skip
|
||||||
/* Handle non-emitting keys */
|
if (unlock_keys(keyboard) == 0) {
|
||||||
if (button) {
|
squeek_layout_set_state_from_press(keyboard->layout, keyboard, button);
|
||||||
const gchar *name = squeek_button_get_name(button);
|
|
||||||
if (g_strcmp0(name, "show_numbers") == 0) {
|
|
||||||
level = 2;
|
|
||||||
} else if (g_strcmp0(name, "show_letters") == 0) {
|
|
||||||
level = 0;
|
|
||||||
} else if (g_strcmp0(name, "show_symbols") == 0) {
|
|
||||||
level = 3;
|
|
||||||
} else if (g_strcmp0(name, "Shift_L") == 0) {
|
|
||||||
level ^= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
squeek_layout_set_level(keyboard->layout, set_key_states(keyboard, button, level));
|
|
||||||
}
|
|
||||||
|
|
||||||
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
|
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
|
||||||
struct squeek_key *key = squeek_button_get_key(button);
|
struct squeek_key *key = squeek_button_get_key(button);
|
||||||
squeek_key_set_pressed(key, TRUE);
|
squeek_key_set_pressed(key, TRUE);
|
||||||
|
|||||||
@ -90,12 +90,9 @@ send_fake_key (SeatEmitter *emitter,
|
|||||||
gboolean pressed,
|
gboolean pressed,
|
||||||
uint32_t timestamp)
|
uint32_t timestamp)
|
||||||
{
|
{
|
||||||
guint level = squeek_layout_get_level(keyboard->layout);
|
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
|
||||||
uint32_t group = (level / 2);
|
|
||||||
|
|
||||||
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
|
|
||||||
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
|
send_virtual_keyboard_key (emitter->virtual_keyboard, keycode - 8, (unsigned)pressed, timestamp);
|
||||||
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group);
|
zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
68
src/data.rs
68
src/data.rs
@ -205,7 +205,8 @@ struct ButtonMeta {
|
|||||||
#[derive(Debug, Deserialize, PartialEq)]
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
enum Action {
|
enum Action {
|
||||||
/// FIXME: start using it
|
#[serde(rename="locking")]
|
||||||
|
Locking { lock_view: String, unlock_view: String },
|
||||||
#[serde(rename="set_view")]
|
#[serde(rename="set_view")]
|
||||||
SetView(String),
|
SetView(String),
|
||||||
#[serde(rename="show_prefs")]
|
#[serde(rename="show_prefs")]
|
||||||
@ -274,14 +275,11 @@ impl Layout {
|
|||||||
pressed: false,
|
pressed: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
keycode: keycodes.get(*name).map(|k| *k),
|
keycode: keycodes.get(*name).map(|k| *k),
|
||||||
symbol: ::symbol::Symbol {
|
symbol: create_symbol(
|
||||||
// FIXME: allow user to switch views
|
&self.buttons,
|
||||||
action: ::symbol::Action::Submit {
|
name,
|
||||||
text: None,
|
self.views.keys().collect()
|
||||||
// TODO: derive keysym name & value from button name
|
),
|
||||||
keys: vec!(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
}))
|
||||||
)});
|
)});
|
||||||
|
|
||||||
@ -334,6 +332,58 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_symbol(
|
||||||
|
button_info: &HashMap<String, ButtonMeta>,
|
||||||
|
name: &str,
|
||||||
|
view_names: Vec<&String>,
|
||||||
|
) -> ::symbol::Symbol {
|
||||||
|
let default_meta = ButtonMeta::default();
|
||||||
|
let symbol_meta = button_info.get(name)
|
||||||
|
.unwrap_or(&default_meta);
|
||||||
|
|
||||||
|
fn filter_view_name(
|
||||||
|
button_name: &str,
|
||||||
|
view_name: String,
|
||||||
|
view_names: &Vec<&String>
|
||||||
|
) -> String {
|
||||||
|
if view_names.contains(&&view_name) {
|
||||||
|
view_name
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Button {} switches to missing view {}",
|
||||||
|
button_name,
|
||||||
|
view_name
|
||||||
|
);
|
||||||
|
"base".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &symbol_meta.action {
|
||||||
|
Some(Action::SetView(view_name)) => ::symbol::Symbol {
|
||||||
|
action: ::symbol::Action::SetLevel(
|
||||||
|
filter_view_name(name, view_name.clone(), &view_names)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Some(Action::Locking { lock_view, unlock_view }) => ::symbol::Symbol {
|
||||||
|
action: ::symbol::Action::LockLevel {
|
||||||
|
lock: filter_view_name(name, lock_view.clone(), &view_names),
|
||||||
|
unlock: filter_view_name(
|
||||||
|
name,
|
||||||
|
unlock_view.clone(),
|
||||||
|
&view_names
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => ::symbol::Symbol {
|
||||||
|
action: ::symbol::Action::Submit {
|
||||||
|
text: None,
|
||||||
|
// TODO: derive keysym name & value from button name
|
||||||
|
keys: vec!(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// TODO: Since this will receive user-provided data,
|
/// TODO: Since this will receive user-provided data,
|
||||||
/// all .expect() on them should be turned into soft fails
|
/// all .expect() on them should be turned into soft fails
|
||||||
fn create_button(
|
fn create_button(
|
||||||
|
|||||||
@ -55,8 +55,8 @@ struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *vi
|
|||||||
void
|
void
|
||||||
squeek_layout_place_contents(struct squeek_layout*);
|
squeek_layout_place_contents(struct squeek_layout*);
|
||||||
struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*);
|
struct squeek_view *squeek_layout_get_current_view(struct squeek_layout*);
|
||||||
uint32_t squeek_layout_get_level(struct squeek_layout*);
|
void squeek_layout_set_state_from_press(struct squeek_layout* layout, LevelKeyboard *keyboard, struct squeek_button* button);
|
||||||
void squeek_layout_set_level(struct squeek_layout* layout, uint32_t level);
|
|
||||||
|
|
||||||
struct squeek_layout *squeek_load_layout(const char *type);
|
struct squeek_layout *squeek_load_layout(const char *type);
|
||||||
const char *squeek_layout_get_keymap(const struct squeek_layout*);
|
const char *squeek_layout_get_keymap(const struct squeek_layout*);
|
||||||
|
|||||||
@ -224,33 +224,6 @@ pub mod c {
|
|||||||
.as_ref() as *const View
|
.as_ref() as *const View
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: very temporary way to minimize level impact
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_layout_get_level(layout: *const Layout) -> u32 {
|
|
||||||
let layout = unsafe { &*layout };
|
|
||||||
match layout.current_view.as_str() {
|
|
||||||
"base" => 0,
|
|
||||||
"upper" => 1,
|
|
||||||
"numbers" => 2,
|
|
||||||
"symbols" => 3,
|
|
||||||
_ => 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C"
|
|
||||||
fn squeek_layout_set_level(layout: *mut Layout, level: u32) {
|
|
||||||
let mut layout = unsafe { &mut*layout };
|
|
||||||
layout.current_view = String::from(match level {
|
|
||||||
0 => "base",
|
|
||||||
1 => "upper",
|
|
||||||
2 => "numbers",
|
|
||||||
3 => "symbols",
|
|
||||||
_ => "base",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char {
|
fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char {
|
||||||
@ -276,6 +249,9 @@ pub mod c {
|
|||||||
button: *const Button,
|
button: *const Button,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct LevelKeyboard(*const c_void);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/// Checks if point falls within bounds,
|
/// Checks if point falls within bounds,
|
||||||
@ -285,6 +261,53 @@ pub mod c {
|
|||||||
origin: Point,
|
origin: Point,
|
||||||
angle: i32
|
angle: i32
|
||||||
) -> u32;
|
) -> u32;
|
||||||
|
|
||||||
|
pub fn eek_keyboard_set_button_locked(
|
||||||
|
keyboard: *mut LevelKeyboard,
|
||||||
|
button: *const Button
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_layout_set_state_from_press(
|
||||||
|
layout: *mut Layout,
|
||||||
|
keyboard: *mut LevelKeyboard,
|
||||||
|
button_ptr: *const Button,
|
||||||
|
) {
|
||||||
|
let layout = unsafe { &mut *layout };
|
||||||
|
let button = unsafe { &*button_ptr };
|
||||||
|
// don't want to leave this borrowed in the function body
|
||||||
|
let state = {
|
||||||
|
let state = button.state.borrow();
|
||||||
|
state.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let view_name = match state.symbol.action {
|
||||||
|
::symbol::Action::SetLevel(name) => {
|
||||||
|
Some(name.clone())
|
||||||
|
},
|
||||||
|
::symbol::Action::LockLevel { lock, unlock } => {
|
||||||
|
let mut current_state = button.state.borrow_mut();
|
||||||
|
current_state.locked ^= true;
|
||||||
|
if current_state.locked {
|
||||||
|
unsafe {
|
||||||
|
eek_keyboard_set_button_locked(
|
||||||
|
keyboard,
|
||||||
|
button_ptr
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(if state.locked { unlock } else { lock }.clone())
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(view_name) = view_name {
|
||||||
|
if let Err(_e) = layout.set_view(view_name.clone()) {
|
||||||
|
eprintln!("No such view: {}, ignoring switch", view_name)
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Places each button in order, starting from 0 on the left,
|
/// Places each button in order, starting from 0 on the left,
|
||||||
@ -464,7 +487,7 @@ pub mod c {
|
|||||||
locked: false,
|
locked: false,
|
||||||
keycode: None,
|
keycode: None,
|
||||||
symbol: Symbol {
|
symbol: Symbol {
|
||||||
action: Action::SetLevel(0),
|
action: Action::SetLevel("default".into()),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -710,6 +733,19 @@ pub struct Layout {
|
|||||||
pub keymap_str: CString,
|
pub keymap_str: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NoSuchView;
|
||||||
|
|
||||||
|
impl Layout {
|
||||||
|
fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
|
||||||
|
if self.views.contains_key(&view) {
|
||||||
|
self.current_view = view;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(NoSuchView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod procedures {
|
mod procedures {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ impl KeySym {
|
|||||||
pub struct XKeySym(pub u32);
|
pub struct XKeySym(pub u32);
|
||||||
|
|
||||||
/// Use to switch layouts
|
/// Use to switch layouts
|
||||||
type Level = u8;
|
type Level = String;
|
||||||
|
|
||||||
/// Use to send modified keypresses
|
/// Use to send modified keypresses
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -34,8 +34,14 @@ pub enum Modifier {
|
|||||||
/// Action to perform on the keypress and, in reverse, on keyrelease
|
/// Action to perform on the keypress and, in reverse, on keyrelease
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Switch to this level TODO: reverse?
|
/// Switch to this view
|
||||||
SetLevel(Level),
|
SetLevel(Level),
|
||||||
|
/// Switch to a view and latch
|
||||||
|
LockLevel {
|
||||||
|
lock: Level,
|
||||||
|
/// When unlocked by pressing it or emitting a key
|
||||||
|
unlock: Level,
|
||||||
|
},
|
||||||
/// Set this modifier TODO: release?
|
/// Set this modifier TODO: release?
|
||||||
SetModifier(Modifier),
|
SetModifier(Modifier),
|
||||||
/// Submit some text
|
/// Submit some text
|
||||||
|
|||||||
Reference in New Issue
Block a user