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:
commit
6fc0303b95
@ -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
23
configure
vendored
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
56
include/ui/input.h
Normal 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 */
|
31
monitor.c
31
monitor.c
@ -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)
|
||||
|
@ -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' } }
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
81
ui/cocoa.m
81
ui/cocoa.m
@ -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];
|
||||
|
69
ui/console.c
69
ui/console.c
@ -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;
|
||||
|
51
ui/curses.c
51
ui/curses.c
@ -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)
|
||||
|
77
ui/gtk.c
77
ui/gtk.c
@ -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
453
ui/input-legacy.c
Normal 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);
|
||||
}
|
||||
}
|
804
ui/input.c
804
ui/input.c
@ -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
108
ui/sdl.c
@ -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
266
ui/sdl2-keymap.h
Normal 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
829
ui/sdl2.c
Normal 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
|
@ -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},
|
||||
};
|
||||
|
@ -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;
|
||||
|
71
ui/vnc.c
71
ui/vnc.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user