From 585ed5e97dc8a259fc6ad7d496874284736d01ec Mon Sep 17 00:00:00 2001 From: Dorota Czaplejewicz Date: Thu, 23 Jan 2020 15:39:40 +0000 Subject: [PATCH] input_method: Use for erasing --- data/keyboards/de.yaml | 2 +- data/keyboards/de_wide.yaml | 2 +- data/keyboards/el.yaml | 2 +- data/keyboards/es.yaml | 2 +- data/keyboards/fi.yaml | 2 +- data/keyboards/it.yaml | 2 +- data/keyboards/jp+kana.yaml | 2 +- data/keyboards/jp+kana_wide.yaml | 2 +- data/keyboards/no.yaml | 2 +- data/keyboards/number.yaml | 2 +- data/keyboards/se.yaml | 2 +- data/keyboards/terminal.yaml | 2 +- data/keyboards/us.yaml | 4 ++-- data/keyboards/us_wide.yaml | 2 +- src/action.rs | 2 ++ src/data.rs | 11 ++++++++- src/imservice.c | 5 ++++ src/imservice.rs | 19 +++++++++++++++ src/keyboard.rs | 41 ++++++++++++++++++++++++-------- src/layout.rs | 4 +++- src/submission.rs | 22 ++++++++++++----- 21 files changed, 101 insertions(+), 33 deletions(-) diff --git a/data/keyboards/de.yaml b/data/keyboards/de.yaml index 66566289..06687ebf 100644 --- a/data/keyboards/de.yaml +++ b/data/keyboards/de.yaml @@ -45,7 +45,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "special" diff --git a/data/keyboards/de_wide.yaml b/data/keyboards/de_wide.yaml index 1f638557..dc5dec0f 100644 --- a/data/keyboards/de_wide.yaml +++ b/data/keyboards/de_wide.yaml @@ -45,7 +45,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "special" diff --git a/data/keyboards/el.yaml b/data/keyboards/el.yaml index f24b207a..6279f75b 100644 --- a/data/keyboards/el.yaml +++ b/data/keyboards/el.yaml @@ -46,7 +46,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "altline" diff --git a/data/keyboards/es.yaml b/data/keyboards/es.yaml index bc7ba73f..7343e7b3 100644 --- a/data/keyboards/es.yaml +++ b/data/keyboards/es.yaml @@ -44,7 +44,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "default" diff --git a/data/keyboards/fi.yaml b/data/keyboards/fi.yaml index ec972f47..25493d70 100644 --- a/data/keyboards/fi.yaml +++ b/data/keyboards/fi.yaml @@ -39,7 +39,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "altline" diff --git a/data/keyboards/it.yaml b/data/keyboards/it.yaml index 7a05ed46..08930472 100644 --- a/data/keyboards/it.yaml +++ b/data/keyboards/it.yaml @@ -46,7 +46,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "default" diff --git a/data/keyboards/jp+kana.yaml b/data/keyboards/jp+kana.yaml index 076a7db1..b129d3d7 100644 --- a/data/keyboards/jp+kana.yaml +++ b/data/keyboards/jp+kana.yaml @@ -195,7 +195,7 @@ buttons: BackSpace: outline: "wide" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase Return: outline: "wide" icon: "key-enter" diff --git a/data/keyboards/jp+kana_wide.yaml b/data/keyboards/jp+kana_wide.yaml index 684cedfc..8f0c536e 100644 --- a/data/keyboards/jp+kana_wide.yaml +++ b/data/keyboards/jp+kana_wide.yaml @@ -195,7 +195,7 @@ buttons: BackSpace: outline: "wide" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase Return: outline: "wide" icon: "key-enter" diff --git a/data/keyboards/no.yaml b/data/keyboards/no.yaml index 27ff21ff..44de74cc 100644 --- a/data/keyboards/no.yaml +++ b/data/keyboards/no.yaml @@ -39,7 +39,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase preferences: action: "show_prefs" outline: "altline" diff --git a/data/keyboards/number.yaml b/data/keyboards/number.yaml index 3f672cd4..126d17ac 100644 --- a/data/keyboards/number.yaml +++ b/data/keyboards/number.yaml @@ -16,7 +16,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase space: outline: spaceline text: " " diff --git a/data/keyboards/se.yaml b/data/keyboards/se.yaml index 0a0a127f..b51f49ad 100644 --- a/data/keyboards/se.yaml +++ b/data/keyboards/se.yaml @@ -39,7 +39,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase preferences: action: "show_prefs" outline: "altline" diff --git a/data/keyboards/terminal.yaml b/data/keyboards/terminal.yaml index 9e8968d0..2b4d4f0e 100644 --- a/data/keyboards/terminal.yaml +++ b/data/keyboards/terminal.yaml @@ -45,7 +45,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase preferences: action: "show_prefs" outline: "special" diff --git a/data/keyboards/us.yaml b/data/keyboards/us.yaml index d150c480..7a7f4dd6 100644 --- a/data/keyboards/us.yaml +++ b/data/keyboards/us.yaml @@ -39,9 +39,9 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: erase preferences: - action: "show_prefs" + action: show_prefs outline: "special" icon: "keyboard-mode-symbolic" show_numbers: diff --git a/data/keyboards/us_wide.yaml b/data/keyboards/us_wide.yaml index 654db8f8..cf349c00 100644 --- a/data/keyboards/us_wide.yaml +++ b/data/keyboards/us_wide.yaml @@ -39,7 +39,7 @@ buttons: BackSpace: outline: "altline" icon: "edit-clear-symbolic" - keysym: "BackSpace" + action: "erase" preferences: action: "show_prefs" outline: "special" diff --git a/src/action.rs b/src/action.rs index 5045007a..98bdcd83 100644 --- a/src/action.rs +++ b/src/action.rs @@ -37,5 +37,7 @@ pub enum Action { /// The key events this symbol submits when submitting text is not possible keys: Vec, }, + /// Erase a position behind the cursor + Erase, ShowPreferences, } diff --git a/src/data.rs b/src/data.rs index 0fa30751..4798a453 100644 --- a/src/data.rs +++ b/src/data.rs @@ -15,6 +15,7 @@ use std::vec::Vec; use xkbcommon::xkb; +use ::action; use ::keyboard::{ KeyState, PressType, generate_keymap, generate_keycodes, FormattingError @@ -259,6 +260,9 @@ enum Action { SetView(String), #[serde(rename="show_prefs")] ShowPrefs, + /// Remove last character + #[serde(rename="erase")] + Erase, } #[derive(Debug, Clone, Deserialize, PartialEq)] @@ -381,6 +385,10 @@ impl Layout { ) }).collect() }, + action::Action::Erase => vec![ + *keymap.get("BackSpace") + .expect(&format!("BackSpace missing from keymap")), + ], _ => Vec::new(), }; ( @@ -547,6 +555,7 @@ fn create_action( SubmitData::Action( Action::ShowPrefs ) => ::action::Action::ShowPreferences, + SubmitData::Action(Action::Erase) => action::Action::Erase, SubmitData::Keysym(keysym) => ::action::Action::Submit { text: None, keys: vec!(::action::KeySym( @@ -581,7 +590,7 @@ fn create_action( false => format!("U{:04X}", codepoint as u32), }) }).collect(), - } + }, } } diff --git a/src/imservice.c b/src/imservice.c index 9a92be67..b6b04784 100644 --- a/src/imservice.c +++ b/src/imservice.c @@ -55,6 +55,11 @@ eek_input_method_commit_string(struct zwp_input_method_v2 *zwp_input_method_v2, zwp_input_method_v2_commit_string(zwp_input_method_v2, text); } +void +eek_input_method_delete_surrounding_text(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t before_length, uint32_t after_length) { + zwp_input_method_v2_delete_surrounding_text(zwp_input_method_v2, before_length, after_length); +}; + void eek_input_method_commit(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t serial) { diff --git a/src/imservice.rs b/src/imservice.rs index 2adf9717..e040157f 100644 --- a/src/imservice.rs +++ b/src/imservice.rs @@ -35,6 +35,7 @@ pub mod c { #[allow(improper_ctypes)] // IMService will never be dereferenced in C pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService); pub fn eek_input_method_commit_string(im: *mut InputMethod, text: *const c_char); + pub fn eek_input_method_delete_surrounding_text(im: *mut InputMethod, before: u32, after: u32); pub fn eek_input_method_commit(im: *mut InputMethod, serial: u32); fn eekboard_context_service_set_hint_purpose(state: *const StateManager, hint: u32, purpose: u32); fn server_context_service_show_keyboard(imservice: *const UIManager); @@ -375,6 +376,24 @@ impl IMService { } } + pub fn delete_surrounding_text( + &self, + before: u32, after: u32, + ) -> Result<(), SubmitError> { + match self.current.active { + true => { + unsafe { + c::eek_input_method_delete_surrounding_text( + self.im, + before, after, + ) + } + Ok(()) + }, + false => Err(SubmitError::NotActive), + } + } + pub fn commit(&mut self) -> Result<(), SubmitError> { match self.current.active { true => { diff --git a/src/keyboard.rs b/src/keyboard.rs index 87c26e0d..bae0cd3b 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -79,9 +79,10 @@ fn sorted<'a, I: Iterator>( pub fn generate_keycodes<'a, C: IntoIterator>( key_names: C ) -> HashMap { + let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s); HashMap::from_iter( // sort to remove a source of indeterminism in keycode assignment - sorted(key_names.into_iter()) + sorted(key_names.into_iter().chain(special_keysyms)) .map(|name| String::from(name)) .zip(9..) ) @@ -108,7 +109,10 @@ impl From for FormattingError { } } -/// Generates a de-facto single level keymap. TODO: actually drop second level +/// Generates a de-facto single level keymap. +// TODO: don't rely on keys and their order, +// but rather on what keysyms and keycodes are in use. +// Iterating actions makes it hard to deduplicate keysyms. pub fn generate_keymap( keystates: &HashMap:: ) -> Result { @@ -123,17 +127,32 @@ pub fn generate_keymap( )?; for (name, state) in keystates.iter() { - if let Action::Submit { text: _, keys } = &state.action { - if let 0 = keys.len() { eprintln!("Key {} has no keysyms", name); }; - for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) { + match &state.action { + Action::Submit { text: _, keys } => { + if let 0 = keys.len() { eprintln!("Key {} has no keysyms", name); }; + for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) { + write!( + buf, + " + <{}> = {};", + named_keysym.0, + keycode, + )?; + } + }, + Action::Erase => { + let mut keycodes = state.keycodes.iter(); write!( buf, " - <{}> = {};", - named_keysym.0, - keycode, + = {};", + keycodes.next().expect("Erase key has no keycode"), )?; - } + if let Some(_) = keycodes.next() { + eprintln!("BUG: Erase key has multiple keycodes"); + } + }, + _ => {}, } } @@ -145,7 +164,9 @@ pub fn generate_keymap( xkb_symbols \"squeekboard\" {{ name[Group1] = \"Letters\"; - name[Group2] = \"Numbers/Symbols\";" + name[Group2] = \"Numbers/Symbols\"; + + key {{ [ BackSpace ] }};" )?; for (name, state) in keystates.iter() { diff --git a/src/layout.rs b/src/layout.rs index 8f8b0055..bc3b3a07 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -887,7 +887,9 @@ mod seat { // process changes match action { - Action::Submit { text: _, keys: _ } => { + Action::Submit { text: _, keys: _ } + | Action::Erase + => { unstick_locks(layout).apply(); submission.handle_release(KeyState::get_id(rckey), time); }, diff --git a/src/submission.rs b/src/submission.rs index 01dd979b..f42f2e03 100644 --- a/src/submission.rs +++ b/src/submission.rs @@ -116,16 +116,18 @@ impl Submission { key: &KeyState, key_id: KeyStateId, time: Timestamp, ) { - let key_string = match &key.action { - Action::Submit { text, keys: _ } => text, + match &key.action { + Action::Submit { text: _, keys: _ } + | Action::Erase + => (), _ => { - eprintln!("BUG: Submitted key with action other than Submit"); + eprintln!("BUG: Submitted key with action other than Submit or Erase"); return; }, }; - let text_was_committed = match (&mut self.imservice, key_string) { - (Some(imservice), Some(text)) => { + let was_committed_as_text = match (&mut self.imservice, &key.action) { + (Some(imservice), Action::Submit { text: Some(text), keys: _ }) => { let submit_result = imservice.commit_string(text) .and_then(|_| imservice.commit()); match submit_result { @@ -133,10 +135,18 @@ impl Submission { Err(imservice::SubmitError::NotActive) => false, } }, + (Some(imservice), Action::Erase) => { + let submit_result = imservice.delete_surrounding_text(1, 0) + .and_then(|_| imservice.commit()); + match submit_result { + Ok(()) => true, + Err(imservice::SubmitError::NotActive) => false, + } + } (_, _) => false, }; - let submit_action = match text_was_committed { + let submit_action = match was_committed_as_text { true => SubmittedAction::IMService, false => { self.virtual_keyboard.switch(