Merge branch 'text_input_enable' into 'master'
Submit and delete strings via text_input See merge request Librem5/squeekboard!304
This commit is contained in:
@ -45,7 +45,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "special"
|
outline: "special"
|
||||||
|
|||||||
@ -45,7 +45,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "special"
|
outline: "special"
|
||||||
|
|||||||
@ -46,7 +46,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
|
|||||||
@ -44,7 +44,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "default"
|
outline: "default"
|
||||||
|
|||||||
@ -39,7 +39,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
|
|||||||
@ -46,7 +46,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "default"
|
outline: "default"
|
||||||
|
|||||||
@ -195,7 +195,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "wide"
|
outline: "wide"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
Return:
|
Return:
|
||||||
outline: "wide"
|
outline: "wide"
|
||||||
icon: "key-enter"
|
icon: "key-enter"
|
||||||
|
|||||||
@ -195,7 +195,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "wide"
|
outline: "wide"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
Return:
|
Return:
|
||||||
outline: "wide"
|
outline: "wide"
|
||||||
icon: "key-enter"
|
icon: "key-enter"
|
||||||
|
|||||||
@ -39,7 +39,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
|
|||||||
@ -16,7 +16,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
space:
|
space:
|
||||||
outline: spaceline
|
outline: spaceline
|
||||||
text: " "
|
text: " "
|
||||||
|
|||||||
@ -39,7 +39,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
|
|||||||
@ -45,7 +45,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "special"
|
outline: "special"
|
||||||
|
|||||||
@ -39,9 +39,9 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: erase
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: show_prefs
|
||||||
outline: "special"
|
outline: "special"
|
||||||
icon: "keyboard-mode-symbolic"
|
icon: "keyboard-mode-symbolic"
|
||||||
show_numbers:
|
show_numbers:
|
||||||
|
|||||||
@ -39,7 +39,7 @@ buttons:
|
|||||||
BackSpace:
|
BackSpace:
|
||||||
outline: "altline"
|
outline: "altline"
|
||||||
icon: "edit-clear-symbolic"
|
icon: "edit-clear-symbolic"
|
||||||
keysym: "BackSpace"
|
action: "erase"
|
||||||
preferences:
|
preferences:
|
||||||
action: "show_prefs"
|
action: "show_prefs"
|
||||||
outline: "special"
|
outline: "special"
|
||||||
|
|||||||
@ -31,10 +31,13 @@ pub enum Action {
|
|||||||
SetModifier(Modifier),
|
SetModifier(Modifier),
|
||||||
/// Submit some text
|
/// Submit some text
|
||||||
Submit {
|
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>,
|
text: Option<CString>,
|
||||||
/// The key events this symbol submits when submitting text is not possible
|
/// The key events this symbol submits when submitting text is not possible
|
||||||
keys: Vec<KeySym>,
|
keys: Vec<KeySym>,
|
||||||
},
|
},
|
||||||
|
/// Erase a position behind the cursor
|
||||||
|
Erase,
|
||||||
ShowPreferences,
|
ShowPreferences,
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/data.rs
11
src/data.rs
@ -15,6 +15,7 @@ use std::vec::Vec;
|
|||||||
|
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
|
|
||||||
|
use ::action;
|
||||||
use ::keyboard::{
|
use ::keyboard::{
|
||||||
KeyState, PressType,
|
KeyState, PressType,
|
||||||
generate_keymap, generate_keycodes, FormattingError
|
generate_keymap, generate_keycodes, FormattingError
|
||||||
@ -264,6 +265,9 @@ enum Action {
|
|||||||
SetView(String),
|
SetView(String),
|
||||||
#[serde(rename="show_prefs")]
|
#[serde(rename="show_prefs")]
|
||||||
ShowPrefs,
|
ShowPrefs,
|
||||||
|
/// Remove last character
|
||||||
|
#[serde(rename="erase")]
|
||||||
|
Erase,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||||
@ -386,6 +390,10 @@ impl Layout {
|
|||||||
)
|
)
|
||||||
}).collect()
|
}).collect()
|
||||||
},
|
},
|
||||||
|
action::Action::Erase => vec![
|
||||||
|
*keymap.get("BackSpace")
|
||||||
|
.expect(&format!("BackSpace missing from keymap")),
|
||||||
|
],
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
@ -558,6 +566,7 @@ fn create_action<H: logging::Handler>(
|
|||||||
SubmitData::Action(
|
SubmitData::Action(
|
||||||
Action::ShowPrefs
|
Action::ShowPrefs
|
||||||
) => ::action::Action::ShowPreferences,
|
) => ::action::Action::ShowPreferences,
|
||||||
|
SubmitData::Action(Action::Erase) => action::Action::Erase,
|
||||||
SubmitData::Keysym(keysym) => ::action::Action::Submit {
|
SubmitData::Keysym(keysym) => ::action::Action::Submit {
|
||||||
text: None,
|
text: None,
|
||||||
keys: vec!(::action::KeySym(
|
keys: vec!(::action::KeySym(
|
||||||
@ -589,7 +598,7 @@ fn create_action<H: logging::Handler>(
|
|||||||
false => format!("U{:04X}", codepoint as u32),
|
false => format!("U{:04X}", codepoint as u32),
|
||||||
})
|
})
|
||||||
}).collect(),
|
}).collect(),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,23 @@ void imservice_connect_listeners(struct zwp_input_method_v2 *im, struct imservic
|
|||||||
zwp_input_method_v2_add_listener(im, &input_method_listener, imservice);
|
zwp_input_method_v2_add_listener(im, &input_method_listener, imservice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eek_input_method_commit_string(struct zwp_input_method_v2 *zwp_input_method_v2, const char *text)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
zwp_input_method_v2_commit(zwp_input_method_v2, serial);
|
||||||
|
}
|
||||||
|
|
||||||
/// Declared explicitly because _destroy is inline,
|
/// Declared explicitly because _destroy is inline,
|
||||||
/// making it unavailable in Rust
|
/// making it unavailable in Rust
|
||||||
void imservice_destroy_im(struct zwp_input_method_v2 *im) {
|
void imservice_destroy_im(struct zwp_input_method_v2 *im) {
|
||||||
|
|||||||
@ -1,3 +1,8 @@
|
|||||||
|
/*! Manages zwp_input_method_v2 protocol.
|
||||||
|
*
|
||||||
|
* Library module.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -32,6 +37,9 @@ pub mod c {
|
|||||||
fn imservice_destroy_im(im: *mut c::InputMethod);
|
fn imservice_destroy_im(im: *mut c::InputMethod);
|
||||||
#[allow(improper_ctypes)] // IMService will never be dereferenced in C
|
#[allow(improper_ctypes)] // IMService will never be dereferenced in C
|
||||||
pub fn imservice_connect_listeners(im: *mut InputMethod, imservice: *const IMService);
|
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 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_show_keyboard(imservice: *const UIManager);
|
||||||
fn server_context_service_hide_keyboard(imservice: *const UIManager);
|
fn server_context_service_hide_keyboard(imservice: *const UIManager);
|
||||||
@ -328,7 +336,7 @@ impl Default for IMProtocolState {
|
|||||||
|
|
||||||
pub struct IMService {
|
pub struct IMService {
|
||||||
/// Owned reference (still created and destroyed in C)
|
/// Owned reference (still created and destroyed in C)
|
||||||
pub im: *const c::InputMethod,
|
pub im: *mut c::InputMethod,
|
||||||
/// Unowned reference. Be careful, it's shared with C at large
|
/// Unowned reference. Be careful, it's shared with C at large
|
||||||
state_manager: *const c::StateManager,
|
state_manager: *const c::StateManager,
|
||||||
/// Unowned reference. Be careful, it's shared with C at large
|
/// Unowned reference. Be careful, it's shared with C at large
|
||||||
@ -340,6 +348,11 @@ pub struct IMService {
|
|||||||
serial: Wrapping<u32>,
|
serial: Wrapping<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SubmitError {
|
||||||
|
/// The input method had not been activated
|
||||||
|
NotActive,
|
||||||
|
}
|
||||||
|
|
||||||
impl IMService {
|
impl IMService {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
im: *mut c::InputMethod,
|
im: *mut c::InputMethod,
|
||||||
@ -364,4 +377,51 @@ impl IMService {
|
|||||||
}
|
}
|
||||||
imservice
|
imservice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn commit_string(&self, text: &CString) -> Result<(), SubmitError> {
|
||||||
|
match self.current.active {
|
||||||
|
true => {
|
||||||
|
unsafe {
|
||||||
|
c::eek_input_method_commit_string(self.im, text.as_ptr())
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
false => Err(SubmitError::NotActive),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 => {
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
/*! State of the emulated keyboard and keys.
|
/*! State of the emulated keyboard and keys.
|
||||||
* Regards the keyboard as if it was composed of switches. */
|
* Regards the keyboard as if it was composed of switches. */
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
use ::action::Action;
|
use ::action::Action;
|
||||||
use ::logging;
|
use ::logging;
|
||||||
|
|
||||||
|
// Traits
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::iter::{ FromIterator, IntoIterator };
|
use std::iter::{ FromIterator, IntoIterator };
|
||||||
|
|
||||||
@ -20,6 +23,11 @@ pub enum PressType {
|
|||||||
|
|
||||||
pub type KeyCode = u32;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyState {
|
pub struct KeyState {
|
||||||
pub pressed: PressType,
|
pub pressed: PressType,
|
||||||
@ -49,6 +57,12 @@ impl KeyState {
|
|||||||
..self
|
..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
|
/// Sorts an iterator by converting it to a Vector and back
|
||||||
@ -66,9 +80,10 @@ fn sorted<'a, I: Iterator<Item=&'a str>>(
|
|||||||
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
|
pub fn generate_keycodes<'a, C: IntoIterator<Item=&'a str>>(
|
||||||
key_names: C
|
key_names: C
|
||||||
) -> HashMap<String, u32> {
|
) -> HashMap<String, u32> {
|
||||||
|
let special_keysyms = ["BackSpace", "Return"].iter().map(|&s| s);
|
||||||
HashMap::from_iter(
|
HashMap::from_iter(
|
||||||
// sort to remove a source of indeterminism in keycode assignment
|
// 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))
|
.map(|name| String::from(name))
|
||||||
.zip(9..)
|
.zip(9..)
|
||||||
)
|
)
|
||||||
@ -95,7 +110,10 @@ impl From<io::Error> 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(
|
pub fn generate_keymap(
|
||||||
keystates: &HashMap::<String, KeyState>
|
keystates: &HashMap::<String, KeyState>
|
||||||
) -> Result<String, FormattingError> {
|
) -> Result<String, FormattingError> {
|
||||||
@ -110,22 +128,40 @@ pub fn generate_keymap(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (name, state) in keystates.iter() {
|
for (name, state) in keystates.iter() {
|
||||||
if let Action::Submit { text: _, keys } = &state.action {
|
match &state.action {
|
||||||
if let 0 = keys.len() {
|
Action::Submit { text: _, keys } => {
|
||||||
log_print!(
|
if let 0 = keys.len() {
|
||||||
logging::Level::Warning,
|
log_print!(
|
||||||
"Key {} has no keysyms", name,
|
logging::Level::Warning,
|
||||||
);
|
"Key {} has no keysyms", name,
|
||||||
};
|
);
|
||||||
for (named_keysym, keycode) in keys.iter().zip(&state.keycodes) {
|
};
|
||||||
|
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!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"
|
"
|
||||||
<{}> = {};",
|
<BackSpace> = {};",
|
||||||
named_keysym.0,
|
keycodes.next().expect("Erase key has no keycode"),
|
||||||
keycode,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
if let Some(_) = keycodes.next() {
|
||||||
|
log_print!(
|
||||||
|
logging::Level::Bug,
|
||||||
|
"Erase key has multiple keycodes",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +173,9 @@ pub fn generate_keymap(
|
|||||||
xkb_symbols \"squeekboard\" {{
|
xkb_symbols \"squeekboard\" {{
|
||||||
|
|
||||||
name[Group1] = \"Letters\";
|
name[Group1] = \"Letters\";
|
||||||
name[Group2] = \"Numbers/Symbols\";"
|
name[Group2] = \"Numbers/Symbols\";
|
||||||
|
|
||||||
|
key <BackSpace> {{ [ BackSpace ] }};"
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (name, state) in keystates.iter() {
|
for (name, state) in keystates.iter() {
|
||||||
|
|||||||
@ -876,11 +876,7 @@ mod seat {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut key = rckey.borrow_mut();
|
let mut key = rckey.borrow_mut();
|
||||||
submission.virtual_keyboard.switch(
|
submission.handle_press(&key, KeyState::get_id(rckey), time);
|
||||||
&key.keycodes,
|
|
||||||
PressType::Pressed,
|
|
||||||
time,
|
|
||||||
);
|
|
||||||
key.pressed = PressType::Pressed;
|
key.pressed = PressType::Pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,13 +902,11 @@ mod seat {
|
|||||||
|
|
||||||
// process changes
|
// process changes
|
||||||
match action {
|
match action {
|
||||||
Action::Submit { text: _, keys: _ } => {
|
Action::Submit { text: _, keys: _ }
|
||||||
|
| Action::Erase
|
||||||
|
=> {
|
||||||
unstick_locks(layout).apply();
|
unstick_locks(layout).apply();
|
||||||
submission.virtual_keyboard.switch(
|
submission.handle_release(KeyState::get_id(rckey), time);
|
||||||
&key.keycodes,
|
|
||||||
PressType::Released,
|
|
||||||
time,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
Action::SetView(view) => {
|
Action::SetView(view) => {
|
||||||
try_set_view(layout, view)
|
try_set_view(layout, view)
|
||||||
|
|||||||
@ -16,8 +16,12 @@
|
|||||||
* The text-input interface may be enabled and disabled at arbitrary times,
|
* The text-input interface may be enabled and disabled at arbitrary times,
|
||||||
* and those events SHOULD NOT cause any lost events.
|
* and those events SHOULD NOT cause any lost events.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
use ::action::Action;
|
||||||
|
use ::imservice;
|
||||||
use ::imservice::IMService;
|
use ::imservice::IMService;
|
||||||
|
use ::keyboard::{ KeyCode, KeyState, KeyStateId, PressType };
|
||||||
|
use ::logging;
|
||||||
use ::vkeyboard::VirtualKeyboard;
|
use ::vkeyboard::VirtualKeyboard;
|
||||||
|
|
||||||
/// Gathers stuff defined in C or called by C
|
/// Gathers stuff defined in C or called by C
|
||||||
@ -57,6 +61,7 @@ pub mod c {
|
|||||||
Submission {
|
Submission {
|
||||||
imservice,
|
imservice,
|
||||||
virtual_keyboard: VirtualKeyboard(vk),
|
virtual_keyboard: VirtualKeyboard(vk),
|
||||||
|
pressed: Vec::new(),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -92,9 +97,91 @@ pub mod c {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Timestamp(pub u32);
|
pub struct Timestamp(pub u32);
|
||||||
|
|
||||||
pub struct Submission {
|
enum SubmittedAction {
|
||||||
// used by C callbacks internally, TODO: make use with virtual keyboard
|
/// A collection of keycodes that were pressed
|
||||||
#[allow(dead_code)]
|
VirtualKeyboard(Vec<KeyCode>),
|
||||||
imservice: Option<Box<IMService>>,
|
IMService,
|
||||||
pub virtual_keyboard: VirtualKeyboard,
|
}
|
||||||
|
|
||||||
|
pub struct Submission {
|
||||||
|
imservice: Option<Box<IMService>>,
|
||||||
|
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,
|
||||||
|
) {
|
||||||
|
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, &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,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(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 was_committed_as_text {
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user