mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
Merge branch 'queue/qmp' of git://repo.or.cz/qemu/qmp-unstable
* 'queue/qmp' of git://repo.or.cz/qemu/qmp-unstable: tcx: tcx_screen_dump(): add error handling tcx: tcx24_screen_dump(): add error handling g364fb: g364fb_screen_dump(): add error handling omap_lcdc: omap_ppm_save(): add error handling omap_lcdc: rename ppm_save() to omap_ppm_save() vga: ppm_save(): add error handling qapi: convert screendump console: vga_hw_screen_dump_ptr: take Error argument error: add error_setg() json-parser: Fix potential NULL pointer segfault qapi: Fix potential NULL pointer segfault qapi: convert sendkey monitor: move key_defs[] table and introduce two help functions qapi: add the QKeyCode enum qapi: generate list struct and visit_list for enum hmp: rename arguments monitor: rename keyname '<' to 'less' fix doc of using raw values with sendkey Add support for pretty-printing response in qmp-shell
This commit is contained in:
commit
e22b1e9907
@ -33,6 +33,7 @@
|
||||
import qmp
|
||||
import readline
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
class QMPCompleter(list):
|
||||
def complete(self, text, state):
|
||||
@ -52,10 +53,11 @@ class QMPShellBadPort(QMPShellError):
|
||||
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
|
||||
# _execute_cmd()). Let's design a better one.
|
||||
class QMPShell(qmp.QEMUMonitorProtocol):
|
||||
def __init__(self, address):
|
||||
def __init__(self, address, pp=None):
|
||||
qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
|
||||
self._greeting = None
|
||||
self._completer = None
|
||||
self._pp = pp
|
||||
|
||||
def __get_address(self, arg):
|
||||
"""
|
||||
@ -114,7 +116,11 @@ class QMPShell(qmp.QEMUMonitorProtocol):
|
||||
if resp is None:
|
||||
print 'Disconnected'
|
||||
return False
|
||||
print resp
|
||||
|
||||
if self._pp is not None:
|
||||
self._pp.pprint(resp)
|
||||
else:
|
||||
print resp
|
||||
return True
|
||||
|
||||
def connect(self):
|
||||
@ -222,22 +228,36 @@ def die(msg):
|
||||
def fail_cmdline(option=None):
|
||||
if option:
|
||||
sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
|
||||
sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
|
||||
sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
addr = ''
|
||||
qemu = None
|
||||
hmp = False
|
||||
pp = None
|
||||
|
||||
try:
|
||||
if len(sys.argv) == 2:
|
||||
qemu = QMPShell(sys.argv[1])
|
||||
addr = sys.argv[1]
|
||||
elif len(sys.argv) == 3:
|
||||
if sys.argv[1] != '-H':
|
||||
fail_cmdline(sys.argv[1])
|
||||
qemu = HMPShell(sys.argv[2])
|
||||
addr = sys.argv[2]
|
||||
else:
|
||||
fail_cmdline()
|
||||
for arg in sys.argv[1:]:
|
||||
if arg == "-H":
|
||||
if qemu is not None:
|
||||
fail_cmdline(arg)
|
||||
hmp = True
|
||||
elif arg == "-p":
|
||||
if pp is not None:
|
||||
fail_cmdline(arg)
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
else:
|
||||
if qemu is not None:
|
||||
fail_cmdline(arg)
|
||||
if hmp:
|
||||
qemu = HMPShell(arg)
|
||||
else:
|
||||
qemu = QMPShell(arg, pp)
|
||||
addr = arg
|
||||
|
||||
if qemu is None:
|
||||
fail_cmdline()
|
||||
except QMPShellBadPort:
|
||||
die('bad port number in command-line')
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "qemu-common.h"
|
||||
#include "console.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qmp-commands.h"
|
||||
|
||||
//#define DEBUG_CONSOLE
|
||||
#define DEFAULT_BACKSCROLL 512
|
||||
@ -176,7 +177,7 @@ void vga_hw_invalidate(void)
|
||||
active_console->hw_invalidate(active_console->hw);
|
||||
}
|
||||
|
||||
void vga_hw_screen_dump(const char *filename)
|
||||
void qmp_screendump(const char *filename, Error **errp)
|
||||
{
|
||||
TextConsole *previous_active_console;
|
||||
bool cswitch;
|
||||
@ -190,9 +191,9 @@ void vga_hw_screen_dump(const char *filename)
|
||||
console_select(0);
|
||||
}
|
||||
if (consoles[0] && consoles[0]->hw_screen_dump) {
|
||||
consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
|
||||
consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
|
||||
} else {
|
||||
error_report("screen dump not implemented");
|
||||
error_setg(errp, "device doesn't support screendump\n");
|
||||
}
|
||||
|
||||
if (cswitch) {
|
||||
|
10
console.h
10
console.h
@ -6,6 +6,8 @@
|
||||
#include "notify.h"
|
||||
#include "monitor.h"
|
||||
#include "trace.h"
|
||||
#include "qapi-types.h"
|
||||
#include "error.h"
|
||||
|
||||
/* keyboard/mouse support */
|
||||
|
||||
@ -343,7 +345,8 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
||||
|
||||
typedef void (*vga_hw_update_ptr)(void *);
|
||||
typedef void (*vga_hw_invalidate_ptr)(void *);
|
||||
typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch);
|
||||
typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch,
|
||||
Error **errp);
|
||||
typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
|
||||
|
||||
DisplayState *graphic_console_init(vga_hw_update_ptr update,
|
||||
@ -354,7 +357,6 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update,
|
||||
|
||||
void vga_hw_update(void);
|
||||
void vga_hw_invalidate(void);
|
||||
void vga_hw_screen_dump(const char *filename);
|
||||
void vga_hw_text_update(console_ch_t *chardata);
|
||||
|
||||
int is_graphic_console(void);
|
||||
@ -397,4 +399,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
|
||||
/* curses.c */
|
||||
void curses_display_init(DisplayState *ds, int full_screen);
|
||||
|
||||
/* input.c */
|
||||
int index_from_key(const char *key);
|
||||
int index_from_keycode(int code);
|
||||
|
||||
#endif
|
||||
|
6
error.h
6
error.h
@ -29,6 +29,12 @@ typedef struct Error Error;
|
||||
*/
|
||||
void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
|
||||
|
||||
/**
|
||||
* Same as error_set(), but sets a generic error
|
||||
*/
|
||||
#define error_setg(err, fmt, ...) \
|
||||
error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Returns true if an indirect pointer to an error is pointing to a valid
|
||||
* error object.
|
||||
|
@ -194,8 +194,7 @@ ETEXI
|
||||
.args_type = "filename:F",
|
||||
.params = "filename",
|
||||
.help = "save screen into PPM image 'filename'",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_screen_dump,
|
||||
.mhandler.cmd = hmp_screen_dump,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@ -502,19 +501,19 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "sendkey",
|
||||
.args_type = "string:s,hold_time:i?",
|
||||
.args_type = "keys:s,hold-time:i?",
|
||||
.params = "keys [hold_ms]",
|
||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||
.mhandler.cmd = do_sendkey,
|
||||
.mhandler.cmd = hmp_send_key,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item sendkey @var{keys}
|
||||
@findex sendkey
|
||||
|
||||
Send @var{keys} to the emulator. @var{keys} could be the name of the
|
||||
key or @code{#} followed by the raw value in either decimal or hexadecimal
|
||||
format. Use @code{-} to press several keys simultaneously. Example:
|
||||
Send @var{keys} to the guest. @var{keys} could be the name of the
|
||||
key or the raw value in hexadecimal format. Use @code{-} to press
|
||||
several keys simultaneously. Example:
|
||||
@example
|
||||
sendkey ctrl-alt-f1
|
||||
@end example
|
||||
|
64
hmp.c
64
hmp.c
@ -19,6 +19,7 @@
|
||||
#include "qemu-timer.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "monitor.h"
|
||||
#include "console.h"
|
||||
|
||||
static void hmp_handle_error(Monitor *mon, Error **errp)
|
||||
{
|
||||
@ -1102,3 +1103,66 @@ void hmp_closefd(Monitor *mon, const QDict *qdict)
|
||||
qmp_closefd(fdname, &errp);
|
||||
hmp_handle_error(mon, &errp);
|
||||
}
|
||||
|
||||
void hmp_send_key(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *keys = qdict_get_str(qdict, "keys");
|
||||
QKeyCodeList *keylist, *head = NULL, *tmp = NULL;
|
||||
int has_hold_time = qdict_haskey(qdict, "hold-time");
|
||||
int hold_time = qdict_get_try_int(qdict, "hold-time", -1);
|
||||
Error *err = NULL;
|
||||
char keyname_buf[16];
|
||||
char *separator;
|
||||
int keyname_len, idx;
|
||||
|
||||
while (1) {
|
||||
separator = strchr(keys, '-');
|
||||
keyname_len = separator ? separator - keys : strlen(keys);
|
||||
pstrcpy(keyname_buf, sizeof(keyname_buf), keys);
|
||||
|
||||
/* Be compatible with old interface, convert user inputted "<" */
|
||||
if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) {
|
||||
pstrcpy(keyname_buf, sizeof(keyname_buf), "less");
|
||||
keyname_len = 4;
|
||||
}
|
||||
keyname_buf[keyname_len] = 0;
|
||||
|
||||
idx = index_from_key(keyname_buf);
|
||||
if (idx == Q_KEY_CODE_MAX) {
|
||||
monitor_printf(mon, "invalid parameter: %s\n", keyname_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
keylist = g_malloc0(sizeof(*keylist));
|
||||
keylist->value = idx;
|
||||
keylist->next = NULL;
|
||||
|
||||
if (!head) {
|
||||
head = keylist;
|
||||
}
|
||||
if (tmp) {
|
||||
tmp->next = keylist;
|
||||
}
|
||||
tmp = keylist;
|
||||
|
||||
if (!separator) {
|
||||
break;
|
||||
}
|
||||
keys = separator + 1;
|
||||
}
|
||||
|
||||
if (idx != Q_KEY_CODE_MAX) {
|
||||
qmp_send_key(head, has_hold_time, hold_time, &err);
|
||||
}
|
||||
hmp_handle_error(mon, &err);
|
||||
qapi_free_QKeyCodeList(head);
|
||||
}
|
||||
|
||||
void hmp_screen_dump(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *filename = qdict_get_str(qdict, "filename");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_screendump(filename, &err);
|
||||
hmp_handle_error(mon, &err);
|
||||
}
|
||||
|
2
hmp.h
2
hmp.h
@ -71,5 +71,7 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
|
||||
void hmp_getfd(Monitor *mon, const QDict *qdict);
|
||||
void hmp_closefd(Monitor *mon, const QDict *qdict);
|
||||
void hmp_send_key(Monitor *mon, const QDict *qdict);
|
||||
void hmp_screen_dump(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
@ -933,13 +933,13 @@ static void blizzard_update_display(void *opaque)
|
||||
}
|
||||
|
||||
static void blizzard_screen_dump(void *opaque, const char *filename,
|
||||
bool cswitch)
|
||||
bool cswitch, Error **errp)
|
||||
{
|
||||
BlizzardState *s = (BlizzardState *) opaque;
|
||||
|
||||
blizzard_update_display(opaque);
|
||||
if (s && ds_get_data(s->state))
|
||||
ppm_save(filename, s->state->surface);
|
||||
ppm_save(filename, s->state->surface, errp);
|
||||
}
|
||||
|
||||
#define DEPTH 8
|
||||
|
55
hw/g364fb.c
55
hw/g364fb.c
@ -289,10 +289,11 @@ static void g364fb_reset(G364State *s)
|
||||
g364fb_invalidate_display(s);
|
||||
}
|
||||
|
||||
static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
G364State *s = opaque;
|
||||
int y, x;
|
||||
int ret, y, x;
|
||||
uint8_t index;
|
||||
uint8_t *data_buffer;
|
||||
FILE *f;
|
||||
@ -300,35 +301,63 @@ static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
qemu_flush_coalesced_mmio_buffer();
|
||||
|
||||
if (s->depth != 8) {
|
||||
error_report("g364: unknown guest depth %d", s->depth);
|
||||
error_setg(errp, "g364: unknown guest depth %d", s->depth);
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
if (!f) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->ctla & CTLA_FORCE_BLANK) {
|
||||
/* blank screen */
|
||||
fprintf(f, "P4\n%d %d\n",
|
||||
s->width, s->height);
|
||||
ret = fprintf(f, "P4\n%d %d\n", s->width, s->height);
|
||||
if (ret < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
for (y = 0; y < s->height; y++)
|
||||
for (x = 0; x < s->width; x++)
|
||||
fputc(0, f);
|
||||
for (x = 0; x < s->width; x++) {
|
||||
ret = fputc(0, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data_buffer = s->vram + s->top_of_screen;
|
||||
fprintf(f, "P6\n%d %d\n%d\n",
|
||||
s->width, s->height, 255);
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
|
||||
if (ret < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
for (y = 0; y < s->height; y++)
|
||||
for (x = 0; x < s->width; x++, data_buffer++) {
|
||||
index = *data_buffer;
|
||||
fputc(s->color_palette[index][0], f);
|
||||
fputc(s->color_palette[index][1], f);
|
||||
fputc(s->color_palette[index][2], f);
|
||||
ret = fputc(s->color_palette[index][0], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->color_palette[index][1], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->color_palette[index][2], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
fclose(f);
|
||||
return;
|
||||
|
||||
write_err:
|
||||
error_setg(errp, "failed to write to file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
unlink(filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* called for accesses to io ports */
|
||||
|
@ -224,18 +224,24 @@ static void omap_update_display(void *opaque)
|
||||
omap_lcd->invalidate = 0;
|
||||
}
|
||||
|
||||
static int ppm_save(const char *filename, uint8_t *data,
|
||||
int w, int h, int linesize)
|
||||
static void omap_ppm_save(const char *filename, uint8_t *data,
|
||||
int w, int h, int linesize, Error **errp)
|
||||
{
|
||||
FILE *f;
|
||||
uint8_t *d, *d1;
|
||||
unsigned int v;
|
||||
int y, x, bpp;
|
||||
int ret, y, x, bpp;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
return -1;
|
||||
fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
|
||||
if (!f) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
|
||||
if (ret < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
d1 = data;
|
||||
bpp = linesize / w;
|
||||
for (y = 0; y < h; y ++) {
|
||||
@ -244,35 +250,61 @@ static int ppm_save(const char *filename, uint8_t *data,
|
||||
v = *(uint32_t *) d;
|
||||
switch (bpp) {
|
||||
case 2:
|
||||
fputc((v >> 8) & 0xf8, f);
|
||||
fputc((v >> 3) & 0xfc, f);
|
||||
fputc((v << 3) & 0xf8, f);
|
||||
ret = fputc((v >> 8) & 0xf8, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc((v >> 3) & 0xfc, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc((v << 3) & 0xf8, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
default:
|
||||
fputc((v >> 16) & 0xff, f);
|
||||
fputc((v >> 8) & 0xff, f);
|
||||
fputc((v) & 0xff, f);
|
||||
ret = fputc((v >> 16) & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc((v >> 8) & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc((v) & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
d += bpp;
|
||||
}
|
||||
d1 += linesize;
|
||||
}
|
||||
out:
|
||||
fclose(f);
|
||||
return 0;
|
||||
return;
|
||||
|
||||
write_err:
|
||||
error_setg(errp, "failed to write to file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
unlink(filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void omap_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
struct omap_lcd_panel_s *omap_lcd = opaque;
|
||||
|
||||
omap_update_display(opaque);
|
||||
if (omap_lcd && ds_get_data(omap_lcd->state))
|
||||
ppm_save(filename, ds_get_data(omap_lcd->state),
|
||||
omap_lcd->width, omap_lcd->height,
|
||||
ds_get_linesize(omap_lcd->state));
|
||||
omap_ppm_save(filename, ds_get_data(omap_lcd->state),
|
||||
omap_lcd->width, omap_lcd->height,
|
||||
ds_get_linesize(omap_lcd->state), errp);
|
||||
}
|
||||
|
||||
static void omap_invalidate_display(void *opaque) {
|
||||
|
7
hw/qxl.c
7
hw/qxl.c
@ -1595,7 +1595,8 @@ static void qxl_hw_invalidate(void *opaque)
|
||||
vga->invalidate(vga);
|
||||
}
|
||||
|
||||
static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
PCIQXLDevice *qxl = opaque;
|
||||
VGACommonState *vga = &qxl->vga;
|
||||
@ -1604,10 +1605,10 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
case QXL_MODE_COMPAT:
|
||||
case QXL_MODE_NATIVE:
|
||||
qxl_render_update(qxl);
|
||||
ppm_save(filename, qxl->ssd.ds->surface);
|
||||
ppm_save(filename, qxl->ssd.ds->surface, errp);
|
||||
break;
|
||||
case QXL_MODE_VGA:
|
||||
vga->screen_dump(vga, filename, cswitch);
|
||||
vga->screen_dump(vga, filename, cswitch, errp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
97
hw/tcx.c
97
hw/tcx.c
@ -56,8 +56,10 @@ typedef struct TCXState {
|
||||
uint8_t dac_index, dac_state;
|
||||
} TCXState;
|
||||
|
||||
static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch);
|
||||
static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch);
|
||||
static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp);
|
||||
static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp);
|
||||
|
||||
static void tcx_set_dirty(TCXState *s)
|
||||
{
|
||||
@ -574,45 +576,76 @@ static int tcx_init1(SysBusDevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
TCXState *s = opaque;
|
||||
FILE *f;
|
||||
uint8_t *d, *d1, v;
|
||||
int y, x;
|
||||
int ret, y, x;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
if (!f) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
|
||||
}
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
|
||||
if (ret < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
d1 = s->vram;
|
||||
for(y = 0; y < s->height; y++) {
|
||||
d = d1;
|
||||
for(x = 0; x < s->width; x++) {
|
||||
v = *d;
|
||||
fputc(s->r[v], f);
|
||||
fputc(s->g[v], f);
|
||||
fputc(s->b[v], f);
|
||||
ret = fputc(s->r[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->g[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->b[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
d++;
|
||||
}
|
||||
d1 += MAXX;
|
||||
}
|
||||
|
||||
out:
|
||||
fclose(f);
|
||||
return;
|
||||
|
||||
write_err:
|
||||
error_setg(errp, "failed to write to file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
unlink(filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
TCXState *s = opaque;
|
||||
FILE *f;
|
||||
uint8_t *d, *d1, v;
|
||||
uint32_t *s24, *cptr, dval;
|
||||
int y, x;
|
||||
int ret, y, x;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
if (!f) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
|
||||
}
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
|
||||
if (ret < 0) {
|
||||
goto write_err;
|
||||
}
|
||||
d1 = s->vram;
|
||||
s24 = s->vram24;
|
||||
cptr = s->cplane;
|
||||
@ -621,20 +654,46 @@ static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
for(x = 0; x < s->width; x++, d++, s24++) {
|
||||
if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
|
||||
dval = *s24 & 0x00ffffff;
|
||||
fputc((dval >> 16) & 0xff, f);
|
||||
fputc((dval >> 8) & 0xff, f);
|
||||
fputc(dval & 0xff, f);
|
||||
ret = fputc((dval >> 16) & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc((dval >> 8) & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(dval & 0xff, f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
} else {
|
||||
v = *d;
|
||||
fputc(s->r[v], f);
|
||||
fputc(s->g[v], f);
|
||||
fputc(s->b[v], f);
|
||||
ret = fputc(s->r[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->g[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
ret = fputc(s->b[v], f);
|
||||
if (ret == EOF) {
|
||||
goto write_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
d1 += MAXX;
|
||||
}
|
||||
|
||||
out:
|
||||
fclose(f);
|
||||
return;
|
||||
|
||||
write_err:
|
||||
error_setg(errp, "failed to write to file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
unlink(filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static Property tcx_properties[] = {
|
||||
|
38
hw/vga.c
38
hw/vga.c
@ -166,7 +166,8 @@ static uint32_t expand4[256];
|
||||
static uint16_t expand2[256];
|
||||
static uint8_t expand4to8[16];
|
||||
|
||||
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch);
|
||||
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp);
|
||||
|
||||
static void vga_update_memory_access(VGACommonState *s)
|
||||
{
|
||||
@ -2389,7 +2390,7 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
|
||||
/********************************************************/
|
||||
/* vga screen dump */
|
||||
|
||||
int ppm_save(const char *filename, struct DisplaySurface *ds)
|
||||
void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
|
||||
{
|
||||
FILE *f;
|
||||
uint8_t *d, *d1;
|
||||
@ -2401,10 +2402,16 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
|
||||
|
||||
trace_ppm_save(filename, ds);
|
||||
f = fopen(filename, "wb");
|
||||
if (!f)
|
||||
return -1;
|
||||
fprintf(f, "P6\n%d %d\n%d\n",
|
||||
ds->width, ds->height, 255);
|
||||
if (!f) {
|
||||
error_setg(errp, "failed to open file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
ret = fprintf(f, "P6\n%d %d\n%d\n", ds->width, ds->height, 255);
|
||||
if (ret < 0) {
|
||||
linebuf = NULL;
|
||||
goto write_err;
|
||||
}
|
||||
linebuf = g_malloc(ds->width * 3);
|
||||
d1 = ds->data;
|
||||
for(y = 0; y < ds->height; y++) {
|
||||
@ -2425,17 +2432,30 @@ int ppm_save(const char *filename, struct DisplaySurface *ds)
|
||||
d += ds->pf.bytes_per_pixel;
|
||||
}
|
||||
d1 += ds->linesize;
|
||||
clearerr(f);
|
||||
ret = fwrite(linebuf, 1, pbuf - linebuf, f);
|
||||
(void)ret;
|
||||
if (ferror(f)) {
|
||||
goto write_err;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(linebuf);
|
||||
fclose(f);
|
||||
return 0;
|
||||
return;
|
||||
|
||||
write_err:
|
||||
error_setg(errp, "failed to write to file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
unlink(filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* save the vga display in a PPM image even if no display is
|
||||
available */
|
||||
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
VGACommonState *s = opaque;
|
||||
|
||||
@ -2443,5 +2463,5 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
vga_invalidate_display(s);
|
||||
}
|
||||
vga_hw_update();
|
||||
ppm_save(filename, s->ds->surface);
|
||||
ppm_save(filename, s->ds->surface, errp);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <hw/hw.h>
|
||||
#include "error.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define ST01_V_RETRACE 0x08
|
||||
@ -204,7 +205,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr);
|
||||
void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
|
||||
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
|
||||
int ppm_save(const char *filename, struct DisplaySurface *ds);
|
||||
void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp);
|
||||
|
||||
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
|
||||
void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
|
||||
|
@ -1003,18 +1003,19 @@ static void vmsvga_invalidate_display(void *opaque)
|
||||
|
||||
/* save the vga display in a PPM image even if no display is
|
||||
available */
|
||||
static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch)
|
||||
static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
|
||||
Error **errp)
|
||||
{
|
||||
struct vmsvga_state_s *s = opaque;
|
||||
if (!s->enable) {
|
||||
s->vga.screen_dump(&s->vga, filename, cswitch);
|
||||
s->vga.screen_dump(&s->vga, filename, cswitch, errp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->depth == 32) {
|
||||
DisplaySurface *ds = qemu_create_displaysurface_from(s->width,
|
||||
s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr);
|
||||
ppm_save(filename, ds);
|
||||
ppm_save(filename, ds, errp);
|
||||
g_free(ds);
|
||||
}
|
||||
}
|
||||
|
251
input.c
251
input.c
@ -28,6 +28,7 @@
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi-types.h"
|
||||
|
||||
static QEMUPutKBDEvent *qemu_put_kbd_event;
|
||||
static void *qemu_put_kbd_event_opaque;
|
||||
@ -37,6 +38,256 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_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)
|
||||
{
|
||||
int i, keycode;
|
||||
char *endp;
|
||||
|
||||
for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
|
||||
if (!strcmp(key, QKeyCode_lookup[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strstart(key, "0x", NULL)) {
|
||||
keycode = strtoul(key, &endp, 0);
|
||||
if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) {
|
||||
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
|
||||
if (keycode == key_defs[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return Q_KEY_CODE_MAX if the key is invalid */
|
||||
return i;
|
||||
}
|
||||
|
||||
int index_from_keycode(int code)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
|
||||
if (key_defs[i] == code) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return Q_KEY_CODE_MAX if the code is invalid */
|
||||
return i;
|
||||
}
|
||||
|
||||
static QKeyCodeList *keycodes;
|
||||
static QEMUTimer *key_timer;
|
||||
|
||||
static void release_keys(void *opaque)
|
||||
{
|
||||
int keycode;
|
||||
QKeyCodeList *p;
|
||||
|
||||
for (p = keycodes; p != NULL; p = p->next) {
|
||||
keycode = key_defs[p->value];
|
||||
if (keycode & 0x80) {
|
||||
kbd_put_keycode(0xe0);
|
||||
}
|
||||
kbd_put_keycode(keycode | 0x80);
|
||||
}
|
||||
qapi_free_QKeyCodeList(keycodes);
|
||||
keycodes = NULL;
|
||||
}
|
||||
|
||||
void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t hold_time,
|
||||
Error **errp)
|
||||
{
|
||||
int keycode;
|
||||
QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL;
|
||||
|
||||
if (!key_timer) {
|
||||
key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
|
||||
}
|
||||
|
||||
if (keycodes != NULL) {
|
||||
qemu_del_timer(key_timer);
|
||||
release_keys(NULL);
|
||||
}
|
||||
if (!has_hold_time) {
|
||||
hold_time = 100;
|
||||
}
|
||||
|
||||
for (p = keys; p != NULL; p = p->next) {
|
||||
keylist = g_malloc0(sizeof(*keylist));
|
||||
keylist->value = p->value;
|
||||
keylist->next = NULL;
|
||||
|
||||
if (!head) {
|
||||
head = keylist;
|
||||
}
|
||||
if (tmp) {
|
||||
tmp->next = keylist;
|
||||
}
|
||||
tmp = keylist;
|
||||
|
||||
/* key down events */
|
||||
keycode = key_defs[p->value];
|
||||
if (keycode & 0x80) {
|
||||
kbd_put_keycode(0xe0);
|
||||
}
|
||||
kbd_put_keycode(keycode & 0x7f);
|
||||
}
|
||||
keycodes = head;
|
||||
|
||||
/* delayed key up events */
|
||||
qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
|
||||
muldiv64(get_ticks_per_sec(), hold_time, 1000));
|
||||
}
|
||||
|
||||
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
|
||||
{
|
||||
qemu_put_kbd_event_opaque = opaque;
|
||||
|
251
monitor.c
251
monitor.c
@ -1016,12 +1016,6 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_logfile(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
cpu_set_log_filename(qdict_get_str(qdict, "filename"));
|
||||
@ -1290,245 +1284,6 @@ static void do_sum(Monitor *mon, const QDict *qdict)
|
||||
monitor_printf(mon, "%05d\n", sum);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int keycode;
|
||||
const char *name;
|
||||
} KeyDef;
|
||||
|
||||
static const KeyDef key_defs[] = {
|
||||
{ 0x2a, "shift" },
|
||||
{ 0x36, "shift_r" },
|
||||
|
||||
{ 0x38, "alt" },
|
||||
{ 0xb8, "alt_r" },
|
||||
{ 0x64, "altgr" },
|
||||
{ 0xe4, "altgr_r" },
|
||||
{ 0x1d, "ctrl" },
|
||||
{ 0x9d, "ctrl_r" },
|
||||
|
||||
{ 0xdd, "menu" },
|
||||
|
||||
{ 0x01, "esc" },
|
||||
|
||||
{ 0x02, "1" },
|
||||
{ 0x03, "2" },
|
||||
{ 0x04, "3" },
|
||||
{ 0x05, "4" },
|
||||
{ 0x06, "5" },
|
||||
{ 0x07, "6" },
|
||||
{ 0x08, "7" },
|
||||
{ 0x09, "8" },
|
||||
{ 0x0a, "9" },
|
||||
{ 0x0b, "0" },
|
||||
{ 0x0c, "minus" },
|
||||
{ 0x0d, "equal" },
|
||||
{ 0x0e, "backspace" },
|
||||
|
||||
{ 0x0f, "tab" },
|
||||
{ 0x10, "q" },
|
||||
{ 0x11, "w" },
|
||||
{ 0x12, "e" },
|
||||
{ 0x13, "r" },
|
||||
{ 0x14, "t" },
|
||||
{ 0x15, "y" },
|
||||
{ 0x16, "u" },
|
||||
{ 0x17, "i" },
|
||||
{ 0x18, "o" },
|
||||
{ 0x19, "p" },
|
||||
{ 0x1a, "bracket_left" },
|
||||
{ 0x1b, "bracket_right" },
|
||||
{ 0x1c, "ret" },
|
||||
|
||||
{ 0x1e, "a" },
|
||||
{ 0x1f, "s" },
|
||||
{ 0x20, "d" },
|
||||
{ 0x21, "f" },
|
||||
{ 0x22, "g" },
|
||||
{ 0x23, "h" },
|
||||
{ 0x24, "j" },
|
||||
{ 0x25, "k" },
|
||||
{ 0x26, "l" },
|
||||
{ 0x27, "semicolon" },
|
||||
{ 0x28, "apostrophe" },
|
||||
{ 0x29, "grave_accent" },
|
||||
|
||||
{ 0x2b, "backslash" },
|
||||
{ 0x2c, "z" },
|
||||
{ 0x2d, "x" },
|
||||
{ 0x2e, "c" },
|
||||
{ 0x2f, "v" },
|
||||
{ 0x30, "b" },
|
||||
{ 0x31, "n" },
|
||||
{ 0x32, "m" },
|
||||
{ 0x33, "comma" },
|
||||
{ 0x34, "dot" },
|
||||
{ 0x35, "slash" },
|
||||
|
||||
{ 0x37, "asterisk" },
|
||||
|
||||
{ 0x39, "spc" },
|
||||
{ 0x3a, "caps_lock" },
|
||||
{ 0x3b, "f1" },
|
||||
{ 0x3c, "f2" },
|
||||
{ 0x3d, "f3" },
|
||||
{ 0x3e, "f4" },
|
||||
{ 0x3f, "f5" },
|
||||
{ 0x40, "f6" },
|
||||
{ 0x41, "f7" },
|
||||
{ 0x42, "f8" },
|
||||
{ 0x43, "f9" },
|
||||
{ 0x44, "f10" },
|
||||
{ 0x45, "num_lock" },
|
||||
{ 0x46, "scroll_lock" },
|
||||
|
||||
{ 0xb5, "kp_divide" },
|
||||
{ 0x37, "kp_multiply" },
|
||||
{ 0x4a, "kp_subtract" },
|
||||
{ 0x4e, "kp_add" },
|
||||
{ 0x9c, "kp_enter" },
|
||||
{ 0x53, "kp_decimal" },
|
||||
{ 0x54, "sysrq" },
|
||||
|
||||
{ 0x52, "kp_0" },
|
||||
{ 0x4f, "kp_1" },
|
||||
{ 0x50, "kp_2" },
|
||||
{ 0x51, "kp_3" },
|
||||
{ 0x4b, "kp_4" },
|
||||
{ 0x4c, "kp_5" },
|
||||
{ 0x4d, "kp_6" },
|
||||
{ 0x47, "kp_7" },
|
||||
{ 0x48, "kp_8" },
|
||||
{ 0x49, "kp_9" },
|
||||
|
||||
{ 0x56, "<" },
|
||||
|
||||
{ 0x57, "f11" },
|
||||
{ 0x58, "f12" },
|
||||
|
||||
{ 0xb7, "print" },
|
||||
|
||||
{ 0xc7, "home" },
|
||||
{ 0xc9, "pgup" },
|
||||
{ 0xd1, "pgdn" },
|
||||
{ 0xcf, "end" },
|
||||
|
||||
{ 0xcb, "left" },
|
||||
{ 0xc8, "up" },
|
||||
{ 0xd0, "down" },
|
||||
{ 0xcd, "right" },
|
||||
|
||||
{ 0xd2, "insert" },
|
||||
{ 0xd3, "delete" },
|
||||
#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
|
||||
{ 0xf0, "stop" },
|
||||
{ 0xf1, "again" },
|
||||
{ 0xf2, "props" },
|
||||
{ 0xf3, "undo" },
|
||||
{ 0xf4, "front" },
|
||||
{ 0xf5, "copy" },
|
||||
{ 0xf6, "open" },
|
||||
{ 0xf7, "paste" },
|
||||
{ 0xf8, "find" },
|
||||
{ 0xf9, "cut" },
|
||||
{ 0xfa, "lf" },
|
||||
{ 0xfb, "help" },
|
||||
{ 0xfc, "meta_l" },
|
||||
{ 0xfd, "meta_r" },
|
||||
{ 0xfe, "compose" },
|
||||
#endif
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
static int get_keycode(const char *key)
|
||||
{
|
||||
const KeyDef *p;
|
||||
char *endp;
|
||||
int ret;
|
||||
|
||||
for(p = key_defs; p->name != NULL; p++) {
|
||||
if (!strcmp(key, p->name))
|
||||
return p->keycode;
|
||||
}
|
||||
if (strstart(key, "0x", NULL)) {
|
||||
ret = strtoul(key, &endp, 0);
|
||||
if (*endp == '\0' && ret >= 0x01 && ret <= 0xff)
|
||||
return ret;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define MAX_KEYCODES 16
|
||||
static uint8_t keycodes[MAX_KEYCODES];
|
||||
static int nb_pending_keycodes;
|
||||
static QEMUTimer *key_timer;
|
||||
|
||||
static void release_keys(void *opaque)
|
||||
{
|
||||
int keycode;
|
||||
|
||||
while (nb_pending_keycodes > 0) {
|
||||
nb_pending_keycodes--;
|
||||
keycode = keycodes[nb_pending_keycodes];
|
||||
if (keycode & 0x80)
|
||||
kbd_put_keycode(0xe0);
|
||||
kbd_put_keycode(keycode | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_sendkey(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
char keyname_buf[16];
|
||||
char *separator;
|
||||
int keyname_len, keycode, i;
|
||||
const char *string = qdict_get_str(qdict, "string");
|
||||
int has_hold_time = qdict_haskey(qdict, "hold_time");
|
||||
int hold_time = qdict_get_try_int(qdict, "hold_time", -1);
|
||||
|
||||
if (nb_pending_keycodes > 0) {
|
||||
qemu_del_timer(key_timer);
|
||||
release_keys(NULL);
|
||||
}
|
||||
if (!has_hold_time)
|
||||
hold_time = 100;
|
||||
i = 0;
|
||||
while (1) {
|
||||
separator = strchr(string, '-');
|
||||
keyname_len = separator ? separator - string : strlen(string);
|
||||
if (keyname_len > 0) {
|
||||
pstrcpy(keyname_buf, sizeof(keyname_buf), string);
|
||||
if (keyname_len > sizeof(keyname_buf) - 1) {
|
||||
monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf);
|
||||
return;
|
||||
}
|
||||
if (i == MAX_KEYCODES) {
|
||||
monitor_printf(mon, "too many keys\n");
|
||||
return;
|
||||
}
|
||||
keyname_buf[keyname_len] = 0;
|
||||
keycode = get_keycode(keyname_buf);
|
||||
if (keycode < 0) {
|
||||
monitor_printf(mon, "unknown key: '%s'\n", keyname_buf);
|
||||
return;
|
||||
}
|
||||
keycodes[i++] = keycode;
|
||||
}
|
||||
if (!separator)
|
||||
break;
|
||||
string = separator + 1;
|
||||
}
|
||||
nb_pending_keycodes = i;
|
||||
/* key down events */
|
||||
for (i = 0; i < nb_pending_keycodes; i++) {
|
||||
keycode = keycodes[i];
|
||||
if (keycode & 0x80)
|
||||
kbd_put_keycode(0xe0);
|
||||
kbd_put_keycode(keycode & 0x7f);
|
||||
}
|
||||
/* delayed key up events */
|
||||
qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) +
|
||||
muldiv64(get_ticks_per_sec(), hold_time, 1000));
|
||||
}
|
||||
|
||||
static int mouse_button_state;
|
||||
|
||||
static void do_mouse_move(Monitor *mon, const QDict *qdict)
|
||||
@ -4315,7 +4070,6 @@ static void monitor_find_completion(const char *cmdline)
|
||||
int nb_args, i, len;
|
||||
const char *ptype, *str;
|
||||
const mon_cmd_t *cmd;
|
||||
const KeyDef *key;
|
||||
|
||||
parse_cmdline(cmdline, &nb_args, args);
|
||||
#ifdef DEBUG_COMPLETION
|
||||
@ -4389,8 +4143,8 @@ static void monitor_find_completion(const char *cmdline)
|
||||
if (sep)
|
||||
str = sep + 1;
|
||||
readline_set_completion_index(cur_mon->rs, strlen(str));
|
||||
for(key = key_defs; key->name != NULL; key++) {
|
||||
cmd_completion(str, key->name);
|
||||
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
|
||||
cmd_completion(str, QKeyCode_lookup[i]);
|
||||
}
|
||||
} else if (!strcmp(cmd->name, "help|?")) {
|
||||
readline_set_completion_index(cur_mon->rs, strlen(str));
|
||||
@ -4926,7 +4680,6 @@ void monitor_init(CharDriverState *chr, int flags)
|
||||
Monitor *mon;
|
||||
|
||||
if (is_first_init) {
|
||||
key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
|
||||
monitor_protocol_event_init();
|
||||
is_first_init = 0;
|
||||
}
|
||||
|
@ -2493,3 +2493,62 @@
|
||||
# Since: 1.2.0
|
||||
##
|
||||
{ 'command': 'query-target', 'returns': 'TargetInfo' }
|
||||
|
||||
##
|
||||
# @QKeyCode:
|
||||
#
|
||||
# An enumeration of key name.
|
||||
#
|
||||
# This is used by the send-key command.
|
||||
#
|
||||
# Since: 1.3.0
|
||||
##
|
||||
{ 'enum': 'QKeyCode',
|
||||
'data': [ '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',
|
||||
'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon',
|
||||
'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b',
|
||||
'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock',
|
||||
'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10',
|
||||
'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply',
|
||||
'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0',
|
||||
'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8',
|
||||
'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' ] }
|
||||
|
||||
##
|
||||
# @send-key:
|
||||
#
|
||||
# Send keys to guest.
|
||||
#
|
||||
# @keys: key sequence. 'keys' is the name of the key. Use a JSON array to
|
||||
# press several keys simultaneously.
|
||||
#
|
||||
# @hold-time: #optional time to delay key up events, milliseconds. Defaults
|
||||
# to 100
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
# If key is unknown or redundant, InvalidParameter
|
||||
#
|
||||
# Since: 1.3.0
|
||||
#
|
||||
##
|
||||
{ 'command': 'send-key',
|
||||
'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } }
|
||||
|
||||
##
|
||||
# @screendump:
|
||||
#
|
||||
# Write a PPM of the VGA screen to a file.
|
||||
#
|
||||
# @filename: the path of a new PPM file to store the image
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'screendump', 'data': {'filename': 'str'} }
|
||||
|
@ -146,10 +146,7 @@ EQMP
|
||||
{
|
||||
.name = "screendump",
|
||||
.args_type = "filename:F",
|
||||
.params = "filename",
|
||||
.help = "save screen into PPM image 'filename'",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_screen_dump,
|
||||
.mhandler.cmd_new = qmp_marshal_input_screendump,
|
||||
},
|
||||
|
||||
SQMP
|
||||
@ -332,6 +329,34 @@ Example:
|
||||
-> { "execute": "device_del", "arguments": { "id": "net1" } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "send-key",
|
||||
.args_type = "keys:O,hold-time:i?",
|
||||
.mhandler.cmd_new = qmp_marshal_input_send_key,
|
||||
},
|
||||
|
||||
SQMP
|
||||
send-key
|
||||
----------
|
||||
|
||||
Send keys to VM.
|
||||
|
||||
Arguments:
|
||||
|
||||
keys array:
|
||||
- "key": key sequence (a json-array of key enum values)
|
||||
|
||||
- hold-time: time to delay key up events, milliseconds. Defaults to 100
|
||||
(json-int, optional)
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "send-key",
|
||||
"arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ typedef struct QObject {
|
||||
|
||||
/* High-level interface for qobject_decref() */
|
||||
#define QDECREF(obj) \
|
||||
qobject_decref(QOBJECT(obj))
|
||||
qobject_decref(obj ? QOBJECT(obj) : NULL)
|
||||
|
||||
/* Initialize an object to default values */
|
||||
#define QOBJECT_INIT(obj, qtype_type) \
|
||||
|
@ -28,6 +28,16 @@ typedef struct %(name)sList
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_fwd_enum_struct(name, members):
|
||||
return mcgen('''
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
%(name)s value;
|
||||
struct %(name)sList *next;
|
||||
} %(name)sList;
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_struct(structname, fieldname, members):
|
||||
ret = mcgen('''
|
||||
struct %(name)s
|
||||
@ -276,7 +286,8 @@ for expr in exprs:
|
||||
if expr.has_key('type'):
|
||||
ret += generate_fwd_struct(expr['type'], expr['data'])
|
||||
elif expr.has_key('enum'):
|
||||
ret += generate_enum(expr['enum'], expr['data'])
|
||||
ret += generate_enum(expr['enum'], expr['data']) + "\n"
|
||||
ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
|
||||
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
|
||||
elif expr.has_key('union'):
|
||||
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
|
||||
@ -300,6 +311,9 @@ for expr in exprs:
|
||||
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
|
||||
ret += generate_type_cleanup_decl(expr['union'])
|
||||
fdef.write(generate_type_cleanup(expr['union']) + "\n")
|
||||
elif expr.has_key('enum'):
|
||||
ret += generate_type_cleanup_decl(expr['enum'] + "List")
|
||||
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
|
||||
else:
|
||||
continue
|
||||
fdecl.write(ret)
|
||||
|
@ -157,7 +157,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
|
||||
if (!error_is_set(errp)) {
|
||||
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
|
||||
if (!err) {
|
||||
if (!obj || *obj) {
|
||||
if (obj && *obj) {
|
||||
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
|
||||
if (!err) {
|
||||
switch ((*obj)->kind) {
|
||||
@ -217,6 +217,16 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name,
|
||||
|
||||
return ret
|
||||
|
||||
def generate_enum_declaration(name, members, genlist=True):
|
||||
ret = ""
|
||||
if genlist:
|
||||
ret += mcgen('''
|
||||
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
return ret
|
||||
|
||||
def generate_decl_enum(name, members, genlist=True):
|
||||
return mcgen('''
|
||||
|
||||
@ -335,10 +345,12 @@ for expr in exprs:
|
||||
ret += generate_declaration(expr['union'], expr['data'])
|
||||
fdecl.write(ret)
|
||||
elif expr.has_key('enum'):
|
||||
ret = generate_visit_enum(expr['enum'], expr['data'])
|
||||
ret = generate_visit_list(expr['enum'], expr['data'])
|
||||
ret += generate_visit_enum(expr['enum'], expr['data'])
|
||||
fdef.write(ret)
|
||||
|
||||
ret = generate_decl_enum(expr['enum'], expr['data'])
|
||||
ret += generate_enum_declaration(expr['enum'], expr['data'])
|
||||
fdecl.write(ret)
|
||||
|
||||
fdecl.write('''
|
||||
|
Loading…
Reference in New Issue
Block a user