Merge remote-tracking branch 'upstream/master' into center
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"
 | 
				
			||||||
 | 
				
			|||||||
@ -116,6 +116,7 @@ settings_get_layout(GSettings *settings, char **type, char **layout)
 | 
				
			|||||||
    GVariant *inputs = g_settings_get_value(settings, "sources");
 | 
					    GVariant *inputs = g_settings_get_value(settings, "sources");
 | 
				
			||||||
    // current layout is always first
 | 
					    // current layout is always first
 | 
				
			||||||
    g_variant_get_child(inputs, 0, "(ss)", type, layout);
 | 
					    g_variant_get_child(inputs, 0, "(ss)", type, layout);
 | 
				
			||||||
 | 
					    g_variant_unref(inputs);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
@ -139,9 +140,11 @@ eekboard_context_service_update_layout(EekboardContextService *context, enum squ
 | 
				
			|||||||
    switch (priv->purpose) {
 | 
					    switch (priv->purpose) {
 | 
				
			||||||
    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
 | 
					    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
 | 
				
			||||||
    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
 | 
					    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE:
 | 
				
			||||||
 | 
					        g_free(keyboard_layout);
 | 
				
			||||||
        keyboard_layout = g_strdup("number");
 | 
					        keyboard_layout = g_strdup("number");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
 | 
					    case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL:
 | 
				
			||||||
 | 
					        g_free(keyboard_layout);
 | 
				
			||||||
        keyboard_layout = g_strdup("terminal");
 | 
					        keyboard_layout = g_strdup("terminal");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
 | 
				
			|||||||
@ -31,10 +31,29 @@ 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,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Action {
 | 
				
			||||||
 | 
					    pub fn is_locked(&self, view_name: &str) -> bool {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Action::LockView { lock, unlock: _ } => lock == view_name,
 | 
				
			||||||
 | 
					            _ => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn is_active(&self, view_name: &str) -> bool {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Action::SetView(view) => view == view_name,
 | 
				
			||||||
 | 
					            Action::LockView { lock, unlock: _ } => lock == view_name,
 | 
				
			||||||
 | 
					            _ => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/data.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								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,13 +390,16 @@ impl Layout {
 | 
				
			|||||||
                            )
 | 
					                            )
 | 
				
			||||||
                    }).collect()
 | 
					                    }).collect()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                action::Action::Erase => vec![
 | 
				
			||||||
 | 
					                    *keymap.get("BackSpace")
 | 
				
			||||||
 | 
					                        .expect(&format!("BackSpace missing from keymap")),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
                _ => Vec::new(),
 | 
					                _ => Vec::new(),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                name.into(),
 | 
					                name.into(),
 | 
				
			||||||
                KeyState {
 | 
					                KeyState {
 | 
				
			||||||
                    pressed: PressType::Released,
 | 
					                    pressed: PressType::Released,
 | 
				
			||||||
                    locked: false,
 | 
					 | 
				
			||||||
                    keycodes,
 | 
					                    keycodes,
 | 
				
			||||||
                    action,
 | 
					                    action,
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -574,6 +581,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(
 | 
				
			||||||
@ -605,7 +613,7 @@ fn create_action<H: logging::Handler>(
 | 
				
			|||||||
                    false => format!("U{:04X}", codepoint as u32),
 | 
					                    false => format!("U{:04X}", codepoint as u32),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }).collect(),
 | 
					            }).collect(),
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,7 @@ mod c {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Draws all buttons that are not in the base state
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_layout_draw_all_changed(
 | 
					    fn squeek_layout_draw_all_changed(
 | 
				
			||||||
@ -49,12 +50,13 @@ mod c {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        layout.foreach_visible_button(|offset, button| {
 | 
					        layout.foreach_visible_button(|offset, button| {
 | 
				
			||||||
            let state = RefCell::borrow(&button.state).clone();
 | 
					            let state = RefCell::borrow(&button.state).clone();
 | 
				
			||||||
            if state.pressed == keyboard::PressType::Pressed || state.locked {
 | 
					            let locked = state.action.is_active(&layout.current_view);
 | 
				
			||||||
 | 
					            if state.pressed == keyboard::PressType::Pressed || locked {
 | 
				
			||||||
                render_button_at_position(
 | 
					                render_button_at_position(
 | 
				
			||||||
                    renderer, &cr,
 | 
					                    renderer, &cr,
 | 
				
			||||||
                    offset,
 | 
					                    offset,
 | 
				
			||||||
                    button.as_ref(),
 | 
					                    button.as_ref(),
 | 
				
			||||||
                    state.pressed, state.locked,
 | 
					                    state.pressed, locked,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
@ -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,10 +23,14 @@ 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,
 | 
				
			||||||
    pub locked: bool,
 | 
					 | 
				
			||||||
    /// A cache of raw keycodes derived from Action::Sumbit given a keymap
 | 
					    /// A cache of raw keycodes derived from Action::Sumbit given a keymap
 | 
				
			||||||
    pub keycodes: Vec<KeyCode>,
 | 
					    pub keycodes: Vec<KeyCode>,
 | 
				
			||||||
    /// Static description of what the key does when pressed or released
 | 
					    /// Static description of what the key does when pressed or released
 | 
				
			||||||
@ -31,17 +38,6 @@ pub struct KeyState {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl KeyState {
 | 
					impl KeyState {
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub fn into_activated(self) -> KeyState {
 | 
					 | 
				
			||||||
        match self.action {
 | 
					 | 
				
			||||||
            Action::LockView { lock: _, unlock: _ } => KeyState {
 | 
					 | 
				
			||||||
                locked: self.locked ^ true,
 | 
					 | 
				
			||||||
                ..self
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            _ => self,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn into_released(self) -> KeyState {
 | 
					    pub fn into_released(self) -> KeyState {
 | 
				
			||||||
        KeyState {
 | 
					        KeyState {
 | 
				
			||||||
@ -49,6 +45,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 +68,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 +98,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 +116,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 +161,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() {
 | 
				
			||||||
@ -195,7 +221,6 @@ mod tests {
 | 
				
			|||||||
                    keys: vec!(KeySym("a".into()), KeySym("c".into())),
 | 
					                    keys: vec!(KeySym("a".into()), KeySym("c".into())),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                keycodes: vec!(9, 10),
 | 
					                keycodes: vec!(9, 10),
 | 
				
			||||||
                locked: false,
 | 
					 | 
				
			||||||
                pressed: PressType::Released,
 | 
					                pressed: PressType::Released,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        }).unwrap();
 | 
					        }).unwrap();
 | 
				
			||||||
 | 
				
			|||||||
@ -629,7 +629,6 @@ pub struct Layout {
 | 
				
			|||||||
    // When the list tracks actual location,
 | 
					    // When the list tracks actual location,
 | 
				
			||||||
    // it becomes possible to place popovers and other UI accurately.
 | 
					    // it becomes possible to place popovers and other UI accurately.
 | 
				
			||||||
    pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
 | 
					    pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
 | 
				
			||||||
    pub locked_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A builder structure for picking up layout data from storage
 | 
					/// A builder structure for picking up layout data from storage
 | 
				
			||||||
@ -661,7 +660,6 @@ impl Layout {
 | 
				
			|||||||
            views: data.views,
 | 
					            views: data.views,
 | 
				
			||||||
            keymap_str: data.keymap_str,
 | 
					            keymap_str: data.keymap_str,
 | 
				
			||||||
            pressed_keys: HashSet::new(),
 | 
					            pressed_keys: HashSet::new(),
 | 
				
			||||||
            locked_keys: HashSet::new(),
 | 
					 | 
				
			||||||
            margins: data.margins,
 | 
					            margins: data.margins,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -672,7 +670,7 @@ impl Layout {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn get_current_view(&self) -> &View {
 | 
					    pub fn get_current_view(&self) -> &View {
 | 
				
			||||||
        &self.get_current_view_position().1
 | 
					        &self.views.get(&self.current_view).expect("Selected nonexistent view").1
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
 | 
					    fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
 | 
				
			||||||
@ -742,6 +740,23 @@ impl Layout {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
 | 
				
			||||||
 | 
					        let mut out = Vec::new();
 | 
				
			||||||
 | 
					        let view = self.get_current_view();
 | 
				
			||||||
 | 
					        for (_, row) in &view.get_rows() {
 | 
				
			||||||
 | 
					            for (_, button) in &row.buttons {
 | 
				
			||||||
 | 
					                let locked = {
 | 
				
			||||||
 | 
					                    let state = RefCell::borrow(&button.state).clone();
 | 
				
			||||||
 | 
					                    state.action.is_locked(&self.current_view)
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                if locked {
 | 
				
			||||||
 | 
					                    out.push(button.state.clone());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        out
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod procedures {
 | 
					mod procedures {
 | 
				
			||||||
@ -868,9 +883,9 @@ mod seat {
 | 
				
			|||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    fn unstick_locks(layout: &mut Layout) -> ViewChange {
 | 
					    fn unstick_locks(layout: &mut Layout) -> ViewChange {
 | 
				
			||||||
        let mut new_view = None;
 | 
					        let mut new_view = None;
 | 
				
			||||||
        for key in layout.locked_keys.clone() {
 | 
					        for key in layout.get_locked_keys().clone() {
 | 
				
			||||||
            let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
					            let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
				
			||||||
            let mut key = RefCell::borrow_mut(key);
 | 
					            let key = RefCell::borrow(key);
 | 
				
			||||||
            match &key.action {
 | 
					            match &key.action {
 | 
				
			||||||
                Action::LockView { lock: _, unlock: view } => {
 | 
					                Action::LockView { lock: _, unlock: view } => {
 | 
				
			||||||
                    new_view = Some(view.clone());
 | 
					                    new_view = Some(view.clone());
 | 
				
			||||||
@ -881,7 +896,6 @@ mod seat {
 | 
				
			|||||||
                    a,
 | 
					                    a,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            key.locked = false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        ViewChange {
 | 
					        ViewChange {
 | 
				
			||||||
@ -903,11 +917,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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -926,32 +936,26 @@ mod seat {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // update
 | 
					        // update
 | 
				
			||||||
        let key = key.into_released();
 | 
					        let key = key.into_released();
 | 
				
			||||||
        let key = match action {
 | 
					        let mut locked = key.action.is_locked(&layout.current_view);
 | 
				
			||||||
            Action::LockView { lock: _, unlock: _ } => key.into_activated(),
 | 
					 | 
				
			||||||
            _ => key,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 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)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Action::LockView { lock, unlock } => {
 | 
					            Action::LockView { lock, unlock } => {
 | 
				
			||||||
                // The button that triggered this will be in the right state
 | 
					                locked ^= true;
 | 
				
			||||||
                // due to commit at the end.
 | 
					 | 
				
			||||||
                unstick_locks(layout)
 | 
					                unstick_locks(layout)
 | 
				
			||||||
                    // It doesn't matter what the resulting view should be,
 | 
					                    // It doesn't matter what the resulting view should be,
 | 
				
			||||||
                    // it's getting changed anyway.
 | 
					                    // it's getting changed anyway.
 | 
				
			||||||
                    .choose_view(
 | 
					                    .choose_view(
 | 
				
			||||||
                        match key.locked {
 | 
					                        match locked {
 | 
				
			||||||
                            true => lock.clone(),
 | 
					                            true => lock.clone(),
 | 
				
			||||||
                            false => unlock.clone(),
 | 
					                            false => unlock.clone(),
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@ -993,11 +997,6 @@ mod seat {
 | 
				
			|||||||
        let pointer = ::util::Pointer(rckey.clone());
 | 
					        let pointer = ::util::Pointer(rckey.clone());
 | 
				
			||||||
        // Apply state changes
 | 
					        // Apply state changes
 | 
				
			||||||
        layout.pressed_keys.remove(&pointer);
 | 
					        layout.pressed_keys.remove(&pointer);
 | 
				
			||||||
        if key.locked {
 | 
					 | 
				
			||||||
            layout.locked_keys.insert(pointer);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            layout.locked_keys.remove(&pointer);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Commit activated button state changes
 | 
					        // Commit activated button state changes
 | 
				
			||||||
        RefCell::replace(rckey, key);
 | 
					        RefCell::replace(rckey, key);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1012,7 +1011,6 @@ mod test {
 | 
				
			|||||||
    pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
 | 
					    pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
 | 
				
			||||||
        Rc::new(RefCell::new(::keyboard::KeyState {
 | 
					        Rc::new(RefCell::new(::keyboard::KeyState {
 | 
				
			||||||
            pressed: PressType::Released,
 | 
					            pressed: PressType::Released,
 | 
				
			||||||
            locked: false,
 | 
					 | 
				
			||||||
            keycodes: Vec::new(),
 | 
					            keycodes: Vec::new(),
 | 
				
			||||||
            action: Action::SetView("default".into()),
 | 
					            action: Action::SetView("default".into()),
 | 
				
			||||||
        }))
 | 
					        }))
 | 
				
			||||||
@ -1088,7 +1086,6 @@ mod test {
 | 
				
			|||||||
            current_view: String::new(),
 | 
					            current_view: String::new(),
 | 
				
			||||||
            keymap_str: CString::new("").unwrap(),
 | 
					            keymap_str: CString::new("").unwrap(),
 | 
				
			||||||
            kind: ArrangementKind::Base,
 | 
					            kind: ArrangementKind::Base,
 | 
				
			||||||
            locked_keys: HashSet::new(),
 | 
					 | 
				
			||||||
            pressed_keys: HashSet::new(),
 | 
					            pressed_keys: HashSet::new(),
 | 
				
			||||||
            // Lots of bottom margin
 | 
					            // Lots of bottom margin
 | 
				
			||||||
            margins: Margins {
 | 
					            margins: Margins {
 | 
				
			||||||
 | 
				
			|||||||
@ -91,6 +91,11 @@ mod variants {
 | 
				
			|||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                let ret = glib_sys::g_variant_builder_end(builder);
 | 
					                let ret = glib_sys::g_variant_builder_end(builder);
 | 
				
			||||||
                glib_sys::g_variant_builder_unref(builder);
 | 
					                glib_sys::g_variant_builder_unref(builder);
 | 
				
			||||||
 | 
					                // HACK: This is to prevent C taking ownership
 | 
				
			||||||
 | 
					                // of "floating" Variants,
 | 
				
			||||||
 | 
					                // where Rust gets to keep a stale reference
 | 
				
			||||||
 | 
					                // and crash when trying to drop it.
 | 
				
			||||||
 | 
					                glib_sys::g_variant_ref_sink(ret);
 | 
				
			||||||
                glib::Variant::from_glib_full(ret)
 | 
					                glib::Variant::from_glib_full(ret)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -141,7 +146,7 @@ fn set_layout(kind: String, name: String) {
 | 
				
			|||||||
        .chain(inputs).collect();
 | 
					        .chain(inputs).collect();
 | 
				
			||||||
    settings.set_value(
 | 
					    settings.set_value(
 | 
				
			||||||
        "sources",
 | 
					        "sources",
 | 
				
			||||||
        &variants::ArrayPairString(inputs).to_variant()
 | 
					        &variants::ArrayPairString(inputs).to_variant(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    settings.apply();
 | 
					    settings.apply();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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