Commit 42cb73cd authored by Dorota Czaplejewicz's avatar Dorota Czaplejewicz
Browse files

submission: Handle submitting strings

parent d1bc23e9
......@@ -31,7 +31,8 @@ pub enum Action {
SetModifier(Modifier),
/// Submit some text
Submit {
/// Text to submit with input-method
/// Text to submit with input-method.
/// If None, then keys are to be submitted instead.
text: Option<CString>,
/// The key events this symbol submits when submitting text is not possible
keys: Vec<KeySym>,
......
......@@ -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_commit(struct zwp_input_method_v2 *zwp_input_method_v2, uint32_t serial)
{
zwp_input_method_v2_commit(zwp_input_method_v2, serial);
}
/// Declared explicitly because _destroy is inline,
/// making it unavailable in Rust
......
/*! Manages zwp_input_method_v2 protocol.
*
* Library module.
*/
use std::boxed::Box;
use std::ffi;
use std::ffi::CString;
use std::num::Wrapping;
use std::string::String;
......@@ -31,7 +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_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);
fn server_context_service_hide_keyboard(imservice: *const UIManager);
......@@ -332,8 +336,6 @@ pub struct IMService {
pub enum SubmitError {
/// The input method had not been activated
NotActive,
/// Submitted text has null bytes
NullBytes(ffi::NulError),
}
impl IMService {
......@@ -361,10 +363,9 @@ impl IMService {
imservice
}
pub fn commit_string(&self, text: &str) -> Result<(), SubmitError> {
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
match self.current.active {
true => {
let text = CString::new(text).map_err(SubmitError::NullBytes)?;
unsafe {
c::eek_input_method_commit_string(self.im, text.as_ptr())
}
......@@ -373,4 +374,21 @@ impl IMService {
false => Err(SubmitError::NotActive),
}
}
pub fn commit(&mut self) -> Result<(), SubmitError> {
match self.current.active {
true => {
unsafe {
c::eek_input_method_commit(self.im, self.serial.0)
}
self.serial += Wrapping(1u32);
Ok(())
},
false => Err(SubmitError::NotActive),
}
}
pub fn is_active(&self) -> bool {
self.current.active
}
}
/*! State of the emulated keyboard and keys.
* Regards the keyboard as if it was composed of switches. */
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::io;
use std::rc::Rc;
use std::string::FromUtf8Error;
use ::action::Action;
// Traits
use std::io::Write;
use std::iter::{ FromIterator, IntoIterator };
......@@ -19,6 +22,11 @@ pub enum PressType {
pub type KeyCode = u32;
/// When the submitted actions of keys need to be tracked,
/// they need a stable, comparable ID
#[derive(PartialEq)]
pub struct KeyStateId(*const KeyState);
#[derive(Debug, Clone)]
pub struct KeyState {
pub pressed: PressType,
......@@ -48,6 +56,12 @@ impl KeyState {
..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 {
KeyStateId(keystate.as_ptr() as *const KeyState)
}
}
/// Sorts an iterator by converting it to a Vector and back
......
......@@ -861,11 +861,7 @@ mod seat {
eprintln!("Warning: key {:?} was already pressed", rckey);
}
let mut key = rckey.borrow_mut();
submission.virtual_keyboard.switch(
&key.keycodes,
PressType::Pressed,
time,
);
submission.handle_press(&key, KeyState::get_id(rckey), time);
key.pressed = PressType::Pressed;
}
......@@ -893,11 +889,7 @@ mod seat {
match action {
Action::Submit { text: _, keys: _ } => {
unstick_locks(layout).apply();
submission.virtual_keyboard.switch(
&key.keycodes,
PressType::Released,
time,
);
submission.handle_release(KeyState::get_id(rckey), time);
},
Action::SetView(view) => {
try_set_view(layout, view)
......
......@@ -16,8 +16,11 @@
* The text-input interface may be enabled and disabled at arbitrary times,
* and those events SHOULD NOT cause any lost events.
* */
use ::action::Action;
use ::imservice;
use ::imservice::IMService;
use ::keyboard::{ KeyCode, KeyState, KeyStateId, PressType };
use ::vkeyboard::VirtualKeyboard;
/// Gathers stuff defined in C or called by C
......@@ -57,6 +60,7 @@ pub mod c {
Submission {
imservice,
virtual_keyboard: VirtualKeyboard(vk),
pressed: Vec::new(),
}
))
}
......@@ -92,9 +96,78 @@ pub mod c {
#[derive(Clone, Copy)]
pub struct Timestamp(pub u32);
enum SubmittedAction {
/// A collection of keycodes that were pressed
VirtualKeyboard(Vec<KeyCode>),
IMService,
}
pub struct Submission {
// used by C callbacks internally, TODO: make use with virtual keyboard
#[allow(dead_code)]
imservice: Option<Box<IMService>>,
pub virtual_keyboard: VirtualKeyboard,
virtual_keyboard: VirtualKeyboard,
pressed: Vec<(KeyStateId, SubmittedAction)>,
}
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,
time: Timestamp,
) {
let key_string = match &key.action {
Action::Submit { text, keys: _ } => text,
_ => {
eprintln!("BUG: Submitted key with action other than Submit");
return;
},
};
let text_was_committed = match (&mut self.imservice, key_string) {
(Some(imservice), Some(text)) => {
let submit_result = imservice.commit_string(text)
.and_then(|_| imservice.commit());
match submit_result {
Ok(()) => true,
Err(imservice::SubmitError::NotActive) => false,
}
},
(_, _) => false,
};
let submit_action = match text_was_committed {
true => SubmittedAction::IMService,
false => {
self.virtual_keyboard.switch(
&key.keycodes,
PressType::Pressed,
time,
);
SubmittedAction::VirtualKeyboard(key.keycodes.clone())
},
};
self.pressed.push((key_id, submit_action));
}
pub fn handle_release(&mut self, key_id: KeyStateId, time: Timestamp) {
let index = self.pressed.iter().position(|(id, _)| *id == key_id);
if let Some(index) = index {
let (_id, action) = self.pressed.remove(index);
match action {
// string already sent, nothing to do
SubmittedAction::IMService => {},
// no matter if the imservice got activated,
// keys must be released
SubmittedAction::VirtualKeyboard(keycodes) => {
self.virtual_keyboard.switch(
&keycodes,
PressType::Released,
time,
)
},
}
};
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment