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,7 +128,8 @@ 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 {
 | 
				
			||||||
 | 
					            Action::Submit { text: _, keys } => {
 | 
				
			||||||
                if let 0 = keys.len() {
 | 
					                if let 0 = keys.len() {
 | 
				
			||||||
                    log_print!(
 | 
					                    log_print!(
 | 
				
			||||||
                        logging::Level::Warning,
 | 
					                        logging::Level::Warning,
 | 
				
			||||||
@ -126,6 +145,23 @@ pub fn generate_keymap(
 | 
				
			|||||||
                        keycode,
 | 
					                        keycode,
 | 
				
			||||||
                    )?;
 | 
					                    )?;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Action::Erase => {
 | 
				
			||||||
 | 
					                let mut keycodes = state.keycodes.iter();
 | 
				
			||||||
 | 
					                write!(
 | 
				
			||||||
 | 
					                    buf,
 | 
				
			||||||
 | 
					                    "
 | 
				
			||||||
 | 
					        <BackSpace> = {};",
 | 
				
			||||||
 | 
					                    keycodes.next().expect("Erase key has no 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)
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,11 @@
 | 
				
			|||||||
 * 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