Merge branch 'modifiers' into 'master'
Add simple modifiers support See merge request Librem5/squeekboard!306
This commit is contained in:
		@ -99,8 +99,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
 | 
				
			|||||||
        eek_renderer_set_scale_factor (priv->renderer,
 | 
					        eek_renderer_set_scale_factor (priv->renderer,
 | 
				
			||||||
                                       gtk_widget_get_scale_factor (self));
 | 
					                                       gtk_widget_get_scale_factor (self));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    eek_renderer_render_keyboard (priv->renderer, priv->submission, cr);
 | 
				
			||||||
    eek_renderer_render_keyboard (priv->renderer, cr);
 | 
					 | 
				
			||||||
    return FALSE;
 | 
					    return FALSE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -214,8 +214,10 @@ render_button_label (cairo_t     *cr,
 | 
				
			|||||||
    g_object_unref (layout);
 | 
					    g_object_unref (layout);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: Pass just the active modifiers instead of entire submission
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
eek_renderer_render_keyboard (EekRenderer *self,
 | 
					eek_renderer_render_keyboard (EekRenderer *self,
 | 
				
			||||||
 | 
					                              struct submission *submission,
 | 
				
			||||||
                                   cairo_t     *cr)
 | 
					                                   cairo_t     *cr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
					    EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
 | 
				
			||||||
@ -235,7 +237,7 @@ eek_renderer_render_keyboard (EekRenderer *self,
 | 
				
			|||||||
    cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale);
 | 
					    cairo_scale (cr, priv->widget_to_layout.scale, priv->widget_to_layout.scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    squeek_draw_layout_base_view(priv->keyboard->layout, self, cr);
 | 
					    squeek_draw_layout_base_view(priv->keyboard->layout, self, cr);
 | 
				
			||||||
    squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr);
 | 
					    squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr, submission);
 | 
				
			||||||
    cairo_restore (cr);
 | 
					    cairo_restore (cr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
#include <pango/pangocairo.h>
 | 
					#include <pango/pangocairo.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek-types.h"
 | 
					#include "eek-types.h"
 | 
				
			||||||
 | 
					#include "src/submission.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_BEGIN_DECLS
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -59,7 +60,7 @@ cairo_surface_t *eek_renderer_get_icon_surface(const gchar     *icon_name,
 | 
				
			|||||||
                                                gint             size,
 | 
					                                                gint             size,
 | 
				
			||||||
                                                gint             scale);
 | 
					                                                gint             scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void             eek_renderer_render_keyboard  (EekRenderer     *renderer,
 | 
					void             eek_renderer_render_keyboard  (EekRenderer     *renderer, struct submission *submission,
 | 
				
			||||||
                                                cairo_t         *cr);
 | 
					                                                cairo_t         *cr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct transformation
 | 
					struct transformation
 | 
				
			||||||
 | 
				
			|||||||
@ -10,8 +10,11 @@ pub struct KeySym(pub String);
 | 
				
			|||||||
type View = String;
 | 
					type View = String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Use to send modified keypresses
 | 
					/// Use to send modified keypresses
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
pub enum Modifier {
 | 
					pub enum Modifier {
 | 
				
			||||||
 | 
					    /// Control and Alt are the only modifiers
 | 
				
			||||||
 | 
					    /// which doesn't interfere with levels,
 | 
				
			||||||
 | 
					    /// so it's simple to implement as levels are deprecated in squeekboard.
 | 
				
			||||||
    Control,
 | 
					    Control,
 | 
				
			||||||
    Alt,
 | 
					    Alt,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -27,8 +30,8 @@ pub enum Action {
 | 
				
			|||||||
        /// When unlocked by pressing it or emitting a key
 | 
					        /// When unlocked by pressing it or emitting a key
 | 
				
			||||||
        unlock: View,
 | 
					        unlock: View,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /// Set this modifier TODO: release?
 | 
					    /// Hold this modifier for as long as the button is pressed
 | 
				
			||||||
    SetModifier(Modifier),
 | 
					    ApplyModifier(Modifier),
 | 
				
			||||||
    /// Submit some text
 | 
					    /// Submit some text
 | 
				
			||||||
    Submit {
 | 
					    Submit {
 | 
				
			||||||
        /// Text to submit with input-method.
 | 
					        /// Text to submit with input-method.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										65
									
								
								src/data.rs
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								src/data.rs
									
									
									
									
									
								
							@ -240,14 +240,20 @@ type ButtonIds = String;
 | 
				
			|||||||
#[derive(Debug, Default, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Default, Deserialize, PartialEq)]
 | 
				
			||||||
#[serde(deny_unknown_fields)]
 | 
					#[serde(deny_unknown_fields)]
 | 
				
			||||||
struct ButtonMeta {
 | 
					struct ButtonMeta {
 | 
				
			||||||
    /// Special action to perform on activation. Conflicts with keysym, text.
 | 
					    // TODO: structure (action, keysym, text, modifier) as an enum
 | 
				
			||||||
 | 
					    // to detect conflicts and missing values at compile time
 | 
				
			||||||
 | 
					    /// Special action to perform on activation.
 | 
				
			||||||
 | 
					    /// Conflicts with keysym, text, modifier.
 | 
				
			||||||
    action: Option<Action>,
 | 
					    action: Option<Action>,
 | 
				
			||||||
    /// The name of the XKB keysym to emit on activation.
 | 
					    /// The name of the XKB keysym to emit on activation.
 | 
				
			||||||
    /// Conflicts with action, text
 | 
					    /// Conflicts with action, text, modifier.
 | 
				
			||||||
    keysym: Option<String>,
 | 
					    keysym: Option<String>,
 | 
				
			||||||
    /// The text to submit on activation. Will be derived from ID if not present
 | 
					    /// The text to submit on activation. Will be derived from ID if not present
 | 
				
			||||||
    /// Conflicts with action, keysym
 | 
					    /// Conflicts with action, keysym, modifier.
 | 
				
			||||||
    text: Option<String>,
 | 
					    text: Option<String>,
 | 
				
			||||||
 | 
					    /// The modifier to apply while the key is locked
 | 
				
			||||||
 | 
					    /// Conflicts with action, keysym, text
 | 
				
			||||||
 | 
					    modifier: Option<Modifier>,
 | 
				
			||||||
    /// If not present, will be derived from text or the button ID
 | 
					    /// If not present, will be derived from text or the button ID
 | 
				
			||||||
    label: Option<String>,
 | 
					    label: Option<String>,
 | 
				
			||||||
    /// Conflicts with label
 | 
					    /// Conflicts with label
 | 
				
			||||||
@ -270,6 +276,20 @@ enum Action {
 | 
				
			|||||||
    Erase,
 | 
					    Erase,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Deserialize)]
 | 
				
			||||||
 | 
					#[serde(deny_unknown_fields)]
 | 
				
			||||||
 | 
					enum Modifier {
 | 
				
			||||||
 | 
					    Control,
 | 
				
			||||||
 | 
					    Shift,
 | 
				
			||||||
 | 
					    Lock,
 | 
				
			||||||
 | 
					    #[serde(alias="Mod1")]
 | 
				
			||||||
 | 
					    Alt,
 | 
				
			||||||
 | 
					    Mod2,
 | 
				
			||||||
 | 
					    Mod3,
 | 
				
			||||||
 | 
					    Mod4,
 | 
				
			||||||
 | 
					    Mod5,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
 | 
					#[derive(Debug, Clone, Deserialize, PartialEq)]
 | 
				
			||||||
#[serde(deny_unknown_fields)]
 | 
					#[serde(deny_unknown_fields)]
 | 
				
			||||||
struct Outline {
 | 
					struct Outline {
 | 
				
			||||||
@ -510,22 +530,27 @@ fn create_action<H: logging::Handler>(
 | 
				
			|||||||
        Action(Action),
 | 
					        Action(Action),
 | 
				
			||||||
        Text(String),
 | 
					        Text(String),
 | 
				
			||||||
        Keysym(String),
 | 
					        Keysym(String),
 | 
				
			||||||
 | 
					        Modifier(Modifier),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let submission = match (
 | 
					    let submission = match (
 | 
				
			||||||
        &symbol_meta.action,
 | 
					        &symbol_meta.action,
 | 
				
			||||||
        &symbol_meta.keysym,
 | 
					        &symbol_meta.keysym,
 | 
				
			||||||
        &symbol_meta.text
 | 
					        &symbol_meta.text,
 | 
				
			||||||
 | 
					        &symbol_meta.modifier,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        (Some(action), None, None) => SubmitData::Action(action.clone()),
 | 
					        (Some(action), None, None, None) => SubmitData::Action(action.clone()),
 | 
				
			||||||
        (None, Some(keysym), None) => SubmitData::Keysym(keysym.clone()),
 | 
					        (None, Some(keysym), None, None) => SubmitData::Keysym(keysym.clone()),
 | 
				
			||||||
        (None, None, Some(text)) => SubmitData::Text(text.clone()),
 | 
					        (None, None, Some(text), None) => SubmitData::Text(text.clone()),
 | 
				
			||||||
        (None, None, None) => SubmitData::Text(name.into()),
 | 
					        (None, None, None, Some(modifier)) => {
 | 
				
			||||||
 | 
					            SubmitData::Modifier(modifier.clone())
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        (None, None, None, None) => SubmitData::Text(name.into()),
 | 
				
			||||||
        _ => {
 | 
					        _ => {
 | 
				
			||||||
            warning_handler.handle(
 | 
					            warning_handler.handle(
 | 
				
			||||||
                logging::Level::Warning,
 | 
					                logging::Level::Warning,
 | 
				
			||||||
                &format!(
 | 
					                &format!(
 | 
				
			||||||
                    "Button {} has more than one of (action, keysym, text)",
 | 
					                    "Button {} has more than one of (action, keysym, text, modifier)",
 | 
				
			||||||
                    name,
 | 
					                    name,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
@ -614,6 +639,26 @@ fn create_action<H: logging::Handler>(
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
            }).collect(),
 | 
					            }).collect(),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        SubmitData::Modifier(modifier) => match modifier {
 | 
				
			||||||
 | 
					            Modifier::Control => action::Action::ApplyModifier(
 | 
				
			||||||
 | 
					                action::Modifier::Control,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Modifier::Alt => action::Action::ApplyModifier(
 | 
				
			||||||
 | 
					                action::Modifier::Alt,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            unsupported_modifier => {
 | 
				
			||||||
 | 
					                warning_handler.handle(
 | 
				
			||||||
 | 
					                    logging::Level::Bug,
 | 
				
			||||||
 | 
					                    &format!(
 | 
				
			||||||
 | 
					                        "Modifier {:?} unsupported", unsupported_modifier,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                action::Action::Submit {
 | 
				
			||||||
 | 
					                    text: None,
 | 
				
			||||||
 | 
					                    keys: Vec::new(),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -711,6 +756,7 @@ mod tests {
 | 
				
			|||||||
                        keysym: None,
 | 
					                        keysym: None,
 | 
				
			||||||
                        action: None,
 | 
					                        action: None,
 | 
				
			||||||
                        text: None,
 | 
					                        text: None,
 | 
				
			||||||
 | 
					                        modifier: None,
 | 
				
			||||||
                        label: Some("test".into()),
 | 
					                        label: Some("test".into()),
 | 
				
			||||||
                        outline: None,
 | 
					                        outline: None,
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -852,6 +898,7 @@ mod tests {
 | 
				
			|||||||
                        keysym: None,
 | 
					                        keysym: None,
 | 
				
			||||||
                        text: None,
 | 
					                        text: None,
 | 
				
			||||||
                        action: None,
 | 
					                        action: None,
 | 
				
			||||||
 | 
					                        modifier: None,
 | 
				
			||||||
                        label: Some("test".into()),
 | 
					                        label: Some("test".into()),
 | 
				
			||||||
                        outline: None,
 | 
					                        outline: None,
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,9 +3,11 @@
 | 
				
			|||||||
use cairo;
 | 
					use cairo;
 | 
				
			||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use ::action::Action;
 | 
				
			||||||
use ::keyboard;
 | 
					use ::keyboard;
 | 
				
			||||||
use ::layout::{ Button, Layout };
 | 
					use ::layout::{ Button, Layout };
 | 
				
			||||||
use ::layout::c::{ EekGtkKeyboard, Point };
 | 
					use ::layout::c::{ EekGtkKeyboard, Point };
 | 
				
			||||||
 | 
					use ::submission::Submission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use glib::translate::FromGlibPtrNone;
 | 
					use glib::translate::FromGlibPtrNone;
 | 
				
			||||||
use gtk::WidgetExt;
 | 
					use gtk::WidgetExt;
 | 
				
			||||||
@ -44,13 +46,21 @@ mod c {
 | 
				
			|||||||
        layout: *mut Layout,
 | 
					        layout: *mut Layout,
 | 
				
			||||||
        renderer: EekRenderer,
 | 
					        renderer: EekRenderer,
 | 
				
			||||||
        cr: *mut cairo_sys::cairo_t,
 | 
					        cr: *mut cairo_sys::cairo_t,
 | 
				
			||||||
 | 
					        submission: *const Submission,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let layout = unsafe { &mut *layout };
 | 
					        let layout = unsafe { &mut *layout };
 | 
				
			||||||
 | 
					        let submission = unsafe { &*submission };
 | 
				
			||||||
        let cr = unsafe { cairo::Context::from_raw_none(cr) };
 | 
					        let cr = unsafe { cairo::Context::from_raw_none(cr) };
 | 
				
			||||||
 | 
					        let active_modifiers = submission.get_active_modifiers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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();
 | 
				
			||||||
            let locked = state.action.is_active(&layout.current_view);
 | 
					            let active_mod = match &state.action {
 | 
				
			||||||
 | 
					                Action::ApplyModifier(m) => active_modifiers.contains(m),
 | 
				
			||||||
 | 
					                _ => false,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            let locked = state.action.is_active(&layout.current_view)
 | 
				
			||||||
 | 
					                | active_mod;
 | 
				
			||||||
            if state.pressed == keyboard::PressType::Pressed || locked {
 | 
					            if state.pressed == keyboard::PressType::Pressed || locked {
 | 
				
			||||||
                render_button_at_position(
 | 
					                render_button_at_position(
 | 
				
			||||||
                    renderer, &cr,
 | 
					                    renderer, &cr,
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,24 @@ pub enum PressType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub type KeyCode = u32;
 | 
					pub type KeyCode = u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bitflags!{
 | 
				
			||||||
 | 
					    /// Map to `virtual_keyboard.modifiers` modifiers values
 | 
				
			||||||
 | 
					    /// From https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Keyboard_State
 | 
				
			||||||
 | 
					    pub struct Modifiers: u8 {
 | 
				
			||||||
 | 
					        const SHIFT = 0x1;
 | 
				
			||||||
 | 
					        const LOCK = 0x2;
 | 
				
			||||||
 | 
					        const CONTROL = 0x4;
 | 
				
			||||||
 | 
					        /// Alt
 | 
				
			||||||
 | 
					        const MOD1 = 0x8;
 | 
				
			||||||
 | 
					        const MOD2 = 0x10;
 | 
				
			||||||
 | 
					        const MOD3 = 0x20;
 | 
				
			||||||
 | 
					        /// Meta
 | 
				
			||||||
 | 
					        const MOD4 = 0x40;
 | 
				
			||||||
 | 
					        /// AltGr
 | 
				
			||||||
 | 
					        const MOD5 = 0x80;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// When the submitted actions of keys need to be tracked,
 | 
					/// When the submitted actions of keys need to be tracked,
 | 
				
			||||||
/// they need a stable, comparable ID
 | 
					/// they need a stable, comparable ID
 | 
				
			||||||
#[derive(PartialEq)]
 | 
					#[derive(PartialEq)]
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@
 | 
				
			|||||||
#include "eek/eek-gtk-keyboard.h"
 | 
					#include "eek/eek-gtk-keyboard.h"
 | 
				
			||||||
#include "eek/eek-renderer.h"
 | 
					#include "eek/eek-renderer.h"
 | 
				
			||||||
#include "eek/eek-types.h"
 | 
					#include "eek/eek-types.h"
 | 
				
			||||||
 | 
					#include "src/submission.h"
 | 
				
			||||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
					#include "virtual-keyboard-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum squeek_arrangement_kind {
 | 
					enum squeek_arrangement_kind {
 | 
				
			||||||
@ -53,6 +54,6 @@ void squeek_layout_drag(struct squeek_layout *layout,
 | 
				
			|||||||
                        struct transformation widget_to_layout,
 | 
					                        struct transformation widget_to_layout,
 | 
				
			||||||
                        uint32_t timestamp, EekboardContextService *manager,
 | 
					                        uint32_t timestamp, EekboardContextService *manager,
 | 
				
			||||||
                        EekGtkKeyboard *ui_keyboard);
 | 
					                        EekGtkKeyboard *ui_keyboard);
 | 
				
			||||||
void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
					void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr, struct submission *submission);
 | 
				
			||||||
void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
					void squeek_draw_layout_base_view(struct squeek_layout *layout, EekRenderer* renderer, cairo_t     *cr);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -990,6 +990,18 @@ mod seat {
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    .apply()
 | 
					                    .apply()
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            Action::ApplyModifier(modifier) => {
 | 
				
			||||||
 | 
					                // FIXME: key id is unneeded with stateless locks
 | 
				
			||||||
 | 
					                let key_id = KeyState::get_id(rckey);
 | 
				
			||||||
 | 
					                let gets_locked = !submission.is_modifier_active(modifier.clone());
 | 
				
			||||||
 | 
					                match gets_locked {
 | 
				
			||||||
 | 
					                    true => submission.handle_add_modifier(
 | 
				
			||||||
 | 
					                        key_id,
 | 
				
			||||||
 | 
					                        modifier, time,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    false => submission.handle_drop_modifier(key_id, time),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            // only show when UI is present
 | 
					            // only show when UI is present
 | 
				
			||||||
            Action::ShowPreferences => if let Some(ui) = &ui {
 | 
					            Action::ShowPreferences => if let Some(ui) = &ui {
 | 
				
			||||||
                // only show when layout manager is available
 | 
					                // only show when layout manager is available
 | 
				
			||||||
@ -1016,10 +1028,6 @@ mod seat {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            Action::SetModifier(_) => log_print!(
 | 
					 | 
				
			||||||
                logging::Level::Bug,
 | 
					 | 
				
			||||||
                "Modifiers unsupported",
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let pointer = ::util::Pointer(rckey.clone());
 | 
					        let pointer = ::util::Pointer(rckey.clone());
 | 
				
			||||||
 | 
				
			|||||||
@ -16,14 +16,19 @@
 | 
				
			|||||||
 * 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 std::collections::HashSet;
 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
 
 | 
					use ::action::Modifier;
 | 
				
			||||||
use ::imservice;
 | 
					use ::imservice;
 | 
				
			||||||
use ::imservice::IMService;
 | 
					use ::imservice::IMService;
 | 
				
			||||||
use ::keyboard::{ KeyCode, KeyStateId, PressType };
 | 
					use ::keyboard::{ KeyCode, KeyStateId, Modifiers, PressType };
 | 
				
			||||||
 | 
					use ::util::vec_remove;
 | 
				
			||||||
use ::vkeyboard::VirtualKeyboard;
 | 
					use ::vkeyboard::VirtualKeyboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// traits
 | 
				
			||||||
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
@ -60,6 +65,7 @@ pub mod c {
 | 
				
			|||||||
        Box::<Submission>::into_raw(Box::new(
 | 
					        Box::<Submission>::into_raw(Box::new(
 | 
				
			||||||
            Submission {
 | 
					            Submission {
 | 
				
			||||||
                imservice,
 | 
					                imservice,
 | 
				
			||||||
 | 
					                modifiers_active: Vec::new(),
 | 
				
			||||||
                virtual_keyboard: VirtualKeyboard(vk),
 | 
					                virtual_keyboard: VirtualKeyboard(vk),
 | 
				
			||||||
                pressed: Vec::new(),
 | 
					                pressed: Vec::new(),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -106,6 +112,7 @@ enum SubmittedAction {
 | 
				
			|||||||
pub struct Submission {
 | 
					pub struct Submission {
 | 
				
			||||||
    imservice: Option<Box<IMService>>,
 | 
					    imservice: Option<Box<IMService>>,
 | 
				
			||||||
    virtual_keyboard: VirtualKeyboard,
 | 
					    virtual_keyboard: VirtualKeyboard,
 | 
				
			||||||
 | 
					    modifiers_active: Vec<(KeyStateId, Modifier)>,
 | 
				
			||||||
    pressed: Vec<(KeyStateId, SubmittedAction)>,
 | 
					    pressed: Vec<(KeyStateId, SubmittedAction)>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,8 +132,10 @@ impl Submission {
 | 
				
			|||||||
        keycodes: &Vec<KeyCode>,
 | 
					        keycodes: &Vec<KeyCode>,
 | 
				
			||||||
        time: Timestamp,
 | 
					        time: Timestamp,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let was_committed_as_text = match &mut self.imservice {
 | 
					        let mods_are_on = !self.modifiers_active.is_empty();
 | 
				
			||||||
            Some(imservice) => {
 | 
					
 | 
				
			||||||
 | 
					        let was_committed_as_text = match (&mut self.imservice, mods_are_on) {
 | 
				
			||||||
 | 
					            (Some(imservice), false) => {
 | 
				
			||||||
                enum Outcome {
 | 
					                enum Outcome {
 | 
				
			||||||
                    Submitted(Result<(), imservice::SubmitError>),
 | 
					                    Submitted(Result<(), imservice::SubmitError>),
 | 
				
			||||||
                    NotSubmitted,
 | 
					                    NotSubmitted,
 | 
				
			||||||
@ -157,7 +166,7 @@ impl Submission {
 | 
				
			|||||||
                    Outcome::NotSubmitted => false,
 | 
					                    Outcome::NotSubmitted => false,
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            _ => false,
 | 
					            (_, _) => false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let submit_action = match was_committed_as_text {
 | 
					        let submit_action = match was_committed_as_text {
 | 
				
			||||||
@ -194,4 +203,44 @@ impl Submission {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    pub fn handle_add_modifier(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        key_id: KeyStateId,
 | 
				
			||||||
 | 
					        modifier: Modifier, _time: Timestamp,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        self.modifiers_active.push((key_id, modifier));
 | 
				
			||||||
 | 
					        self.update_modifiers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn handle_drop_modifier(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        key_id: KeyStateId,
 | 
				
			||||||
 | 
					        _time: Timestamp,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        vec_remove(&mut self.modifiers_active, |(id, _)| *id == key_id);
 | 
				
			||||||
 | 
					        self.update_modifiers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn update_modifiers(&mut self) {
 | 
				
			||||||
 | 
					        let raw_modifiers = self.modifiers_active.iter()
 | 
				
			||||||
 | 
					            .map(|(_id, m)| match m {
 | 
				
			||||||
 | 
					                Modifier::Control => Modifiers::CONTROL,
 | 
				
			||||||
 | 
					                Modifier::Alt => Modifiers::MOD1,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .fold(Modifiers::empty(), |m, n| m | n);
 | 
				
			||||||
 | 
					        self.virtual_keyboard.set_modifiers_state(raw_modifiers);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn is_modifier_active(&self, modifier: Modifier) -> bool {
 | 
				
			||||||
 | 
					        self.modifiers_active.iter()
 | 
				
			||||||
 | 
					            .position(|(_id, m)| *m == modifier)
 | 
				
			||||||
 | 
					            .is_some()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn get_active_modifiers(&self) -> HashSet<Modifier> {
 | 
				
			||||||
 | 
					        HashSet::from_iter(
 | 
				
			||||||
 | 
					            self.modifiers_active.iter().map(|(_id, m)| m.clone())
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -195,6 +195,12 @@ pub trait WarningHandler {
 | 
				
			|||||||
    fn handle(&mut self, warning: &str);
 | 
					    fn handle(&mut self, warning: &str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Removes the first matcing item
 | 
				
			||||||
 | 
					pub fn vec_remove<T, F: FnMut(&T) -> bool>(v: &mut Vec<T>, pred: F) -> Option<T> {
 | 
				
			||||||
 | 
					    let idx = v.iter().position(pred);
 | 
				
			||||||
 | 
					    idx.map(|idx| v.remove(idx))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/*! Managing the events belonging to virtual-keyboard interface. */
 | 
					/*! Managing the events belonging to virtual-keyboard interface. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::keyboard::{ KeyCode, PressType };
 | 
					use ::keyboard::{ KeyCode, Modifiers, PressType };
 | 
				
			||||||
use ::layout::c::LevelKeyboard;
 | 
					use ::layout::c::LevelKeyboard;
 | 
				
			||||||
use ::submission::Timestamp;
 | 
					use ::submission::Timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -26,6 +26,11 @@ pub mod c {
 | 
				
			|||||||
            virtual_keyboard: ZwpVirtualKeyboardV1,
 | 
					            virtual_keyboard: ZwpVirtualKeyboardV1,
 | 
				
			||||||
            keyboard: LevelKeyboard,
 | 
					            keyboard: LevelKeyboard,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        pub fn eek_virtual_keyboard_set_modifiers(
 | 
				
			||||||
 | 
					            virtual_keyboard: ZwpVirtualKeyboardV1,
 | 
				
			||||||
 | 
					            modifiers: u32,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,7 +38,7 @@ pub mod c {
 | 
				
			|||||||
pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1);
 | 
					pub struct VirtualKeyboard(pub c::ZwpVirtualKeyboardV1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl VirtualKeyboard {
 | 
					impl VirtualKeyboard {
 | 
				
			||||||
    // TODO: split out keyboard state management
 | 
					    // TODO: error out if keymap not set
 | 
				
			||||||
    pub fn switch(
 | 
					    pub fn switch(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        keycodes: &Vec<KeyCode>,
 | 
					        keycodes: &Vec<KeyCode>,
 | 
				
			||||||
@ -68,12 +73,16 @@ impl VirtualKeyboard {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    pub fn set_modifiers_state(&self, modifiers: Modifiers) {
 | 
				
			||||||
 | 
					        let modifiers = modifiers.bits() as u32;
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            c::eek_virtual_keyboard_set_modifiers(self.0, modifiers);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    pub fn update_keymap(&self, keyboard: LevelKeyboard) {
 | 
					    pub fn update_keymap(&self, keyboard: LevelKeyboard) {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            c::eek_virtual_keyboard_update_keymap(
 | 
					            c::eek_virtual_keyboard_update_keymap(self.0, keyboard);
 | 
				
			||||||
                self.0,
 | 
					 | 
				
			||||||
                keyboard,
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,12 @@ void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virt
 | 
				
			|||||||
        keyboard->keymap_fd, keyboard->keymap_len);
 | 
					        keyboard->keymap_fd, keyboard->keymap_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eek_virtual_keyboard_set_modifiers(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t mods_depressed) {
 | 
				
			||||||
 | 
					    zwp_virtual_keyboard_v1_modifiers(zwp_virtual_keyboard_v1,
 | 
				
			||||||
 | 
					                                      mods_depressed, 0, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int squeek_output_add_listener(struct wl_output *wl_output,
 | 
					int squeek_output_add_listener(struct wl_output *wl_output,
 | 
				
			||||||
                                const struct wl_output_listener *listener, void *data) {
 | 
					                                const struct wl_output_listener *listener, void *data) {
 | 
				
			||||||
    return wl_output_add_listener(wl_output, listener, data);
 | 
					    return wl_output_add_listener(wl_output, listener, data);
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user