aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-02-05 14:01:29 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-02-05 14:01:29 +0000
commit01a9a51ffaf4699827ea6425cb2b834a356e159d (patch)
tree9e068156b4102402649fcbceb8c3a2e462cfae25
parent1c3d45df5e94042d5fb2bb31416072563ab30e49 (diff)
parent19c1b9fd3dd5955893c0d3c187a4180313e9a0f1 (diff)
Merge remote-tracking branch 'remotes/kraxel/tags/ui-20190205-pull-request' into staging
ui: add kbd stats tracker. ui: gtk scroll fixes. ui: egl cursor scale fix. ui: more sdl1 cleanup. # gpg: Signature made Tue 05 Feb 2019 10:57:42 GMT # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/ui-20190205-pull-request: keymap: fix keyup mappings keymap: pass full keyboard state to keysym2scancode kbd-state: use state tracker for vnc kbd-state: use state tracker for gtk sdl2: use only QKeyCode in sdl2_process_key() kbd-state: use state tracker for sdl2 sdl2: remove sdl2_reset_keys() function kbd-state: add keyboard state tracker ui/egl-helpers: Augment parameter list of egl_texture_blend() to convey scales of viewport ui/cocoa.m: Fix macOS 10.14 deprecation warnings ui/sdl_keysym: Remove obsolete SDL1.2 related code ui: listen for GDK_SMOOTH_SCROLL events ui: don't send any event if delta_y == 0 Remove deprecated -no-frame option Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--include/ui/egl-helpers.h2
-rw-r--r--include/ui/gtk.h2
-rw-r--r--include/ui/kbd-state.h101
-rw-r--r--include/ui/sdl2.h3
-rw-r--r--qemu-deprecated.texi6
-rw-r--r--qemu-options.hx11
-rw-r--r--ui/Makefile.objs2
-rw-r--r--ui/cocoa.m28
-rw-r--r--ui/curses.c2
-rw-r--r--ui/egl-headless.c3
-rw-r--r--ui/egl-helpers.c9
-rw-r--r--ui/gtk-egl.c3
-rw-r--r--ui/gtk.c43
-rw-r--r--ui/kbd-state.c130
-rw-r--r--ui/keymaps.c55
-rw-r--r--ui/keymaps.h3
-rw-r--r--ui/sdl2-input.c50
-rw-r--r--ui/sdl2.c12
-rw-r--r--ui/sdl_keysym.h278
-rw-r--r--ui/spice-display.c2
-rw-r--r--ui/vnc.c119
-rw-r--r--ui/vnc.h5
-rw-r--r--vl.c23
24 files changed, 360 insertions, 533 deletions
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 85877b7e43..4b5a6b77f9 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -102,7 +102,6 @@ extern const char *keyboard_layout;
extern int win2k_install_hack;
extern int alt_grab;
extern int ctrl_grab;
-extern int no_frame;
extern int smp_cpus;
extern unsigned int max_cpus;
extern int cursor_hide;
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 3fc656a7ba..b976cb8728 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -27,7 +27,7 @@ void egl_fb_read(void *dst, egl_fb *src);
void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
- int x, int y);
+ int x, int y, double scale_x, double scale_y);
#ifdef CONFIG_OPENGL_DMABUF
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 99edd3c085..d9eedad976 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -22,6 +22,7 @@
#include <gdk/gdkwayland.h>
#endif
+#include "ui/kbd-state.h"
#if defined(CONFIG_OPENGL)
#include "ui/egl-helpers.h"
#include "ui/egl-context.h"
@@ -32,6 +33,7 @@ typedef struct GtkDisplayState GtkDisplayState;
typedef struct VirtualGfxConsole {
GtkWidget *drawing_area;
DisplayChangeListener dcl;
+ QKbdState *kbd;
DisplaySurface *ds;
pixman_image_t *convert;
cairo_surface_t *surface;
diff --git a/include/ui/kbd-state.h b/include/ui/kbd-state.h
new file mode 100644
index 0000000000..d87833553a
--- /dev/null
+++ b/include/ui/kbd-state.h
@@ -0,0 +1,101 @@
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+#ifndef QEMU_UI_KBD_STATE_H
+#define QEMU_UI_KBD_STATE_H 1
+
+#include "qapi/qapi-types-ui.h"
+
+typedef enum QKbdModifier QKbdModifier;
+
+enum QKbdModifier {
+ QKBD_MOD_NONE = 0,
+
+ QKBD_MOD_SHIFT,
+ QKBD_MOD_CTRL,
+ QKBD_MOD_ALT,
+ QKBD_MOD_ALTGR,
+
+ QKBD_MOD_NUMLOCK,
+ QKBD_MOD_CAPSLOCK,
+
+ QKBD_MOD__MAX
+};
+
+typedef struct QKbdState QKbdState;
+
+/**
+ * qkbd_state_init: init keyboard state tracker.
+ *
+ * Allocates and initializes keyboard state struct.
+ *
+ * @con: QemuConsole for this state tracker. Gets passed down to
+ * qemu_input_*() functions when sending key events to the guest.
+ */
+QKbdState *qkbd_state_init(QemuConsole *con);
+
+/**
+ * qkbd_state_free: free keyboard tracker state.
+ *
+ * @kbd: state tracker state.
+ */
+void qkbd_state_free(QKbdState *kbd);
+
+/**
+ * qkbd_state_key_event: process key event.
+ *
+ * Update keyboard state, send event to the guest.
+ *
+ * This function takes care to not send suspious events (keyup event
+ * for a key not pressed for example).
+ *
+ * @kbd: state tracker state.
+ * @qcode: the key pressed or released.
+ * @down: true for key down events, false otherwise.
+ */
+void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down);
+
+/**
+ * qkbd_state_set_delay: set key press delay.
+ *
+ * When set the specified delay will be added after each key event,
+ * using qemu_input_event_send_key_delay().
+ *
+ * @kbd: state tracker state.
+ * @delay_ms: the delay in miliseconds.
+ */
+void qkbd_state_set_delay(QKbdState *kbd, int delay_ms);
+
+/**
+ * qkbd_state_key_get: get key state.
+ *
+ * Returns true when the key is down.
+ *
+ * @kbd: state tracker state.
+ * @qcode: the key to query.
+ */
+bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode);
+
+/**
+ * qkbd_state_modifier_get: get modifier state.
+ *
+ * Returns true when the modifier is active.
+ *
+ * @kbd: state tracker state.
+ * @mod: the modifier to query.
+ */
+bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod);
+
+/**
+ * qkbd_state_lift_all_keys: lift all pressed keys.
+ *
+ * This sends key up events to the guest for all keys which are in
+ * down state.
+ *
+ * @kbd: state tracker state.
+ */
+void qkbd_state_lift_all_keys(QKbdState *kbd);
+
+#endif /* QEMU_UI_KBD_STATE_H */
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index f6db642b65..0875b8d56b 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -10,6 +10,7 @@
# include <SDL_image.h>
#endif
+#include "ui/kbd-state.h"
#ifdef CONFIG_OPENGL
# include "ui/egl-helpers.h"
#endif
@@ -30,6 +31,7 @@ struct sdl2_console {
int idle_counter;
int ignore_hotkeys;
SDL_GLContext winctx;
+ QKbdState *kbd;
#ifdef CONFIG_OPENGL
QemuGLShader *gls;
egl_fb guest_fb;
@@ -44,7 +46,6 @@ void sdl2_window_destroy(struct sdl2_console *scon);
void sdl2_window_resize(struct sdl2_console *scon);
void sdl2_poll_events(struct sdl2_console *scon);
-void sdl2_reset_keys(struct sdl2_console *scon);
void sdl2_process_key(struct sdl2_console *scon,
SDL_KeyboardEvent *ev);
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 8a6174df0c..674cc3fdf8 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -37,12 +37,6 @@ would automatically enable USB support on the machine type.
If using the new syntax, USB support must be explicitly
enabled via the ``-machine usb=on'' argument.
-@subsection -no-frame (since 2.12.0)
-
-The @code{--no-frame} argument works with SDL 1.2 only. The other user
-interfaces never implemented this in the first place. So this will be
-removed together with SDL 1.2 support.
-
@subsection -virtioconsole (since 3.0.0)
Option @option{-virtioconsole} has been replaced by
diff --git a/qemu-options.hx b/qemu-options.hx
index 521511ec13..0180467dee 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1294,17 +1294,6 @@ mode using a curses/ncurses interface. Nothing is displayed in graphical
mode.
ETEXI
-DEF("no-frame", 0, QEMU_OPTION_no_frame,
- "-no-frame open SDL window without a frame and window decorations\n",
- QEMU_ARCH_ALL)
-STEXI
-@item -no-frame
-@findex -no-frame
-Do not use decorations for SDL windows and start them using the whole
-available screen space. This makes the using QEMU in a dedicated desktop
-workspace more convenient.
-ETEXI
-
DEF("alt-grab", 0, QEMU_OPTION_alt_grab,
"-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n",
QEMU_ARCH_ALL)
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 9b6f0c6b67..7f8b3da791 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -8,7 +8,7 @@ vnc-obj-y += vnc-ws.o
vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o
-common-obj-y += input.o input-keymap.o input-legacy.o
+common-obj-y += input.o input-keymap.o input-legacy.o kbd-state.o
common-obj-$(CONFIG_LINUX) += input-linux.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
common-obj-$(CONFIG_COCOA) += cocoa.o
diff --git a/ui/cocoa.m b/ui/cocoa.m
index ddc058e76e..e2567d6946 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -54,6 +54,9 @@
#ifndef MAC_OS_X_VERSION_10_12
#define MAC_OS_X_VERSION_10_12 101200
#endif
+#ifndef MAC_OS_X_VERSION_10_13
+#define MAC_OS_X_VERSION_10_13 101300
+#endif
/* macOS 10.12 deprecated many constants, #define the new names for older SDKs */
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
@@ -90,6 +93,14 @@
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
#define NSModalResponseOK NSFileHandlingPanelOKButton
#endif
+/* 10.14 deprecates NSOnState and NSOffState in favor of
+ * NSControlStateValueOn/Off, which were introduced in 10.13.
+ * Define for older versions
+ */
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
+#define NSControlStateValueOn NSOnState
+#define NSControlStateValueOff NSOffState
+#endif
//#define DEBUG
@@ -377,7 +388,12 @@ QemuCocoaView *cocoaView;
COCOA_DEBUG("QemuCocoaView: drawRect\n");
// get CoreGraphic context
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
+#else
+ CGContextRef viewContextRef = [[NSGraphicsContext currentContext] CGContext];
+#endif
+
CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
CGContextSetShouldAntialias (viewContextRef, NO);
@@ -1147,9 +1163,9 @@ QemuCocoaView *cocoaView;
{
stretch_video = !stretch_video;
if (stretch_video == true) {
- [sender setState: NSOnState];
+ [sender setState: NSControlStateValueOn];
} else {
- [sender setState: NSOffState];
+ [sender setState: NSControlStateValueOff];
}
}
@@ -1390,15 +1406,15 @@ QemuCocoaView *cocoaView;
{
/* Unselect the currently selected item */
for (NSMenuItem *item in [menu itemArray]) {
- if (item.state == NSOnState) {
- [item setState: NSOffState];
+ if (item.state == NSControlStateValueOn) {
+ [item setState: NSControlStateValueOff];
break;
}
}
}
// check the menu item
- [sender setState: NSOnState];
+ [sender setState: NSControlStateValueOn];
// get the throttle percentage
throttle_pct = [sender tag];
@@ -1502,7 +1518,7 @@ int main (int argc, const char * argv[]) {
initWithTitle: [NSString stringWithFormat: @"%d%%", percentage] action:@selector(adjustSpeed:) keyEquivalent:@""] autorelease];
if (percentage == 100) {
- [menuItem setState: NSOnState];
+ [menuItem setState: NSControlStateValueOn];
}
/* Calculate the throttle percentage */
diff --git a/ui/curses.c b/ui/curses.c
index f4e7a12f74..6e0091c3b2 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -273,7 +273,7 @@ static void curses_refresh(DisplayChangeListener *dcl)
}
keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK,
- false, false, false);
+ NULL, false);
if (keycode == 0)
continue;
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 519e7bad32..e67b47aeff 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -142,7 +142,8 @@ static void egl_scanout_flush(DisplayChangeListener *dcl,
egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
!edpy->y_0_top);
egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
- !edpy->y_0_top, edpy->pos_x, edpy->pos_y);
+ !edpy->y_0_top, edpy->pos_x, edpy->pos_y,
+ 1.0, 1.0);
} else {
/* no cursor -> use simple framebuffer blit */
egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 5e115b3fb4..e90eef8c9c 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -120,14 +120,15 @@ void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip)
}
void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
- int x, int y)
+ int x, int y, double scale_x, double scale_y)
{
glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
+ int w = scale_x * src->width;
+ int h = scale_y * src->height;
if (flip) {
- glViewport(x, y, src->width, src->height);
+ glViewport(x, y, w, h);
} else {
- glViewport(x, dst->height - src->height - y,
- src->width, src->height);
+ glViewport(x, dst->height - h - y, w, h);
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, src->texture);
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index afd17148c0..42801b688b 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -278,7 +278,8 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
vc->gfx.y0_top);
egl_texture_blend(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.cursor_fb,
vc->gfx.y0_top,
- vc->gfx.cursor_x, vc->gfx.cursor_y);
+ vc->gfx.cursor_x, vc->gfx.cursor_y,
+ vc->gfx.scale_x, vc->gfx.scale_y);
} else {
egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 87c0e33d2a..949b143e4e 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -122,17 +122,6 @@
#define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
-static const int modifier_keycode[] = {
- Q_KEY_CODE_SHIFT,
- Q_KEY_CODE_SHIFT_R,
- Q_KEY_CODE_CTRL,
- Q_KEY_CODE_CTRL_R,
- Q_KEY_CODE_ALT,
- Q_KEY_CODE_ALT_R,
- Q_KEY_CODE_META_L,
- Q_KEY_CODE_META_R,
-};
-
static const guint16 *keycode_map;
static size_t keycode_maplen;
@@ -187,7 +176,6 @@ struct GtkDisplayState {
bool external_pause_update;
- bool modifier_pressed[ARRAY_SIZE(modifier_keycode)];
bool ignore_keys;
DisplayOptions *opts;
@@ -426,20 +414,12 @@ static void gd_update_full_redraw(VirtualConsole *vc)
static void gtk_release_modifiers(GtkDisplayState *s)
{
VirtualConsole *vc = gd_vc_find_current(s);
- int i, qcode;
if (vc->type != GD_VC_GFX ||
!qemu_console_is_graphic(vc->gfx.dcl.con)) {
return;
}
- for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) {
- qcode = modifier_keycode[i];
- if (!s->modifier_pressed[i]) {
- continue;
- }
- qemu_input_event_send_key_qcode(vc->gfx.dcl.con, qcode, false);
- s->modifier_pressed[i] = false;
- }
+ qkbd_state_lift_all_keys(vc->gfx.kbd);
}
static void gd_widget_reparent(GtkWidget *from, GtkWidget *to,
@@ -1004,7 +984,9 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll,
&delta_x, &delta_y)) {
return TRUE;
}
- if (delta_y > 0) {
+ if (delta_y == 0) {
+ return TRUE;
+ } else if (delta_y > 0) {
btn = INPUT_BUTTON_WHEEL_DOWN;
} else {
btn = INPUT_BUTTON_WHEEL_UP;
@@ -1113,7 +1095,6 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
VirtualConsole *vc = opaque;
GtkDisplayState *s = vc->s;
int qcode;
- int i;
if (s->ignore_keys) {
s->ignore_keys = (key->type == GDK_KEY_PRESS);
@@ -1134,8 +1115,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
|| key->hardware_keycode == VK_PAUSE
#endif
) {
- qemu_input_event_send_key_qcode(vc->gfx.dcl.con, Q_KEY_CODE_PAUSE,
- key->type == GDK_KEY_PRESS);
+ qkbd_state_key_event(vc->gfx.kbd, Q_KEY_CODE_PAUSE,
+ key->type == GDK_KEY_PRESS);
return TRUE;
}
@@ -1144,14 +1125,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
trace_gd_key_event(vc->label, key->hardware_keycode, qcode,
(key->type == GDK_KEY_PRESS) ? "down" : "up");
- for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) {
- if (qcode == modifier_keycode[i]) {
- s->modifier_pressed[i] = (key->type == GDK_KEY_PRESS);
- }
- }
-
- qemu_input_event_send_key_qcode(vc->gfx.dcl.con, qcode,
- key->type == GDK_KEY_PRESS);
+ qkbd_state_key_event(vc->gfx.kbd, qcode,
+ key->type == GDK_KEY_PRESS);
return TRUE;
}
@@ -2043,6 +2018,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
GDK_ENTER_NOTIFY_MASK |
GDK_LEAVE_NOTIFY_MASK |
GDK_SCROLL_MASK |
+ GDK_SMOOTH_SCROLL_MASK |
GDK_KEY_PRESS_MASK);
gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE);
@@ -2052,6 +2028,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
vc->tab_item, gtk_label_new(vc->label));
+ vc->gfx.kbd = qkbd_state_init(con);
vc->gfx.dcl.con = con;
register_displaychangelistener(&vc->gfx.dcl);
diff --git a/ui/kbd-state.c b/ui/kbd-state.c
new file mode 100644
index 0000000000..ac14add70e
--- /dev/null
+++ b/ui/kbd-state.c
@@ -0,0 +1,130 @@
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitmap.h"
+#include "qemu/queue.h"
+#include "ui/console.h"
+#include "ui/input.h"
+#include "ui/kbd-state.h"
+
+struct QKbdState {
+ QemuConsole *con;
+ int key_delay_ms;
+ DECLARE_BITMAP(keys, Q_KEY_CODE__MAX);
+ DECLARE_BITMAP(mods, QKBD_MOD__MAX);
+};
+
+static void qkbd_state_modifier_update(QKbdState *kbd,
+ QKeyCode qcode1, QKeyCode qcode2,
+ QKbdModifier mod)
+{
+ if (test_bit(qcode1, kbd->keys) || test_bit(qcode2, kbd->keys)) {
+ set_bit(mod, kbd->mods);
+ } else {
+ clear_bit(mod, kbd->mods);
+ }
+}
+
+bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod)
+{
+ return test_bit(mod, kbd->mods);
+}
+
+bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode)
+{
+ return test_bit(qcode, kbd->keys);
+}
+
+void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
+{
+ bool state = test_bit(qcode, kbd->keys);
+
+ if (state == down) {
+ /*
+ * Filter out events which don't change the keyboard state.
+ *
+ * Most notably this allows to simply send along all key-up
+ * events, and this function will filter out everything where
+ * the corresponding key-down event wasn't send to the guest,
+ * for example due to being a host hotkey.
+ */
+ return;
+ }
+
+ /* update key and modifier state */
+ change_bit(qcode, kbd->keys);
+ switch (qcode) {
+ case Q_KEY_CODE_SHIFT:
+ case Q_KEY_CODE_SHIFT_R:
+ qkbd_state_modifier_update(kbd, Q_KEY_CODE_SHIFT, Q_KEY_CODE_SHIFT_R,
+ QKBD_MOD_SHIFT);
+ break;
+ case Q_KEY_CODE_CTRL:
+ case Q_KEY_CODE_CTRL_R:
+ qkbd_state_modifier_update(kbd, Q_KEY_CODE_CTRL, Q_KEY_CODE_CTRL_R,
+ QKBD_MOD_CTRL);
+ break;
+ case Q_KEY_CODE_ALT:
+ qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT, Q_KEY_CODE_ALT,
+ QKBD_MOD_ALT);
+ break;
+ case Q_KEY_CODE_ALT_R:
+ qkbd_state_modifier_update(kbd, Q_KEY_CODE_ALT_R, Q_KEY_CODE_ALT_R,
+ QKBD_MOD_ALTGR);
+ break;
+ case Q_KEY_CODE_CAPS_LOCK:
+ if (down) {
+ change_bit(QKBD_MOD_CAPSLOCK, kbd->mods);
+ }
+ break;
+ case Q_KEY_CODE_NUM_LOCK:
+ if (down) {
+ change_bit(QKBD_MOD_NUMLOCK, kbd->mods);
+ }
+ break;
+ default:
+ /* keep gcc happy */
+ break;
+ }
+
+ /* send to guest */
+ if (qemu_console_is_graphic(kbd->con)) {
+ qemu_input_event_send_key_qcode(kbd->con, qcode, down);
+ if (kbd->key_delay_ms) {
+ qemu_input_event_send_key_delay(kbd->key_delay_ms);
+ }
+ }
+}
+
+void qkbd_state_lift_all_keys(QKbdState *kbd)
+{
+ int qcode;
+
+ for (qcode = 0; qcode < Q_KEY_CODE__MAX; qcode++) {
+ if (test_bit(qcode, kbd->keys)) {
+ qkbd_state_key_event(kbd, qcode, false);
+ }
+ }
+}
+
+void qkbd_state_set_delay(QKbdState *kbd, int delay_ms)
+{
+ kbd->key_delay_ms = delay_ms;
+}
+
+void qkbd_state_free(QKbdState *kbd)
+{
+ g_free(kbd);
+}
+
+QKbdState *qkbd_state_init(QemuConsole *con)
+{
+ QKbdState *kbd = g_new0(QKbdState, 1);
+
+ kbd->con = con;
+
+ return kbd;
+}
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 6e44f738ed..544b55c27b 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -28,6 +28,7 @@
#include "trace.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "ui/input.h"
struct keysym2code {
uint32_t count;
@@ -188,7 +189,7 @@ kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
int keysym2scancode(kbd_layout_t *k, int keysym,
- bool shift, bool altgr, bool ctrl)
+ QKbdState *kbd, bool down)
{
static const uint32_t mask =
SCANCODE_SHIFT | SCANCODE_ALTGR | SCANCODE_CTRL;
@@ -212,27 +213,39 @@ int keysym2scancode(kbd_layout_t *k, int keysym,
return keysym2code->keycodes[0];
}
- /*
- * We have multiple keysym -> keycode mappings.
- *
- * Check whenever we find one mapping where the modifier state of
- * the mapping matches the current user interface modifier state.
- * If so, prefer that one.
- */
- mods = 0;
- if (shift) {
- mods |= SCANCODE_SHIFT;
- }
- if (altgr) {
- mods |= SCANCODE_ALTGR;
- }
- if (ctrl) {
- mods |= SCANCODE_CTRL;
- }
+ /* We have multiple keysym -> keycode mappings. */
+ if (down) {
+ /*
+ * On keydown: Check whenever we find one mapping where the
+ * modifier state of the mapping matches the current user
+ * interface modifier state. If so, prefer that one.
+ */
+ mods = 0;
+ if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_SHIFT)) {
+ mods |= SCANCODE_SHIFT;
+ }
+ if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_ALTGR)) {
+ mods |= SCANCODE_ALTGR;
+ }
+ if (kbd && qkbd_state_modifier_get(kbd, QKBD_MOD_CTRL)) {
+ mods |= SCANCODE_CTRL;
+ }
- for (i = 0; i < keysym2code->count; i++) {
- if ((keysym2code->keycodes[i] & mask) == mods) {
- return keysym2code->keycodes[i];
+ for (i = 0; i < keysym2code->count; i++) {
+ if ((keysym2code->keycodes[i] & mask) == mods) {
+ return keysym2code->keycodes[i];
+ }
+ }
+ } else {
+ /*
+ * On keyup: Try find a key which is actually down.
+ */
+ for (i = 0; i < keysym2code->count; i++) {
+ QKeyCode qcode = qemu_input_key_number_to_qcode
+ (keysym2code->keycodes[i]);
+ if (kbd && qkbd_state_key_get(kbd, qcode)) {
+ return keysym2code->keycodes[i];
+ }
}
}
return keysym2code->keycodes[0];
diff --git a/ui/keymaps.h b/ui/keymaps.h
index 4e9c87fb8f..b6d48aac40 100644
--- a/ui/keymaps.h
+++ b/ui/keymaps.h
@@ -26,6 +26,7 @@
#define QEMU_KEYMAPS_H
#include "qemu-common.h"
+#include "ui/kbd-state.h"
typedef struct {
const char* name;
@@ -55,7 +56,7 @@ typedef struct kbd_layout_t kbd_layout_t;
kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
const char *language, Error **errp);
int keysym2scancode(kbd_layout_t *k, int keysym,
- bool shift, bool altgr, bool ctrl);
+ QKbdState *kbd, bool down);
int keycode_is_keypad(kbd_layout_t *k, int keycode);
int keysym_is_numlock(kbd_layout_t *k, int keysym);
diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index 1378b63dd9..664364a5e5 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -30,63 +30,23 @@
#include "ui/sdl2.h"
#include "sysemu/sysemu.h"
-static uint8_t modifiers_state[SDL_NUM_SCANCODES];
-
-void sdl2_reset_keys(struct sdl2_console *scon)
-{
- QemuConsole *con = scon ? scon->dcl.con : NULL;
- int i;
-
- for (i = 0 ;
- i < SDL_NUM_SCANCODES && i < qemu_input_map_usb_to_qcode_len ;
- i++) {
- if (modifiers_state[i]) {
- int qcode = qemu_input_map_usb_to_qcode[i];
- qemu_input_event_send_key_qcode(con, qcode, false);
- modifiers_state[i] = 0;
- }
- }
-}
-
void sdl2_process_key(struct sdl2_console *scon,
SDL_KeyboardEvent *ev)
{
int qcode;
- QemuConsole *con = scon ? scon->dcl.con : NULL;
+ QemuConsole *con = scon->dcl.con;
if (ev->keysym.scancode >= qemu_input_map_usb_to_qcode_len) {
return;
}
-
qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode];
-
- /* modifier state tracking */
- switch (ev->keysym.scancode) {
- case SDL_SCANCODE_LCTRL:
- case SDL_SCANCODE_LSHIFT:
- case SDL_SCANCODE_LALT:
- case SDL_SCANCODE_LGUI:
- case SDL_SCANCODE_RCTRL:
- case SDL_SCANCODE_RSHIFT:
- case SDL_SCANCODE_RALT:
- case SDL_SCANCODE_RGUI:
- if (ev->type == SDL_KEYUP) {
- modifiers_state[ev->keysym.scancode] = 0;
- } else {
- modifiers_state[ev->keysym.scancode] = 1;
- }
- break;
- default:
- /* nothing */
- break;
- }
+ qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN);
if (!qemu_console_is_graphic(con)) {
- bool ctrl = (modifiers_state[SDL_SCANCODE_LCTRL] ||
- modifiers_state[SDL_SCANCODE_RCTRL]);
+ bool ctrl = qkbd_state_modifier_get(scon->kbd, QKBD_MOD_CTRL);
if (ev->type == SDL_KEYDOWN) {
- switch (ev->keysym.scancode) {
- case SDL_SCANCODE_RETURN:
+ switch (qcode) {
+ case Q_KEY_CODE_RET:
kbd_put_keysym_console(con, '\n');
break;
default:
diff --git a/ui/sdl2.c b/ui/sdl2.c
index cde7feba91..1277cf28fb 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -38,7 +38,6 @@ static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
static int gui_saved_grab;
static int gui_fullscreen;
-static int gui_keysym;
static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
static SDL_Cursor *sdl_cursor_normal;
static SDL_Cursor *sdl_cursor_hidden;
@@ -330,6 +329,7 @@ static void handle_keydown(SDL_Event *ev)
int win;
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
int gui_key_modifier_pressed = get_mod_state();
+ int gui_keysym = 0;
if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) {
switch (ev->key.keysym.scancode) {
@@ -410,16 +410,9 @@ static void handle_keydown(SDL_Event *ev)
static void handle_keyup(SDL_Event *ev)
{
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
- int gui_key_modifier_pressed = get_mod_state();
scon->ignore_hotkeys = false;
-
- if (!gui_key_modifier_pressed) {
- gui_keysym = 0;
- }
- if (!gui_keysym) {
- sdl2_process_key(scon, &ev->key);
- }
+ sdl2_process_key(scon, &ev->key);
}
static void handle_textinput(SDL_Event *ev)
@@ -823,6 +816,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
sdl2_console[i].dcl.ops = &dcl_2d_ops;
#endif
sdl2_console[i].dcl.con = con;
+ sdl2_console[i].kbd = qkbd_state_init(con);
register_displaychangelistener(&sdl2_console[i].dcl);
#if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11)
diff --git a/ui/sdl_keysym.h b/ui/sdl_keysym.h
deleted file mode 100644
index 599d9fc64d..0000000000
--- a/ui/sdl_keysym.h
+++ /dev/null
@@ -1,278 +0,0 @@
-
-#include "keymaps.h"
-
-static const name2keysym_t name2keysym[]={
-/* ascii */
- { "space", 0x020},
- { "exclam", 0x021},
- { "quotedbl", 0x022},
- { "numbersign", 0x023},
- { "dollar", 0x024},
- { "percent", 0x025},
- { "ampersand", 0x026},
- { "apostrophe", 0x027},
- { "parenleft", 0x028},
- { "parenright", 0x029},
- { "asterisk", 0x02a},
- { "plus", 0x02b},
- { "comma", 0x02c},
- { "minus", 0x02d},
- { "period", 0x02e},
- { "slash", 0x02f},
- { "0", 0x030},
- { "1", 0x031},
- { "2", 0x032},
- { "3", 0x033},
- { "4", 0x034},
- { "5", 0x035},
- { "6", 0x036},
- { "7", 0x037},
- { "8", 0x038},
- { "9", 0x039},
- { "colon", 0x03a},
- { "semicolon", 0x03b},
- { "less", 0x03c},
- { "equal", 0x03d},
- { "greater", 0x03e},
- { "question", 0x03f},
- { "at", 0x040},
- { "A", 0x041},
- { "B", 0x042},
- { "C", 0x043},
- { "D", 0x044},
- { "E", 0x045},
- { "F", 0x046},
- { "G", 0x047},
- { "H", 0x048},
- { "I", 0x049},
- { "J", 0x04a},
- { "K", 0x04b},
- { "L", 0x04c},
- { "M", 0x04d},
- { "N", 0x04e},
- { "O", 0x04f},
- { "P", 0x050},
- { "Q", 0x051},
- { "R", 0x052},
- { "S", 0x053},
- { "T", 0x054},
- { "U", 0x055},
- { "V", 0x056},
- { "W", 0x057},
- { "X", 0x058},
- { "Y", 0x059},
- { "Z", 0x05a},
- { "bracketleft", 0x05b},
- { "backslash", 0x05c},
- { "bracketright", 0x05d},
- { "asciicircum", 0x05e},
- { "underscore", 0x05f},
- { "grave", 0x060},
- { "a", 0x061},
- { "b", 0x062},
- { "c", 0x063},
- { "d", 0x064},
- { "e", 0x065},
- { "f", 0x066},
- { "g", 0x067},
- { "h", 0x068},
- { "i", 0x069},
- { "j", 0x06a},
- { "k", 0x06b},
- { "l", 0x06c},
- { "m", 0x06d},
- { "n", 0x06e},
- { "o", 0x06f},
- { "p", 0x070},
- { "q", 0x071},
- { "r", 0x072},
- { "s", 0x073},
- { "t", 0x074},
- { "u", 0x075},
- { "v", 0x076},
- { "w", 0x077},
- { "x", 0x078},
- { "y", 0x079},
- { "z", 0x07a},
- { "braceleft", 0x07b},
- { "bar", 0x07c},
- { "braceright", 0x07d},
- { "asciitilde", 0x07e},
-
-/* latin 1 extensions */
-{ "nobreakspace", 0x0a0},
-{ "exclamdown", 0x0a1},
-{ "cent", 0x0a2},
-{ "sterling", 0x0a3},
-{ "currency", 0x0a4},
-{ "yen", 0x0a5},
-{ "brokenbar", 0x0a6},
-{ "section", 0x0a7},
-{ "diaeresis", 0x0a8},
-{ "copyright", 0x0a9},
-{ "ordfeminine", 0x0aa},
-{ "guillemotleft", 0x0ab},
-{ "notsign", 0x0ac},
-{ "hyphen", 0x0ad},
-{ "registered", 0x0ae},
-{ "macron", 0x0af},
-{ "degree", 0x0b0},
-{ "plusminus", 0x0b1},
-{ "twosuperior", 0x0b2},
-{ "threesuperior", 0x0b3},
-{ "acute", 0x0b4},
-{ "mu", 0x0b5},
-{ "paragraph", 0x0b6},
-{ "periodcentered", 0x0b7},
-{ "cedilla", 0x0b8},
-{ "onesuperior", 0x0b9},
-{ "masculine", 0x0ba},
-{ "guillemotright", 0x0bb},
-{ "onequarter", 0x0bc},
-{ "onehalf", 0x0bd},
-{ "threequarters", 0x0be},
-{ "questiondown", 0x0bf},
-{ "Agrave", 0x0c0},
-{ "Aacute", 0x0c1},
-{ "Acircumflex", 0x0c2},
-{ "Atilde", 0x0c3},
-{ "Adiaeresis", 0x0c4},
-{ "Aring", 0x0c5},
-{ "AE", 0x0c6},
-{ "Ccedilla", 0x0c7},
-{ "Egrave", 0x0c8},
-{ "Eacute", 0x0c9},
-{ "Ecircumflex", 0x0ca},
-{ "Ediaeresis", 0x0cb},
-{ "Igrave", 0x0cc},
-{ "Iacute", 0x0cd},
-{ "Icircumflex", 0x0ce},
-{ "Idiaeresis", 0x0cf},
-{ "ETH", 0x0d0},
-{ "Eth", 0x0d0},
-{ "Ntilde", 0x0d1},
-{ "Ograve", 0x0d2},
-{ "Oacute", 0x0d3},
-{ "Ocircumflex", 0x0d4},
-{ "Otilde", 0x0d5},
-{ "Odiaeresis", 0x0d6},
-{ "multiply", 0x0d7},
-{ "Ooblique", 0x0d8},
-{ "Oslash", 0x0d8},
-{ "Ugrave", 0x0d9},
-{ "Uacute", 0x0da},
-{ "Ucircumflex", 0x0db},
-{ "Udiaeresis", 0x0dc},
-{ "Yacute", 0x0dd},
-{ "THORN", 0x0de},
-{ "Thorn", 0x0de},
-{ "ssharp", 0x0df},
-{ "agrave", 0x0e0},
-{ "aacute", 0x0e1},
-{ "acircumflex", 0x0e2},
-{ "atilde", 0x0e3},
-{ "adiaeresis", 0x0e4},
-{ "aring", 0x0e5},
-{ "ae", 0x0e6},
-{ "ccedilla", 0x0e7},
-{ "egrave", 0x0e8},
-{ "eacute", 0x0e9},
-{ "ecircumflex", 0x0ea},
-{ "ediaeresis", 0x0eb},
-{ "igrave", 0x0ec},
-{ "iacute", 0x0ed},
-{ "icircumflex", 0x0ee},
-{ "idiaeresis", 0x0ef},
-{ "eth", 0x0f0},
-{ "ntilde", 0x0f1},
-{ "ograve", 0x0f2},
-{ "oacute", 0x0f3},
-{ "ocircumflex", 0x0f4},
-{ "otilde", 0x0f5},
-{ "odiaeresis", 0x0f6},
-{ "division", 0x0f7},
-{ "oslash", 0x0f8},
-{ "ooblique", 0x0f8},
-{ "ugrave", 0x0f9},
-{ "uacute", 0x0fa},
-{ "ucircumflex", 0x0fb},
-{ "udiaeresis", 0x0fc},
-{ "yacute", 0x0fd},
-{ "thorn", 0x0fe},
-{ "ydiaeresis", 0x0ff},
-#if SDL_MAJOR_VERSION == 1
-{"EuroSign", SDLK_EURO},
-
- /* modifiers */
-{"Control_L", SDLK_LCTRL},
-{"Control_R", SDLK_RCTRL},
-{"Alt_L", SDLK_LALT},
-{"Alt_R", SDLK_RALT},
-{"Caps_Lock", SDLK_CAPSLOCK},
-{"Meta_L", SDLK_LMETA},
-{"Meta_R", SDLK_RMETA},
-{"Shift_L", SDLK_LSHIFT},
-{"Shift_R", SDLK_RSHIFT},
-{"Super_L", SDLK_LSUPER},
-{"Super_R", SDLK_RSUPER},
-
- /* special keys */
-{"BackSpace", SDLK_BACKSPACE},
-{"Tab", SDLK_TAB},
-{"Return", SDLK_RETURN},
-{"Right", SDLK_RIGHT},
-{"Left", SDLK_LEFT},
-{"Up", SDLK_UP},
-{"Down", SDLK_DOWN},
-{"Page_Down", SDLK_PAGEDOWN},
-{"Page_Up", SDLK_PAGEUP},
-{"Insert", SDLK_INSERT},
-{"Delete", SDLK_DELETE},
-{"Home", SDLK_HOME},
-{"End", SDLK_END},
-{"Scroll_Lock", SDLK_SCROLLOCK},
-{"F1", SDLK_F1},
-{"F2", SDLK_F2},
-{"F3", SDLK_F3},
-{"F4", SDLK_F4},
-{"F5", SDLK_F5},
-{"F6", SDLK_F6},
-{"F7", SDLK_F7},
-{"F8", SDLK_F8},
-{"F9", SDLK_F9},
-{"F10", SDLK_F10},
-{"F11", SDLK_F11},
-{"F12", SDLK_F12},
-{"F13", SDLK_F13},
-{"F14", SDLK_F14},
-{"F15", SDLK_F15},
-{"Sys_Req", SDLK_SYSREQ},
-{"KP_0", SDLK_KP0},
-{"KP_1", SDLK_KP1},
-{"KP_2", SDLK_KP2},
-{"KP_3", SDLK_KP3},
-{"KP_4", SDLK_KP4},
-{"KP_5", SDLK_KP5},
-{"KP_6", SDLK_KP6},
-{"KP_7", SDLK_KP7},
-{"KP_8", SDLK_KP8},
-{"KP_9", SDLK_KP9},
-{"KP_Add", SDLK_KP_PLUS},
-{"KP_Decimal", SDLK_KP_PERIOD},
-{"KP_Divide", SDLK_KP_DIVIDE},
-{"KP_Enter", SDLK_KP_ENTER},
-{"KP_Equal", SDLK_KP_EQUALS},
-{"KP_Multiply", SDLK_KP_MULTIPLY},
-{"KP_Subtract", SDLK_KP_MINUS},
-{"help", SDLK_HELP},
-{"Menu", SDLK_MENU},
-{"Power", SDLK_POWER},
-{"Print", SDLK_PRINT},
-{"Mode_switch", SDLK_MODE},
-{"Multi_Key", SDLK_COMPOSE},
-{"Num_Lock", SDLK_NUMLOCK},
-{"Pause", SDLK_PAUSE},
-{"Escape", SDLK_ESCAPE},
-#endif
-{NULL, 0},
-};
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 52f8cb5ae1..aea6f6ebce 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1090,7 +1090,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
egl_texture_blit(ssd->gls, &ssd->blit_fb, &ssd->guest_fb,
!y_0_top);
egl_texture_blend(ssd->gls, &ssd->blit_fb, &ssd->cursor_fb,
- !y_0_top, x, y);
+ !y_0_top, x, y, 1.0, 1.0);
glFlush();
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 6002d09407..0fef646fc4 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -59,7 +59,6 @@ static QTAILQ_HEAD(, VncDisplay) vnc_displays =
QTAILQ_HEAD_INITIALIZER(vnc_displays);
static int vnc_cursor_define(VncState *vs);
-static void vnc_release_modifiers(VncState *vs);
static void vnc_update_throttle_offset(VncState *vs);
static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
@@ -1267,7 +1266,7 @@ void vnc_disconnect_finish(VncState *vs)
vnc_sasl_client_cleanup(vs);
#endif /* CONFIG_VNC_SASL */
audio_del(vs);
- vnc_release_modifiers(vs);
+ qkbd_state_lift_all_keys(vs->vd->kbd);
if (vs->mouse_mode_notifier.notify != NULL) {
qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
@@ -1756,26 +1755,10 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
qemu_input_event_sync();
}
-static void reset_keys(VncState *vs)
+static void press_key(VncState *vs, QKeyCode qcode)
{
- int i;
- for(i = 0; i < 256; i++) {
- if (vs->modifiers_state[i]) {
- qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
- qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
- vs->modifiers_state[i] = 0;
- }
- }
-}
-
-static void press_key(VncState *vs, int keysym)
-{
- int keycode = keysym2scancode(vs->vd->kbd_layout, keysym,
- false, false, false) & SCANCODE_KEYMASK;
- qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
- qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
- qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
- qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
+ qkbd_state_key_event(vs->vd->kbd, qcode, true);
+ qkbd_state_key_event(vs->vd->kbd, qcode, false);
}
static void vnc_led_state_change(VncState *vs)
@@ -1816,32 +1799,20 @@ static void kbd_leds(void *opaque, int ledstate)
static void do_key_event(VncState *vs, int down, int keycode, int sym)
{
+ QKeyCode qcode = qemu_input_key_number_to_qcode(keycode);
+
/* QEMU console switch */
- switch(keycode) {
- case 0x2a: /* Left Shift */
- case 0x36: /* Right Shift */
- case 0x1d: /* Left CTRL */
- case 0x9d: /* Right CTRL */
- case 0x38: /* Left ALT */
- case 0xb8: /* Right ALT */
- if (down)
- vs->modifiers_state[keycode] = 1;
- else
- vs->modifiers_state[keycode] = 0;
- break;
- case 0x02 ... 0x0a: /* '1' to '9' keys */
- if (vs->vd->dcl.con == NULL &&
- down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+ switch (qcode) {
+ case Q_KEY_CODE_1 ... Q_KEY_CODE_9: /* '1' to '9' keys */
+ if (vs->vd->dcl.con == NULL && down &&
+ qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CTRL) &&
+ qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_ALT)) {
/* Reset the modifiers sent to the current console */
- reset_keys(vs);
- console_select(keycode - 0x02);
+ qkbd_state_lift_all_keys(vs->vd->kbd);
+ console_select(qcode - Q_KEY_CODE_1);
return;
}
- break;
- case 0x3a: /* CapsLock */
- case 0x45: /* NumLock */
- if (down)
- vs->modifiers_state[keycode] ^= 1;
+ default:
break;
}
@@ -1856,16 +1827,14 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
toggles numlock away from the VNC window.
*/
if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
- if (!vs->modifiers_state[0x45]) {
+ if (!qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK)) {
trace_vnc_key_sync_numlock(true);
- vs->modifiers_state[0x45] = 1;
- press_key(vs, 0xff7f);
+ press_key(vs, Q_KEY_CODE_NUM_LOCK);
}
} else {
- if (vs->modifiers_state[0x45]) {
+ if (qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK)) {
trace_vnc_key_sync_numlock(false);
- vs->modifiers_state[0x45] = 0;
- press_key(vs, 0xff7f);
+ press_key(vs, Q_KEY_CODE_NUM_LOCK);
}
}
}
@@ -1878,30 +1847,25 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
toggles capslock away from the VNC window.
*/
int uppercase = !!(sym >= 'A' && sym <= 'Z');
- int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
- int capslock = !!(vs->modifiers_state[0x3a]);
+ bool shift = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_SHIFT);
+ bool capslock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CAPSLOCK);
if (capslock) {
if (uppercase == shift) {
trace_vnc_key_sync_capslock(false);
- vs->modifiers_state[0x3a] = 0;
- press_key(vs, 0xffe5);
+ press_key(vs, Q_KEY_CODE_CAPS_LOCK);
}
} else {
if (uppercase != shift) {
trace_vnc_key_sync_capslock(true);
- vs->modifiers_state[0x3a] = 1;
- press_key(vs, 0xffe5);
+ press_key(vs, Q_KEY_CODE_CAPS_LOCK);
}
}
}
- if (qemu_console_is_graphic(NULL)) {
- qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
- qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
- } else {
- bool numlock = vs->modifiers_state[0x45];
- bool control = (vs->modifiers_state[0x1d] ||
- vs->modifiers_state[0x9d]);
+ qkbd_state_key_event(vs->vd->kbd, qcode, down);
+ if (!qemu_console_is_graphic(NULL)) {
+ bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);
+ bool control = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CTRL);
/* QEMU console emulation */
if (down) {
switch (keycode) {
@@ -2002,27 +1966,6 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
}
-static void vnc_release_modifiers(VncState *vs)
-{
- static const int keycodes[] = {
- /* shift, control, alt keys, both left & right */
- 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
- };
- int i, keycode;
-
- if (!qemu_console_is_graphic(NULL)) {
- return;
- }
- for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
- keycode = keycodes[i];
- if (!vs->modifiers_state[keycode]) {
- continue;
- }
- qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
- qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
- }
-}
-
static const char *code2name(int keycode)
{
return QKeyCode_str(qemu_input_key_number_to_qcode(keycode));
@@ -2030,9 +1973,6 @@ static const char *code2name(int keycode)
static void key_event(VncState *vs, int down, uint32_t sym)
{
- bool shift = vs->modifiers_state[0x2a] || vs->modifiers_state[0x36];
- bool altgr = vs->modifiers_state[0xb8];
- bool ctrl = vs->modifiers_state[0x1d] || vs->modifiers_state[0x9d];
int keycode;
int lsym = sym;
@@ -2041,7 +1981,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
}
keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF,
- shift, altgr, ctrl) & SCANCODE_KEYMASK;
+ vs->vd->kbd, down) & SCANCODE_KEYMASK;
trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
do_key_event(vs, down, keycode, sym);
}
@@ -3259,6 +3199,7 @@ void vnc_display_init(const char *id, Error **errp)
vd->dcl.ops = &dcl_ops;
register_displaychangelistener(&vd->dcl);
+ vd->kbd = qkbd_state_init(vd->dcl.con);
}
@@ -3995,7 +3936,6 @@ void vnc_display_open(const char *id, Error **errp)
vd->led = qemu_add_led_event_handler(kbd_leds, vd);
}
vd->ledstate = 0;
- vd->key_delay_ms = key_delay_ms;
device_id = qemu_opt_get(opts, "display");
if (device_id) {
@@ -4012,10 +3952,13 @@ void vnc_display_open(const char *id, Error **errp)
}
if (con != vd->dcl.con) {
+ qkbd_state_free(vd->kbd);
unregister_displaychangelistener(&vd->dcl);
vd->dcl.con = con;
register_displaychangelistener(&vd->dcl);
+ vd->kbd = qkbd_state_init(vd->dcl.con);
}
+ qkbd_state_set_delay(vd->kbd, key_delay_ms);
if (saddr == NULL) {
goto cleanup;
diff --git a/ui/vnc.h b/ui/vnc.h
index a86e0610e8..81daa7a0eb 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -44,6 +44,7 @@
#include "keymaps.h"
#include "vnc-palette.h"
#include "vnc-enc-zrle.h"
+#include "ui/kbd-state.h"
// #define _VNC_DEBUG 1
@@ -155,7 +156,7 @@ struct VncDisplay
int lock_key_sync;
QEMUPutLEDEntry *led;
int ledstate;
- int key_delay_ms;
+ QKbdState *kbd;
QemuMutex mutex;
QEMUCursor *cursor;
@@ -326,8 +327,6 @@ struct VncState
VncReadEvent *read_handler;
size_t read_handler_expect;
- /* input */
- uint8_t modifiers_state[256];
bool abort;
QemuMutex output_mutex;
diff --git a/vl.c b/vl.c
index 9cf0fbe0b8..33d226fb48 100644
--- a/vl.c
+++ b/vl.c
@@ -160,7 +160,6 @@ static int rtc_host_datetime_offset = -1; /* valid & used only with
QEMUClockType rtc_clock;
int vga_interface_type = VGA_NONE;
static DisplayOptions dpy;
-int no_frame;
static int num_serial_hds;
static Chardev **serial_hds;
Chardev *parallel_hds[MAX_PARALLEL_PORTS];
@@ -2113,18 +2112,7 @@ static void parse_display(const char *p)
while (*opts) {
const char *nextopt;
- if (strstart(opts, ",frame=", &nextopt)) {
- g_printerr("The frame= sdl option is deprecated, and will be\n"
- "removed in a future release.\n");
- opts = nextopt;
- if (strstart(opts, "on", &nextopt)) {
- no_frame = 0;
- } else if (strstart(opts, "off", &nextopt)) {
- no_frame = 1;
- } else {
- goto invalid_sdl_args;
- }
- } else if (strstart(opts, ",alt_grab=", &nextopt)) {
+ if (strstart(opts, ",alt_grab=", &nextopt)) {
opts = nextopt;
if (strstart(opts, "on", &nextopt)) {
alt_grab = 1;
@@ -3596,11 +3584,6 @@ int main(int argc, char **argv, char **envp)
dpy.has_full_screen = true;
dpy.full_screen = true;
break;
- case QEMU_OPTION_no_frame:
- g_printerr("The -no-frame switch is deprecated, and will be\n"
- "removed in a future release.\n");
- no_frame = 1;
- break;
case QEMU_OPTION_alt_grab:
alt_grab = 1;
break;
@@ -4279,8 +4262,8 @@ int main(int argc, char **argv, char **envp)
dpy.type = DISPLAY_TYPE_NONE;
}
- if ((no_frame || alt_grab || ctrl_grab) && dpy.type != DISPLAY_TYPE_SDL) {
- error_report("-no-frame, -alt-grab and -ctrl-grab are only valid "
+ if ((alt_grab || ctrl_grab) && dpy.type != DISPLAY_TYPE_SDL) {
+ error_report("-alt-grab and -ctrl-grab are only valid "
"for SDL, ignoring option");
}
if (dpy.has_window_close &&