ui: convert GTK and SDL1 frontends to keycodemapdb
The x_keycode_to_pc_keycode and evdev_keycode_to_pc_keycode tables are replaced with automatically generated tables. In addition the X11 heuristics are improved to detect running on XQuartz and XWin X11 servers, to activate the correct OS-X and Win32 keycode maps. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Message-id: 20180117164717.15855-3-berrange@redhat.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
		
				
					committed by
					
						 Gerd Hoffmann
						Gerd Hoffmann
					
				
			
			
				
	
			
			
			
						parent
						
							ed7b2624f2
						
					
				
				
					commit
					2ec78706d1
				
			
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							| @@ -232,11 +232,18 @@ KEYCODEMAP_GEN = $(SRC_PATH)/ui/keycodemapdb/tools/keymap-gen | ||||
| KEYCODEMAP_CSV = $(SRC_PATH)/ui/keycodemapdb/data/keymaps.csv | ||||
|  | ||||
| KEYCODEMAP_FILES = \ | ||||
| 		 ui/input-keymap-atset1-to-qcode.c \ | ||||
| 		 ui/input-keymap-linux-to-qcode.c \ | ||||
| 		 ui/input-keymap-qcode-to-qnum.c \ | ||||
| 		 ui/input-keymap-qnum-to-qcode.c \ | ||||
| 		 ui/input-keymap-qcode-to-linux.c \ | ||||
| 		 ui/input-keymap-usb-to-qcode.c \ | ||||
| 		 ui/input-keymap-win32-to-qcode.c \ | ||||
| 		 ui/input-keymap-x11-to-qcode.c \ | ||||
| 		 ui/input-keymap-xorgevdev-to-qcode.c \ | ||||
| 		 ui/input-keymap-xorgkbd-to-qcode.c \ | ||||
| 		 ui/input-keymap-xorgxquartz-to-qcode.c \ | ||||
| 		 ui/input-keymap-xorgxwin-to-qcode.c \ | ||||
| 		 $(NULL) | ||||
|  | ||||
| GENERATED_FILES += $(KEYCODEMAP_FILES) | ||||
|   | ||||
| @@ -68,6 +68,9 @@ void qemu_input_check_mode_change(void); | ||||
| void qemu_add_mouse_mode_change_notifier(Notifier *notify); | ||||
| void qemu_remove_mouse_mode_change_notifier(Notifier *notify); | ||||
|  | ||||
| extern const guint qemu_input_map_atset1_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_atset1_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_linux_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_linux_to_qcode[]; | ||||
|  | ||||
| @@ -83,4 +86,22 @@ extern const guint16 qemu_input_map_qcode_to_linux[]; | ||||
| extern const guint qemu_input_map_usb_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_usb_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_win32_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_win32_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_x11_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_x11_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_xorgevdev_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_xorgevdev_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_xorgkbd_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_xorgkbd_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_xorgxquartz_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_xorgxquartz_to_qcode[]; | ||||
|  | ||||
| extern const guint qemu_input_map_xorgxwin_to_qcode_len; | ||||
| extern const guint16 qemu_input_map_xorgxwin_to_qcode[]; | ||||
|  | ||||
| #endif /* INPUT_H */ | ||||
|   | ||||
| @@ -11,11 +11,12 @@ 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-$(CONFIG_LINUX) += input-linux.o | ||||
| common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o | ||||
| common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o | ||||
| common-obj-$(CONFIG_SDL) += sdl.mo | ||||
| common-obj-$(CONFIG_COCOA) += cocoa.o | ||||
| common-obj-$(CONFIG_CURSES) += curses.o | ||||
| common-obj-$(CONFIG_VNC) += $(vnc-obj-y) | ||||
| common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o | ||||
| common-obj-$(CONFIG_GTK) += gtk.o | ||||
| common-obj-$(if $(CONFIG_WIN32),n,$(if $(CONFIG_SDL),y,$(CONFIG_GTK))) += x_keymap.o | ||||
|  | ||||
| ifeq ($(CONFIG_SDLABI),1.2) | ||||
| sdl.mo-objs := sdl.o sdl_zoom.o | ||||
|   | ||||
							
								
								
									
										201
									
								
								ui/gtk.c
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								ui/gtk.c
									
									
									
									
									
								
							| @@ -52,7 +52,6 @@ | ||||
| #include "ui/input.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "qmp-commands.h" | ||||
| #include "x_keymap.h" | ||||
| #include "keymaps.h" | ||||
| #include "chardev/char.h" | ||||
| #include "qom/object.h" | ||||
| @@ -65,6 +64,48 @@ | ||||
| #define VC_SCALE_MIN    0.25 | ||||
| #define VC_SCALE_STEP   0.25 | ||||
|  | ||||
| #ifdef GDK_WINDOWING_X11 | ||||
| #include "ui/x_keymap.h" | ||||
|  | ||||
| /* Gtk2 compat */ | ||||
| #ifndef GDK_IS_X11_DISPLAY | ||||
| #define GDK_IS_X11_DISPLAY(dpy) (dpy != NULL) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef GDK_WINDOWING_WAYLAND | ||||
| /* Gtk2 compat */ | ||||
| #ifndef GDK_IS_WAYLAND_DISPLAY | ||||
| #define GDK_IS_WAYLAND_DISPLAY(dpy) (dpy != NULL) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef GDK_WINDOWING_WIN32 | ||||
| /* Gtk2 compat */ | ||||
| #ifndef GDK_IS_WIN32_DISPLAY | ||||
| #define GDK_IS_WIN32_DISPLAY(dpy) (dpy != NULL) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef GDK_WINDOWING_BROADWAY | ||||
| /* Gtk2 compat */ | ||||
| #ifndef GDK_IS_BROADWAY_DISPLAY | ||||
| #define GDK_IS_BROADWAY_DISPLAY(dpy) (dpy != NULL) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef GDK_WINDOWING_QUARTZ | ||||
| /* Gtk2 compat */ | ||||
| #ifndef GDK_IS_QUARTZ_DISPLAY | ||||
| #define GDK_IS_QUARTZ_DISPLAY(dpy) (dpy != NULL) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #if !defined(CONFIG_VTE) | ||||
| # define VTE_CHECK_VERSION(a, b, c) 0 | ||||
| #endif | ||||
| @@ -123,10 +164,19 @@ | ||||
| #define HOTKEY_MODIFIERS        (GDK_CONTROL_MASK | GDK_MOD1_MASK) | ||||
|  | ||||
| static const int modifier_keycode[] = { | ||||
|     /* shift, control, alt keys, meta keys, both left & right */ | ||||
|     0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8, 0xdb, 0xdd, | ||||
|     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; | ||||
|  | ||||
| struct GtkDisplayState { | ||||
|     GtkWidget *window; | ||||
|  | ||||
| @@ -178,7 +228,6 @@ struct GtkDisplayState { | ||||
|     bool external_pause_update; | ||||
|  | ||||
|     bool modifier_pressed[ARRAY_SIZE(modifier_keycode)]; | ||||
|     bool has_evdev; | ||||
|     bool ignore_keys; | ||||
| }; | ||||
|  | ||||
| @@ -412,18 +461,18 @@ static void gd_update_full_redraw(VirtualConsole *vc) | ||||
| static void gtk_release_modifiers(GtkDisplayState *s) | ||||
| { | ||||
|     VirtualConsole *vc = gd_vc_find_current(s); | ||||
|     int i, keycode; | ||||
|     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++) { | ||||
|         keycode = modifier_keycode[i]; | ||||
|         qcode = modifier_keycode[i]; | ||||
|         if (!s->modifier_pressed[i]) { | ||||
|             continue; | ||||
|         } | ||||
|         qemu_input_event_send_key_number(vc->gfx.dcl.con, keycode, false); | ||||
|         qemu_input_event_send_key_qcode(vc->gfx.dcl.con, qcode, false); | ||||
|         s->modifier_pressed[i] = false; | ||||
|     } | ||||
| } | ||||
| @@ -1057,47 +1106,75 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll, | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static int gd_map_keycode(GtkDisplayState *s, GdkDisplay *dpy, int gdk_keycode) | ||||
|  | ||||
| static const guint16 *gd_get_keymap(size_t *maplen) | ||||
| { | ||||
|     int qemu_keycode; | ||||
|     GdkDisplay *dpy = gdk_display_get_default(); | ||||
|  | ||||
| #ifdef GDK_WINDOWING_X11 | ||||
|     if (GDK_IS_X11_DISPLAY(dpy)) { | ||||
|         trace_gd_keymap_windowing("x11"); | ||||
|         return qemu_xkeymap_mapping_table( | ||||
|             gdk_x11_display_get_xdisplay(dpy), maplen); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef GDK_WINDOWING_WAYLAND | ||||
|     if (GDK_IS_WAYLAND_DISPLAY(dpy)) { | ||||
|         trace_gd_keymap_windowing("wayland"); | ||||
|         *maplen = qemu_input_map_xorgevdev_to_qcode_len; | ||||
|         return qemu_input_map_xorgevdev_to_qcode; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef GDK_WINDOWING_WIN32 | ||||
|     if (GDK_IS_WIN32_DISPLAY(dpy)) { | ||||
|         qemu_keycode = MapVirtualKey(gdk_keycode, MAPVK_VK_TO_VSC); | ||||
|         switch (qemu_keycode) { | ||||
|         case 103:   /* alt gr */ | ||||
|             qemu_keycode = 56 | SCANCODE_GREY; | ||||
|             break; | ||||
|         } | ||||
|         return qemu_keycode; | ||||
|         trace_gd_keymap_windowing("win32"); | ||||
|         *maplen = qemu_input_map_win32_to_qcode_len; | ||||
|         return qemu_input_map_win32_to_qcode; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     if (gdk_keycode < 9) { | ||||
|         qemu_keycode = 0; | ||||
|     } else if (gdk_keycode < 97) { | ||||
|         qemu_keycode = gdk_keycode - 8; | ||||
| #ifdef GDK_WINDOWING_X11 | ||||
|     } else if (GDK_IS_X11_DISPLAY(dpy) && gdk_keycode < 158) { | ||||
|         if (s->has_evdev) { | ||||
|             qemu_keycode = translate_evdev_keycode(gdk_keycode - 97); | ||||
|         } else { | ||||
|             qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97); | ||||
| #ifdef GDK_WINDOWING_QUARTZ | ||||
|     if (GDK_IS_QUARTZ_DISPLAY(dpy)) { | ||||
|         trace_gd_keymap_windowing("quartz"); | ||||
|         *maplen = qemu_input_map_osx_to_qcode_len; | ||||
|         return qemu_input_map_osx_to_qcode; | ||||
|     } | ||||
| #endif | ||||
| #ifdef GDK_WINDOWING_WAYLAND | ||||
|     } else if (GDK_IS_WAYLAND_DISPLAY(dpy) && gdk_keycode < 158) { | ||||
|         qemu_keycode = translate_evdev_keycode(gdk_keycode - 97); | ||||
|  | ||||
| #ifdef GDK_WINDOWING_BROADWAY | ||||
|     if (GDK_IS_BROADWAY_DISPLAY(dpy)) { | ||||
|         trace_gd_keymap_windowing("broadway"); | ||||
|         g_warning("experimental: using broadway, x11 virtual keysym\n" | ||||
|                   "mapping - with very limited support. See also\n" | ||||
|                   "https://bugzilla.gnome.org/show_bug.cgi?id=700105"); | ||||
|         *maplen = qemu_input_map_x11_to_qcode_len; | ||||
|         return qemu_input_map_x11_to_qcode; | ||||
|     } | ||||
| #endif | ||||
|     } else if (gdk_keycode == 208) { /* Hiragana_Katakana */ | ||||
|         qemu_keycode = 0x70; | ||||
|     } else if (gdk_keycode == 211) { /* backslash */ | ||||
|         qemu_keycode = 0x73; | ||||
|     } else { | ||||
|         qemu_keycode = 0; | ||||
|  | ||||
|     g_warning("Unsupported GDK Windowing platform.\n" | ||||
|               "Disabling extended keycode tables.\n" | ||||
|               "Please report to qemu-devel@nongnu.org\n" | ||||
|               "including the following information:\n" | ||||
|               "\n" | ||||
|               "  - Operating system\n" | ||||
|               "  - GDK Windowing system build\n"); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
|     return qemu_keycode; | ||||
|  | ||||
| static int gd_map_keycode(int scancode) | ||||
| { | ||||
|     if (!keycode_map) { | ||||
|         return 0; | ||||
|     } | ||||
|     if (scancode > keycode_maplen) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     return keycode_map[scancode]; | ||||
| } | ||||
|  | ||||
| static gboolean gd_text_key_down(GtkWidget *widget, | ||||
| @@ -1111,9 +1188,7 @@ static gboolean gd_text_key_down(GtkWidget *widget, | ||||
|     } else if (key->length) { | ||||
|         kbd_put_string_console(con, key->string, key->length); | ||||
|     } else { | ||||
|         int num = gd_map_keycode(vc->s, gtk_widget_get_display(widget), | ||||
|                                  key->hardware_keycode); | ||||
|         int qcode = qemu_input_key_number_to_qcode(num); | ||||
|         int qcode = gd_map_keycode(key->hardware_keycode); | ||||
|         kbd_put_qcode_console(con, qcode); | ||||
|     } | ||||
|     return TRUE; | ||||
| @@ -1123,8 +1198,7 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) | ||||
| { | ||||
|     VirtualConsole *vc = opaque; | ||||
|     GtkDisplayState *s = vc->s; | ||||
|     int gdk_keycode = key->hardware_keycode; | ||||
|     int qemu_keycode; | ||||
|     int qcode; | ||||
|     int i; | ||||
|  | ||||
|     if (s->ignore_keys) { | ||||
| @@ -1138,19 +1212,18 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) | ||||
|         return TRUE; | ||||
|     } | ||||
|  | ||||
|     qemu_keycode = gd_map_keycode(s, gtk_widget_get_display(widget), | ||||
|                                   gdk_keycode); | ||||
|     qcode = gd_map_keycode(key->hardware_keycode); | ||||
|  | ||||
|     trace_gd_key_event(vc->label, gdk_keycode, qemu_keycode, | ||||
|     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 (qemu_keycode == modifier_keycode[i]) { | ||||
|         if (qcode == modifier_keycode[i]) { | ||||
|             s->modifier_pressed[i] = (key->type == GDK_KEY_PRESS); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     qemu_input_event_send_key_number(vc->gfx.dcl.con, qemu_keycode, | ||||
|     qemu_input_event_send_key_qcode(vc->gfx.dcl.con, qcode, | ||||
|                                     key->type == GDK_KEY_PRESS); | ||||
|  | ||||
|     return TRUE; | ||||
| @@ -2200,38 +2273,6 @@ static void gd_create_menus(GtkDisplayState *s) | ||||
|     gtk_window_add_accel_group(GTK_WINDOW(s->window), s->accel_group); | ||||
| } | ||||
|  | ||||
| static void gd_set_keycode_type(GtkDisplayState *s) | ||||
| { | ||||
| #ifdef GDK_WINDOWING_X11 | ||||
|     GdkDisplay *display = gtk_widget_get_display(s->window); | ||||
|     if (GDK_IS_X11_DISPLAY(display)) { | ||||
|         Display *x11_display = gdk_x11_display_get_xdisplay(display); | ||||
|         XkbDescPtr desc = XkbGetMap(x11_display, XkbGBN_AllComponentsMask, | ||||
|                                     XkbUseCoreKbd); | ||||
|         char *keycodes = NULL; | ||||
|  | ||||
|         if (desc && | ||||
|             (XkbGetNames(x11_display, XkbKeycodesNameMask, desc) == Success)) { | ||||
|             keycodes = XGetAtomName(x11_display, desc->names->keycodes); | ||||
|         } | ||||
|         if (keycodes == NULL) { | ||||
|             fprintf(stderr, "could not lookup keycode name\n"); | ||||
|         } else if (strstart(keycodes, "evdev", NULL)) { | ||||
|             s->has_evdev = true; | ||||
|         } else if (!strstart(keycodes, "xfree86", NULL)) { | ||||
|             fprintf(stderr, "unknown keycodes `%s', please report to " | ||||
|                     "qemu-devel@nongnu.org\n", keycodes); | ||||
|         } | ||||
|  | ||||
|         if (desc) { | ||||
|             XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True); | ||||
|         } | ||||
|         if (keycodes) { | ||||
|             XFree(keycodes); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static gboolean gtkinit; | ||||
|  | ||||
| @@ -2339,8 +2380,6 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover) | ||||
|     if (grab_on_hover) { | ||||
|         gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item)); | ||||
|     } | ||||
|  | ||||
|     gd_set_keycode_type(s); | ||||
| } | ||||
|  | ||||
| void early_gtk_display_init(int opengl) | ||||
| @@ -2387,6 +2426,8 @@ void early_gtk_display_init(int opengl) | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     keycode_map = gd_get_keymap(&keycode_maplen); | ||||
|  | ||||
| #if defined(CONFIG_VTE) | ||||
|     type_register(&char_gd_vc_type_info); | ||||
| #endif | ||||
|   | ||||
| @@ -5,11 +5,18 @@ | ||||
|  | ||||
| #include "standard-headers/linux/input.h" | ||||
|  | ||||
| #include "ui/input-keymap-atset1-to-qcode.c" | ||||
| #include "ui/input-keymap-linux-to-qcode.c" | ||||
| #include "ui/input-keymap-qcode-to-qnum.c" | ||||
| #include "ui/input-keymap-qnum-to-qcode.c" | ||||
| #include "ui/input-keymap-qcode-to-linux.c" | ||||
| #include "ui/input-keymap-usb-to-qcode.c" | ||||
| #include "ui/input-keymap-win32-to-qcode.c" | ||||
| #include "ui/input-keymap-x11-to-qcode.c" | ||||
| #include "ui/input-keymap-xorgevdev-to-qcode.c" | ||||
| #include "ui/input-keymap-xorgkbd-to-qcode.c" | ||||
| #include "ui/input-keymap-xorgxquartz-to-qcode.c" | ||||
| #include "ui/input-keymap-xorgxwin-to-qcode.c" | ||||
|  | ||||
| int qemu_input_linux_to_qcode(unsigned int lnx) | ||||
| { | ||||
|   | ||||
							
								
								
									
										103
									
								
								ui/sdl.c
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								ui/sdl.c
									
									
									
									
									
								
							| @@ -34,7 +34,9 @@ | ||||
| #include "ui/console.h" | ||||
| #include "ui/input.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #ifndef WIN32 | ||||
| #include "x_keymap.h" | ||||
| #endif | ||||
| #include "sdl_zoom.h" | ||||
|  | ||||
| static DisplayChangeListener *dcl; | ||||
| @@ -63,6 +65,8 @@ static SDL_PixelFormat host_format; | ||||
| static int scaling_active = 0; | ||||
| static Notifier mouse_mode_notifier; | ||||
| static int idle_counter; | ||||
| static const guint16 *keycode_map; | ||||
| static size_t keycode_maplen; | ||||
|  | ||||
| #define SDL_REFRESH_INTERVAL_BUSY 10 | ||||
| #define SDL_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \ | ||||
| @@ -208,94 +212,45 @@ static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev) | ||||
|     return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK; | ||||
| } | ||||
|  | ||||
| /* specific keyboard conversions from scan codes */ | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|  | ||||
| static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) | ||||
| static const guint16 *sdl_get_keymap(size_t *maplen) | ||||
| { | ||||
|     return ev->keysym.scancode; | ||||
| } | ||||
|  | ||||
| #if defined(WIN32) | ||||
|     *maplen = qemu_input_map_atset1_to_qcode_len; | ||||
|     return qemu_input_map_atset1_to_qcode; | ||||
| #else | ||||
|  | ||||
| #if defined(SDL_VIDEO_DRIVER_X11) | ||||
| #include <X11/XKBlib.h> | ||||
|  | ||||
| static int check_for_evdev(void) | ||||
| { | ||||
|     SDL_SysWMinfo info; | ||||
|     XkbDescPtr desc = NULL; | ||||
|     int has_evdev = 0; | ||||
|     char *keycodes = NULL; | ||||
|  | ||||
|     SDL_VERSION(&info.version); | ||||
|     if (!SDL_GetWMInfo(&info)) { | ||||
|         return 0; | ||||
|     } | ||||
|     desc = XkbGetMap(info.info.x11.display, | ||||
|                      XkbGBN_AllComponentsMask, | ||||
|                      XkbUseCoreKbd); | ||||
|     if (desc && | ||||
|         (XkbGetNames(info.info.x11.display, | ||||
|                      XkbKeycodesNameMask, desc) == Success)) { | ||||
|         keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes); | ||||
|         if (keycodes == NULL) { | ||||
|             fprintf(stderr, "could not lookup keycode name\n"); | ||||
|         } else if (strstart(keycodes, "evdev", NULL)) { | ||||
|             has_evdev = 1; | ||||
|         } else if (!strstart(keycodes, "xfree86", NULL)) { | ||||
|             fprintf(stderr, "unknown keycodes `%s', please report to " | ||||
|                     "qemu-devel@nongnu.org\n", keycodes); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (desc) { | ||||
|         XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True); | ||||
|     } | ||||
|     if (keycodes) { | ||||
|         XFree(keycodes); | ||||
|     } | ||||
|     return has_evdev; | ||||
| } | ||||
| #else | ||||
| static int check_for_evdev(void) | ||||
| { | ||||
| 	return 0; | ||||
|     if (SDL_GetWMInfo(&info) > 0) { | ||||
|         return qemu_xkeymap_mapping_table( | ||||
|             info.info.x11.display, maplen); | ||||
|     } | ||||
| #endif | ||||
|     g_warning("Unsupported SDL video driver / platform.\n" | ||||
|               "Assuming Linux KBD scancodes, but probably wrong.\n" | ||||
|               "Please report to qemu-devel@nongnu.org\n" | ||||
|               "including the following information:\n" | ||||
|               "\n" | ||||
|               "  - Operating system\n" | ||||
|               "  - SDL video driver\n"); | ||||
|     *maplen = qemu_input_map_xorgkbd_to_qcode_len; | ||||
|     return qemu_input_map_xorgkbd_to_qcode; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) | ||||
| { | ||||
|     int keycode; | ||||
|     static int has_evdev = -1; | ||||
|  | ||||
|     if (has_evdev == -1) | ||||
|         has_evdev = check_for_evdev(); | ||||
|  | ||||
|     keycode = ev->keysym.scancode; | ||||
|  | ||||
|     if (keycode < 9) { | ||||
|         keycode = 0; | ||||
|     } else if (keycode < 97) { | ||||
|         keycode -= 8; /* just an offset */ | ||||
|     } else if (keycode < 158) { | ||||
|         /* use conversion table */ | ||||
|         if (has_evdev) | ||||
|             keycode = translate_evdev_keycode(keycode - 97); | ||||
|         else | ||||
|             keycode = translate_xfree86_keycode(keycode - 97); | ||||
|     } else if (keycode == 208) { /* Hiragana_Katakana */ | ||||
|         keycode = 0x70; | ||||
|     } else if (keycode == 211) { /* backslash */ | ||||
|         keycode = 0x73; | ||||
|     } else { | ||||
|         keycode = 0; | ||||
|     if (!keycode_map) { | ||||
|         return 0; | ||||
|     } | ||||
|     return keycode; | ||||
|     if (ev->keysym.scancode > keycode_maplen) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
| #endif | ||||
|     return keycode_map[ev->keysym.scancode]; | ||||
| } | ||||
|  | ||||
| static void reset_keys(void) | ||||
| { | ||||
| @@ -995,6 +950,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) | ||||
|     vi = SDL_GetVideoInfo(); | ||||
|     host_format = *(vi->vfmt); | ||||
|  | ||||
|     keycode_map = sdl_get_keymap(&keycode_maplen); | ||||
|  | ||||
|     /* Load a 32x32x4 image. White pixels are transparent. */ | ||||
|     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); | ||||
|     if (filename) { | ||||
|   | ||||
| @@ -18,9 +18,10 @@ ppm_save(const char *filename, void *display_surface) "%s surface=%p" | ||||
| # ui/gtk.c | ||||
| gd_switch(const char *tab, int width, int height) "tab=%s, width=%d, height=%d" | ||||
| gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d, h=%d" | ||||
| gd_key_event(const char *tab, int gdk_keycode, int qemu_keycode, const char *action) "tab=%s, translated GDK keycode %d to QEMU keycode %d (%s)" | ||||
| gd_key_event(const char *tab, int gdk_keycode, int qkeycode, const char *action) "tab=%s, translated GDK keycode %d to QKeyCode %d (%s)" | ||||
| gd_grab(const char *tab, const char *device, const char *reason) "tab=%s, dev=%s, reason=%s" | ||||
| gd_ungrab(const char *tab, const char *device) "tab=%s, dev=%s" | ||||
| gd_keymap_windowing(const char *name) "backend=%s" | ||||
|  | ||||
| # ui/vnc.c | ||||
| vnc_key_guest_leds(bool caps, bool num, bool scroll) "caps %d, num %d, scroll %d" | ||||
| @@ -79,3 +80,9 @@ qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t b | ||||
| keymap_parse(const char *file) "file %s" | ||||
| keymap_add(const char *type, int sym, int code, const char *line) "%-6s sym=0x%04x code=0x%04x (line: %s)" | ||||
| keymap_unmapped(int sym) "sym=0x%04x" | ||||
|  | ||||
| # ui/x_keymap.c | ||||
| xkeymap_extension(const char *name) "extension '%s'" | ||||
| xkeymap_vendor(const char *name) "vendor '%s'" | ||||
| xkeymap_keycodes(const char *name) "keycodes '%s'" | ||||
| xkeymap_keymap(const char *name) "keymap '%s'" | ||||
|   | ||||
							
								
								
									
										254
									
								
								ui/x_keymap.c
									
									
									
									
									
								
							
							
						
						
									
										254
									
								
								ui/x_keymap.c
									
									
									
									
									
								
							| @@ -1,169 +1,111 @@ | ||||
| /* | ||||
|  * QEMU SDL display driver | ||||
|  * QEMU X11 keymaps | ||||
|  * | ||||
|  * Copyright (c) 2003 Fabrice Bellard | ||||
|  * Copyright (C) 2009-2010 Daniel P. Berrange <dan@berrange.com> | ||||
|  * Copyright (C) 2017 Red Hat, Inc | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
|  | ||||
| #include "qemu/osdep.h" | ||||
| #include "qemu-common.h" | ||||
|  | ||||
| #include "x_keymap.h" | ||||
| #include "trace.h" | ||||
| #include "qemu/notify.h" | ||||
| #include "ui/input.h" | ||||
|  | ||||
| static const uint8_t x_keycode_to_pc_keycode[115] = { | ||||
|    0xc7,      /*  97  Home   */ | ||||
|    0xc8,      /*  98  Up     */ | ||||
|    0xc9,      /*  99  PgUp   */ | ||||
|    0xcb,      /* 100  Left   */ | ||||
|    0x4c,        /* 101  KP-5   */ | ||||
|    0xcd,      /* 102  Right  */ | ||||
|    0xcf,      /* 103  End    */ | ||||
|    0xd0,      /* 104  Down   */ | ||||
|    0xd1,      /* 105  PgDn   */ | ||||
|    0xd2,      /* 106  Ins    */ | ||||
|    0xd3,      /* 107  Del    */ | ||||
|    0x9c,      /* 108  Enter  */ | ||||
|    0x9d,      /* 109  Ctrl-R */ | ||||
|    0x0,       /* 110  Pause  */ | ||||
|    0xb7,      /* 111  Print  */ | ||||
|    0xb5,      /* 112  Divide */ | ||||
|    0xb8,      /* 113  Alt-R  */ | ||||
|    0xc6,      /* 114  Break  */ | ||||
|    0x0,         /* 115 */ | ||||
|    0x0,         /* 116 */ | ||||
|    0x0,         /* 117 */ | ||||
|    0x0,         /* 118 */ | ||||
|    0x0,         /* 119 */ | ||||
|    0x0,         /* 120 */ | ||||
|    0x0,         /* 121 */ | ||||
|    0x0,         /* 122 */ | ||||
|    0x0,         /* 123 */ | ||||
|    0x0,         /* 124 */ | ||||
|    0x0,         /* 125 */ | ||||
|    0x0,         /* 126 */ | ||||
|    0x0,         /* 127 */ | ||||
|    0x0,         /* 128 */ | ||||
|    0x79,         /* 129 Henkan */ | ||||
|    0x0,         /* 130 */ | ||||
|    0x7b,         /* 131 Muhenkan */ | ||||
|    0x0,         /* 132 */ | ||||
|    0x7d,         /* 133 Yen */ | ||||
|    0x0,         /* 134 */ | ||||
|    0x0,         /* 135 */ | ||||
|    0x47,         /* 136 KP_7 */ | ||||
|    0x48,         /* 137 KP_8 */ | ||||
|    0x49,         /* 138 KP_9 */ | ||||
|    0x4b,         /* 139 KP_4 */ | ||||
|    0x4c,         /* 140 KP_5 */ | ||||
|    0x4d,         /* 141 KP_6 */ | ||||
|    0x4f,         /* 142 KP_1 */ | ||||
|    0x50,         /* 143 KP_2 */ | ||||
|    0x51,         /* 144 KP_3 */ | ||||
|    0x52,         /* 145 KP_0 */ | ||||
|    0x53,         /* 146 KP_. */ | ||||
|    0x47,         /* 147 KP_HOME */ | ||||
|    0x48,         /* 148 KP_UP */ | ||||
|    0x49,         /* 149 KP_PgUp */ | ||||
|    0x4b,         /* 150 KP_Left */ | ||||
|    0x4c,         /* 151 KP_ */ | ||||
|    0x4d,         /* 152 KP_Right */ | ||||
|    0x4f,         /* 153 KP_End */ | ||||
|    0x50,         /* 154 KP_Down */ | ||||
|    0x51,         /* 155 KP_PgDn */ | ||||
|    0x52,         /* 156 KP_Ins */ | ||||
|    0x53,         /* 157 KP_Del */ | ||||
| }; | ||||
| #include <X11/XKBlib.h> | ||||
|  | ||||
| /* This table is generated based off the xfree86 -> scancode mapping above | ||||
|  * and the keycode mappings in /usr/share/X11/xkb/keycodes/evdev | ||||
|  * and  /usr/share/X11/xkb/keycodes/xfree86 | ||||
| static gboolean check_for_xwin(Display *dpy) | ||||
| { | ||||
|     const char *vendor = ServerVendor(dpy); | ||||
|  | ||||
|     trace_xkeymap_vendor(vendor); | ||||
|  | ||||
|     if (strstr(vendor, "Cygwin/X")) { | ||||
|         return TRUE; | ||||
|     } | ||||
|  | ||||
|     return FALSE; | ||||
| } | ||||
|  | ||||
| static gboolean check_for_xquartz(Display *dpy) | ||||
| { | ||||
|     int nextensions; | ||||
|     int i; | ||||
|     gboolean match = FALSE; | ||||
|     char **extensions = XListExtensions(dpy, &nextensions); | ||||
|     for (i = 0 ; extensions != NULL && i < nextensions ; i++) { | ||||
|         trace_xkeymap_extension(extensions[i]); | ||||
|         if (strcmp(extensions[i], "Apple-WM") == 0 || | ||||
|             strcmp(extensions[i], "Apple-DRI") == 0) { | ||||
|             match = TRUE; | ||||
|         } | ||||
|     } | ||||
|     if (extensions) { | ||||
|         XFreeExtensionList(extensions); | ||||
|     } | ||||
|  | ||||
|     return match; | ||||
| } | ||||
|  | ||||
| const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen) | ||||
| { | ||||
|     XkbDescPtr desc; | ||||
|     const gchar *keycodes = NULL; | ||||
|  | ||||
|     /* There is no easy way to determine what X11 server | ||||
|      * and platform & keyboard driver is in use. Thus we | ||||
|      * do best guess heuristics. | ||||
|      * | ||||
|      * This will need more work for people with other | ||||
|      * X servers..... patches welcomed. | ||||
|      */ | ||||
|  | ||||
| static const uint8_t evdev_keycode_to_pc_keycode[61] = { | ||||
|     0x73,      /*  97 EVDEV - RO   ("Internet" Keyboards) */ | ||||
|     0,         /*  98 EVDEV - KATA (Katakana) */ | ||||
|     0,         /*  99 EVDEV - HIRA (Hiragana) */ | ||||
|     0x79,      /* 100 EVDEV - HENK (Henkan) */ | ||||
|     0x70,      /* 101 EVDEV - HKTG (Hiragana/Katakana toggle) */ | ||||
|     0x7b,      /* 102 EVDEV - MUHE (Muhenkan) */ | ||||
|     0,         /* 103 EVDEV - JPCM (KPJPComma) */ | ||||
|     0x9c,      /* 104 KPEN */ | ||||
|     0x9d,      /* 105 RCTL */ | ||||
|     0xb5,      /* 106 KPDV */ | ||||
|     0xb7,      /* 107 PRSC */ | ||||
|     0xb8,      /* 108 RALT */ | ||||
|     0,         /* 109 EVDEV - LNFD ("Internet" Keyboards) */ | ||||
|     0xc7,      /* 110 HOME */ | ||||
|     0xc8,      /* 111 UP */ | ||||
|     0xc9,      /* 112 PGUP */ | ||||
|     0xcb,      /* 113 LEFT */ | ||||
|     0xcd,      /* 114 RGHT */ | ||||
|     0xcf,      /* 115 END */ | ||||
|     0xd0,      /* 116 DOWN */ | ||||
|     0xd1,      /* 117 PGDN */ | ||||
|     0xd2,      /* 118 INS */ | ||||
|     0xd3,      /* 119 DELE */ | ||||
|     0,         /* 120 EVDEV - I120 ("Internet" Keyboards) */ | ||||
|     0,         /* 121 EVDEV - MUTE */ | ||||
|     0,         /* 122 EVDEV - VOL- */ | ||||
|     0,         /* 123 EVDEV - VOL+ */ | ||||
|     0,         /* 124 EVDEV - POWR */ | ||||
|     0,         /* 125 EVDEV - KPEQ */ | ||||
|     0,         /* 126 EVDEV - I126 ("Internet" Keyboards) */ | ||||
|     0,         /* 127 EVDEV - PAUS */ | ||||
|     0,         /* 128 EVDEV - ???? */ | ||||
|     0x7e,      /* 129 EVDEV - KP_COMMA (brazilian) */ | ||||
|     0xf1,      /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */ | ||||
|     0xf2,      /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */ | ||||
|     0x7d,      /* 132 AE13 (Yen)*/ | ||||
|     0xdb,      /* 133 EVDEV - LWIN */ | ||||
|     0xdc,      /* 134 EVDEV - RWIN */ | ||||
|     0xdd,      /* 135 EVDEV - MENU */ | ||||
|     0,         /* 136 EVDEV - STOP */ | ||||
|     0,         /* 137 EVDEV - AGAI */ | ||||
|     0,         /* 138 EVDEV - PROP */ | ||||
|     0,         /* 139 EVDEV - UNDO */ | ||||
|     0,         /* 140 EVDEV - FRNT */ | ||||
|     0,         /* 141 EVDEV - COPY */ | ||||
|     0,         /* 142 EVDEV - OPEN */ | ||||
|     0,         /* 143 EVDEV - PAST */ | ||||
|     0,         /* 144 EVDEV - FIND */ | ||||
|     0,         /* 145 EVDEV - CUT  */ | ||||
|     0,         /* 146 EVDEV - HELP */ | ||||
|     0,         /* 147 EVDEV - I147 */ | ||||
|     0,         /* 148 EVDEV - I148 */ | ||||
|     0,         /* 149 EVDEV - I149 */ | ||||
|     0,         /* 150 EVDEV - I150 */ | ||||
|     0,         /* 151 EVDEV - I151 */ | ||||
|     0,         /* 152 EVDEV - I152 */ | ||||
|     0,         /* 153 EVDEV - I153 */ | ||||
|     0,         /* 154 EVDEV - I154 */ | ||||
|     0,         /* 155 EVDEV - I156 */ | ||||
|     0,         /* 156 EVDEV - I157 */ | ||||
|     0,         /* 157 EVDEV - I158 */ | ||||
| }; | ||||
|  | ||||
| uint8_t translate_xfree86_keycode(const int key) | ||||
| { | ||||
|     return x_keycode_to_pc_keycode[key]; | ||||
|     desc = XkbGetMap(dpy, | ||||
|                      XkbGBN_AllComponentsMask, | ||||
|                      XkbUseCoreKbd); | ||||
|     if (desc) { | ||||
|         if (XkbGetNames(dpy, XkbKeycodesNameMask, desc) == Success) { | ||||
|             keycodes = XGetAtomName (dpy, desc->names->keycodes); | ||||
|             if (!keycodes) { | ||||
|                 g_warning("could not lookup keycode name"); | ||||
|             } else { | ||||
|                 trace_xkeymap_keycodes(keycodes); | ||||
|             } | ||||
|         } | ||||
|         XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True); | ||||
|     } | ||||
|  | ||||
| uint8_t translate_evdev_keycode(const int key) | ||||
| { | ||||
|     return evdev_keycode_to_pc_keycode[key]; | ||||
|     if (check_for_xwin(dpy)) { | ||||
|         trace_xkeymap_keymap("xwin"); | ||||
|         *maplen = qemu_input_map_xorgxwin_to_qcode_len; | ||||
|         return qemu_input_map_xorgxwin_to_qcode; | ||||
|     } else if (check_for_xquartz(dpy)) { | ||||
|         trace_xkeymap_keymap("xquartz"); | ||||
|         *maplen = qemu_input_map_xorgxquartz_to_qcode_len; | ||||
|         return qemu_input_map_xorgxquartz_to_qcode; | ||||
|     } else if (keycodes && g_str_has_prefix(keycodes, "evdev")) { | ||||
|         trace_xkeymap_keymap("evdev"); | ||||
|         *maplen = qemu_input_map_xorgevdev_to_qcode_len; | ||||
|         return qemu_input_map_xorgevdev_to_qcode; | ||||
|     } else if (keycodes && g_str_has_prefix(keycodes, "xfree86")) { | ||||
|         trace_xkeymap_keymap("kbd"); | ||||
|         *maplen = qemu_input_map_xorgkbd_to_qcode_len; | ||||
|         return qemu_input_map_xorgkbd_to_qcode; | ||||
|     } else { | ||||
|         trace_xkeymap_keymap("NULL"); | ||||
|         g_warning("Unknown X11 keycode mapping '%s'.\n" | ||||
|                   "Please report to qemu-devel@nongnu.org\n" | ||||
|                   "including the following information:\n" | ||||
|                   "\n" | ||||
|                   "  - Operating system\n" | ||||
|                   "  - X11 Server\n" | ||||
|                   "  - xprop -root\n" | ||||
|                   "  - xdpyinfo\n", | ||||
|                   keycodes ? keycodes : "<null>"); | ||||
|         return NULL; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * QEMU SDL display driver | ||||
|  * QEMU X11 keymaps | ||||
|  * | ||||
|  * Copyright (c) 2003 Fabrice Bellard | ||||
|  * Copyright (c) 2017 Red Hat, Inc. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
| @@ -25,8 +25,8 @@ | ||||
| #ifndef QEMU_X_KEYMAP_H | ||||
| #define QEMU_X_KEYMAP_H | ||||
|  | ||||
| uint8_t translate_xfree86_keycode(const int key); | ||||
| #include <X11/Xlib.h> | ||||
|  | ||||
| uint8_t translate_evdev_keycode(const int key); | ||||
| const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen); | ||||
|  | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user