This records user input (keyboard and mouse events) in record mode and replays
these input events in replay mode.
Signed-off-by: Pavel Dovgalyuk pavel.dovga...@ispras.ru
---
include/ui/input.h |2 +
replay/Makefile.objs |1
replay/replay-events.c | 48
replay/replay-input.c| 108 ++
replay/replay-internal.h | 11 -
replay/replay.h |5 ++
ui/input.c | 80 ++
7 files changed, 235 insertions(+), 20 deletions(-)
create mode 100755 replay/replay-input.c
diff --git a/include/ui/input.h b/include/ui/input.h
index 5d5ac00..d06a12d 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -33,7 +33,9 @@ void qemu_input_handler_bind(QemuInputHandlerState *s,
const char *device_id, int head,
Error **errp);
void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
+void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt);
void qemu_input_event_sync(void);
+void qemu_input_event_sync_impl(void);
InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index 257c320..3936296 100755
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -2,3 +2,4 @@ obj-y += replay.o
obj-y += replay-internal.o
obj-y += replay-events.o
obj-y += replay-time.o
+obj-y += replay-input.o
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 4da5de0..308186b 100755
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -13,6 +13,7 @@
#include replay.h
#include replay-internal.h
#include block/thread-pool.h
+#include ui/input.h
typedef struct Event {
int event_kind;
@@ -43,6 +44,16 @@ static void replay_run_event(Event *event)
case REPLAY_ASYNC_EVENT_THREAD:
thread_pool_work((ThreadPool *)event-opaque, event-opaque2);
break;
+case REPLAY_ASYNC_EVENT_INPUT:
+qemu_input_event_send_impl(NULL, (InputEvent *)event-opaque);
+/* Using local variables, when replaying. Do not free them. */
+if (replay_mode == REPLAY_MODE_RECORD) {
+qapi_free_InputEvent((InputEvent *)event-opaque);
+}
+break;
+case REPLAY_ASYNC_EVENT_INPUT_SYNC:
+qemu_input_event_sync_impl();
+break;
default:
fprintf(stderr, Replay: invalid async event ID (%d) in the queue\n,
event-event_kind);
@@ -136,6 +147,16 @@ void replay_add_thread_event(void *opaque, void *opaque2,
uint64_t id)
replay_add_event_internal(REPLAY_ASYNC_EVENT_THREAD, opaque, opaque2, id);
}
+void replay_add_input_event(struct InputEvent *event)
+{
+replay_add_event_internal(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
+}
+
+void replay_add_input_sync_event(void)
+{
+replay_add_event_internal(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
+}
+
void replay_save_events(int opt)
{
qemu_mutex_lock(lock);
@@ -153,6 +174,9 @@ void replay_save_events(int opt)
case REPLAY_ASYNC_EVENT_THREAD:
replay_put_qword(event-id);
break;
+case REPLAY_ASYNC_EVENT_INPUT:
+replay_save_input_event(event-opaque);
+break;
}
}
@@ -178,6 +202,7 @@ void replay_read_events(int opt)
break;
}
/* Execute some events without searching them in the queue */
+Event e;
switch (read_event_kind) {
case REPLAY_ASYNC_EVENT_BH:
case REPLAY_ASYNC_EVENT_THREAD:
@@ -185,6 +210,29 @@ void replay_read_events(int opt)
read_id = replay_get_qword();
}
break;
+case REPLAY_ASYNC_EVENT_INPUT:
+e.event_kind = read_event_kind;
+e.opaque = replay_read_input_event();
+
+replay_run_event(e);
+
+replay_has_unread_data = 0;
+read_event_kind = -1;
+read_opt = -1;
+replay_fetch_data_kind();
+/* continue with the next event */
+continue;
+case REPLAY_ASYNC_EVENT_INPUT_SYNC:
+e.event_kind = read_event_kind;
+e.opaque = 0;
+replay_run_event(e);
+
+replay_has_unread_data = 0;
+read_event_kind = -1;
+read_opt = -1;
+replay_fetch_data_kind();
+/* continue with the next event */
+continue;
default:
fprintf(stderr, Unknown ID %d of replay event\n,
read_event_kind);
exit(1);
diff --git a/replay/replay-input.c b/replay/replay-input.c
new file mode 100755
index 000..f5d1482
--- /dev/null
+++ b/replay/replay-input.c
@@ -0,0 +1,108 @@
+/*
+ * replay-input.c
+ *
+ * Copyright (c) 2010-2014 Institute for System Programming
+ *