commit a9233e93623694396ee63d1959c83afb470406b1
parent ec4e18824393d3270f552c88d4f03ff7c29d090f
Author: Michael Forney <mforney@mforney.org>
Date: Thu, 31 Jul 2014 19:58:01 -0700
Reset keyboard state on session deactivation
This prevents an inconsistent state of the keyboard when the VT is
switched away with keys held down.
Diffstat:
5 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/libswc/keyboard.c b/libswc/keyboard.c
@@ -31,6 +31,7 @@
#include "keyboard.h"
#include "util.h"
+#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -149,6 +150,34 @@ void keyboard_finalize(struct keyboard * keyboard)
xkb_finalize(&keyboard->xkb);
}
+void keyboard_reset(struct keyboard * keyboard)
+{
+ struct key * key;
+ uint32_t time = swc_time();
+
+ /* Send simulated key release events for all current key handlers. */
+ wl_array_for_each(key, &keyboard->keys)
+ {
+ if (key->handler)
+ {
+ key->press.serial = wl_display_next_serial(swc.display);
+ key->handler->key(keyboard, time, &key->press,
+ WL_KEYBOARD_KEY_STATE_RELEASED);
+ /* Don't bother updating the XKB state because we will be resetting
+ * it later on and it is unlikely that a key handler cares about the
+ * keyboard state for release events. */
+ }
+ }
+
+ /* We should have removed all the client keys by calling the client key
+ * handler. */
+ assert(keyboard->client_keys.size == 0);
+ keyboard->keys.size = 0;
+ keyboard->modifier_state = (struct keyboard_modifier_state) { };
+ keyboard->modifiers = 0;
+ xkb_reset_state(&keyboard->xkb);
+}
+
/**
* Sets the focus of the keyboard to the specified surface.
*/
diff --git a/libswc/keyboard.h b/libswc/keyboard.h
@@ -74,6 +74,7 @@ struct keyboard
bool keyboard_initialize(struct keyboard * keyboard);
void keyboard_finalize(struct keyboard * keyboard);
+void keyboard_reset(struct keyboard * keyboard);
void keyboard_set_focus(struct keyboard * keyboard,
struct compositor_view * view);
struct wl_resource * keyboard_bind(struct keyboard * keyboard,
diff --git a/libswc/seat.c b/libswc/seat.c
@@ -146,6 +146,7 @@ static void handle_launch_event(struct wl_listener * listener, void * data)
#ifdef ENABLE_LIBINPUT
libinput_suspend(seat.libinput);
#endif
+ keyboard_reset(&seat.keyboard);
break;
case SWC_LAUNCH_EVENT_ACTIVATED:
{
diff --git a/libswc/xkb.c b/libswc/xkb.c
@@ -89,6 +89,21 @@ void xkb_finalize(struct xkb * xkb)
xkb_context_unref(xkb->context);
}
+bool xkb_reset_state(struct xkb * xkb)
+{
+ struct xkb_state * state;
+
+ if (!(state = xkb_state_new(xkb->keymap.map)))
+ {
+ ERROR("Failed to allocate new XKB state\n");
+ return false;
+ }
+
+ xkb_state_unref(xkb->state);
+ xkb->state = state;
+ return true;
+}
+
bool xkb_update_keymap(struct xkb * xkb)
{
const char * keymap_directory = getenv("XDG_RUNTIME_DIR") ?: "/tmp";
diff --git a/libswc/xkb.h b/libswc/xkb.h
@@ -51,6 +51,7 @@ struct xkb
bool xkb_initialize(struct xkb * xkb);
void xkb_finalize(struct xkb * xkb);
+bool xkb_reset_state(struct xkb * xkb);
bool xkb_update_keymap(struct xkb * xkb);