Commit c99efc43 authored by Dorota Czaplejewicz's avatar Dorota Czaplejewicz
Browse files

presses: Move press handling to Rust

This fixes some rendering things which would happen with multiple state-sharing buttons. It also removes some interfaces exposing rows, views, layouts, and buttons, bringing the code closer to removing them from the FFI entirely.
parent 3b6c1940
......@@ -37,6 +37,9 @@
#include "eek-gtk-keyboard.h"
#include "eekboard/eekboard-context-service.h"
#include "src/layout.h"
enum {
PROP_0,
PROP_LAST
......@@ -58,14 +61,7 @@ typedef struct _EekGtkKeyboardPrivate
G_DEFINE_TYPE_WITH_PRIVATE (EekGtkKeyboard, eek_gtk_keyboard, GTK_TYPE_DRAWING_AREA)
static void on_button_pressed (struct squeek_button *button, struct squeek_view *view,
EekGtkKeyboard *self);
static void on_button_released (const struct squeek_button *button,
struct squeek_view *view,
EekGtkKeyboard *self);
static void render_pressed_button (GtkWidget *widget, struct button_place *place);
static void render_locked_button (GtkWidget *widget,
struct button_place *place);
static void render_released_button (GtkWidget *widget,
const struct squeek_button *button);
......@@ -105,30 +101,10 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
gtk_widget_get_scale_factor (self));
}
// render the keyboard without any key activity (TODO: from a cached buffer)
eek_renderer_render_keyboard (priv->renderer, cr);
struct squeek_view *view = squeek_layout_get_current_view(priv->keyboard->layout);
/* redraw pressed key */
const GList *list = priv->keyboard->pressed_keys;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = squeek_view_find_key(
view, head->data
);
if (place.button)
render_pressed_button (self, &place);
}
/* redraw locked key */
list = priv->keyboard->locked_keys;
for (const GList *head = list; head; head = g_list_next (head)) {
struct button_place place = squeek_view_find_key(
view, (struct squeek_key *)head->data
);
if (place.button)
render_locked_button (self, &place);
}
// render only a few remaining changes
squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self));
return FALSE;
}
......@@ -152,84 +128,24 @@ static void depress(EekGtkKeyboard *self,
gdouble x, gdouble y, guint32 time)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
struct squeek_view *view = level_keyboard_current(priv->keyboard);
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
if (button) {
eek_keyboard_press_key(
priv->keyboard,
squeek_button_get_key(button),
time
);
on_button_pressed(button, view, self);
}
squeek_layout_depress(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
}
static void drag(EekGtkKeyboard *self,
gdouble x, gdouble y, guint32 time)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
struct squeek_view *view = level_keyboard_current(priv->keyboard);
struct squeek_button *button = eek_renderer_find_button_by_position (priv->renderer, view, x, y);
GList *list, *head;
list = g_list_copy(priv->keyboard->pressed_keys);
if (button) {
gboolean found = FALSE;
for (head = list; head; head = g_list_next (head)) {
struct squeek_key *key = head->data;
if (squeek_button_has_key(button, key)) {
found = TRUE;
} else {
eek_keyboard_release_key(priv->keyboard, key, time);
// The released handler proceeds to ignore this info...
// let's do this for consistency nevertheless
struct button_place place = squeek_view_find_key(view, key);
on_button_released(place.button, view, self);
}
}
g_list_free (list);
if (!found) {
eek_keyboard_press_key(
priv->keyboard,
squeek_button_get_key(button),
time
);
on_button_pressed(button, view, self);
}
} else {
for (head = list; head; head = g_list_next (head)) {
struct squeek_key *key = head->data;
eek_keyboard_release_key(priv->keyboard, key, time);
// The released handler proceeds to ignore this info...
// let's do this for consistency nevertheless
struct button_place place = squeek_view_find_key(view, key);
on_button_released(place.button, view, self);
}
g_list_free (list);
}
squeek_layout_drag(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
x, y, eek_renderer_get_transformation(priv->renderer), time, self);
}
static void release(EekGtkKeyboard *self, guint32 time)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
struct squeek_view *view = level_keyboard_current(priv->keyboard);
GList *list = g_list_copy(priv->keyboard->pressed_keys);
for (GList *head = list; head; head = g_list_next (head)) {
struct squeek_key *key = head->data;
eek_keyboard_release_key(priv->keyboard, key, time);
// The released handler proceeds to ignore this info...
// let's do this for consistency nevertheless
struct button_place place = squeek_view_find_key(view, key);
on_button_released(place.button, view, self);
}
g_list_free (list);
squeek_layout_release(priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard, time, self);
}
static gboolean
......@@ -304,15 +220,9 @@ eek_gtk_keyboard_real_unmap (GtkWidget *self)
eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self));
if (priv->keyboard) {
GList *head;
for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
/* Unlike other places where we call this, we don't call
on_button_released afterwards since we don't want to queue a
redraw. */
eek_keyboard_release_key(priv->keyboard, head->data,
gdk_event_get_time(NULL));
}
squeek_layout_release_all_only(
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
gdk_event_get_time(NULL));
}
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
......@@ -344,13 +254,9 @@ eek_gtk_keyboard_dispose (GObject *object)
}
if (priv->keyboard) {
GList *head;
for (head = priv->keyboard->pressed_keys; head; head = g_list_next (head)) {
eek_keyboard_release_key(priv->keyboard, head->data,
gdk_event_get_time(NULL));
}
squeek_layout_release_all_only(
priv->keyboard->layout, priv->keyboard->manager->virtual_keyboard,
gdk_event_get_time(NULL));
priv->keyboard = NULL;
}
......@@ -420,18 +326,17 @@ render_pressed_button (GtkWidget *widget,
cairo_region_destroy (region);
}
static void
render_locked_button (GtkWidget *widget, struct button_place *place)
void
eek_gtk_render_locked_button (EekGtkKeyboard *self, struct button_place place)
{
EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget);
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
GdkWindow *window = gtk_widget_get_window (widget);
GdkWindow *window = gtk_widget_get_window (GTK_WIDGET(self));
cairo_region_t *region = gdk_window_get_clip_region (window);
GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region);
cairo_t *cr = gdk_drawing_context_get_cairo_context (context);
eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE);
eek_renderer_render_button (priv->renderer, cr, &place, 1.0, TRUE);
gdk_window_end_draw_frame (window, context);
......@@ -459,9 +364,8 @@ render_released_button (GtkWidget *widget,
cairo_region_destroy (region);
}
static void
on_button_pressed (struct squeek_button *button,
struct squeek_view *view,
void
eek_gtk_on_button_pressed (struct button_place place,
EekGtkKeyboard *self)
{
EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self);
......@@ -470,10 +374,6 @@ on_button_pressed (struct squeek_button *button,
if (!priv->renderer)
return;
struct button_place place = {
.button = button,
.row = squeek_view_get_row(view, button),
};
if (!place.row) {
return;
}
......@@ -489,8 +389,8 @@ on_button_pressed (struct squeek_button *button,
#endif
}
static void
on_button_released (const struct squeek_button *button,
void
eek_gtk_on_button_released (const struct squeek_button *button,
struct squeek_view *view,
EekGtkKeyboard *self)
{
......
......@@ -28,7 +28,7 @@
#include <glib.h>
#include <gtk/gtk.h>
#include "eek-keyboard.h"
typedef struct _LevelKeyboard LevelKeyboard; // including causes weird bugs
G_BEGIN_DECLS
#define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type())
......
......@@ -38,65 +38,6 @@
#include "eek-keyboard.h"
void
eek_keyboard_set_key_locked (LevelKeyboard *keyboard,
struct squeek_key *key)
{
keyboard->locked_keys =
g_list_prepend (keyboard->locked_keys, key);
}
/// Unlock all locked keys.
/// All locked keys will unlock at the next keypress (should be called "stuck")
/// Returns the number of handled keys
/// TODO: may need to check key type in order to chain locks
/// before pressing an "emitting" key
static int unlock_keys(LevelKeyboard *keyboard) {
int handled = 0;
for (GList *head = keyboard->locked_keys; head; ) {
struct squeek_key *key = head->data;
GList *next = g_list_next (head);
keyboard->locked_keys =
g_list_remove_link (keyboard->locked_keys, head);
squeek_layout_set_state_from_press(keyboard->layout, keyboard, key);
g_list_free1 (head);
head = next;
handled++;
}
return handled;
}
static void
set_level_from_press (LevelKeyboard *keyboard, struct squeek_key *key)
{
// If the currently locked key was already handled in the unlock phase,
// then skip
if (unlock_keys(keyboard) == 0) {
squeek_layout_set_state_from_press(keyboard->layout, keyboard, key);
}
}
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp) {
keyboard->pressed_keys = g_list_prepend (keyboard->pressed_keys, key);
squeek_key_press(key, keyboard->manager->virtual_keyboard, KEY_PRESS, timestamp);
}
void eek_keyboard_release_key(LevelKeyboard *keyboard,
struct squeek_key *key,
guint32 timestamp) {
for (GList *head = keyboard->pressed_keys; head; head = g_list_next (head)) {
if (squeek_key_equal(head->data, key)) {
keyboard->pressed_keys = g_list_remove_link (keyboard->pressed_keys, head);
g_list_free1 (head);
break;
}
}
set_level_from_press (keyboard, key);
squeek_key_press(key, keyboard->manager->virtual_keyboard, KEY_RELEASE, timestamp);
}
void level_keyboard_deinit(LevelKeyboard *self) {
squeek_layout_free(self->layout);
}
......
......@@ -35,29 +35,17 @@ G_BEGIN_DECLS
/// Keyboard state holder
struct _LevelKeyboard {
struct squeek_layout *layout;
struct squeek_layout *layout; // owned
struct xkb_keymap *keymap;
int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd
GList *pressed_keys; // struct squeek_key*
GList *locked_keys; // struct squeek_key*
guint id; // as a key to layout choices
EekboardContextService *manager; // unowned reference
};
typedef struct _LevelKeyboard LevelKeyboard;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
void eek_keyboard_press_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
void eek_keyboard_release_key(LevelKeyboard *keyboard, struct squeek_key *key, guint32 timestamp);
gchar * eek_keyboard_get_keymap
(LevelKeyboard *keyboard);
......
......@@ -24,6 +24,7 @@
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "eek-keyboard.h"
#include "eek-renderer.h"
enum {
......@@ -454,8 +455,8 @@ eek_renderer_real_render_button (EekRenderer *self,
struct squeek_key *key = squeek_button_get_key(place->button);
render_button (
self, cr, place,
squeek_key_is_pressed(key),
squeek_key_is_locked (key)
squeek_key_is_pressed(key) != 0,
squeek_key_is_locked (key) != 0
);
cairo_restore (cr);
}
......@@ -959,29 +960,16 @@ eek_are_bounds_inside (EekBounds bounds, EekPoint point, EekPoint origin, int32_
return 0;
}
/**
* eek_renderer_find_key_by_position:
* @renderer: The renderer normally used to render the key
* @x: The horizontal widget coordinate of the position to test for a key
* @y: The vertical widget coordinate of the position to test for a key
*
* Return value: the key located at the position x, y in widget coordinates, or
* NULL if no key can be found at that location
**/
struct squeek_button *
eek_renderer_find_button_by_position (EekRenderer *renderer,
struct squeek_view *view,
gdouble x,
gdouble y)
{
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer) {
struct transformation failed = {0};
g_return_val_if_fail (EEK_IS_RENDERER(renderer), failed);
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
/* Transform from widget coordinates to keyboard coordinates */
EekPoint point = {
.x = (x - priv->origin_x)/priv->scale,
.y = (y - priv->origin_y)/priv->scale,
struct transformation ret = {
.origin_x = priv->origin_x,
.origin_y = priv->origin_y,
.scale = priv->scale,
};
return squeek_view_find_button_by_position(view, point);
return ret;
}
......@@ -24,8 +24,8 @@
#include <gtk/gtk.h>
#include <pango/pangocairo.h>
#include "eek-keyboard.h"
#include "eek-types.h"
#include "src/layout.h"
G_BEGIN_DECLS
......@@ -102,14 +102,14 @@ void eek_renderer_get_foreground_color
EekColor *color);
void eek_renderer_set_border_width (EekRenderer *renderer,
gdouble border_width);
struct squeek_button *eek_renderer_find_button_by_position(EekRenderer *renderer, struct squeek_view *view,
gdouble x,
gdouble y);
void eek_renderer_apply_transformation_for_button
(EekRenderer *renderer,
cairo_t *cr, struct button_place *place,
gdouble scale,
gboolean rotate);
struct transformation
eek_renderer_get_transformation (EekRenderer *renderer);
G_END_DECLS
#endif /* EEK_RENDERER_H */
......@@ -112,5 +112,10 @@ EekColor *eek_color_new (gdouble red,
EekColor *eek_color_copy (const EekColor *color);
void eek_color_free (EekColor *color);
struct transformation {
gdouble origin_x;
gdouble origin_y;
gdouble scale;
};
G_END_DECLS
#endif /* EEK_TYPES_H */
......@@ -14,7 +14,7 @@ use std::vec::Vec;
use xkbcommon::xkb;
use ::keyboard::{
KeyState,
KeyState, PressType,
generate_keymap, generate_keycodes, FormattingError
};
use ::resources;
......@@ -346,7 +346,7 @@ impl Layout {
(
name.into(),
KeyState {
pressed: false,
pressed: PressType::Released,
locked: false,
keycodes,
action,
......@@ -407,6 +407,8 @@ impl Layout {
CString::new(keymap_str)
.expect("Invalid keymap string generated")
},
locked_keys: HashSet::new(),
pressed_keys: HashSet::new(),
})
}
}
......
......@@ -9,13 +9,4 @@ struct squeek_key;
uint32_t squeek_key_is_pressed(struct squeek_key *key);
uint32_t squeek_key_is_locked(struct squeek_key *key);
void squeek_key_set_locked(struct squeek_key *key, uint32_t pressed);
uint32_t squeek_key_equal(struct squeek_key* key, struct squeek_key* key1);
enum key_press {
KEY_RELEASE = 0,
KEY_PRESS = 1,
};
void squeek_key_press(struct squeek_key *key, struct zwp_virtual_keyboard_v1*, enum key_press press, uint32_t timestamp);
#endif
/*! State of the emulated keyboard and keys */
/*! State of the emulated keyboard and keys.
* Regards the keyboard as if it was composed of switches. */
use std::collections::HashMap;
use std::fmt;
use std::io;
use std::rc::Rc;
use std::string::FromUtf8Error;
use ::action::Action;
......@@ -17,34 +17,10 @@ pub mod c {
use super::*;
use ::util::c;
use std::os::raw::c_void;
pub type CKeyState = c::Wrapped<KeyState>;
#[repr(transparent)]
pub struct ZwpVirtualKeyboardV1(*const c_void);
#[no_mangle]
extern "C" {
/// Checks if point falls within bounds,
/// which are relative to origin and rotated by angle (I think)
pub fn eek_virtual_keyboard_v1_key(
virtual_keyboard: *mut ZwpVirtualKeyboardV1,
timestamp: u32,
keycode: u32,
press: u32,
);
}
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
/// Compares pointers to the data
#[no_mangle]
pub extern "C"
fn squeek_key_equal(key: CKeyState, key2: CKeyState) -> u32 {
return Rc::ptr_eq(&key.clone_ref(), &key2.clone_ref()) as u32
}
#[no_mangle]
pub extern "C"
fn squeek_key_is_pressed(key: CKeyState) -> u32 {
......@@ -57,59 +33,17 @@ pub mod c {
fn squeek_key_is_locked(key: CKeyState) -> u32 {
return key.clone_owned().locked as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
let key = key.clone_ref();
let mut key = key.borrow_mut();
key.locked = locked != 0;
}
#[no_mangle]
pub extern "C"
fn squeek_key_press(
key: CKeyState,
virtual_keyboard: *mut ZwpVirtualKeyboardV1,
press: u32,
timestamp: u32,
) {
let key = key.clone_ref();
let mut key = key.borrow_mut();
key.pressed = press != 0;
}
let keycodes_count = key.keycodes.len();
for keycode in key.keycodes.iter() {
let keycode = keycode - 8;
match (key.pressed, keycodes_count) {
// Pressing a key made out of a single keycode is simple:
// press on press, release on release.
(_, 1) => unsafe {
eek_virtual_keyboard_v1_key(
virtual_keyboard, timestamp, keycode, press
);
},
// A key made of multiple keycodes
// has to submit them one after the other
(true, _) => unsafe {
eek_virtual_keyboard_v1_key(
virtual_keyboard, timestamp, keycode, 1
);
eek_virtual_keyboard_v1_key(
virtual_keyboard, timestamp, keycode, 0
);
},
// Design choice here: submit multiple all at press time
// and do nothing at release time
(false, _) => {},
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum PressType {
Released = 0,
Pressed = 1,
}
#[derive(Debug, Clone)]
pub struct KeyState {
pub pressed: bool,
pub pressed: PressType,
pub locked: bool,
/// A cache of raw keycodes derived from Action::Sumbit given a keymap
pub keycodes: Vec<u32>,
......@@ -245,7 +179,7 @@ mod tests {
},
keycodes: vec!(9, 10),
locked: false,
pressed: false,
pressed: PressType::Released,
},
}).unwrap();
......
......@@ -4,30 +4,31 @@
#include <inttypes.h>
#include <glib.h>
#include "eek/eek-element.h"
#include "eek/eek-gtk-keyboard.h"
#include "eek/eek-types.h"
#include "src/keyboard.h"
#include "virtual-keyboard-unstable-v1-client-protocol.h"
struct squeek_button;
struct squeek_row;
struct squeek_view;
struct squeek_layout;
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;