Improve key-repeat behavior.
This commit is contained in:
@ -77,6 +77,8 @@ static void on_symbol_index_changed (EekKeyboard *keyboard,
|
||||
gpointer user_data);
|
||||
static void render_pressed_key (GtkWidget *widget,
|
||||
EekKey *key);
|
||||
static void render_released_key (GtkWidget *widget,
|
||||
EekKey *key);
|
||||
|
||||
static void
|
||||
eek_gtk_keyboard_real_realize (GtkWidget *self)
|
||||
@ -181,19 +183,6 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self,
|
||||
size_allocate (self, allocation);
|
||||
}
|
||||
|
||||
static void
|
||||
set_dragged_key (EekGtkKeyboard *keyboard, EekKey *key)
|
||||
{
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
|
||||
if (priv->dragged_key && priv->dragged_key != key)
|
||||
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
|
||||
if (key && !eek_key_is_pressed (key)) {
|
||||
priv->dragged_key = key;
|
||||
g_signal_emit_by_name (key, "pressed", priv->keyboard);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
eek_gtk_keyboard_real_button_press_event (GtkWidget *self,
|
||||
GdkEventButton *event)
|
||||
@ -204,27 +193,23 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget *self,
|
||||
key = eek_renderer_find_key_by_position (priv->renderer,
|
||||
(gdouble)event->x,
|
||||
(gdouble)event->y);
|
||||
|
||||
set_dragged_key (EEK_GTK_KEYBOARD(self), key);
|
||||
if (key && key != priv->dragged_key) {
|
||||
priv->dragged_key = key;
|
||||
g_signal_emit_by_name (key, "pressed", priv->keyboard);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_dragged_key (EekGtkKeyboard *keyboard)
|
||||
{
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
|
||||
if (priv->dragged_key) {
|
||||
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
|
||||
priv->dragged_key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
eek_gtk_keyboard_real_button_release_event (GtkWidget *self,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
clear_dragged_key (EEK_GTK_KEYBOARD(self));
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
|
||||
if (priv->dragged_key) {
|
||||
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
|
||||
priv->dragged_key = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -238,14 +223,24 @@ eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
|
||||
key = eek_renderer_find_key_by_position (priv->renderer,
|
||||
(gdouble)event->x,
|
||||
(gdouble)event->y);
|
||||
set_dragged_key (EEK_GTK_KEYBOARD(self), key);
|
||||
if (key && key != priv->dragged_key) {
|
||||
if (priv->dragged_key)
|
||||
render_released_key (GTK_WIDGET(self), priv->dragged_key);
|
||||
priv->dragged_key = key;
|
||||
g_signal_emit_by_name (key, "pressed", priv->keyboard);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
eek_gtk_keyboard_real_unmap (GtkWidget *self)
|
||||
{
|
||||
clear_dragged_key (EEK_GTK_KEYBOARD(self));
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
|
||||
|
||||
if (priv->dragged_key) {
|
||||
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
|
||||
priv->dragged_key = NULL;
|
||||
}
|
||||
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
|
||||
}
|
||||
|
||||
@ -451,6 +446,34 @@ render_pressed_key (GtkWidget *widget,
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
render_released_key (GtkWidget *widget,
|
||||
EekKey *key)
|
||||
{
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
|
||||
EekBounds bounds, large_bounds;
|
||||
cairo_t *cr;
|
||||
|
||||
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
|
||||
|
||||
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
|
||||
magnify_bounds (widget, &bounds, &large_bounds, 2.0);
|
||||
cairo_rectangle (cr,
|
||||
large_bounds.x,
|
||||
large_bounds.y,
|
||||
large_bounds.width,
|
||||
large_bounds.height);
|
||||
cairo_rectangle (cr,
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.width,
|
||||
bounds.height);
|
||||
cairo_clip (cr);
|
||||
|
||||
eek_renderer_render_keyboard (priv->renderer, cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
on_key_pressed (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
@ -473,32 +496,12 @@ on_key_released (EekKeyboard *keyboard,
|
||||
{
|
||||
GtkWidget *widget = user_data;
|
||||
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
|
||||
cairo_t *cr;
|
||||
EekBounds bounds, large_bounds;
|
||||
|
||||
/* renderer may have not been set yet if the widget is a popup */
|
||||
if (!priv->renderer)
|
||||
return;
|
||||
|
||||
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
|
||||
|
||||
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
|
||||
magnify_bounds (widget, &bounds, &large_bounds, 2.0);
|
||||
cairo_rectangle (cr,
|
||||
large_bounds.x,
|
||||
large_bounds.y,
|
||||
large_bounds.width,
|
||||
large_bounds.height);
|
||||
cairo_rectangle (cr,
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.width,
|
||||
bounds.height);
|
||||
cairo_clip (cr);
|
||||
|
||||
eek_renderer_render_keyboard (priv->renderer, cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_destroy (cr);
|
||||
render_released_key (widget, key);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@ -748,6 +748,21 @@ eek_keyboard_get_modifier_behavior (EekKeyboard *keyboard)
|
||||
return priv->modifier_behavior;
|
||||
}
|
||||
|
||||
void
|
||||
eek_keyboard_set_modifiers (EekKeyboard *keyboard,
|
||||
EekModifierType modifiers)
|
||||
{
|
||||
EekKeyboardPrivate *priv;
|
||||
|
||||
g_assert (EEK_IS_KEYBOARD(keyboard));
|
||||
priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
|
||||
|
||||
priv->modifiers = modifiers;
|
||||
set_level_from_modifiers (keyboard);
|
||||
|
||||
return priv->modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* eek_keyboard_get_modifiers:
|
||||
* @keyboard: an #EekKeyboard
|
||||
|
||||
@ -135,6 +135,9 @@ void eek_keyboard_set_modifier_behavior
|
||||
EekModifierBehavior modifier_behavior);
|
||||
EekModifierBehavior eek_keyboard_get_modifier_behavior
|
||||
(EekKeyboard *keyboard);
|
||||
void eek_keyboard_set_modifiers
|
||||
(EekKeyboard *keyboard,
|
||||
EekModifierType modifiers);
|
||||
EekModifierType eek_keyboard_get_modifiers
|
||||
(EekKeyboard *keyboard);
|
||||
|
||||
|
||||
@ -87,7 +87,8 @@ static void eek_renderer_real_render_key_label (EekRenderer *self,
|
||||
static void invalidate (EekRenderer *renderer);
|
||||
static void render_key (EekRenderer *self,
|
||||
cairo_t *cr,
|
||||
EekKey *key);
|
||||
EekKey *key,
|
||||
gboolean active);
|
||||
static void on_symbol_index_changed (EekKeyboard *keyboard,
|
||||
gint group,
|
||||
gint level,
|
||||
@ -117,7 +118,7 @@ create_keyboard_surface_key_callback (EekElement *element,
|
||||
bounds.width * priv->scale,
|
||||
bounds.height * priv->scale);
|
||||
cairo_clip (data->cr);
|
||||
render_key (data->renderer, data->cr, EEK_KEY(element));
|
||||
render_key (data->renderer, data->cr, EEK_KEY(element), FALSE);
|
||||
|
||||
cairo_restore (data->cr);
|
||||
}
|
||||
@ -197,7 +198,8 @@ create_keyboard_surface (EekRenderer *renderer)
|
||||
static void
|
||||
render_key_outline (EekRenderer *renderer,
|
||||
cairo_t *cr,
|
||||
EekKey *key)
|
||||
EekKey *key,
|
||||
gboolean active)
|
||||
{
|
||||
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer);
|
||||
EekOutline *outline;
|
||||
@ -215,10 +217,10 @@ render_key_outline (EekRenderer *renderer,
|
||||
if (oref == 0)
|
||||
return;
|
||||
|
||||
if (eek_key_is_pressed (key))
|
||||
theme_node = g_object_get_data (G_OBJECT(key), "theme-node-pressed");
|
||||
else
|
||||
theme_node = g_object_get_data (G_OBJECT(key), "theme-node");
|
||||
theme_node = g_object_get_data (G_OBJECT(key),
|
||||
active ?
|
||||
"theme-node-pressed" :
|
||||
"theme-node");
|
||||
if (theme_node) {
|
||||
eek_theme_node_get_foreground_color (theme_node, &foreground);
|
||||
eek_theme_node_get_background_color (theme_node, &background);
|
||||
@ -428,7 +430,8 @@ calculate_font_size (EekRenderer *renderer,
|
||||
static void
|
||||
render_key (EekRenderer *self,
|
||||
cairo_t *cr,
|
||||
EekKey *key)
|
||||
EekKey *key,
|
||||
gboolean active)
|
||||
{
|
||||
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self);
|
||||
EekOutline *outline;
|
||||
@ -443,7 +446,7 @@ render_key (EekRenderer *self,
|
||||
if (oref == 0)
|
||||
return;
|
||||
|
||||
if (eek_key_is_pressed (key))
|
||||
if (active)
|
||||
outline_surface_cache = priv->active_outline_surface_cache;
|
||||
else
|
||||
outline_surface_cache = priv->outline_surface_cache;
|
||||
@ -463,7 +466,11 @@ render_key (EekRenderer *self,
|
||||
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
|
||||
cairo_paint (cr);
|
||||
|
||||
eek_renderer_render_key_outline (self, cr, key, 1.0, 0);
|
||||
cairo_save (cr);
|
||||
eek_renderer_apply_transformation_for_key (self, cr, key, 1.0, FALSE);
|
||||
render_key_outline (self, cr, key, active);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
g_hash_table_insert (outline_surface_cache,
|
||||
@ -625,7 +632,7 @@ eek_renderer_real_render_key_outline (EekRenderer *self,
|
||||
{
|
||||
cairo_save (cr);
|
||||
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
|
||||
render_key_outline (self, cr, key);
|
||||
render_key_outline (self, cr, key, eek_key_is_pressed (key));
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
@ -638,7 +645,7 @@ eek_renderer_real_render_key (EekRenderer *self,
|
||||
{
|
||||
cairo_save (cr);
|
||||
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
|
||||
render_key (self, cr, key);
|
||||
render_key (self, cr, key, eek_key_is_pressed (key));
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
|
||||
@ -122,6 +122,7 @@ struct _ServerContext {
|
||||
|
||||
EekKey *repeat_key;
|
||||
guint repeat_timeout_id;
|
||||
gboolean repeat_triggered;
|
||||
|
||||
GSettings *settings;
|
||||
ServerContextUIToolkitType ui_toolkit;
|
||||
@ -606,8 +607,8 @@ server_context_init (ServerContext *context)
|
||||
|
||||
static gboolean on_repeat_timeout (ServerContext *context);
|
||||
|
||||
static gboolean
|
||||
on_repeat_timeout (ServerContext *context)
|
||||
static void
|
||||
emit_press_release_dbus_signal (ServerContext *context)
|
||||
{
|
||||
if (context->connection && context->enabled) {
|
||||
guint keycode = eek_key_get_keycode (context->repeat_key);
|
||||
@ -632,13 +633,42 @@ on_repeat_timeout (ServerContext *context)
|
||||
g_variant_new ("(u)", keycode),
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_repeat_timeout (ServerContext *context)
|
||||
{
|
||||
gint delay = g_settings_get_int (context->settings, "repeat-interval");
|
||||
|
||||
emit_press_release_dbus_signal (context);
|
||||
|
||||
context->repeat_timeout_id =
|
||||
g_timeout_add (delay,
|
||||
(GSourceFunc)on_repeat_timeout,
|
||||
context);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_repeat_timeout_init (ServerContext *context)
|
||||
{
|
||||
emit_press_release_dbus_signal (context);
|
||||
|
||||
/* FIXME: clear modifiers for further key repeat; better not
|
||||
depend on modifier behavior is LATCH */
|
||||
eek_keyboard_set_modifiers (context->keyboard, 0);
|
||||
|
||||
/* reschedule repeat timeout only when "repeat" option is set */
|
||||
if (g_settings_get_boolean (context->settings, "repeat")) {
|
||||
gint delay = g_settings_get_int (context->settings, "repeat-interval");
|
||||
context->repeat_timeout_id =
|
||||
g_timeout_add (delay,
|
||||
(GSourceFunc)on_repeat_timeout,
|
||||
context);
|
||||
}
|
||||
} else
|
||||
context->repeat_timeout_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -649,16 +679,39 @@ on_key_pressed (EekKeyboard *keyboard,
|
||||
gpointer user_data)
|
||||
{
|
||||
ServerContext *context = user_data;
|
||||
gint delay = g_settings_get_int (context->settings, "repeat-delay");
|
||||
|
||||
if (context->repeat_timeout_id) {
|
||||
g_source_remove (context->repeat_timeout_id);
|
||||
context->repeat_timeout_id = 0;
|
||||
}
|
||||
|
||||
context->repeat_key = key;
|
||||
context->repeat_timeout_id =
|
||||
g_timeout_add (delay,
|
||||
(GSourceFunc)on_repeat_timeout_init,
|
||||
context);
|
||||
}
|
||||
|
||||
static void
|
||||
on_key_released (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data)
|
||||
{
|
||||
ServerContext *context = user_data;
|
||||
gboolean need_key_press = FALSE;
|
||||
|
||||
if (context->repeat_timeout_id > 0) {
|
||||
g_source_remove (context->repeat_timeout_id);
|
||||
context->repeat_timeout_id = 0;
|
||||
need_key_press = TRUE;
|
||||
}
|
||||
|
||||
if (context->connection && context->enabled) {
|
||||
guint keycode = eek_key_get_keycode (key);
|
||||
GError *error;
|
||||
|
||||
if (need_key_press) {
|
||||
error = NULL;
|
||||
g_dbus_connection_emit_signal (context->connection,
|
||||
NULL,
|
||||
@ -668,33 +721,7 @@ on_key_pressed (EekKeyboard *keyboard,
|
||||
g_variant_new ("(u)", keycode),
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
if (g_settings_get_boolean (context->settings, "repeat")) {
|
||||
gint delay = g_settings_get_int (context->settings, "repeat-delay");
|
||||
context->repeat_key = key;
|
||||
context->repeat_timeout_id =
|
||||
g_timeout_add (delay,
|
||||
(GSourceFunc)on_repeat_timeout,
|
||||
context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_key_released (EekKeyboard *keyboard,
|
||||
EekKey *key,
|
||||
gpointer user_data)
|
||||
{
|
||||
ServerContext *context = user_data;
|
||||
|
||||
if (context->repeat_timeout_id) {
|
||||
g_source_remove (context->repeat_timeout_id);
|
||||
context->repeat_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (context->connection && context->enabled) {
|
||||
guint keycode = eek_key_get_keycode (key);
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
g_dbus_connection_emit_signal (context->connection,
|
||||
|
||||
Reference in New Issue
Block a user