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());
|
||||||
|
|||||||
@ -17,13 +17,18 @@
|
|||||||
* 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