Do not sync if we don't have the focus. If user press the CapsLock but got a mismatch (guest did not reply as expected) do not try to fix the caps lock. This patch is really experimental. For instance contains printf as debugging. Also I think the keyboard logic would be best moved entirely to SpiceGtkSession. Despite however style looks to work very well with different keyboard layouts and combinations. I would like to have it tested from the user experience more that code. Tested: - reboot turn again CapsLock to on if client is on; - English client and English guest; - English client and Japanese guest; - Japanese client with English guest; - Japanese client with Japanese guest. The only issue that I found is that when the client is focused again the CapsLock is emulated and if guest layout is Japanese this could cause input mode to be changed. --- src/spice-gtk-session-priv.h | 3 ++- src/spice-gtk-session.c | 54 ++++++++++++++++++++++++++++++++++++++++++-- src/spice-widget.c | 9 +++++++- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/spice-gtk-session-priv.h b/src/spice-gtk-session-priv.h index b2b6206..d5493ab 100644 --- a/src/spice-gtk-session-priv.h +++ b/src/spice-gtk-session-priv.h @@ -25,13 +25,14 @@ G_BEGIN_DECLS void spice_gtk_session_request_auto_usbredir(SpiceGtkSession *self, gboolean state); gboolean spice_gtk_session_get_read_only(SpiceGtkSession *self); -void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self); void spice_gtk_session_set_pointer_grabbed(SpiceGtkSession *self, gboolean grabbed); gboolean spice_gtk_session_get_pointer_grabbed(SpiceGtkSession *self); void spice_gtk_session_set_keyboard_has_focus(SpiceGtkSession *self, gboolean keyboard_has_focus); void spice_gtk_session_set_mouse_has_pointer(SpiceGtkSession *self, gboolean mouse_has_pointer); gboolean spice_gtk_session_get_keyboard_has_focus(SpiceGtkSession *self); gboolean spice_gtk_session_get_mouse_has_pointer(SpiceGtkSession *self); +void spice_gtk_session_set_focus(SpiceGtkSession *self, gboolean focus); +void spice_gtk_session_capslock_changed(SpiceGtkSession *self); G_END_DECLS diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c index 4201ee0..74c84f7 100644 --- a/src/spice-gtk-session.c +++ b/src/spice-gtk-session.c @@ -66,6 +66,10 @@ struct _SpiceGtkSessionPrivate { gboolean pointer_grabbed; gboolean keyboard_has_focus; gboolean mouse_has_pointer; + /** the session has a window with the focus */ + gboolean has_focus; + /** last time a caps lock was pressed */ + gint64 last_capslock_change; }; /** @@ -103,6 +107,7 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel, static void channel_destroy(SpiceSession *session, SpiceChannel *channel, gpointer user_data); static gboolean read_only(SpiceGtkSession *self); +static void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self); /* ------------------------------------------------------------------ */ /* gobject glue */ @@ -178,6 +183,12 @@ static guint32 get_keyboard_lock_modifiers(void) return modifiers; } +static gboolean spice_gtk_capslock_is_expected(SpiceGtkSession *self) +{ + /* expect a change in 3 seconds from press/release */ + return g_get_monotonic_time() - self->priv->last_capslock_change < 3000000; +} + static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSession *self, SpiceInputsChannel* inputs, gboolean force) @@ -189,6 +200,20 @@ static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio g_object_get(inputs, "key-modifiers", &guest_modifiers, NULL); client_modifiers = get_keyboard_lock_modifiers(); +printf("sync force %d client %d guest %d has_focus %d\n", + force, client_modifiers&SPICE_INPUTS_CAPS_LOCK, guest_modifiers&SPICE_INPUTS_CAPS_LOCK, + self->priv->has_focus); + /* detect if we should swicth the caps lock */ + if (!force) { + if (!self->priv->has_focus) + return; + if (spice_gtk_capslock_is_expected(self)) { +printf("not syncing as caps expected but mismatch\n"); + client_modifiers = (client_modifiers & ~SPICE_INPUTS_CAPS_LOCK) + | (guest_modifiers & SPICE_INPUTS_CAPS_LOCK); + } + } + if (force || client_modifiers != guest_modifiers) { CHANNEL_DEBUG(inputs, "client_modifiers:0x%x, guest_modifiers:0x%x", client_modifiers, guest_modifiers); @@ -1199,8 +1224,7 @@ void spice_gtk_session_paste_from_guest(SpiceGtkSession *self) s->clip_hasdata[selection] = FALSE; } -G_GNUC_INTERNAL -void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self) +static void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self) { GList *l = NULL, *channels = spice_session_get_channels(self->priv->session); @@ -1223,6 +1247,32 @@ void spice_gtk_session_set_pointer_grabbed(SpiceGtkSession *self, gboolean grabb } G_GNUC_INTERNAL +void spice_gtk_session_set_focus(SpiceGtkSession *self, gboolean focus) +{ + g_return_if_fail(SPICE_IS_GTK_SESSION(self)); + + /* TODO detect switch between monitors */ + + /* user switched to the viewer, try to syncronize the keyboard + * modifiers */ + if (focus) + spice_gtk_session_sync_keyboard_modifiers(self); + + +printf("setting focus %d\n", focus); + self->priv->has_focus = focus; +} + +G_GNUC_INTERNAL +void spice_gtk_session_capslock_changed(SpiceGtkSession *self) +{ + g_return_if_fail(SPICE_IS_GTK_SESSION(self)); + +printf("caps lock\n"); + self->priv->last_capslock_change = g_get_monotonic_time(); +} + +G_GNUC_INTERNAL gboolean spice_gtk_session_get_pointer_grabbed(SpiceGtkSession *self) { g_return_val_if_fail(SPICE_IS_GTK_SESSION(self), FALSE); diff --git a/src/spice-widget.c b/src/spice-widget.c index ade3ae4..05aa97d 100644 --- a/src/spice-widget.c +++ b/src/spice-widget.c @@ -1465,6 +1465,10 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key) break; } + /* tell session a capslock was pressed/released */ + if (scancode == 58) + spice_gtk_session_capslock_changed(d->gtk_session); + return true; } @@ -1568,7 +1572,7 @@ static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UN release_keys(display); if (!d->disable_inputs) - spice_gtk_session_sync_keyboard_modifiers(d->gtk_session); + spice_gtk_session_set_focus(d->gtk_session, TRUE); if (d->keyboard_grab_released) memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms); update_keyboard_focus(display, true); @@ -1595,6 +1599,9 @@ static gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_U if (d->keyboard_grab_active) return true; + if (!d->disable_inputs) + spice_gtk_session_set_focus(d->gtk_session, FALSE); + release_keys(display); update_keyboard_focus(display, false); -- 2.5.5 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel