Input handling rewrite.

SDL2 support.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJTFwd4AAoJEEy22O7T6HE4+JAP/jdPnsM8Vzf58mijlKix9Qks
 I/zMLn8Uri4o/cS/BeUZfXB9OetfgqwTDD2t351MSVLURSSFVU6krTj7MGnDr9o/
 NWkHSlG0J+Uoo7EF0cE9RGZEhNi4KUhbJ20Ku2S4xV3kyFSJh0wCzXWijOBZkbc5
 TAbcoUawSjq7mgK6gBqUU5C+JgACsoUohA9pWfj/f5UeQjzdFsNKVxpE7CzH4SX7
 xwl9S+wgnZk+EYQnKkL6A88lv5+8y0hPHTexsxNO5W6JaL0EQEAuTMCcjYCPMS4S
 QqOHVM+ffMVht4iN50mxi9kde7DpuLIKYbFOlWupmjpqE5j8yqzJ6eGk3pbZTrUj
 fcDauZ/+SbM/kwKV3bzm61AM5SoJb9nQ/Jf/MVs3ZdK8yRO4I1itQS6Q7I85Djs1
 BFGhSYEoPMWNiDzh2inTXCUn1wiBArLlfO0II34aCIYn6m8R38k3366YFDyH0P44
 WdnKOi6ZOxjoxoV6b4VFngysRn3c+L+5cea36mCJQZ2ykUtjFu3gLMEtUSz7guRx
 d0iA7BJVetQ2shbnopGQejRZnPusSzd5d0k9IwVPm9hmtcE8AJ9mfDaQPoKSPljv
 niG2INtu9OiNf6G6AqyKJQSREc9VX9AQ2chxQv4GiWjOBjGOi0uUF5uFeFwf8L8n
 NtZEC4K1oWa1Sa1562Td
 =8xIt
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-4' into staging

Input handling rewrite.
SDL2 support.

# gpg: Signature made Wed 05 Mar 2014 11:16:08 GMT using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-input-4: (38 commits)
  ui/sdl2 : initial port to SDL 2.0 (v2.0)
  console: add QemuUIInfo
  console: add head to index to qemu consoles.
  input: remove index_from_keycode (no users)
  input: move do_mouse_set to new core
  input: move qmp_query_mice to new core
  input: add input_mouse_mode tracepoint
  input: move mouse mode notifier to new core
  input-legacy: remove kbd_mouse_event
  input-legacy: remove kbd_mouse_is_absolute
  input-legacy: remove kbd_mouse_has_absolute
  input-legacy: remove kbd_put_keycode
  input: trace events
  input: mouse: switch cocoa ui to new core
  input: keyboard: switch cocoa ui to new core
  input: mouse: switch monitor to new core
  input: mouse: switch spice ui to new core
  input: mouse: switch vnc ui to new core
  input: mouse: switch sdl ui to new core
  input: mouse: switch gtk ui to new core
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-03-07 18:29:32 +00:00
commit 6fc0303b95
43 changed files with 2389 additions and 801 deletions

View File

@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void)
BaumDriverState *baum;
CharDriverState *chr;
brlapi_handle_t *handle;
#ifdef CONFIG_SDL
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
SDL_SysWMinfo info;
#endif
int tty;
@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void)
goto fail;
}
#ifdef CONFIG_SDL
#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
memset(&info, 0, sizeof(info));
SDL_VERSION(&info.version);
if (SDL_GetWMInfo(&info))

23
configure vendored
View File

@ -236,6 +236,7 @@ fdt=""
netmap="no"
pixman=""
sdl=""
sdlabi="1.2"
virtfs=""
vnc="yes"
sparse="no"
@ -395,6 +396,7 @@ query_pkg_config() {
}
pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
ARFLAGS="${ARFLAGS-rv}"
@ -804,6 +806,8 @@ for opt do
;;
--enable-sdl) sdl="yes"
;;
--with-sdlabi=*) sdlabi="$optarg"
;;
--disable-qom-cast-debug) qom_cast_debug="no"
;;
--enable-qom-cast-debug) qom_cast_debug="yes"
@ -1225,6 +1229,7 @@ Advanced options (experts only):
--disable-werror disable compilation abort on warning
--disable-sdl disable SDL
--enable-sdl enable SDL
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
--disable-gtk disable gtk UI
--enable-gtk enable gtk UI
--disable-virtfs disable VirtFS
@ -1986,12 +1991,22 @@ fi
# Look for sdl configuration program (pkg-config or sdl-config). Try
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
sdl_config=sdl-config
if test $sdlabi = "2.0"; then
sdl_config=$sdl2_config
sdlname=sdl2
sdlconfigname=sdl2_config
else
sdlname=sdl
sdlconfigname=sdl_config
fi
if $pkg_config sdl --exists; then
sdlconfig="$pkg_config sdl"
if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then
sdl_config=$sdlconfigname
fi
if $pkg_config $sdlname --exists; then
sdlconfig="$pkg_config $sdlname"
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
elif has ${sdl_config}; then
sdlconfig="$sdl_config"

View File

@ -630,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
"musicpal-lcd", MP_LCD_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
qemu_console_resize(s->con, 128*3, 64*3);
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);

View File

@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
s->fb = g_malloc(0x180000);
s->con = graphic_console_init(NULL, &blizzard_ops, s);
s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {

View File

@ -306,7 +306,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
qemu_console_resize(s->con, s->width, s->height);
}

View File

@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
s->con = graphic_console_init(dev, s->hw_ops, s);
s->con = graphic_console_init(dev, 0, s->hw_ops, s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
/* setup PCI */

View File

@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
"exynos4210.fimd", FIMD_REGS_SIZE);
sysbus_init_mmio(dev, &s->iomem);
s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
return 0;
}

View File

@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
{
s->vram = g_malloc0(s->vram_size);
s->con = graphic_console_init(dev, &g364fb_ops, s);
s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",

View File

@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
sysbus_init_mmio(dev, &s->iomem);
s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
return 0;
}

View File

@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
"milkymist-vgafb", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
return 0;
}

View File

@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
memory_region_add_subregion(sysmem, base, &s->iomem);
s->con = graphic_console_init(NULL, &omap_ops, s);
s->con = graphic_console_init(NULL, 0, &omap_ops, s);
return s;
}

View File

@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
return 0;
}

View File

@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
"pxa2xx-lcd-controller", 0x00100000);
memory_region_add_subregion(sysmem, base, &s->iomem);
s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {

View File

@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
portio_list_set_flush_coalesced(qxl_vga_port_list);
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qemu_spice_display_init_common(&qxl->ssd);
rc = qxl_init_common(qxl);
@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
qxl->vga.vram_size);
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
return qxl_init_common(qxl);
}

View File

@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
}
/* create qemu graphic console */
s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
}

View File

@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = SSD0303(i2c);
s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
return 0;
}

View File

@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
s->col_end = 63;
s->row_end = 79;
s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);

View File

@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
s->scr_width = 480;
s->scr_height = 640;
s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
return s;
}

View File

@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
&s->vram_mem, vram_offset, size);
sysbus_init_mmio(dev, &s->vram_cplane);
s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
TCX_THC_NREGS_8);
sysbus_init_mmio(dev, &s->thc8);
s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
}
qemu_console_resize(s->con, s->width, s->height);

View File

@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
vga_common_init(&s->vga, NULL);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
vga_init_vbe(&s->vga, NULL, address_space);
return 0;

View File

@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
isa_mem_base + 0x000a0000,
vga_io_memory, 1);
memory_region_set_coalescing(vga_io_memory);
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
/* ROM BIOS */

View File

@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* XXX: VGA_RAM_SIZE must be a power of two */
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);

View File

@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
s->scratch_size = SVGA_SCRATCH_SIZE;
s->scratch = g_malloc(s->scratch_size * 4);
s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
s->fifo_size = SVGA_FIFO_SIZE;
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);

View File

@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename)
}
/* cheat curses that we have a graphic console, only under ocd console */
graphic_console_init(NULL, &no_ops, NULL);
graphic_console_init(NULL, 0, &no_ops, NULL);
}
static void puv3_init(QEMUMachineInitArgs *args)

View File

@ -14,6 +14,8 @@
#define MOUSE_EVENT_LBUTTON 0x01
#define MOUSE_EVENT_RBUTTON 0x02
#define MOUSE_EVENT_MBUTTON 0x04
#define MOUSE_EVENT_WHEELUP 0x08
#define MOUSE_EVENT_WHEELDN 0x10
/* identical to the ps/2 keyboard bits */
#define QEMU_SCROLL_LOCK_LED (1 << 0)
@ -44,17 +46,7 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry);
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque);
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
void kbd_put_keycode(int keycode);
void kbd_put_ledstate(int ledstate);
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
/* Does the current mouse generate absolute events */
int kbd_mouse_is_absolute(void);
void qemu_add_mouse_mode_change_notifier(Notifier *notify);
void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
/* Of all the mice, is there one that generates absolute events */
int kbd_mouse_has_absolute(void);
struct MouseTransformInfo {
/* Touchscreen resolution */
@ -128,6 +120,14 @@ struct DisplaySurface {
struct PixelFormat pf;
};
typedef struct QemuUIInfo {
/* geometry */
int xoff;
int yoff;
uint32_t width;
uint32_t height;
} QemuUIInfo;
/* cursor data format is 32bit RGBA */
typedef struct QEMUCursor {
int width, height;
@ -212,6 +212,8 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
uint64_t interval);
void unregister_displaychangelistener(DisplayChangeListener *dcl);
int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *surface);
@ -274,9 +276,10 @@ typedef struct GraphicHwOps {
void (*gfx_update)(void *opaque);
void (*text_update)(void *opaque, console_ch_t *text);
void (*update_interval)(void *opaque, uint64_t interval);
int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
} GraphicHwOps;
QemuConsole *graphic_console_init(DeviceState *dev,
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *ops,
void *opaque);
@ -285,10 +288,15 @@ void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev);
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con);
int qemu_console_get_index(QemuConsole *con);
uint32_t qemu_console_get_head(QemuConsole *con);
QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con);
int qemu_console_get_width(QemuConsole *con, int fallback);
int qemu_console_get_height(QemuConsole *con, int fallback);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
@ -334,7 +342,6 @@ void curses_display_init(DisplayState *ds, int full_screen);
/* input.c */
int index_from_key(const char *key);
int index_from_keycode(int code);
/* gtk.c */
void early_gtk_display_init(void);

56
include/ui/input.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef INPUT_H
#define INPUT_H
#include "qapi-types.h"
#define INPUT_EVENT_MASK_KEY (1<<INPUT_EVENT_KIND_KEY)
#define INPUT_EVENT_MASK_BTN (1<<INPUT_EVENT_KIND_BTN)
#define INPUT_EVENT_MASK_REL (1<<INPUT_EVENT_KIND_REL)
#define INPUT_EVENT_MASK_ABS (1<<INPUT_EVENT_KIND_ABS)
#define INPUT_EVENT_ABS_SIZE 0x8000
typedef struct QemuInputHandler QemuInputHandler;
typedef struct QemuInputHandlerState QemuInputHandlerState;
typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src,
InputEvent *evt);
typedef void (*QemuInputHandlerSync)(DeviceState *dev);
struct QemuInputHandler {
const char *name;
uint32_t mask;
QemuInputHandlerEvent event;
QemuInputHandlerSync sync;
};
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
QemuInputHandler *handler);
void qemu_input_handler_activate(QemuInputHandlerState *s);
void qemu_input_handler_unregister(QemuInputHandlerState *s);
void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
void qemu_input_event_sync(void);
InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
InputEvent *qemu_input_event_new_btn(InputButton btn, bool down);
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
uint32_t button_old, uint32_t button_new);
bool qemu_input_is_absolute(void);
int qemu_input_scale_axis(int value, int size_in, int size_out);
InputEvent *qemu_input_event_new_move(InputEventKind kind,
InputAxis axis, int value);
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value);
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis,
int value, int size);
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);
#endif /* INPUT_H */

View File

@ -39,6 +39,7 @@
#include "monitor/monitor.h"
#include "qemu/readline.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/blockdev.h"
#include "audio/audio.h"
#include "disas/disas.h"
@ -1463,23 +1464,43 @@ static int mouse_button_state;
static void do_mouse_move(Monitor *mon, const QDict *qdict)
{
int dx, dy, dz;
int dx, dy, dz, button;
const char *dx_str = qdict_get_str(qdict, "dx_str");
const char *dy_str = qdict_get_str(qdict, "dy_str");
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
dx = strtol(dx_str, NULL, 0);
dy = strtol(dy_str, NULL, 0);
dz = 0;
if (dz_str)
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
if (dz_str) {
dz = strtol(dz_str, NULL, 0);
kbd_mouse_event(dx, dy, dz, mouse_button_state);
if (dz != 0) {
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
qemu_input_queue_btn(NULL, button, true);
qemu_input_event_sync();
qemu_input_queue_btn(NULL, button, false);
}
}
qemu_input_event_sync();
}
static void do_mouse_button(Monitor *mon, const QDict *qdict)
{
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
};
int button_state = qdict_get_int(qdict, "button_state");
if (mouse_button_state == button_state) {
return;
}
qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
qemu_input_event_sync();
mouse_button_state = button_state;
kbd_mouse_event(0, 0, 0, mouse_button_state);
}
static void do_ioport_read(Monitor *mon, const QDict *qdict)

View File

@ -3555,9 +3555,12 @@
# This is used by the send-key command.
#
# Since: 1.3.0
#
# 'unmapped' and 'pause' since 2.0
##
{ 'enum': 'QKeyCode',
'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
'data': [ 'unmapped',
'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e',
'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right',
@ -3571,7 +3574,7 @@
'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
'lf', 'help', 'meta_l', 'meta_r', 'compose' ] }
'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] }
##
# @KeyValue
@ -4566,3 +4569,79 @@
# Since: 1.7
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
##
# @InputButton
#
# Button of a pointer input device (mouse, tablet).
#
# Since: 2.0
##
{ 'enum' : 'InputButton',
'data' : [ 'Left', 'Middle', 'Right', 'WheelUp', 'WheelDown' ] }
##
# @InputButton
#
# Position axis of a pointer input device (mouse, tablet).
#
# Since: 2.0
##
{ 'enum' : 'InputAxis',
'data' : [ 'X', 'Y' ] }
##
# @InputKeyEvent
#
# Keyboard input event.
#
# @key: Which key this event is for.
# @down: True for key-down and false for key-up events.
#
# Since: 2.0
##
{ 'type' : 'InputKeyEvent',
'data' : { 'key' : 'KeyValue',
'down' : 'bool' } }
##
# @InputBtnEvent
#
# Pointer button input event.
#
# @button: Which button this event is for.
# @down: True for key-down and false for key-up events.
#
# Since: 2.0
##
{ 'type' : 'InputBtnEvent',
'data' : { 'button' : 'InputButton',
'down' : 'bool' } }
##
# @InputMoveEvent
#
# Pointer motion input event.
#
# @axis: Which axis is referenced by @value.
# @value: Pointer position. For absolute coordinates the
# valid range is 0 -> 0x7ffff
#
# Since: 2.0
##
{ 'type' : 'InputMoveEvent',
'data' : { 'axis' : 'InputAxis',
'value' : 'int' } }
##
# @InputEvent
#
# Input event union.
#
# Since: 2.0
##
{ 'union' : 'InputEvent',
'data' : { 'key' : 'InputKeyEvent',
'btn' : 'InputBtnEvent',
'rel' : 'InputMoveEvent',
'abs' : 'InputMoveEvent' } }

View File

@ -1020,6 +1020,15 @@ gd_switch(int width, int height) "width=%d, height=%d"
gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)"
# ui/input.c
input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%d, down %d"
input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"
input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x"
input_event_sync(void) ""
input_mouse_mode(int absolute) "absolute %d"
# hw/display/vmware_vga.c
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"

View File

@ -7,14 +7,14 @@ vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o
vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o console.o cursor.o input.o qemu-pixman.o
common-obj-y += keymaps.o console.o cursor.o input.o input-legacy.o qemu-pixman.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o
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
$(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS)
$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS)
$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)

View File

@ -27,6 +27,7 @@
#include "qemu-common.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
#ifndef MAC_OS_X_VERSION_10_4
@ -49,14 +50,6 @@
#endif
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
#define COCOA_MOUSE_EVENT \
if (isTabletEnabled) { \
kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
} else if (isMouseGrabbed) { \
kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
} else { \
[NSApp sendEvent:event]; \
}
typedef struct {
int width;
@ -67,6 +60,7 @@ typedef struct {
NSWindow *normalWindow;
static DisplayChangeListener *dcl;
static int last_buttons;
int gArgc;
char **gArgv;
@ -501,6 +495,7 @@ QemuCocoaView *cocoaView;
int buttons = 0;
int keycode;
bool mouse_event = false;
NSPoint p = [event locationInWindow];
switch ([event type]) {
@ -514,16 +509,14 @@ QemuCocoaView *cocoaView;
if (keycode) {
if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
kbd_put_keycode(keycode);
kbd_put_keycode(keycode | 0x80);
qemu_input_event_send_key_number(dcl->con, keycode, true);
qemu_input_event_send_key_number(dcl->con, keycode, false);
} else if (qemu_console_is_graphic(NULL)) {
if (keycode & 0x80)
kbd_put_keycode(0xe0);
if (modifiers_state[keycode] == 0) { // keydown
kbd_put_keycode(keycode & 0x7f);
qemu_input_event_send_key_number(dcl->con, keycode, true);
modifiers_state[keycode] = 1;
} else { // keyup
kbd_put_keycode(keycode | 0x80);
qemu_input_event_send_key_number(dcl->con, keycode, false);
modifiers_state[keycode] = 0;
}
}
@ -557,9 +550,7 @@ QemuCocoaView *cocoaView;
// handle keys for graphic console
} else if (qemu_console_is_graphic(NULL)) {
if (keycode & 0x80) //check bit for e0 in front
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
qemu_input_event_send_key_number(dcl->con, keycode, true);
// handlekeys for Monitor
} else {
@ -607,9 +598,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
qemu_input_event_send_key_number(dcl->con, keycode, false);
}
break;
case NSMouseMoved:
@ -626,7 +615,7 @@ QemuCocoaView *cocoaView;
}
}
}
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSLeftMouseDown:
if ([event modifierFlags] & NSCommandKeyMask) {
@ -634,15 +623,15 @@ QemuCocoaView *cocoaView;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSRightMouseDown:
buttons |= MOUSE_EVENT_RBUTTON;
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSOtherMouseDown:
buttons |= MOUSE_EVENT_MBUTTON;
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSLeftMouseDragged:
if ([event modifierFlags] & NSCommandKeyMask) {
@ -650,19 +639,19 @@ QemuCocoaView *cocoaView;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSRightMouseDragged:
buttons |= MOUSE_EVENT_RBUTTON;
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSOtherMouseDragged:
buttons |= MOUSE_EVENT_MBUTTON;
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSLeftMouseUp:
if (isTabletEnabled) {
COCOA_MOUSE_EVENT
mouse_event = true;
} else if (!isMouseGrabbed) {
if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
[self grabMouse];
@ -670,18 +659,20 @@ QemuCocoaView *cocoaView;
[NSApp sendEvent:event];
}
} else {
COCOA_MOUSE_EVENT
mouse_event = true;
}
break;
case NSRightMouseUp:
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSOtherMouseUp:
COCOA_MOUSE_EVENT
mouse_event = true;
break;
case NSScrollWheel:
if (isTabletEnabled || isMouseGrabbed) {
kbd_mouse_event(0, 0, -[event deltaY], 0);
buttons |= ([event deltaY] < 0) ?
MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN;
mouse_event = true;
} else {
[NSApp sendEvent:event];
}
@ -689,6 +680,30 @@ QemuCocoaView *cocoaView;
default:
[NSApp sendEvent:event];
}
if (mouse_event) {
if (last_buttons != buttons) {
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
[INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP,
[INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN,
};
qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
last_buttons = buttons;
}
if (isTabletEnabled) {
qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width);
qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, p.y, screen.height);
} else if (isMouseGrabbed) {
qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]);
qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]);
} else {
[NSApp sendEvent:event];
}
qemu_input_event_sync();
}
}
- (void) grabMouse
@ -1023,7 +1038,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
if (kbd_mouse_is_absolute()) {
if (qemu_input_is_absolute()) {
if (![cocoaView isAbsoluteEnabled]) {
if ([cocoaView isMouseGrabbed]) {
[cocoaView ungrabMouse];

View File

@ -124,6 +124,8 @@ struct QemuConsole {
/* Graphic console state. */
Object *device;
uint32_t head;
QemuUIInfo ui_info;
const GraphicHwOps *hw_ops;
void *hw;
@ -1179,6 +1181,8 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
s = QEMU_CONSOLE(obj);
object_property_add_link(obj, "device", TYPE_DEVICE,
(Object **)&s->device, &local_err);
object_property_add_uint32_ptr(obj, "head",
&s->head, &local_err);
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
(console_type == GRAPHIC_CONSOLE))) {
@ -1344,6 +1348,16 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
gui_setup_refresh(ds);
}
int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
{
assert(con != NULL);
con->ui_info = *info;
if (con->hw_ops->ui_info) {
return con->hw_ops->ui_info(con->hw, con->head, info);
}
return -1;
}
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
{
DisplayState *s = con->ds;
@ -1569,7 +1583,7 @@ DisplayState *init_displaystate(void)
return display_state;
}
QemuConsole *graphic_console_init(DeviceState *dev,
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *hw_ops,
void *opaque)
{
@ -1587,6 +1601,8 @@ QemuConsole *graphic_console_init(DeviceState *dev,
if (dev) {
object_property_set_link(OBJECT(s), OBJECT(dev),
"device", &local_err);
object_property_set_int(OBJECT(s), head,
"head", &local_err);
}
s->surface = qemu_create_displaysurface(width, height);
@ -1601,10 +1617,11 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index)
return consoles[index];
}
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
{
Error *local_err = NULL;
Object *obj;
uint32_t h;
int i;
for (i = 0; i < nb_consoles; i++) {
@ -1613,9 +1630,15 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
}
obj = object_property_get_link(OBJECT(consoles[i]),
"device", &local_err);
if (DEVICE(obj) == dev) {
return consoles[i];
if (DEVICE(obj) != dev) {
continue;
}
h = object_property_get_int(OBJECT(consoles[i]),
"head", &local_err);
if (h != head) {
continue;
}
return consoles[i];
}
return NULL;
}
@ -1641,6 +1664,44 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
return con && (con->console_type != TEXT_CONSOLE);
}
int qemu_console_get_index(QemuConsole *con)
{
if (con == NULL) {
con = active_console;
}
return con ? con->index : -1;
}
uint32_t qemu_console_get_head(QemuConsole *con)
{
if (con == NULL) {
con = active_console;
}
return con ? con->head : -1;
}
QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
{
assert(con != NULL);
return &con->ui_info;
}
int qemu_console_get_width(QemuConsole *con, int fallback)
{
if (con == NULL) {
con = active_console;
}
return con ? surface_width(con->surface) : fallback;
}
int qemu_console_get_height(QemuConsole *con, int fallback)
{
if (con == NULL) {
con = active_console;
}
return con ? surface_height(con->surface) : fallback;
}
static void text_console_set_echo(CharDriverState *chr, bool echo)
{
QemuConsole *s = chr->opaque;

View File

@ -30,6 +30,7 @@
#include "qemu-common.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
#define FONT_HEIGHT 16
@ -274,32 +275,34 @@ static void curses_refresh(DisplayChangeListener *dcl)
if (qemu_console_is_graphic(NULL)) {
/* since terminals don't know about key press and release
* events, we need to emit both for each key received */
if (keycode & SHIFT)
kbd_put_keycode(SHIFT_CODE);
if (keycode & CNTRL)
kbd_put_keycode(CNTRL_CODE);
if (keycode & ALT)
kbd_put_keycode(ALT_CODE);
if (keycode & ALTGR) {
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(ALT_CODE);
if (keycode & SHIFT) {
qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
}
if (keycode & GREY)
kbd_put_keycode(GREY_CODE);
kbd_put_keycode(keycode & KEY_MASK);
if (keycode & GREY)
kbd_put_keycode(GREY_CODE);
kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
if (keycode & ALTGR) {
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(ALT_CODE | KEY_RELEASE);
if (keycode & CNTRL) {
qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
}
if (keycode & ALT) {
qemu_input_event_send_key_number(NULL, ALT_CODE, true);
}
if (keycode & ALTGR) {
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
}
qemu_input_event_send_key_number(NULL, keycode, true);
qemu_input_event_send_key_number(NULL, keycode, false);
if (keycode & ALTGR) {
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
}
if (keycode & ALT) {
qemu_input_event_send_key_number(NULL, ALT_CODE, false);
}
if (keycode & CNTRL) {
qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
}
if (keycode & SHIFT) {
qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
}
if (keycode & ALT)
kbd_put_keycode(ALT_CODE | KEY_RELEASE);
if (keycode & CNTRL)
kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
if (keycode & SHIFT)
kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
} else {
keysym = curses2qemu[chr];
if (keysym == -1)

View File

@ -59,6 +59,7 @@
#include "trace.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "qmp-commands.h"
#include "x_keymap.h"
@ -193,7 +194,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
on_vga = gd_on_vga(s);
if ((override || on_vga) &&
(s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
(s->full_screen || qemu_input_is_absolute() || gd_is_grab_active(s))) {
gdk_window_set_cursor(window, s->null_cursor);
} else {
gdk_window_set_cursor(window, NULL);
@ -280,10 +281,7 @@ static void gtk_release_modifiers(GtkDisplayState *s)
if (!s->modifier_pressed[i]) {
continue;
}
if (keycode & SCANCODE_GREY) {
kbd_put_keycode(SCANCODE_EMUL0);
}
kbd_put_keycode(keycode | SCANCODE_UP);
qemu_input_event_send_key_number(s->dcl.con, keycode, false);
s->modifier_pressed[i] = false;
}
}
@ -582,7 +580,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
void *opaque)
{
GtkDisplayState *s = opaque;
int dx, dy;
int x, y;
int mx, my;
int fbh, fbw;
@ -610,25 +607,21 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
return TRUE;
}
if (kbd_mouse_is_absolute()) {
dx = x * 0x7FFF / (surface_width(s->ds) - 1);
dy = y * 0x7FFF / (surface_height(s->ds) - 1);
} else if (s->last_x == -1 || s->last_y == -1) {
dx = 0;
dy = 0;
} else {
dx = x - s->last_x;
dy = y - s->last_y;
if (qemu_input_is_absolute()) {
qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x,
surface_width(s->ds));
qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y,
surface_height(s->ds));
qemu_input_event_sync();
} else if (s->last_x != -1 && s->last_y != -1 && gd_is_grab_active(s)) {
qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x);
qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y);
qemu_input_event_sync();
}
s->last_x = x;
s->last_y = y;
if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) {
kbd_mouse_event(dx, dy, 0, s->button_mask);
}
if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
if (!qemu_input_is_absolute() && gd_is_grab_active(s)) {
GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
int x = (int)motion->x_root;
int y = (int)motion->y_root;
@ -673,35 +666,20 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
void *opaque)
{
GtkDisplayState *s = opaque;
int dx, dy;
int n;
InputButton btn;
if (button->button == 1) {
n = 0x01;
btn = INPUT_BUTTON_LEFT;
} else if (button->button == 2) {
n = 0x04;
btn = INPUT_BUTTON_MIDDLE;
} else if (button->button == 3) {
n = 0x02;
btn = INPUT_BUTTON_RIGHT;
} else {
n = 0x00;
return TRUE;
}
if (button->type == GDK_BUTTON_PRESS) {
s->button_mask |= n;
} else if (button->type == GDK_BUTTON_RELEASE) {
s->button_mask &= ~n;
}
if (kbd_mouse_is_absolute()) {
dx = s->last_x * 0x7FFF / (surface_width(s->ds) - 1);
dy = s->last_y * 0x7FFF / (surface_height(s->ds) - 1);
} else {
dx = 0;
dy = 0;
}
kbd_mouse_event(dx, dy, 0, s->button_mask);
qemu_input_queue_btn(s->dcl.con, btn, button->type == GDK_BUTTON_PRESS);
qemu_input_event_sync();
return TRUE;
}
@ -745,17 +723,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
}
}
if (qemu_keycode & SCANCODE_GREY) {
kbd_put_keycode(SCANCODE_EMUL0);
}
if (key->type == GDK_KEY_PRESS) {
kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
} else if (key->type == GDK_KEY_RELEASE) {
kbd_put_keycode(qemu_keycode | SCANCODE_UP);
} else {
g_assert_not_reached();
}
qemu_input_event_send_key_number(s->dcl.con, qemu_keycode,
key->type == GDK_KEY_PRESS);
return TRUE;
}

453
ui/input-legacy.c Normal file
View File

@ -0,0 +1,453 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* 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.
*/
#include "sysemu/sysemu.h"
#include "monitor/monitor.h"
#include "ui/console.h"
#include "qapi/error.h"
#include "qmp-commands.h"
#include "qapi-types.h"
#include "ui/keymaps.h"
#include "ui/input.h"
struct QEMUPutMouseEntry {
QEMUPutMouseEvent *qemu_put_mouse_event;
void *qemu_put_mouse_event_opaque;
int qemu_put_mouse_event_absolute;
/* new input core */
QemuInputHandler h;
QemuInputHandlerState *s;
int axis[INPUT_AXIS_MAX];
int buttons;
};
struct QEMUPutKbdEntry {
QEMUPutKBDEvent *put_kbd;
void *opaque;
QemuInputHandlerState *s;
};
struct QEMUPutLEDEntry {
QEMUPutLEDEvent *put_led;
void *opaque;
QTAILQ_ENTRY(QEMUPutLEDEntry) next;
};
static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
QTAILQ_HEAD_INITIALIZER(led_handlers);
static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
QTAILQ_HEAD_INITIALIZER(mouse_handlers);
static const int key_defs[] = {
[Q_KEY_CODE_SHIFT] = 0x2a,
[Q_KEY_CODE_SHIFT_R] = 0x36,
[Q_KEY_CODE_ALT] = 0x38,
[Q_KEY_CODE_ALT_R] = 0xb8,
[Q_KEY_CODE_ALTGR] = 0x64,
[Q_KEY_CODE_ALTGR_R] = 0xe4,
[Q_KEY_CODE_CTRL] = 0x1d,
[Q_KEY_CODE_CTRL_R] = 0x9d,
[Q_KEY_CODE_MENU] = 0xdd,
[Q_KEY_CODE_ESC] = 0x01,
[Q_KEY_CODE_1] = 0x02,
[Q_KEY_CODE_2] = 0x03,
[Q_KEY_CODE_3] = 0x04,
[Q_KEY_CODE_4] = 0x05,
[Q_KEY_CODE_5] = 0x06,
[Q_KEY_CODE_6] = 0x07,
[Q_KEY_CODE_7] = 0x08,
[Q_KEY_CODE_8] = 0x09,
[Q_KEY_CODE_9] = 0x0a,
[Q_KEY_CODE_0] = 0x0b,
[Q_KEY_CODE_MINUS] = 0x0c,
[Q_KEY_CODE_EQUAL] = 0x0d,
[Q_KEY_CODE_BACKSPACE] = 0x0e,
[Q_KEY_CODE_TAB] = 0x0f,
[Q_KEY_CODE_Q] = 0x10,
[Q_KEY_CODE_W] = 0x11,
[Q_KEY_CODE_E] = 0x12,
[Q_KEY_CODE_R] = 0x13,
[Q_KEY_CODE_T] = 0x14,
[Q_KEY_CODE_Y] = 0x15,
[Q_KEY_CODE_U] = 0x16,
[Q_KEY_CODE_I] = 0x17,
[Q_KEY_CODE_O] = 0x18,
[Q_KEY_CODE_P] = 0x19,
[Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
[Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
[Q_KEY_CODE_RET] = 0x1c,
[Q_KEY_CODE_A] = 0x1e,
[Q_KEY_CODE_S] = 0x1f,
[Q_KEY_CODE_D] = 0x20,
[Q_KEY_CODE_F] = 0x21,
[Q_KEY_CODE_G] = 0x22,
[Q_KEY_CODE_H] = 0x23,
[Q_KEY_CODE_J] = 0x24,
[Q_KEY_CODE_K] = 0x25,
[Q_KEY_CODE_L] = 0x26,
[Q_KEY_CODE_SEMICOLON] = 0x27,
[Q_KEY_CODE_APOSTROPHE] = 0x28,
[Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
[Q_KEY_CODE_BACKSLASH] = 0x2b,
[Q_KEY_CODE_Z] = 0x2c,
[Q_KEY_CODE_X] = 0x2d,
[Q_KEY_CODE_C] = 0x2e,
[Q_KEY_CODE_V] = 0x2f,
[Q_KEY_CODE_B] = 0x30,
[Q_KEY_CODE_N] = 0x31,
[Q_KEY_CODE_M] = 0x32,
[Q_KEY_CODE_COMMA] = 0x33,
[Q_KEY_CODE_DOT] = 0x34,
[Q_KEY_CODE_SLASH] = 0x35,
[Q_KEY_CODE_ASTERISK] = 0x37,
[Q_KEY_CODE_SPC] = 0x39,
[Q_KEY_CODE_CAPS_LOCK] = 0x3a,
[Q_KEY_CODE_F1] = 0x3b,
[Q_KEY_CODE_F2] = 0x3c,
[Q_KEY_CODE_F3] = 0x3d,
[Q_KEY_CODE_F4] = 0x3e,
[Q_KEY_CODE_F5] = 0x3f,
[Q_KEY_CODE_F6] = 0x40,
[Q_KEY_CODE_F7] = 0x41,
[Q_KEY_CODE_F8] = 0x42,
[Q_KEY_CODE_F9] = 0x43,
[Q_KEY_CODE_F10] = 0x44,
[Q_KEY_CODE_NUM_LOCK] = 0x45,
[Q_KEY_CODE_SCROLL_LOCK] = 0x46,
[Q_KEY_CODE_KP_DIVIDE] = 0xb5,
[Q_KEY_CODE_KP_MULTIPLY] = 0x37,
[Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
[Q_KEY_CODE_KP_ADD] = 0x4e,
[Q_KEY_CODE_KP_ENTER] = 0x9c,
[Q_KEY_CODE_KP_DECIMAL] = 0x53,
[Q_KEY_CODE_SYSRQ] = 0x54,
[Q_KEY_CODE_KP_0] = 0x52,
[Q_KEY_CODE_KP_1] = 0x4f,
[Q_KEY_CODE_KP_2] = 0x50,
[Q_KEY_CODE_KP_3] = 0x51,
[Q_KEY_CODE_KP_4] = 0x4b,
[Q_KEY_CODE_KP_5] = 0x4c,
[Q_KEY_CODE_KP_6] = 0x4d,
[Q_KEY_CODE_KP_7] = 0x47,
[Q_KEY_CODE_KP_8] = 0x48,
[Q_KEY_CODE_KP_9] = 0x49,
[Q_KEY_CODE_LESS] = 0x56,
[Q_KEY_CODE_F11] = 0x57,
[Q_KEY_CODE_F12] = 0x58,
[Q_KEY_CODE_PRINT] = 0xb7,
[Q_KEY_CODE_HOME] = 0xc7,
[Q_KEY_CODE_PGUP] = 0xc9,
[Q_KEY_CODE_PGDN] = 0xd1,
[Q_KEY_CODE_END] = 0xcf,
[Q_KEY_CODE_LEFT] = 0xcb,
[Q_KEY_CODE_UP] = 0xc8,
[Q_KEY_CODE_DOWN] = 0xd0,
[Q_KEY_CODE_RIGHT] = 0xcd,
[Q_KEY_CODE_INSERT] = 0xd2,
[Q_KEY_CODE_DELETE] = 0xd3,
#ifdef NEED_CPU_H
#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
[Q_KEY_CODE_STOP] = 0xf0,
[Q_KEY_CODE_AGAIN] = 0xf1,
[Q_KEY_CODE_PROPS] = 0xf2,
[Q_KEY_CODE_UNDO] = 0xf3,
[Q_KEY_CODE_FRONT] = 0xf4,
[Q_KEY_CODE_COPY] = 0xf5,
[Q_KEY_CODE_OPEN] = 0xf6,
[Q_KEY_CODE_PASTE] = 0xf7,
[Q_KEY_CODE_FIND] = 0xf8,
[Q_KEY_CODE_CUT] = 0xf9,
[Q_KEY_CODE_LF] = 0xfa,
[Q_KEY_CODE_HELP] = 0xfb,
[Q_KEY_CODE_META_L] = 0xfc,
[Q_KEY_CODE_META_R] = 0xfd,
[Q_KEY_CODE_COMPOSE] = 0xfe,
#endif
#endif
[Q_KEY_CODE_MAX] = 0,
};
int index_from_key(const char *key)
{
int i;
for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
if (!strcmp(key, QKeyCode_lookup[i])) {
break;
}
}
/* Return Q_KEY_CODE_MAX if the key is invalid */
return i;
}
static int *keycodes;
static int keycodes_size;
static QEMUTimer *key_timer;
static int keycode_from_keyvalue(const KeyValue *value)
{
if (value->kind == KEY_VALUE_KIND_QCODE) {
return key_defs[value->qcode];
} else {
assert(value->kind == KEY_VALUE_KIND_NUMBER);
return value->number;
}
}
static void free_keycodes(void)
{
g_free(keycodes);
keycodes = NULL;
keycodes_size = 0;
}
static void release_keys(void *opaque)
{
while (keycodes_size > 0) {
qemu_input_event_send_key_number(NULL, keycodes[--keycodes_size],
false);
}
free_keycodes();
}
void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
Error **errp)
{
int keycode;
KeyValueList *p;
if (!key_timer) {
key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
}
if (keycodes != NULL) {
timer_del(key_timer);
release_keys(NULL);
}
if (!has_hold_time) {
hold_time = 100;
}
for (p = keys; p != NULL; p = p->next) {
/* key down events */
keycode = keycode_from_keyvalue(p->value);
if (keycode < 0x01 || keycode > 0xff) {
error_setg(errp, "invalid hex keycode 0x%x", keycode);
free_keycodes();
return;
}
qemu_input_event_send_key_number(NULL, keycode, true);
keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
keycodes[keycodes_size++] = keycode;
}
/* delayed key up events */
timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
muldiv64(get_ticks_per_sec(), hold_time, 1000));
}
static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
int keycode = keycode_from_keyvalue(evt->key->key);
if (!entry || !entry->put_kbd) {
return;
}
if (evt->key->key->kind == KEY_VALUE_KIND_QCODE &&
evt->key->key->qcode == Q_KEY_CODE_PAUSE) {
/* specific case */
int v = evt->key->down ? 0 : 0x80;
entry->put_kbd(entry->opaque, 0xe1);
entry->put_kbd(entry->opaque, 0x1d | v);
entry->put_kbd(entry->opaque, 0x45 | v);
return;
}
if (keycode & SCANCODE_GREY) {
entry->put_kbd(entry->opaque, SCANCODE_EMUL0);
keycode &= ~SCANCODE_GREY;
}
if (!evt->key->down) {
keycode |= SCANCODE_UP;
}
entry->put_kbd(entry->opaque, keycode);
}
static QemuInputHandler legacy_kbd_handler = {
.name = "legacy-kbd",
.mask = INPUT_EVENT_MASK_KEY,
.event = legacy_kbd_event,
};
QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
{
QEMUPutKbdEntry *entry;
entry = g_new0(QEMUPutKbdEntry, 1);
entry->put_kbd = func;
entry->opaque = opaque;
entry->s = qemu_input_handler_register((DeviceState *)entry,
&legacy_kbd_handler);
return entry;
}
void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry)
{
qemu_input_handler_unregister(entry->s);
g_free(entry);
}
static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
static const int bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
};
QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
switch (evt->kind) {
case INPUT_EVENT_KIND_BTN:
if (evt->btn->down) {
s->buttons |= bmap[evt->btn->button];
} else {
s->buttons &= ~bmap[evt->btn->button];
}
break;
case INPUT_EVENT_KIND_ABS:
s->axis[evt->abs->axis] = evt->abs->value;
break;
case INPUT_EVENT_KIND_REL:
s->axis[evt->rel->axis] += evt->rel->value;
break;
default:
break;
}
}
static void legacy_mouse_sync(DeviceState *dev)
{
QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
s->axis[INPUT_AXIS_X],
s->axis[INPUT_AXIS_Y],
0,
s->buttons);
if (!s->qemu_put_mouse_event_absolute) {
s->axis[INPUT_AXIS_X] = 0;
s->axis[INPUT_AXIS_Y] = 0;
}
}
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
void *opaque, int absolute,
const char *name)
{
QEMUPutMouseEntry *s;
s = g_malloc0(sizeof(QEMUPutMouseEntry));
s->qemu_put_mouse_event = func;
s->qemu_put_mouse_event_opaque = opaque;
s->qemu_put_mouse_event_absolute = absolute;
s->h.name = name;
s->h.mask = INPUT_EVENT_MASK_BTN |
(absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL);
s->h.event = legacy_mouse_event;
s->h.sync = legacy_mouse_sync;
s->s = qemu_input_handler_register((DeviceState *)s,
&s->h);
return s;
}
void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
{
qemu_input_handler_activate(entry->s);
}
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
{
qemu_input_handler_unregister(entry->s);
g_free(entry);
}
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
void *opaque)
{
QEMUPutLEDEntry *s;
s = g_malloc0(sizeof(QEMUPutLEDEntry));
s->put_led = func;
s->opaque = opaque;
QTAILQ_INSERT_TAIL(&led_handlers, s, next);
return s;
}
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
{
if (entry == NULL)
return;
QTAILQ_REMOVE(&led_handlers, entry, next);
g_free(entry);
}
void kbd_put_ledstate(int ledstate)
{
QEMUPutLEDEntry *cursor;
QTAILQ_FOREACH(cursor, &led_handlers, next) {
cursor->put_led(cursor->opaque, ledstate);
}
}

View File

@ -1,551 +1,300 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* 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.
*/
#include "sysemu/sysemu.h"
#include "monitor/monitor.h"
#include "ui/console.h"
#include "qapi/error.h"
#include "qmp-commands.h"
#include "qapi-types.h"
#include "ui/keymaps.h"
#include "qmp-commands.h"
#include "trace.h"
#include "ui/input.h"
#include "ui/console.h"
struct QEMUPutMouseEntry {
QEMUPutMouseEvent *qemu_put_mouse_event;
void *qemu_put_mouse_event_opaque;
int qemu_put_mouse_event_absolute;
char *qemu_put_mouse_event_name;
int index;
/* used internally by qemu for handling mice */
QTAILQ_ENTRY(QEMUPutMouseEntry) node;
struct QemuInputHandlerState {
DeviceState *dev;
QemuInputHandler *handler;
int id;
int events;
QTAILQ_ENTRY(QemuInputHandlerState) node;
};
struct QEMUPutKbdEntry {
QEMUPutKBDEvent *put_kbd;
void *opaque;
QTAILQ_ENTRY(QEMUPutKbdEntry) next;
};
struct QEMUPutLEDEntry {
QEMUPutLEDEvent *put_led;
void *opaque;
QTAILQ_ENTRY(QEMUPutLEDEntry) next;
};
static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
QTAILQ_HEAD_INITIALIZER(led_handlers);
static QTAILQ_HEAD(, QEMUPutKbdEntry) kbd_handlers =
QTAILQ_HEAD_INITIALIZER(kbd_handlers);
static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
QTAILQ_HEAD_INITIALIZER(mouse_handlers);
static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
QTAILQ_HEAD_INITIALIZER(handlers);
static NotifierList mouse_mode_notifiers =
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
static const int key_defs[] = {
[Q_KEY_CODE_SHIFT] = 0x2a,
[Q_KEY_CODE_SHIFT_R] = 0x36,
[Q_KEY_CODE_ALT] = 0x38,
[Q_KEY_CODE_ALT_R] = 0xb8,
[Q_KEY_CODE_ALTGR] = 0x64,
[Q_KEY_CODE_ALTGR_R] = 0xe4,
[Q_KEY_CODE_CTRL] = 0x1d,
[Q_KEY_CODE_CTRL_R] = 0x9d,
[Q_KEY_CODE_MENU] = 0xdd,
[Q_KEY_CODE_ESC] = 0x01,
[Q_KEY_CODE_1] = 0x02,
[Q_KEY_CODE_2] = 0x03,
[Q_KEY_CODE_3] = 0x04,
[Q_KEY_CODE_4] = 0x05,
[Q_KEY_CODE_5] = 0x06,
[Q_KEY_CODE_6] = 0x07,
[Q_KEY_CODE_7] = 0x08,
[Q_KEY_CODE_8] = 0x09,
[Q_KEY_CODE_9] = 0x0a,
[Q_KEY_CODE_0] = 0x0b,
[Q_KEY_CODE_MINUS] = 0x0c,
[Q_KEY_CODE_EQUAL] = 0x0d,
[Q_KEY_CODE_BACKSPACE] = 0x0e,
[Q_KEY_CODE_TAB] = 0x0f,
[Q_KEY_CODE_Q] = 0x10,
[Q_KEY_CODE_W] = 0x11,
[Q_KEY_CODE_E] = 0x12,
[Q_KEY_CODE_R] = 0x13,
[Q_KEY_CODE_T] = 0x14,
[Q_KEY_CODE_Y] = 0x15,
[Q_KEY_CODE_U] = 0x16,
[Q_KEY_CODE_I] = 0x17,
[Q_KEY_CODE_O] = 0x18,
[Q_KEY_CODE_P] = 0x19,
[Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
[Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
[Q_KEY_CODE_RET] = 0x1c,
[Q_KEY_CODE_A] = 0x1e,
[Q_KEY_CODE_S] = 0x1f,
[Q_KEY_CODE_D] = 0x20,
[Q_KEY_CODE_F] = 0x21,
[Q_KEY_CODE_G] = 0x22,
[Q_KEY_CODE_H] = 0x23,
[Q_KEY_CODE_J] = 0x24,
[Q_KEY_CODE_K] = 0x25,
[Q_KEY_CODE_L] = 0x26,
[Q_KEY_CODE_SEMICOLON] = 0x27,
[Q_KEY_CODE_APOSTROPHE] = 0x28,
[Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
[Q_KEY_CODE_BACKSLASH] = 0x2b,
[Q_KEY_CODE_Z] = 0x2c,
[Q_KEY_CODE_X] = 0x2d,
[Q_KEY_CODE_C] = 0x2e,
[Q_KEY_CODE_V] = 0x2f,
[Q_KEY_CODE_B] = 0x30,
[Q_KEY_CODE_N] = 0x31,
[Q_KEY_CODE_M] = 0x32,
[Q_KEY_CODE_COMMA] = 0x33,
[Q_KEY_CODE_DOT] = 0x34,
[Q_KEY_CODE_SLASH] = 0x35,
[Q_KEY_CODE_ASTERISK] = 0x37,
[Q_KEY_CODE_SPC] = 0x39,
[Q_KEY_CODE_CAPS_LOCK] = 0x3a,
[Q_KEY_CODE_F1] = 0x3b,
[Q_KEY_CODE_F2] = 0x3c,
[Q_KEY_CODE_F3] = 0x3d,
[Q_KEY_CODE_F4] = 0x3e,
[Q_KEY_CODE_F5] = 0x3f,
[Q_KEY_CODE_F6] = 0x40,
[Q_KEY_CODE_F7] = 0x41,
[Q_KEY_CODE_F8] = 0x42,
[Q_KEY_CODE_F9] = 0x43,
[Q_KEY_CODE_F10] = 0x44,
[Q_KEY_CODE_NUM_LOCK] = 0x45,
[Q_KEY_CODE_SCROLL_LOCK] = 0x46,
[Q_KEY_CODE_KP_DIVIDE] = 0xb5,
[Q_KEY_CODE_KP_MULTIPLY] = 0x37,
[Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
[Q_KEY_CODE_KP_ADD] = 0x4e,
[Q_KEY_CODE_KP_ENTER] = 0x9c,
[Q_KEY_CODE_KP_DECIMAL] = 0x53,
[Q_KEY_CODE_SYSRQ] = 0x54,
[Q_KEY_CODE_KP_0] = 0x52,
[Q_KEY_CODE_KP_1] = 0x4f,
[Q_KEY_CODE_KP_2] = 0x50,
[Q_KEY_CODE_KP_3] = 0x51,
[Q_KEY_CODE_KP_4] = 0x4b,
[Q_KEY_CODE_KP_5] = 0x4c,
[Q_KEY_CODE_KP_6] = 0x4d,
[Q_KEY_CODE_KP_7] = 0x47,
[Q_KEY_CODE_KP_8] = 0x48,
[Q_KEY_CODE_KP_9] = 0x49,
[Q_KEY_CODE_LESS] = 0x56,
[Q_KEY_CODE_F11] = 0x57,
[Q_KEY_CODE_F12] = 0x58,
[Q_KEY_CODE_PRINT] = 0xb7,
[Q_KEY_CODE_HOME] = 0xc7,
[Q_KEY_CODE_PGUP] = 0xc9,
[Q_KEY_CODE_PGDN] = 0xd1,
[Q_KEY_CODE_END] = 0xcf,
[Q_KEY_CODE_LEFT] = 0xcb,
[Q_KEY_CODE_UP] = 0xc8,
[Q_KEY_CODE_DOWN] = 0xd0,
[Q_KEY_CODE_RIGHT] = 0xcd,
[Q_KEY_CODE_INSERT] = 0xd2,
[Q_KEY_CODE_DELETE] = 0xd3,
#ifdef NEED_CPU_H
#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
[Q_KEY_CODE_STOP] = 0xf0,
[Q_KEY_CODE_AGAIN] = 0xf1,
[Q_KEY_CODE_PROPS] = 0xf2,
[Q_KEY_CODE_UNDO] = 0xf3,
[Q_KEY_CODE_FRONT] = 0xf4,
[Q_KEY_CODE_COPY] = 0xf5,
[Q_KEY_CODE_OPEN] = 0xf6,
[Q_KEY_CODE_PASTE] = 0xf7,
[Q_KEY_CODE_FIND] = 0xf8,
[Q_KEY_CODE_CUT] = 0xf9,
[Q_KEY_CODE_LF] = 0xfa,
[Q_KEY_CODE_HELP] = 0xfb,
[Q_KEY_CODE_META_L] = 0xfc,
[Q_KEY_CODE_META_R] = 0xfd,
[Q_KEY_CODE_COMPOSE] = 0xfe,
#endif
#endif
[Q_KEY_CODE_MAX] = 0,
};
int index_from_key(const char *key)
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
QemuInputHandler *handler)
{
int i;
QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
static int id = 1;
for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
if (!strcmp(key, QKeyCode_lookup[i])) {
s->dev = dev;
s->handler = handler;
s->id = id++;
QTAILQ_INSERT_TAIL(&handlers, s, node);
qemu_input_check_mode_change();
return s;
}
void qemu_input_handler_activate(QemuInputHandlerState *s)
{
QTAILQ_REMOVE(&handlers, s, node);
QTAILQ_INSERT_HEAD(&handlers, s, node);
qemu_input_check_mode_change();
}
void qemu_input_handler_unregister(QemuInputHandlerState *s)
{
QTAILQ_REMOVE(&handlers, s, node);
g_free(s);
qemu_input_check_mode_change();
}
static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask)
{
QemuInputHandlerState *s;
QTAILQ_FOREACH(s, &handlers, node) {
if (mask & s->handler->mask) {
return s;
}
}
return NULL;
}
static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
switch (graphic_rotate) {
case 90:
if (evt->abs->axis == INPUT_AXIS_X) {
evt->abs->axis = INPUT_AXIS_Y;
} else if (evt->abs->axis == INPUT_AXIS_Y) {
evt->abs->axis = INPUT_AXIS_X;
evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
}
break;
case 180:
evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
break;
case 270:
if (evt->abs->axis == INPUT_AXIS_X) {
evt->abs->axis = INPUT_AXIS_Y;
evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
} else if (evt->abs->axis == INPUT_AXIS_Y) {
evt->abs->axis = INPUT_AXIS_X;
}
break;
}
}
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{
const char *name;
int idx = -1;
if (src) {
idx = qemu_console_get_index(src);
}
switch (evt->kind) {
case INPUT_EVENT_KIND_KEY:
switch (evt->key->key->kind) {
case KEY_VALUE_KIND_NUMBER:
trace_input_event_key_number(idx, evt->key->key->number,
evt->key->down);
break;
case KEY_VALUE_KIND_QCODE:
name = QKeyCode_lookup[evt->key->key->qcode];
trace_input_event_key_qcode(idx, name, evt->key->down);
break;
case KEY_VALUE_KIND_MAX:
/* keep gcc happy */
break;
}
break;
case INPUT_EVENT_KIND_BTN:
name = InputButton_lookup[evt->btn->button];
trace_input_event_btn(idx, name, evt->btn->down);
break;
case INPUT_EVENT_KIND_REL:
name = InputAxis_lookup[evt->rel->axis];
trace_input_event_rel(idx, name, evt->rel->value);
break;
case INPUT_EVENT_KIND_ABS:
name = InputAxis_lookup[evt->abs->axis];
trace_input_event_abs(idx, name, evt->abs->value);
break;
case INPUT_EVENT_KIND_MAX:
/* keep gcc happy */
break;
}
/* Return Q_KEY_CODE_MAX if the key is invalid */
return i;
}
int index_from_keycode(int code)
void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
{
int i;
QemuInputHandlerState *s;
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
if (key_defs[i] == code) {
break;
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
return;
}
qemu_input_event_trace(src, evt);
/* pre processing */
if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
qemu_input_transform_abs_rotate(evt);
}
/* send event */
s = qemu_input_find_handler(1 << evt->kind);
s->handler->event(s->dev, src, evt);
s->events++;
}
void qemu_input_event_sync(void)
{
QemuInputHandlerState *s;
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
return;
}
trace_input_event_sync();
QTAILQ_FOREACH(s, &handlers, node) {
if (!s->events) {
continue;
}
}
/* Return Q_KEY_CODE_MAX if the code is invalid */
return i;
}
static int *keycodes;
static int keycodes_size;
static QEMUTimer *key_timer;
static int keycode_from_keyvalue(const KeyValue *value)
{
if (value->kind == KEY_VALUE_KIND_QCODE) {
return key_defs[value->qcode];
} else {
assert(value->kind == KEY_VALUE_KIND_NUMBER);
return value->number;
}
}
static void free_keycodes(void)
{
g_free(keycodes);
keycodes = NULL;
keycodes_size = 0;
}
static void release_keys(void *opaque)
{
while (keycodes_size > 0) {
if (keycodes[--keycodes_size] & SCANCODE_GREY) {
kbd_put_keycode(SCANCODE_EMUL0);
if (s->handler->sync) {
s->handler->sync(s->dev);
}
kbd_put_keycode(keycodes[keycodes_size] | SCANCODE_UP);
s->events = 0;
}
free_keycodes();
}
void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
Error **errp)
InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
{
int keycode;
KeyValueList *p;
InputEvent *evt = g_new0(InputEvent, 1);
evt->key = g_new0(InputKeyEvent, 1);
evt->kind = INPUT_EVENT_KIND_KEY;
evt->key->key = key;
evt->key->down = down;
return evt;
}
if (!key_timer) {
key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
}
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
{
InputEvent *evt;
evt = qemu_input_event_new_key(key, down);
qemu_input_event_send(src, evt);
qemu_input_event_sync();
qapi_free_InputEvent(evt);
}
if (keycodes != NULL) {
timer_del(key_timer);
release_keys(NULL);
}
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
{
KeyValue *key = g_new0(KeyValue, 1);
key->kind = KEY_VALUE_KIND_NUMBER;
key->number = num;
qemu_input_event_send_key(src, key, down);
}
if (!has_hold_time) {
hold_time = 100;
}
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
{
KeyValue *key = g_new0(KeyValue, 1);
key->kind = KEY_VALUE_KIND_QCODE;
key->qcode = q;
qemu_input_event_send_key(src, key, down);
}
for (p = keys; p != NULL; p = p->next) {
/* key down events */
keycode = keycode_from_keyvalue(p->value);
if (keycode < 0x01 || keycode > 0xff) {
error_setg(errp, "invalid hex keycode 0x%x", keycode);
free_keycodes();
return;
InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
{
InputEvent *evt = g_new0(InputEvent, 1);
evt->btn = g_new0(InputBtnEvent, 1);
evt->kind = INPUT_EVENT_KIND_BTN;
evt->btn->button = btn;
evt->btn->down = down;
return evt;
}
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
{
InputEvent *evt;
evt = qemu_input_event_new_btn(btn, down);
qemu_input_event_send(src, evt);
qapi_free_InputEvent(evt);
}
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
uint32_t button_old, uint32_t button_new)
{
InputButton btn;
uint32_t mask;
for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
mask = button_map[btn];
if ((button_old & mask) == (button_new & mask)) {
continue;
}
if (keycode & SCANCODE_GREY) {
kbd_put_keycode(SCANCODE_EMUL0);
}
kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
keycodes[keycodes_size++] = keycode;
qemu_input_queue_btn(src, btn, button_new & mask);
}
/* delayed key up events */
timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
muldiv64(get_ticks_per_sec(), hold_time, 1000));
}
QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
bool qemu_input_is_absolute(void)
{
QEMUPutKbdEntry *entry;
QemuInputHandlerState *s;
entry = g_malloc0(sizeof(QEMUPutKbdEntry));
entry->put_kbd = func;
entry->opaque = opaque;
QTAILQ_INSERT_HEAD(&kbd_handlers, entry, next);
return entry;
s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS);
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
}
void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry)
int qemu_input_scale_axis(int value, int size_in, int size_out)
{
QTAILQ_REMOVE(&kbd_handlers, entry, next);
if (size_in < 2) {
return size_out / 2;
}
return (int64_t)value * (size_out - 1) / (size_in - 1);
}
static void check_mode_change(void)
InputEvent *qemu_input_event_new_move(InputEventKind kind,
InputAxis axis, int value)
{
static int current_is_absolute, current_has_absolute;
InputEvent *evt = g_new0(InputEvent, 1);
InputMoveEvent *move = g_new0(InputMoveEvent, 1);
evt->kind = kind;
evt->data = move;
move->axis = axis;
move->value = value;
return evt;
}
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
{
InputEvent *evt;
evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
qemu_input_event_send(src, evt);
qapi_free_InputEvent(evt);
}
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
{
InputEvent *evt;
int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
qemu_input_event_send(src, evt);
qapi_free_InputEvent(evt);
}
void qemu_input_check_mode_change(void)
{
static int current_is_absolute;
int is_absolute;
int has_absolute;
is_absolute = kbd_mouse_is_absolute();
has_absolute = kbd_mouse_has_absolute();
is_absolute = qemu_input_is_absolute();
if (is_absolute != current_is_absolute ||
has_absolute != current_has_absolute) {
if (is_absolute != current_is_absolute) {
trace_input_mouse_mode(is_absolute);
notifier_list_notify(&mouse_mode_notifiers, NULL);
}
current_is_absolute = is_absolute;
current_has_absolute = has_absolute;
}
QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
void *opaque, int absolute,
const char *name)
{
QEMUPutMouseEntry *s;
static int mouse_index = 0;
s = g_malloc0(sizeof(QEMUPutMouseEntry));
s->qemu_put_mouse_event = func;
s->qemu_put_mouse_event_opaque = opaque;
s->qemu_put_mouse_event_absolute = absolute;
s->qemu_put_mouse_event_name = g_strdup(name);
s->index = mouse_index++;
QTAILQ_INSERT_TAIL(&mouse_handlers, s, node);
check_mode_change();
return s;
}
void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
{
QTAILQ_REMOVE(&mouse_handlers, entry, node);
QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node);
check_mode_change();
}
void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
{
QTAILQ_REMOVE(&mouse_handlers, entry, node);
g_free(entry->qemu_put_mouse_event_name);
g_free(entry);
check_mode_change();
}
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
void *opaque)
{
QEMUPutLEDEntry *s;
s = g_malloc0(sizeof(QEMUPutLEDEntry));
s->put_led = func;
s->opaque = opaque;
QTAILQ_INSERT_TAIL(&led_handlers, s, next);
return s;
}
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
{
if (entry == NULL)
return;
QTAILQ_REMOVE(&led_handlers, entry, next);
g_free(entry);
}
void kbd_put_keycode(int keycode)
{
QEMUPutKbdEntry *entry = QTAILQ_FIRST(&kbd_handlers);
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
return;
}
if (entry && entry->put_kbd) {
entry->put_kbd(entry->opaque, keycode);
}
}
void kbd_put_ledstate(int ledstate)
{
QEMUPutLEDEntry *cursor;
QTAILQ_FOREACH(cursor, &led_handlers, next) {
cursor->put_led(cursor->opaque, ledstate);
}
}
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
QEMUPutMouseEntry *entry;
QEMUPutMouseEvent *mouse_event;
void *mouse_event_opaque;
int width, height;
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
return;
}
if (QTAILQ_EMPTY(&mouse_handlers)) {
return;
}
entry = QTAILQ_FIRST(&mouse_handlers);
mouse_event = entry->qemu_put_mouse_event;
mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
if (mouse_event) {
if (entry->qemu_put_mouse_event_absolute) {
width = 0x7fff;
height = 0x7fff;
} else {
width = graphic_width - 1;
height = graphic_height - 1;
}
switch (graphic_rotate) {
case 0:
mouse_event(mouse_event_opaque,
dx, dy, dz, buttons_state);
break;
case 90:
mouse_event(mouse_event_opaque,
width - dy, dx, dz, buttons_state);
break;
case 180:
mouse_event(mouse_event_opaque,
width - dx, height - dy, dz, buttons_state);
break;
case 270:
mouse_event(mouse_event_opaque,
dy, height - dx, dz, buttons_state);
break;
}
}
}
int kbd_mouse_is_absolute(void)
{
if (QTAILQ_EMPTY(&mouse_handlers)) {
return 0;
}
return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute;
}
int kbd_mouse_has_absolute(void)
{
QEMUPutMouseEntry *entry;
QTAILQ_FOREACH(entry, &mouse_handlers, node) {
if (entry->qemu_put_mouse_event_absolute) {
return 1;
}
}
return 0;
}
MouseInfoList *qmp_query_mice(Error **errp)
{
MouseInfoList *mice_list = NULL;
QEMUPutMouseEntry *cursor;
bool current = true;
QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
MouseInfoList *info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
info->value->index = cursor->index;
info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
info->value->current = current;
current = false;
info->next = mice_list;
mice_list = info;
}
return mice_list;
}
void do_mouse_set(Monitor *mon, const QDict *qdict)
{
QEMUPutMouseEntry *cursor;
int index = qdict_get_int(qdict, "index");
int found = 0;
if (QTAILQ_EMPTY(&mouse_handlers)) {
monitor_printf(mon, "No mouse devices connected\n");
return;
}
QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
if (cursor->index == index) {
found = 1;
qemu_activate_mouse_event_handler(cursor);
break;
}
}
if (!found) {
monitor_printf(mon, "Mouse at given index not found\n");
}
check_mode_change();
}
void qemu_add_mouse_mode_change_notifier(Notifier *notify)
@ -557,3 +306,52 @@ void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
{
notifier_remove(notify);
}
MouseInfoList *qmp_query_mice(Error **errp)
{
MouseInfoList *mice_list = NULL;
MouseInfoList *info;
QemuInputHandlerState *s;
bool current = true;
QTAILQ_FOREACH(s, &handlers, node) {
if (!(s->handler->mask &
(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
continue;
}
info = g_new0(MouseInfoList, 1);
info->value = g_new0(MouseInfo, 1);
info->value->index = s->id;
info->value->name = g_strdup(s->handler->name);
info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
info->value->current = current;
current = false;
info->next = mice_list;
mice_list = info;
}
return mice_list;
}
void do_mouse_set(Monitor *mon, const QDict *qdict)
{
QemuInputHandlerState *s;
int index = qdict_get_int(qdict, "index");
int found = 0;
QTAILQ_FOREACH(s, &handlers, node) {
if (s->id == index) {
found = 1;
qemu_input_handler_activate(s);
break;
}
}
if (!found) {
monitor_printf(mon, "Mouse at given index not found\n");
}
qemu_input_check_mode_change();
}

108
ui/sdl.c
View File

@ -26,10 +26,13 @@
#undef WIN32_LEAN_AND_MEAN
#include <SDL.h>
#if SDL_MAJOR_VERSION == 1
#include <SDL_syswm.h>
#include "qemu-common.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "x_keymap.h"
#include "sdl_zoom.h"
@ -261,9 +264,7 @@ static void reset_keys(void)
int i;
for(i = 0; i < 256; i++) {
if (modifiers_state[i]) {
if (i & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(i | SCANCODE_UP);
qemu_input_event_send_key_number(dcl->con, i, false);
modifiers_state[i] = 0;
}
}
@ -271,16 +272,12 @@ static void reset_keys(void)
static void sdl_process_key(SDL_KeyboardEvent *ev)
{
int keycode, v;
int keycode;
if (ev->keysym.sym == SDLK_PAUSE) {
/* specific case */
v = 0;
if (ev->type == SDL_KEYUP)
v |= SCANCODE_UP;
kbd_put_keycode(0xe1);
kbd_put_keycode(0x1d | v);
kbd_put_keycode(0x45 | v);
qemu_input_event_send_key_qcode(dcl->con, Q_KEY_CODE_PAUSE,
ev->type == SDL_KEYDOWN);
return;
}
@ -312,19 +309,15 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
case 0x45: /* num lock */
case 0x3a: /* caps lock */
/* SDL does not send the key up event, so we generate it */
kbd_put_keycode(keycode);
kbd_put_keycode(keycode | SCANCODE_UP);
qemu_input_event_send_key_number(dcl->con, keycode, true);
qemu_input_event_send_key_number(dcl->con, keycode, false);
return;
#endif
}
/* now send the key code */
if (keycode & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
if (ev->type == SDL_KEYUP)
kbd_put_keycode(keycode | SCANCODE_UP);
else
kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
qemu_input_event_send_key_number(dcl->con, keycode,
ev->type == SDL_KEYDOWN);
}
static void sdl_update_caption(void)
@ -360,7 +353,7 @@ static void sdl_hide_cursor(void)
if (!cursor_hide)
return;
if (kbd_mouse_is_absolute()) {
if (qemu_input_is_absolute()) {
SDL_ShowCursor(1);
SDL_SetCursor(sdl_cursor_hidden);
} else {
@ -373,10 +366,10 @@ static void sdl_show_cursor(void)
if (!cursor_hide)
return;
if (!kbd_mouse_is_absolute() || !qemu_console_is_graphic(NULL)) {
if (!qemu_input_is_absolute() || !qemu_console_is_graphic(NULL)) {
SDL_ShowCursor(1);
if (guest_cursor &&
(gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
(gui_grab || qemu_input_is_absolute() || absolute_enabled))
SDL_SetCursor(guest_sprite);
else
SDL_SetCursor(sdl_cursor_normal);
@ -395,8 +388,9 @@ static void sdl_grab_start(void)
}
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
if (!kbd_mouse_is_absolute() && !absolute_enabled)
if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouse(guest_x, guest_y);
}
} else
sdl_hide_cursor();
SDL_WM_GrabInput(SDL_GRAB_ON);
@ -425,7 +419,7 @@ static void absolute_mouse_grab(void)
static void sdl_mouse_mode_change(Notifier *notify, void *data)
{
if (kbd_mouse_is_absolute()) {
if (qemu_input_is_absolute()) {
if (!absolute_enabled) {
absolute_enabled = 1;
if (qemu_console_is_graphic(NULL)) {
@ -440,33 +434,36 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
}
}
static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
{
int buttons = 0;
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
[INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
[INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
};
static uint32_t prev_state;
if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
buttons |= MOUSE_EVENT_LBUTTON;
}
if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
buttons |= MOUSE_EVENT_RBUTTON;
}
if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
buttons |= MOUSE_EVENT_MBUTTON;
if (prev_state != state) {
qemu_input_update_buttons(dcl->con, bmap, prev_state, state);
prev_state = state;
}
if (kbd_mouse_is_absolute()) {
dx = x * 0x7FFF / (real_screen->w - 1);
dy = y * 0x7FFF / (real_screen->h - 1);
if (qemu_input_is_absolute()) {
qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x,
real_screen->w);
qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y,
real_screen->h);
} else if (guest_cursor) {
x -= guest_x;
y -= guest_y;
guest_x += x;
guest_y += y;
dx = x;
dy = y;
qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, x);
qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, y);
}
kbd_mouse_event(dx, dy, dz, buttons);
qemu_input_event_sync();
}
static void sdl_scale(int width, int height)
@ -694,7 +691,7 @@ static void handle_mousemotion(SDL_Event *ev)
int max_x, max_y;
if (qemu_console_is_graphic(NULL) &&
(kbd_mouse_is_absolute() || absolute_enabled)) {
(qemu_input_is_absolute() || absolute_enabled)) {
max_x = real_screen->w - 1;
max_y = real_screen->h - 1;
if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
@ -707,8 +704,8 @@ static void handle_mousemotion(SDL_Event *ev)
sdl_grab_start();
}
}
if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel,
ev->motion.x, ev->motion.y, ev->motion.state);
}
}
@ -717,35 +714,24 @@ static void handle_mousebutton(SDL_Event *ev)
{
int buttonstate = SDL_GetMouseState(NULL, NULL);
SDL_MouseButtonEvent *bev;
int dz;
if (!qemu_console_is_graphic(NULL)) {
return;
}
bev = &ev->button;
if (!gui_grab && !kbd_mouse_is_absolute()) {
if (!gui_grab && !qemu_input_is_absolute()) {
if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
sdl_grab_start();
}
} else {
dz = 0;
if (ev->type == SDL_MOUSEBUTTONDOWN) {
buttonstate |= SDL_BUTTON(bev->button);
} else {
buttonstate &= ~SDL_BUTTON(bev->button);
}
#ifdef SDL_BUTTON_WHEELUP
if (bev->button == SDL_BUTTON_WHEELUP &&
ev->type == SDL_MOUSEBUTTONDOWN) {
dz = -1;
} else if (bev->button == SDL_BUTTON_WHEELDOWN &&
ev->type == SDL_MOUSEBUTTONDOWN) {
dz = 1;
}
#endif
sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
sdl_send_mouse_event(0, 0, bev->x, bev->y, buttonstate);
}
}
@ -760,7 +746,7 @@ static void handle_activation(SDL_Event *ev)
}
#endif
if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) &&
(kbd_mouse_is_absolute() || absolute_enabled)) {
(qemu_input_is_absolute() || absolute_enabled)) {
absolute_mouse_grab();
}
if (ev->active.state & SDL_APPACTIVE) {
@ -832,10 +818,11 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl,
if (on) {
if (!guest_cursor)
sdl_show_cursor();
if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
SDL_SetCursor(guest_sprite);
if (!kbd_mouse_is_absolute() && !absolute_enabled)
if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouse(x, y);
}
}
} else if (gui_grab)
sdl_hide_cursor();
@ -863,7 +850,7 @@ static void sdl_mouse_define(DisplayChangeListener *dcl,
g_free(mask);
if (guest_cursor &&
(gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
(gui_grab || qemu_input_is_absolute() || absolute_enabled))
SDL_SetCursor(guest_sprite);
}
@ -966,3 +953,4 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
atexit(sdl_cleanup);
}
#endif

266
ui/sdl2-keymap.h Normal file
View File

@ -0,0 +1,266 @@
/* map SDL2 scancodes to QKeyCode */
static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = {
[SDL_SCANCODE_A] = Q_KEY_CODE_A,
[SDL_SCANCODE_B] = Q_KEY_CODE_B,
[SDL_SCANCODE_C] = Q_KEY_CODE_C,
[SDL_SCANCODE_D] = Q_KEY_CODE_D,
[SDL_SCANCODE_E] = Q_KEY_CODE_E,
[SDL_SCANCODE_F] = Q_KEY_CODE_F,
[SDL_SCANCODE_G] = Q_KEY_CODE_G,
[SDL_SCANCODE_H] = Q_KEY_CODE_H,
[SDL_SCANCODE_I] = Q_KEY_CODE_I,
[SDL_SCANCODE_J] = Q_KEY_CODE_J,
[SDL_SCANCODE_K] = Q_KEY_CODE_K,
[SDL_SCANCODE_L] = Q_KEY_CODE_L,
[SDL_SCANCODE_M] = Q_KEY_CODE_M,
[SDL_SCANCODE_N] = Q_KEY_CODE_N,
[SDL_SCANCODE_O] = Q_KEY_CODE_O,
[SDL_SCANCODE_P] = Q_KEY_CODE_P,
[SDL_SCANCODE_Q] = Q_KEY_CODE_Q,
[SDL_SCANCODE_R] = Q_KEY_CODE_R,
[SDL_SCANCODE_S] = Q_KEY_CODE_S,
[SDL_SCANCODE_T] = Q_KEY_CODE_T,
[SDL_SCANCODE_U] = Q_KEY_CODE_U,
[SDL_SCANCODE_V] = Q_KEY_CODE_V,
[SDL_SCANCODE_W] = Q_KEY_CODE_W,
[SDL_SCANCODE_X] = Q_KEY_CODE_X,
[SDL_SCANCODE_Y] = Q_KEY_CODE_Y,
[SDL_SCANCODE_Z] = Q_KEY_CODE_Z,
[SDL_SCANCODE_1] = Q_KEY_CODE_1,
[SDL_SCANCODE_2] = Q_KEY_CODE_2,
[SDL_SCANCODE_3] = Q_KEY_CODE_3,
[SDL_SCANCODE_4] = Q_KEY_CODE_4,
[SDL_SCANCODE_5] = Q_KEY_CODE_5,
[SDL_SCANCODE_6] = Q_KEY_CODE_6,
[SDL_SCANCODE_7] = Q_KEY_CODE_7,
[SDL_SCANCODE_8] = Q_KEY_CODE_8,
[SDL_SCANCODE_9] = Q_KEY_CODE_9,
[SDL_SCANCODE_0] = Q_KEY_CODE_0,
[SDL_SCANCODE_RETURN] = Q_KEY_CODE_RET,
[SDL_SCANCODE_ESCAPE] = Q_KEY_CODE_ESC,
[SDL_SCANCODE_BACKSPACE] = Q_KEY_CODE_BACKSPACE,
[SDL_SCANCODE_TAB] = Q_KEY_CODE_TAB,
[SDL_SCANCODE_SPACE] = Q_KEY_CODE_SPC,
[SDL_SCANCODE_MINUS] = Q_KEY_CODE_MINUS,
[SDL_SCANCODE_EQUALS] = Q_KEY_CODE_EQUAL,
[SDL_SCANCODE_LEFTBRACKET] = Q_KEY_CODE_BRACKET_LEFT,
[SDL_SCANCODE_RIGHTBRACKET] = Q_KEY_CODE_BRACKET_RIGHT,
[SDL_SCANCODE_BACKSLASH] = Q_KEY_CODE_BACKSLASH,
#if 0
[SDL_SCANCODE_NONUSHASH] = Q_KEY_CODE_NONUSHASH,
#endif
[SDL_SCANCODE_SEMICOLON] = Q_KEY_CODE_SEMICOLON,
[SDL_SCANCODE_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE,
[SDL_SCANCODE_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT,
[SDL_SCANCODE_COMMA] = Q_KEY_CODE_COMMA,
[SDL_SCANCODE_PERIOD] = Q_KEY_CODE_DOT,
[SDL_SCANCODE_SLASH] = Q_KEY_CODE_SLASH,
[SDL_SCANCODE_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK,
[SDL_SCANCODE_F1] = Q_KEY_CODE_F1,
[SDL_SCANCODE_F2] = Q_KEY_CODE_F2,
[SDL_SCANCODE_F3] = Q_KEY_CODE_F3,
[SDL_SCANCODE_F4] = Q_KEY_CODE_F4,
[SDL_SCANCODE_F5] = Q_KEY_CODE_F5,
[SDL_SCANCODE_F6] = Q_KEY_CODE_F6,
[SDL_SCANCODE_F7] = Q_KEY_CODE_F7,
[SDL_SCANCODE_F8] = Q_KEY_CODE_F8,
[SDL_SCANCODE_F9] = Q_KEY_CODE_F9,
[SDL_SCANCODE_F10] = Q_KEY_CODE_F10,
[SDL_SCANCODE_F11] = Q_KEY_CODE_F11,
[SDL_SCANCODE_F12] = Q_KEY_CODE_F12,
[SDL_SCANCODE_PRINTSCREEN] = Q_KEY_CODE_PRINT,
[SDL_SCANCODE_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK,
[SDL_SCANCODE_PAUSE] = Q_KEY_CODE_PAUSE,
[SDL_SCANCODE_INSERT] = Q_KEY_CODE_INSERT,
[SDL_SCANCODE_HOME] = Q_KEY_CODE_HOME,
[SDL_SCANCODE_PAGEUP] = Q_KEY_CODE_PGUP,
[SDL_SCANCODE_DELETE] = Q_KEY_CODE_DELETE,
[SDL_SCANCODE_END] = Q_KEY_CODE_END,
[SDL_SCANCODE_PAGEDOWN] = Q_KEY_CODE_PGDN,
[SDL_SCANCODE_RIGHT] = Q_KEY_CODE_RIGHT,
[SDL_SCANCODE_LEFT] = Q_KEY_CODE_LEFT,
[SDL_SCANCODE_DOWN] = Q_KEY_CODE_DOWN,
[SDL_SCANCODE_UP] = Q_KEY_CODE_UP,
[SDL_SCANCODE_NUMLOCKCLEAR] = Q_KEY_CODE_NUM_LOCK,
[SDL_SCANCODE_KP_DIVIDE] = Q_KEY_CODE_KP_DIVIDE,
[SDL_SCANCODE_KP_MULTIPLY] = Q_KEY_CODE_KP_MULTIPLY,
[SDL_SCANCODE_KP_MINUS] = Q_KEY_CODE_KP_SUBTRACT,
[SDL_SCANCODE_KP_PLUS] = Q_KEY_CODE_KP_ADD,
[SDL_SCANCODE_KP_ENTER] = Q_KEY_CODE_KP_ENTER,
[SDL_SCANCODE_KP_1] = Q_KEY_CODE_KP_1,
[SDL_SCANCODE_KP_2] = Q_KEY_CODE_KP_2,
[SDL_SCANCODE_KP_3] = Q_KEY_CODE_KP_3,
[SDL_SCANCODE_KP_4] = Q_KEY_CODE_KP_4,
[SDL_SCANCODE_KP_5] = Q_KEY_CODE_KP_5,
[SDL_SCANCODE_KP_6] = Q_KEY_CODE_KP_6,
[SDL_SCANCODE_KP_7] = Q_KEY_CODE_KP_7,
[SDL_SCANCODE_KP_8] = Q_KEY_CODE_KP_8,
[SDL_SCANCODE_KP_9] = Q_KEY_CODE_KP_9,
[SDL_SCANCODE_KP_0] = Q_KEY_CODE_KP_0,
[SDL_SCANCODE_KP_PERIOD] = Q_KEY_CODE_KP_DECIMAL,
#if 0
[SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_NONUSBACKSLASH,
[SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_APPLICATION,
[SDL_SCANCODE_POWER] = Q_KEY_CODE_POWER,
[SDL_SCANCODE_KP_EQUALS] = Q_KEY_CODE_KP_EQUALS,
[SDL_SCANCODE_F13] = Q_KEY_CODE_F13,
[SDL_SCANCODE_F14] = Q_KEY_CODE_F14,
[SDL_SCANCODE_F15] = Q_KEY_CODE_F15,
[SDL_SCANCODE_F16] = Q_KEY_CODE_F16,
[SDL_SCANCODE_F17] = Q_KEY_CODE_F17,
[SDL_SCANCODE_F18] = Q_KEY_CODE_F18,
[SDL_SCANCODE_F19] = Q_KEY_CODE_F19,
[SDL_SCANCODE_F20] = Q_KEY_CODE_F20,
[SDL_SCANCODE_F21] = Q_KEY_CODE_F21,
[SDL_SCANCODE_F22] = Q_KEY_CODE_F22,
[SDL_SCANCODE_F23] = Q_KEY_CODE_F23,
[SDL_SCANCODE_F24] = Q_KEY_CODE_F24,
[SDL_SCANCODE_EXECUTE] = Q_KEY_CODE_EXECUTE,
#endif
[SDL_SCANCODE_HELP] = Q_KEY_CODE_HELP,
[SDL_SCANCODE_MENU] = Q_KEY_CODE_MENU,
#if 0
[SDL_SCANCODE_SELECT] = Q_KEY_CODE_SELECT,
#endif
[SDL_SCANCODE_STOP] = Q_KEY_CODE_STOP,
[SDL_SCANCODE_AGAIN] = Q_KEY_CODE_AGAIN,
[SDL_SCANCODE_UNDO] = Q_KEY_CODE_UNDO,
[SDL_SCANCODE_CUT] = Q_KEY_CODE_CUT,
[SDL_SCANCODE_COPY] = Q_KEY_CODE_COPY,
[SDL_SCANCODE_PASTE] = Q_KEY_CODE_PASTE,
[SDL_SCANCODE_FIND] = Q_KEY_CODE_FIND,
#if 0
[SDL_SCANCODE_MUTE] = Q_KEY_CODE_MUTE,
[SDL_SCANCODE_VOLUMEUP] = Q_KEY_CODE_VOLUMEUP,
[SDL_SCANCODE_VOLUMEDOWN] = Q_KEY_CODE_VOLUMEDOWN,
[SDL_SCANCODE_KP_COMMA] = Q_KEY_CODE_KP_COMMA,
[SDL_SCANCODE_KP_EQUALSAS400] = Q_KEY_CODE_KP_EQUALSAS400,
[SDL_SCANCODE_INTERNATIONAL1] = Q_KEY_CODE_INTERNATIONAL1,
[SDL_SCANCODE_INTERNATIONAL2] = Q_KEY_CODE_INTERNATIONAL2,
[SDL_SCANCODE_INTERNATIONAL3] = Q_KEY_CODE_INTERNATIONAL3,
[SDL_SCANCODE_INTERNATIONAL4] = Q_KEY_CODE_INTERNATIONAL4,
[SDL_SCANCODE_INTERNATIONAL5] = Q_KEY_CODE_INTERNATIONAL5,
[SDL_SCANCODE_INTERNATIONAL6] = Q_KEY_CODE_INTERNATIONAL6,
[SDL_SCANCODE_INTERNATIONAL7] = Q_KEY_CODE_INTERNATIONAL7,
[SDL_SCANCODE_INTERNATIONAL8] = Q_KEY_CODE_INTERNATIONAL8,
[SDL_SCANCODE_INTERNATIONAL9] = Q_KEY_CODE_INTERNATIONAL9,
[SDL_SCANCODE_LANG1] = Q_KEY_CODE_LANG1,
[SDL_SCANCODE_LANG2] = Q_KEY_CODE_LANG2,
[SDL_SCANCODE_LANG3] = Q_KEY_CODE_LANG3,
[SDL_SCANCODE_LANG4] = Q_KEY_CODE_LANG4,
[SDL_SCANCODE_LANG5] = Q_KEY_CODE_LANG5,
[SDL_SCANCODE_LANG6] = Q_KEY_CODE_LANG6,
[SDL_SCANCODE_LANG7] = Q_KEY_CODE_LANG7,
[SDL_SCANCODE_LANG8] = Q_KEY_CODE_LANG8,
[SDL_SCANCODE_LANG9] = Q_KEY_CODE_LANG9,
[SDL_SCANCODE_ALTERASE] = Q_KEY_CODE_ALTERASE,
#endif
[SDL_SCANCODE_SYSREQ] = Q_KEY_CODE_SYSRQ,
#if 0
[SDL_SCANCODE_CANCEL] = Q_KEY_CODE_CANCEL,
[SDL_SCANCODE_CLEAR] = Q_KEY_CODE_CLEAR,
[SDL_SCANCODE_PRIOR] = Q_KEY_CODE_PRIOR,
[SDL_SCANCODE_RETURN2] = Q_KEY_CODE_RETURN2,
[SDL_SCANCODE_SEPARATOR] = Q_KEY_CODE_SEPARATOR,
[SDL_SCANCODE_OUT] = Q_KEY_CODE_OUT,
[SDL_SCANCODE_OPER] = Q_KEY_CODE_OPER,
[SDL_SCANCODE_CLEARAGAIN] = Q_KEY_CODE_CLEARAGAIN,
[SDL_SCANCODE_CRSEL] = Q_KEY_CODE_CRSEL,
[SDL_SCANCODE_EXSEL] = Q_KEY_CODE_EXSEL,
[SDL_SCANCODE_KP_00] = Q_KEY_CODE_KP_00,
[SDL_SCANCODE_KP_000] = Q_KEY_CODE_KP_000,
[SDL_SCANCODE_THOUSANDSSEPARATOR] = Q_KEY_CODE_THOUSANDSSEPARATOR,
[SDL_SCANCODE_DECIMALSEPARATOR] = Q_KEY_CODE_DECIMALSEPARATOR,
[SDL_SCANCODE_CURRENCYUNIT] = Q_KEY_CODE_CURRENCYUNIT,
[SDL_SCANCODE_CURRENCYSUBUNIT] = Q_KEY_CODE_CURRENCYSUBUNIT,
[SDL_SCANCODE_KP_LEFTPAREN] = Q_KEY_CODE_KP_LEFTPAREN,
[SDL_SCANCODE_KP_RIGHTPAREN] = Q_KEY_CODE_KP_RIGHTPAREN,
[SDL_SCANCODE_KP_LEFTBRACE] = Q_KEY_CODE_KP_LEFTBRACE,
[SDL_SCANCODE_KP_RIGHTBRACE] = Q_KEY_CODE_KP_RIGHTBRACE,
[SDL_SCANCODE_KP_TAB] = Q_KEY_CODE_KP_TAB,
[SDL_SCANCODE_KP_BACKSPACE] = Q_KEY_CODE_KP_BACKSPACE,
[SDL_SCANCODE_KP_A] = Q_KEY_CODE_KP_A,
[SDL_SCANCODE_KP_B] = Q_KEY_CODE_KP_B,
[SDL_SCANCODE_KP_C] = Q_KEY_CODE_KP_C,
[SDL_SCANCODE_KP_D] = Q_KEY_CODE_KP_D,
[SDL_SCANCODE_KP_E] = Q_KEY_CODE_KP_E,
[SDL_SCANCODE_KP_F] = Q_KEY_CODE_KP_F,
[SDL_SCANCODE_KP_XOR] = Q_KEY_CODE_KP_XOR,
[SDL_SCANCODE_KP_POWER] = Q_KEY_CODE_KP_POWER,
[SDL_SCANCODE_KP_PERCENT] = Q_KEY_CODE_KP_PERCENT,
[SDL_SCANCODE_KP_LESS] = Q_KEY_CODE_KP_LESS,
[SDL_SCANCODE_KP_GREATER] = Q_KEY_CODE_KP_GREATER,
[SDL_SCANCODE_KP_AMPERSAND] = Q_KEY_CODE_KP_AMPERSAND,
[SDL_SCANCODE_KP_DBLAMPERSAND] = Q_KEY_CODE_KP_DBLAMPERSAND,
[SDL_SCANCODE_KP_VERTICALBAR] = Q_KEY_CODE_KP_VERTICALBAR,
[SDL_SCANCODE_KP_DBLVERTICALBAR] = Q_KEY_CODE_KP_DBLVERTICALBAR,
[SDL_SCANCODE_KP_COLON] = Q_KEY_CODE_KP_COLON,
[SDL_SCANCODE_KP_HASH] = Q_KEY_CODE_KP_HASH,
[SDL_SCANCODE_KP_SPACE] = Q_KEY_CODE_KP_SPACE,
[SDL_SCANCODE_KP_AT] = Q_KEY_CODE_KP_AT,
[SDL_SCANCODE_KP_EXCLAM] = Q_KEY_CODE_KP_EXCLAM,
[SDL_SCANCODE_KP_MEMSTORE] = Q_KEY_CODE_KP_MEMSTORE,
[SDL_SCANCODE_KP_MEMRECALL] = Q_KEY_CODE_KP_MEMRECALL,
[SDL_SCANCODE_KP_MEMCLEAR] = Q_KEY_CODE_KP_MEMCLEAR,
[SDL_SCANCODE_KP_MEMADD] = Q_KEY_CODE_KP_MEMADD,
[SDL_SCANCODE_KP_MEMSUBTRACT] = Q_KEY_CODE_KP_MEMSUBTRACT,
[SDL_SCANCODE_KP_MEMMULTIPLY] = Q_KEY_CODE_KP_MEMMULTIPLY,
[SDL_SCANCODE_KP_MEMDIVIDE] = Q_KEY_CODE_KP_MEMDIVIDE,
[SDL_SCANCODE_KP_PLUSMINUS] = Q_KEY_CODE_KP_PLUSMINUS,
[SDL_SCANCODE_KP_CLEAR] = Q_KEY_CODE_KP_CLEAR,
[SDL_SCANCODE_KP_CLEARENTRY] = Q_KEY_CODE_KP_CLEARENTRY,
[SDL_SCANCODE_KP_BINARY] = Q_KEY_CODE_KP_BINARY,
[SDL_SCANCODE_KP_OCTAL] = Q_KEY_CODE_KP_OCTAL,
[SDL_SCANCODE_KP_DECIMAL] = Q_KEY_CODE_KP_DECIMAL,
[SDL_SCANCODE_KP_HEXADECIMAL] = Q_KEY_CODE_KP_HEXADECIMAL,
#endif
[SDL_SCANCODE_LCTRL] = Q_KEY_CODE_CTRL,
[SDL_SCANCODE_LSHIFT] = Q_KEY_CODE_SHIFT,
[SDL_SCANCODE_LALT] = Q_KEY_CODE_ALT,
[SDL_SCANCODE_LGUI] = Q_KEY_CODE_META_L,
[SDL_SCANCODE_RCTRL] = Q_KEY_CODE_CTRL_R,
[SDL_SCANCODE_RSHIFT] = Q_KEY_CODE_SHIFT_R,
[SDL_SCANCODE_RALT] = Q_KEY_CODE_ALTGR,
[SDL_SCANCODE_RGUI] = Q_KEY_CODE_META_R,
#if 0
[SDL_SCANCODE_MODE] = Q_KEY_CODE_MODE,
[SDL_SCANCODE_AUDIONEXT] = Q_KEY_CODE_AUDIONEXT,
[SDL_SCANCODE_AUDIOPREV] = Q_KEY_CODE_AUDIOPREV,
[SDL_SCANCODE_AUDIOSTOP] = Q_KEY_CODE_AUDIOSTOP,
[SDL_SCANCODE_AUDIOPLAY] = Q_KEY_CODE_AUDIOPLAY,
[SDL_SCANCODE_AUDIOMUTE] = Q_KEY_CODE_AUDIOMUTE,
[SDL_SCANCODE_MEDIASELECT] = Q_KEY_CODE_MEDIASELECT,
[SDL_SCANCODE_WWW] = Q_KEY_CODE_WWW,
[SDL_SCANCODE_MAIL] = Q_KEY_CODE_MAIL,
[SDL_SCANCODE_CALCULATOR] = Q_KEY_CODE_CALCULATOR,
[SDL_SCANCODE_COMPUTER] = Q_KEY_CODE_COMPUTER,
[SDL_SCANCODE_AC_SEARCH] = Q_KEY_CODE_AC_SEARCH,
[SDL_SCANCODE_AC_HOME] = Q_KEY_CODE_AC_HOME,
[SDL_SCANCODE_AC_BACK] = Q_KEY_CODE_AC_BACK,
[SDL_SCANCODE_AC_FORWARD] = Q_KEY_CODE_AC_FORWARD,
[SDL_SCANCODE_AC_STOP] = Q_KEY_CODE_AC_STOP,
[SDL_SCANCODE_AC_REFRESH] = Q_KEY_CODE_AC_REFRESH,
[SDL_SCANCODE_AC_BOOKMARKS] = Q_KEY_CODE_AC_BOOKMARKS,
[SDL_SCANCODE_BRIGHTNESSDOWN] = Q_KEY_CODE_BRIGHTNESSDOWN,
[SDL_SCANCODE_BRIGHTNESSUP] = Q_KEY_CODE_BRIGHTNESSUP,
[SDL_SCANCODE_DISPLAYSWITCH] = Q_KEY_CODE_DISPLAYSWITCH,
[SDL_SCANCODE_KBDILLUMTOGGLE] = Q_KEY_CODE_KBDILLUMTOGGLE,
[SDL_SCANCODE_KBDILLUMDOWN] = Q_KEY_CODE_KBDILLUMDOWN,
[SDL_SCANCODE_KBDILLUMUP] = Q_KEY_CODE_KBDILLUMUP,
[SDL_SCANCODE_EJECT] = Q_KEY_CODE_EJECT,
[SDL_SCANCODE_SLEEP] = Q_KEY_CODE_SLEEP,
[SDL_SCANCODE_APP1] = Q_KEY_CODE_APP1,
[SDL_SCANCODE_APP2] = Q_KEY_CODE_APP2,
#endif
};

829
ui/sdl2.c Normal file
View File

@ -0,0 +1,829 @@
/*
* QEMU SDL display driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* 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.
*/
/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
#undef WIN32_LEAN_AND_MEAN
#include <SDL.h>
#if SDL_MAJOR_VERSION == 2
#include <SDL_syswm.h>
#include "qemu-common.h"
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "sdl_zoom.h"
#include "sdl2-keymap.h"
static int sdl2_num_outputs;
static struct sdl2_state {
DisplayChangeListener dcl;
DisplaySurface *surface;
SDL_Texture *texture;
SDL_Window *real_window;
SDL_Renderer *real_renderer;
int idx;
int last_vm_running; /* per console for caption reasons */
int x, y;
} *sdl2_console;
static SDL_Surface *guest_sprite_surface;
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
static bool gui_saved_scaling;
static int gui_saved_width;
static int gui_saved_height;
static int gui_saved_grab;
static int gui_fullscreen;
static int gui_noframe;
static int gui_key_modifier_pressed;
static int gui_keysym;
static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
static uint8_t modifiers_state[SDL_NUM_SCANCODES];
static SDL_Cursor *sdl_cursor_normal;
static SDL_Cursor *sdl_cursor_hidden;
static int absolute_enabled;
static int guest_cursor;
static int guest_x, guest_y;
static SDL_Cursor *guest_sprite;
static int scaling_active;
static Notifier mouse_mode_notifier;
static void sdl_update_caption(struct sdl2_state *scon);
static struct sdl2_state *get_scon_from_window(uint32_t window_id)
{
int i;
for (i = 0; i < sdl2_num_outputs; i++) {
if (sdl2_console[i].real_window == SDL_GetWindowFromID(window_id)) {
return &sdl2_console[i];
}
}
return NULL;
}
static void sdl_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
SDL_Rect rect;
DisplaySurface *surf = qemu_console_surface(dcl->con);
if (!surf) {
return;
}
if (!scon->texture) {
return;
}
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
SDL_UpdateTexture(scon->texture, NULL, surface_data(surf),
surface_stride(surf));
SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect);
SDL_RenderPresent(scon->real_renderer);
}
static void do_sdl_resize(struct sdl2_state *scon, int width, int height,
int bpp)
{
int flags;
if (scon->real_window && scon->real_renderer) {
if (width && height) {
SDL_RenderSetLogicalSize(scon->real_renderer, width, height);
SDL_SetWindowSize(scon->real_window, width, height);
} else {
SDL_DestroyRenderer(scon->real_renderer);
SDL_DestroyWindow(scon->real_window);
scon->real_renderer = NULL;
scon->real_window = NULL;
}
} else {
if (!width || !height) {
return;
}
flags = 0;
if (gui_fullscreen) {
flags |= SDL_WINDOW_FULLSCREEN;
} else {
flags |= SDL_WINDOW_RESIZABLE;
}
scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height, flags);
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
sdl_update_caption(scon);
}
}
static void sdl_switch(DisplayChangeListener *dcl,
DisplaySurface *new_surface)
{
struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
int format = 0;
int idx = scon->idx;
DisplaySurface *old_surface = scon->surface;
/* temporary hack: allows to call sdl_switch to handle scaling changes */
if (new_surface) {
scon->surface = new_surface;
}
if (!new_surface && idx > 0) {
scon->surface = NULL;
}
if (new_surface == NULL) {
do_sdl_resize(scon, 0, 0, 0);
} else {
do_sdl_resize(scon, surface_width(scon->surface),
surface_height(scon->surface), 0);
}
if (old_surface && scon->texture) {
SDL_DestroyTexture(scon->texture);
scon->texture = NULL;
}
if (new_surface) {
if (!scon->texture) {
if (surface_bits_per_pixel(scon->surface) == 16) {
format = SDL_PIXELFORMAT_RGB565;
} else if (surface_bits_per_pixel(scon->surface) == 32) {
format = SDL_PIXELFORMAT_ARGB8888;
}
scon->texture = SDL_CreateTexture(scon->real_renderer, format,
SDL_TEXTUREACCESS_STREAMING,
surface_width(new_surface),
surface_height(new_surface));
}
}
}
static void reset_keys(void)
{
int i;
for (i = 0; i < 256; i++) {
if (modifiers_state[i]) {
int qcode = sdl2_scancode_to_qcode[i];
qemu_input_event_send_key_qcode(NULL, qcode, false);
modifiers_state[i] = 0;
}
}
}
static void sdl_process_key(SDL_KeyboardEvent *ev)
{
int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
switch (ev->keysym.scancode) {
#if 0
case SDL_SCANCODE_NUMLOCKCLEAR:
case SDL_SCANCODE_CAPSLOCK:
/* SDL does not send the key up event, so we generate it */
qemu_input_event_send_key_qcode(NULL, qcode, true);
qemu_input_event_send_key_qcode(NULL, qcode, false);
return;
#endif
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;
}
/* fall though */
default:
qemu_input_event_send_key_qcode(NULL, qcode,
ev->type == SDL_KEYDOWN);
}
}
static void sdl_update_caption(struct sdl2_state *scon)
{
char win_title[1024];
char icon_title[1024];
const char *status = "";
if (!runstate_is_running()) {
status = " [Stopped]";
} else if (gui_grab) {
if (alt_grab) {
status = " - Press Ctrl-Alt-Shift to exit mouse grab";
} else if (ctrl_grab) {
status = " - Press Right-Ctrl to exit mouse grab";
} else {
status = " - Press Ctrl-Alt to exit mouse grab";
}
}
if (qemu_name) {
snprintf(win_title, sizeof(win_title), "QEMU (%s-%d)%s", qemu_name,
scon->idx, status);
snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
} else {
snprintf(win_title, sizeof(win_title), "QEMU%s", status);
snprintf(icon_title, sizeof(icon_title), "QEMU");
}
if (scon->real_window) {
SDL_SetWindowTitle(scon->real_window, win_title);
}
}
static void sdl_hide_cursor(void)
{
if (!cursor_hide) {
return;
}
if (qemu_input_is_absolute()) {
SDL_ShowCursor(1);
SDL_SetCursor(sdl_cursor_hidden);
} else {
SDL_ShowCursor(0);
}
}
static void sdl_show_cursor(void)
{
if (!cursor_hide) {
return;
}
if (!qemu_input_is_absolute()) {
SDL_ShowCursor(1);
if (guest_cursor &&
(gui_grab || qemu_input_is_absolute() || absolute_enabled)) {
SDL_SetCursor(guest_sprite);
} else {
SDL_SetCursor(sdl_cursor_normal);
}
}
}
static void sdl_grab_start(struct sdl2_state *scon)
{
/*
* If the application is not active, do not try to enter grab state. This
* prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
* application (SDL bug).
*/
if (!(SDL_GetWindowFlags(scon->real_window) & SDL_WINDOW_INPUT_FOCUS)) {
return;
}
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y);
}
} else {
sdl_hide_cursor();
}
SDL_SetWindowGrab(scon->real_window, SDL_TRUE);
gui_grab = 1;
sdl_update_caption(scon);
}
static void sdl_grab_end(struct sdl2_state *scon)
{
SDL_SetWindowGrab(scon->real_window, SDL_FALSE);
gui_grab = 0;
sdl_show_cursor();
sdl_update_caption(scon);
}
static void absolute_mouse_grab(struct sdl2_state *scon)
{
int mouse_x, mouse_y;
int scr_w, scr_h;
SDL_GetMouseState(&mouse_x, &mouse_y);
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
if (mouse_x > 0 && mouse_x < scr_w - 1 &&
mouse_y > 0 && mouse_y < scr_h - 1) {
sdl_grab_start(scon);
}
}
static void sdl_mouse_mode_change(Notifier *notify, void *data)
{
if (qemu_input_is_absolute()) {
if (!absolute_enabled) {
absolute_enabled = 1;
absolute_mouse_grab(&sdl2_console[0]);
}
} else if (absolute_enabled) {
if (!gui_fullscreen) {
sdl_grab_end(&sdl2_console[0]);
}
absolute_enabled = 0;
}
}
static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy,
int dz, int x, int y, int state)
{
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
#if 0
[INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
[INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
#endif
};
static uint32_t prev_state;
if (prev_state != state) {
qemu_input_update_buttons(scon->dcl.con, bmap, prev_state, state);
prev_state = state;
}
if (qemu_input_is_absolute()) {
int scr_w, scr_h;
int max_w = 0, max_h = 0;
int off_x = 0, off_y = 0;
int cur_off_x = 0, cur_off_y = 0;
int i;
for (i = 0; i < sdl2_num_outputs; i++) {
struct sdl2_state *thiscon = &sdl2_console[i];
if (thiscon->real_window && thiscon->surface) {
SDL_GetWindowSize(thiscon->real_window, &scr_w, &scr_h);
cur_off_x = thiscon->x;
cur_off_y = thiscon->y;
if (scr_w + cur_off_x > max_w) {
max_w = scr_w + cur_off_x;
}
if (scr_h + cur_off_y > max_h) {
max_h = scr_h + cur_off_y;
}
if (i == scon->idx) {
off_x = cur_off_x;
off_y = cur_off_y;
}
}
}
qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w);
qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h);
} else if (guest_cursor) {
x -= guest_x;
y -= guest_y;
guest_x += x;
guest_y += y;
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, x);
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, y);
}
qemu_input_event_sync();
}
static void sdl_scale(struct sdl2_state *scon, int width, int height)
{
int bpp = 0;
do_sdl_resize(scon, width, height, bpp);
scaling_active = 1;
}
static void toggle_full_screen(struct sdl2_state *scon)
{
int width = surface_width(scon->surface);
int height = surface_height(scon->surface);
int bpp = surface_bits_per_pixel(scon->surface);
gui_fullscreen = !gui_fullscreen;
if (gui_fullscreen) {
SDL_GetWindowSize(scon->real_window,
&gui_saved_width, &gui_saved_height);
gui_saved_scaling = scaling_active;
do_sdl_resize(scon, width, height, bpp);
scaling_active = 0;
gui_saved_grab = gui_grab;
sdl_grab_start(scon);
} else {
if (gui_saved_scaling) {
sdl_scale(scon, gui_saved_width, gui_saved_height);
} else {
do_sdl_resize(scon, width, height, 0);
}
if (!gui_saved_grab) {
sdl_grab_end(scon);
}
}
graphic_hw_invalidate(scon->dcl.con);
graphic_hw_update(scon->dcl.con);
}
static void handle_keydown(SDL_Event *ev)
{
int mod_state;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
if (alt_grab) {
mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
(gui_grab_code | KMOD_LSHIFT);
} else if (ctrl_grab) {
mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
} else {
mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
}
gui_key_modifier_pressed = mod_state;
if (gui_key_modifier_pressed) {
switch (ev->key.keysym.scancode) {
case SDL_SCANCODE_F:
toggle_full_screen(scon);
gui_keysym = 1;
break;
case SDL_SCANCODE_U:
if (scaling_active) {
scaling_active = 0;
sdl_switch(&scon->dcl, NULL);
graphic_hw_invalidate(scon->dcl.con);
graphic_hw_update(scon->dcl.con);
}
gui_keysym = 1;
break;
case SDL_SCANCODE_KP_PLUS:
case SDL_SCANCODE_KP_MINUS:
if (!gui_fullscreen) {
int scr_w, scr_h;
int width, height;
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
width = MAX(scr_w + (ev->key.keysym.scancode ==
SDL_SCANCODE_KP_PLUS ? 50 : -50),
160);
height = (surface_height(scon->surface) * width) /
surface_width(scon->surface);
sdl_scale(scon, width, height);
graphic_hw_invalidate(NULL);
graphic_hw_update(NULL);
gui_keysym = 1;
}
default:
break;
}
}
if (!gui_keysym) {
sdl_process_key(&ev->key);
}
}
static void handle_keyup(SDL_Event *ev)
{
int mod_state;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
if (!alt_grab) {
mod_state = (ev->key.keysym.mod & gui_grab_code);
} else {
mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
}
if (!mod_state && gui_key_modifier_pressed) {
gui_key_modifier_pressed = 0;
if (gui_keysym == 0) {
/* exit/enter grab if pressing Ctrl-Alt */
if (!gui_grab) {
sdl_grab_start(scon);
} else if (!gui_fullscreen) {
sdl_grab_end(scon);
}
/* SDL does not send back all the modifiers key, so we must
* correct it. */
reset_keys();
return;
}
gui_keysym = 0;
}
if (!gui_keysym) {
sdl_process_key(&ev->key);
}
}
static void handle_mousemotion(SDL_Event *ev)
{
int max_x, max_y;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
if (qemu_input_is_absolute() || absolute_enabled) {
int scr_w, scr_h;
SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
max_x = scr_w - 1;
max_y = scr_h - 1;
if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
ev->motion.x == max_x || ev->motion.y == max_y)) {
sdl_grab_end(scon);
}
if (!gui_grab &&
(ev->motion.x > 0 && ev->motion.x < max_x &&
ev->motion.y > 0 && ev->motion.y < max_y)) {
sdl_grab_start(scon);
}
}
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, 0,
ev->motion.x, ev->motion.y, ev->motion.state);
}
}
static void handle_mousebutton(SDL_Event *ev)
{
int buttonstate = SDL_GetMouseState(NULL, NULL);
SDL_MouseButtonEvent *bev;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
int dz;
bev = &ev->button;
if (!gui_grab && !qemu_input_is_absolute()) {
if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
sdl_grab_start(scon);
}
} else {
dz = 0;
if (ev->type == SDL_MOUSEBUTTONDOWN) {
buttonstate |= SDL_BUTTON(bev->button);
} else {
buttonstate &= ~SDL_BUTTON(bev->button);
}
#ifdef SDL_BUTTON_WHEELUP
if (bev->button == SDL_BUTTON_WHEELUP &&
ev->type == SDL_MOUSEBUTTONDOWN) {
dz = -1;
} else if (bev->button == SDL_BUTTON_WHEELDOWN &&
ev->type == SDL_MOUSEBUTTONDOWN) {
dz = 1;
}
#endif
sdl_send_mouse_event(scon, 0, 0, dz, bev->x, bev->y, buttonstate);
}
}
static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
{
int w, h;
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
switch (ev->window.event) {
case SDL_WINDOWEVENT_RESIZED:
sdl_scale(scon, ev->window.data1, ev->window.data2);
graphic_hw_invalidate(scon->dcl.con);
graphic_hw_update(scon->dcl.con);
break;
case SDL_WINDOWEVENT_EXPOSED:
SDL_GetWindowSize(SDL_GetWindowFromID(ev->window.windowID), &w, &h);
sdl_update(dcl, 0, 0, w, h);
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_ENTER:
if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) {
absolute_mouse_grab(scon);
}
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
if (gui_grab && !gui_fullscreen) {
sdl_grab_end(scon);
}
break;
case SDL_WINDOWEVENT_RESTORED:
update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT);
break;
case SDL_WINDOWEVENT_MINIMIZED:
update_displaychangelistener(dcl, 500);
break;
case SDL_WINDOWEVENT_CLOSE:
if (!no_quit) {
no_shutdown = 0;
qemu_system_shutdown_request();
}
break;
}
}
static void sdl_refresh(DisplayChangeListener *dcl)
{
struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
SDL_Event ev1, *ev = &ev1;
if (scon->last_vm_running != runstate_is_running()) {
scon->last_vm_running = runstate_is_running();
sdl_update_caption(scon);
}
graphic_hw_update(dcl->con);
while (SDL_PollEvent(ev)) {
switch (ev->type) {
case SDL_KEYDOWN:
handle_keydown(ev);
break;
case SDL_KEYUP:
handle_keyup(ev);
break;
case SDL_QUIT:
if (!no_quit) {
no_shutdown = 0;
qemu_system_shutdown_request();
}
break;
case SDL_MOUSEMOTION:
handle_mousemotion(ev);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
handle_mousebutton(ev);
break;
case SDL_WINDOWEVENT:
handle_windowevent(dcl, ev);
break;
default:
break;
}
}
}
static void sdl_mouse_warp(DisplayChangeListener *dcl,
int x, int y, int on)
{
struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
if (on) {
if (!guest_cursor) {
sdl_show_cursor();
}
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
SDL_SetCursor(guest_sprite);
if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouseInWindow(scon->real_window, x, y);
}
}
} else if (gui_grab) {
sdl_hide_cursor();
}
guest_cursor = on;
guest_x = x, guest_y = y;
}
static void sdl_mouse_define(DisplayChangeListener *dcl,
QEMUCursor *c)
{
if (guest_sprite) {
SDL_FreeCursor(guest_sprite);
}
if (guest_sprite_surface) {
SDL_FreeSurface(guest_sprite_surface);
}
guest_sprite_surface =
SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4,
0xff0000, 0x00ff00, 0xff, 0xff000000);
if (!guest_sprite_surface) {
fprintf(stderr, "Failed to make rgb surface from %p\n", c);
return;
}
guest_sprite = SDL_CreateColorCursor(guest_sprite_surface,
c->hot_x, c->hot_y);
if (!guest_sprite) {
fprintf(stderr, "Failed to make color cursor from %p\n", c);
return;
}
if (guest_cursor &&
(gui_grab || qemu_input_is_absolute() || absolute_enabled)) {
SDL_SetCursor(guest_sprite);
}
}
static void sdl_cleanup(void)
{
if (guest_sprite) {
SDL_FreeCursor(guest_sprite);
}
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "sdl",
.dpy_gfx_update = sdl_update,
.dpy_gfx_switch = sdl_switch,
.dpy_refresh = sdl_refresh,
.dpy_mouse_set = sdl_mouse_warp,
.dpy_cursor_define = sdl_mouse_define,
};
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
{
int flags;
uint8_t data = 0;
char *filename;
int i;
if (no_frame) {
gui_noframe = 1;
}
#ifdef __linux__
/* on Linux, SDL may use fbcon|directfb|svgalib when run without
* accessible $DISPLAY to open X11 window. This is often the case
* when qemu is run using sudo. But in this case, and when actually
* run in X11 environment, SDL fights with X11 for the video card,
* making current display unavailable, often until reboot.
* So make x11 the default SDL video driver if this variable is unset.
* This is a bit hackish but saves us from bigger problem.
* Maybe it's a good idea to fix this in SDL instead.
*/
setenv("SDL_VIDEODRIVER", "x11", 0);
#endif
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
if (SDL_Init(flags)) {
fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
SDL_GetError());
exit(1);
}
for (i = 0;; i++) {
QemuConsole *con = qemu_console_lookup_by_index(i);
if (!con || !qemu_console_is_graphic(con)) {
break;
}
}
sdl2_num_outputs = i;
sdl2_console = g_new0(struct sdl2_state, sdl2_num_outputs);
for (i = 0; i < sdl2_num_outputs; i++) {
QemuConsole *con = qemu_console_lookup_by_index(i);
sdl2_console[i].dcl.ops = &dcl_ops;
sdl2_console[i].dcl.con = con;
register_displaychangelistener(&sdl2_console[i].dcl);
sdl2_console[i].idx = i;
}
/* Load a 32x32x4 image. White pixels are transparent. */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
if (filename) {
SDL_Surface *image = SDL_LoadBMP(filename);
if (image) {
uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
SDL_SetColorKey(image, SDL_TRUE, colorkey);
SDL_SetWindowIcon(sdl2_console[0].real_window, image);
}
g_free(filename);
}
if (full_screen) {
gui_fullscreen = 1;
sdl_grab_start(0);
}
mouse_mode_notifier.notify = sdl_mouse_mode_change;
qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
gui_grab = 0;
sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
sdl_cursor_normal = SDL_GetCursor();
atexit(sdl_cleanup);
}
#endif

View File

@ -200,6 +200,7 @@ static const name2keysym_t name2keysym[]={
{ "yacute", 0x0fd},
{ "thorn", 0x0fe},
{ "ydiaeresis", 0x0ff},
#if SDL_MAJOR_VERSION == 1
{"EuroSign", SDLK_EURO},
/* modifiers */
@ -272,6 +273,6 @@ static const name2keysym_t name2keysym[]={
{"Num_Lock", SDLK_NUMLOCK},
{"Pause", SDLK_PAUSE},
{"Escape", SDLK_ESCAPE},
#endif
{NULL, 0},
};

View File

@ -26,12 +26,15 @@
#include "qemu-common.h"
#include "ui/qemu-spice.h"
#include "ui/console.h"
#include "ui/keymaps.h"
#include "ui/input.h"
/* keyboard bits */
typedef struct QemuSpiceKbd {
SpiceKbdInstance sin;
int ledstate;
bool emul0;
} QemuSpiceKbd;
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
@ -47,9 +50,24 @@ static const SpiceKbdInterface kbd_interface = {
.get_leds = kbd_get_leds,
};
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
{
kbd_put_keycode(frag);
QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
int keycode;
bool up;
if (scancode == SCANCODE_EMUL0) {
kbd->emul0 = true;
return;
}
keycode = scancode & ~SCANCODE_UP;
up = scancode & SCANCODE_UP;
if (kbd->emul0) {
kbd->emul0 = false;
keycode |= SCANCODE_GREY;
}
qemu_input_event_send_key_number(NULL, keycode, !up);
}
static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
@ -80,41 +98,52 @@ static void kbd_leds(void *opaque, int ledstate)
typedef struct QemuSpicePointer {
SpiceMouseInstance mouse;
SpiceTabletInstance tablet;
int width, height, x, y;
int width, height;
uint32_t last_bmask;
Notifier mouse_mode;
bool absolute;
} QemuSpicePointer;
static int map_buttons(int spice_buttons)
static void spice_update_buttons(QemuSpicePointer *pointer,
int wheel, uint32_t button_mask)
{
int qemu_buttons = 0;
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x04,
[INPUT_BUTTON_RIGHT] = 0x02,
[INPUT_BUTTON_WHEEL_UP] = 0x10,
[INPUT_BUTTON_WHEEL_DOWN] = 0x20,
};
/*
* Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this
* isn't what we get passed in via interface callbacks for the
* middle and right button ...
*/
if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) {
qemu_buttons |= MOUSE_EVENT_LBUTTON;
if (wheel < 0) {
button_mask |= 0x10;
}
if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) {
qemu_buttons |= MOUSE_EVENT_MBUTTON;
if (wheel > 0) {
button_mask |= 0x20;
}
if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) {
qemu_buttons |= MOUSE_EVENT_RBUTTON;
if (pointer->last_bmask == button_mask) {
return;
}
return qemu_buttons;
qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask);
pointer->last_bmask = button_mask;
}
static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
uint32_t buttons_state)
{
kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state));
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
spice_update_buttons(pointer, dz, buttons_state);
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
qemu_input_event_sync();
}
static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
{
kbd_mouse_event(0, 0, 0, map_buttons(buttons_state));
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
spice_update_buttons(pointer, 0, buttons_state);
qemu_input_event_sync();
}
static const SpiceMouseInterface mouse_interface = {
@ -145,9 +174,10 @@ static void tablet_position(SpiceTabletInstance* sin, int x, int y,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
pointer->x = x * 0x7FFF / (pointer->width - 1);
pointer->y = y * 0x7FFF / (pointer->height - 1);
kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
spice_update_buttons(pointer, 0, buttons_state);
qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width);
qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->width);
qemu_input_event_sync();
}
@ -156,7 +186,8 @@ static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state));
spice_update_buttons(pointer, wheel, buttons_state);
qemu_input_event_sync();
}
static void tablet_buttons(SpiceTabletInstance *sin,
@ -164,7 +195,8 @@ static void tablet_buttons(SpiceTabletInstance *sin,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
spice_update_buttons(pointer, 0, buttons_state);
qemu_input_event_sync();
}
static const SpiceTabletInterface tablet_interface = {
@ -181,7 +213,7 @@ static const SpiceTabletInterface tablet_interface = {
static void mouse_mode_notifier(Notifier *notifier, void *data)
{
QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
bool is_absolute = kbd_mouse_is_absolute();
bool is_absolute = qemu_input_is_absolute();
if (pointer->absolute == is_absolute) {
return;

View File

@ -33,6 +33,7 @@
#include "qapi/qmp/types.h"
#include "qmp-commands.h"
#include "qemu/osdep.h"
#include "ui/input.h"
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
@ -1483,7 +1484,7 @@ static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
static void check_pointer_type_change(Notifier *notifier, void *data)
{
VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
int absolute = kbd_mouse_is_absolute();
int absolute = qemu_input_is_absolute();
if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
vnc_lock_output(vs);
@ -1502,39 +1503,37 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
int buttons = 0;
int dz = 0;
static uint32_t bmap[INPUT_BUTTON_MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x02,
[INPUT_BUTTON_RIGHT] = 0x04,
[INPUT_BUTTON_WHEEL_UP] = 0x08,
[INPUT_BUTTON_WHEEL_DOWN] = 0x10,
};
QemuConsole *con = vs->vd->dcl.con;
int width = surface_width(vs->vd->ds);
int height = surface_height(vs->vd->ds);
if (button_mask & 0x01)
buttons |= MOUSE_EVENT_LBUTTON;
if (button_mask & 0x02)
buttons |= MOUSE_EVENT_MBUTTON;
if (button_mask & 0x04)
buttons |= MOUSE_EVENT_RBUTTON;
if (button_mask & 0x08)
dz = -1;
if (button_mask & 0x10)
dz = 1;
if (vs->last_bmask != button_mask) {
qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
vs->last_bmask = button_mask;
}
if (vs->absolute) {
kbd_mouse_event(width > 1 ? x * 0x7FFF / (width - 1) : 0x4000,
height > 1 ? y * 0x7FFF / (height - 1) : 0x4000,
dz, buttons);
qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
} else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
x -= 0x7FFF;
y -= 0x7FFF;
kbd_mouse_event(x, y, dz, buttons);
qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
} else {
if (vs->last_x != -1)
kbd_mouse_event(x - vs->last_x,
y - vs->last_y,
dz, buttons);
if (vs->last_x != -1) {
qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
}
vs->last_x = x;
vs->last_y = y;
}
qemu_input_event_sync();
}
static void reset_keys(VncState *vs)
@ -1542,9 +1541,7 @@ static void reset_keys(VncState *vs)
int i;
for(i = 0; i < 256; i++) {
if (vs->modifiers_state[i]) {
if (i & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(i | SCANCODE_UP);
qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
vs->modifiers_state[i] = 0;
}
}
@ -1553,12 +1550,8 @@ static void reset_keys(VncState *vs)
static void press_key(VncState *vs, int keysym)
{
int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
if (keycode & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
if (keycode & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
kbd_put_keycode(keycode | SCANCODE_UP);
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
}
static int current_led_state(VncState *vs)
@ -1700,12 +1693,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
if (qemu_console_is_graphic(NULL)) {
if (keycode & SCANCODE_GREY)
kbd_put_keycode(SCANCODE_EMUL0);
if (down)
kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
else
kbd_put_keycode(keycode | SCANCODE_UP);
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
} else {
bool numlock = vs->modifiers_state[0x45];
bool control = (vs->modifiers_state[0x1d] ||
@ -1826,10 +1814,7 @@ static void vnc_release_modifiers(VncState *vs)
if (!vs->modifiers_state[keycode]) {
continue;
}
if (keycode & SCANCODE_GREY) {
kbd_put_keycode(SCANCODE_EMUL0);
}
kbd_put_keycode(keycode | SCANCODE_UP);
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
}
}

View File

@ -257,6 +257,7 @@ struct VncState
int absolute;
int last_x;
int last_y;
uint32_t last_bmask;
int client_width;
int client_height;
VncShareMode share_mode;