diff --git a/src/keyboard.rs b/src/keyboard.rs index cbdaa00740f7a7ae9a6f4e015c33a05cdf19a304..e1a3a32514024b6cd5657e1db0c07be1b2a1c8c6 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -46,6 +46,14 @@ impl KeyState { } } + #[must_use] + pub fn into_pressed(self) -> KeyState { + KeyState { + pressed: PressType::Pressed, + ..self + } + } + /// KeyStates instances are the unique identifiers of pressed keys, /// and the actions submitted with them. pub fn get_id(keystate: &Rc<RefCell<KeyState>>) -> KeyStateId { diff --git a/src/layout.rs b/src/layout.rs index ec601b66b384443c488a802c52c4a0a8b91e0184..ae554d5a06aa92e205a7666d2fa7e2481e90ede4 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -26,10 +26,10 @@ use std::vec::Vec; use ::action::Action; use ::drawing; -use ::keyboard::{ KeyState, PressType }; +use ::keyboard::KeyState; use ::logging; use ::manager; -use ::submission::{ Submission, Timestamp }; +use ::submission::{ Submission, SubmitData, Timestamp }; use ::util::find_max_double; // Traits @@ -916,9 +916,38 @@ mod seat { "Key {:?} was already pressed", rckey, ); } - let mut key = rckey.borrow_mut(); - submission.handle_press(&key, KeyState::get_id(rckey), time); - key.pressed = PressType::Pressed; + let key: KeyState = { + RefCell::borrow(rckey).clone() + }; + let action = key.action.clone(); + match action { + Action::Submit { + text: Some(text), + keys: _, + } => submission.handle_press( + KeyState::get_id(rckey), + SubmitData::Text(&text), + &key.keycodes, + time, + ), + Action::Submit { + text: None, + keys: _, + } => submission.handle_press( + KeyState::get_id(rckey), + SubmitData::Keycodes, + &key.keycodes, + time, + ), + Action::Erase => submission.handle_press( + KeyState::get_id(rckey), + SubmitData::Erase, + &key.keycodes, + time, + ), + _ => {}, + }; + RefCell::replace(rckey, key.into_pressed()); } pub fn handle_release_key( @@ -1006,6 +1035,7 @@ mod test { use super::*; use std::ffi::CString; + use ::keyboard::PressType; pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> { Rc::new(RefCell::new(::keyboard::KeyState { diff --git a/src/submission.rs b/src/submission.rs index 9ea969b2007b9059d150911b1ae065989b579f7b..e681b2e33337a2c4c973f1ec8306ee72c24e5ee7 100644 --- a/src/submission.rs +++ b/src/submission.rs @@ -17,11 +17,11 @@ * and those events SHOULD NOT cause any lost events. * */ -use ::action::Action; +use std::ffi::CString; + use ::imservice; use ::imservice::IMService; -use ::keyboard::{ KeyCode, KeyState, KeyStateId, PressType }; -use ::logging; +use ::keyboard::{ KeyCode, KeyStateId, PressType }; use ::vkeyboard::VirtualKeyboard; /// Gathers stuff defined in C or called by C @@ -109,59 +109,66 @@ pub struct Submission { pressed: Vec<(KeyStateId, SubmittedAction)>, } +pub enum SubmitData<'a> { + Text(&'a CString), + Erase, + Keycodes, +} + impl Submission { /// Sends a submit text event if possible; /// otherwise sends key press and makes a note of it pub fn handle_press( &mut self, - key: &KeyState, key_id: KeyStateId, + key_id: KeyStateId, + data: SubmitData, + keycodes: &Vec<KeyCode>, time: Timestamp, ) { - match &key.action { - Action::Submit { text: _, keys: _ } - | Action::Erase - => (), - _ => { - log_print!( - logging::Level::Bug, - "Submitted key with action other than Submit or Erase", - ); - return; - }, - }; + let was_committed_as_text = match &mut self.imservice { + Some(imservice) => { + enum Outcome { + Submitted(Result<(), imservice::SubmitError>), + NotSubmitted, + }; + + let submit_outcome = match data { + SubmitData::Text(text) => { + Outcome::Submitted(imservice.commit_string(text)) + }, + SubmitData::Erase => { + /* Delete_surrounding_text takes byte offsets, + * so cannot work without get_surrounding_text. + * This is a bug in the protocol. + */ + // imservice.delete_surrounding_text(1, 0), + Outcome::NotSubmitted + }, + SubmitData::Keycodes => Outcome::NotSubmitted, + }; - 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 { - Ok(()) => true, - Err(imservice::SubmitError::NotActive) => false, + match submit_outcome { + Outcome::Submitted(result) => { + match result.and_then(|()| imservice.commit()) { + Ok(()) => true, + Err(imservice::SubmitError::NotActive) => false, + } + }, + Outcome::NotSubmitted => false, } }, - /* Delete_surrounding_text takes byte offsets, - * so cannot work without get_surrounding_text. - * This is a bug in the protocol. - (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, + _ => false, }; - + let submit_action = match was_committed_as_text { true => SubmittedAction::IMService, false => { self.virtual_keyboard.switch( - &key.keycodes, + keycodes, PressType::Pressed, time, ); - SubmittedAction::VirtualKeyboard(key.keycodes.clone()) + SubmittedAction::VirtualKeyboard(keycodes.clone()) }, };