From 6523275b6af125b782ae2f571adff4f226c4b772 Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Mon, 9 Sep 2019 13:25:03 +0000 Subject: [PATCH] views: Change based on layout file --- data/keyboards/us.yaml | 4 +- eek/eek-keyboard.c | 83 +++++++++++++++---------------------- eekboard/key-emitter.c | 7 +--- src/data.rs | 68 ++++++++++++++++++++++++++----- src/layout.h | 4 +- src/layout.rs | 92 +++++++++++++++++++++++++++++------------- src/symbol.rs | 10 ++++- 7 files changed, 171 insertions(+), 97 deletions(-) diff --git a/data/keyboards/us.yaml b/data/keyboards/us.yaml index 934a5a66..9dd059f1 100644 --- a/data/keyboards/us.yaml +++ b/data/keyboards/us.yaml @@ -40,7 +40,9 @@ views: buttons: Shift_L: action: - set_view: "upper" + locking: + lock_view: "upper" + unlock_view: "base" outline: "altline" icon: "key-shift" BackSpace: diff --git a/eek/eek-keyboard.c b/eek/eek-keyboard.c index 2889118a..137049dd 100644 --- a/eek/eek-keyboard.c +++ b/eek/eek-keyboard.c @@ -49,64 +49,47 @@ eek_modifier_key_free (EekModifierKey *modkey) g_slice_free (EekModifierKey, modkey); } -/// Updates the state of locked keys based on the key that was activated -/// FIXME: make independent of what the key are named, -/// and instead refer to the contained symbols -static guint -set_key_states (LevelKeyboard *keyboard, - struct squeek_button *button, - guint new_level) +void +eek_keyboard_set_button_locked (LevelKeyboard *keyboard, + struct squeek_button *button) { - // 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); - modifier_key->modifiers = 0; - modifier_key->button = button; - keyboard->locked_buttons = + EekModifierKey *modifier_key = g_slice_new (EekModifierKey); + modifier_key->modifiers = 0; + modifier_key->button = button; + keyboard->locked_buttons = 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 - for (GList *head = keyboard->locked_buttons; head; ) { - EekModifierKey *modifier_key = head->data; - GList *next = g_list_next (head); - keyboard->locked_buttons = - g_list_remove_link (keyboard->locked_buttons, head); - squeek_key_set_locked(squeek_button_get_key(modifier_key->button), false); - g_list_free1 (head); - head = next; - } - return 0; - } - return new_level; } -// FIXME: unhardcode, parse some user information as to which key triggers which view (level) +/// 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; ) { + EekModifierKey *modifier_key = head->data; + GList *next = g_list_next (head); + keyboard->locked_buttons = + g_list_remove_link (keyboard->locked_buttons, head); + //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); + head = next; + handled++; + } + return handled; +} + static void set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button) { - /* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */ - guint level = squeek_layout_get_level(keyboard->layout); - /* Handle non-emitting keys */ - if (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; - } + // If the currently locked key was already handled in the unlock phase, + // then skip + if (unlock_keys(keyboard) == 0) { + squeek_layout_set_state_from_press(keyboard->layout, keyboard, button); } - - 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) { diff --git a/eekboard/key-emitter.c b/eekboard/key-emitter.c index 4fa64152..dcd5131d 100644 --- a/eekboard/key-emitter.c +++ b/eekboard/key-emitter.c @@ -90,12 +90,9 @@ send_fake_key (SeatEmitter *emitter, gboolean pressed, uint32_t timestamp) { - guint level = squeek_layout_get_level(keyboard->layout); - uint32_t group = (level / 2); - - zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, group); + zwp_virtual_keyboard_v1_modifiers(emitter->virtual_keyboard, 0, 0, 0, 0); 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 diff --git a/src/data.rs b/src/data.rs index c238f9a6..492f91fa 100644 --- a/src/data.rs +++ b/src/data.rs @@ -205,7 +205,8 @@ struct ButtonMeta { #[derive(Debug, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] enum Action { - /// FIXME: start using it + #[serde(rename="locking")] + Locking { lock_view: String, unlock_view: String }, #[serde(rename="set_view")] SetView(String), #[serde(rename="show_prefs")] @@ -274,14 +275,11 @@ impl Layout { pressed: false, locked: false, keycode: keycodes.get(*name).map(|k| *k), - symbol: ::symbol::Symbol { - // FIXME: allow user to switch views - action: ::symbol::Action::Submit { - text: None, - // TODO: derive keysym name & value from button name - keys: vec!(), - }, - }, + symbol: create_symbol( + &self.buttons, + name, + self.views.keys().collect() + ), })) )}); @@ -334,6 +332,58 @@ impl Layout { } } +fn create_symbol( + button_info: &HashMap, + 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, /// all .expect() on them should be turned into soft fails fn create_button( diff --git a/src/layout.h b/src/layout.h index f3ba2eaf..51a1ef71 100644 --- a/src/layout.h +++ b/src/layout.h @@ -55,8 +55,8 @@ struct squeek_button *squeek_view_find_button_by_position(struct squeek_view *vi void squeek_layout_place_contents(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_level(struct squeek_layout* layout, uint32_t level); +void squeek_layout_set_state_from_press(struct squeek_layout* layout, LevelKeyboard *keyboard, struct squeek_button* button); + struct squeek_layout *squeek_load_layout(const char *type); const char *squeek_layout_get_keymap(const struct squeek_layout*); diff --git a/src/layout.rs b/src/layout.rs index f6a27034..564deed0 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -224,33 +224,6 @@ pub mod c { .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] pub extern "C" fn squeek_layout_get_keymap(layout: *const Layout) -> *const c_char { @@ -275,6 +248,9 @@ pub mod c { row: *const Row, button: *const Button, } + + #[repr(transparent)] + pub struct LevelKeyboard(*const c_void); #[no_mangle] extern "C" { @@ -285,6 +261,53 @@ pub mod c { origin: Point, angle: i32 ) -> 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, @@ -464,7 +487,7 @@ pub mod c { locked: false, keycode: None, symbol: Symbol { - action: Action::SetLevel(0), + action: Action::SetLevel("default".into()), } })) } @@ -710,6 +733,19 @@ pub struct Layout { 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 { use super::*; diff --git a/src/symbol.rs b/src/symbol.rs index b2ce3f1e..e2388f29 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -22,7 +22,7 @@ impl KeySym { pub struct XKeySym(pub u32); /// Use to switch layouts -type Level = u8; +type Level = String; /// Use to send modified keypresses #[derive(Debug, Clone)] @@ -34,8 +34,14 @@ pub enum Modifier { /// Action to perform on the keypress and, in reverse, on keyrelease #[derive(Debug, Clone)] pub enum Action { - /// Switch to this level TODO: reverse? + /// Switch to this view 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? SetModifier(Modifier), /// Submit some text