From 9c3fe1b118d2018a5235d0425716847f826b34b2 Mon Sep 17 00:00:00 2001 From: Daniel Zaoui Date: Tue, 20 Mar 2018 00:04:44 +0200 Subject: [PATCH] Introduce a remote actions injection mechanism By executing an application under the player (option --external-injection), actions can be remotely forwarded. The communication is done via Eina Debug channel. Therefore, efl_debugd must be run before the application. An injection tool has been implemented to show how to communicate with the application. --- src/bin/Makefile.am | 9 +- src/bin/injector.c | 464 ++++++++++++++++++++++++++++++++++++++++++++ src/bin/player.c | 344 +++++++++++++++++++++++++++----- 3 files changed, 767 insertions(+), 50 deletions(-) create mode 100644 src/bin/injector.c diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index e4ea0ea..a8050ad 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -1,6 +1,6 @@ MAINTAINERCLEANFILES = Makefile.in -bin_PROGRAMS = exactness exactness_inspect exactness_play exactness_record +bin_PROGRAMS = exactness exactness_inspect exactness_play exactness_record exactness_inject exactness_SOURCES = exactness.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c @@ -10,6 +10,8 @@ exactness_play_SOURCES = player.c ../lib/tsuite_file_data.c ../lib/tsuite_common exactness_record_SOURCES = recorder.c ../lib/tsuite_file_data.c ../lib/tsuite_common.c ../lib/file.c +exactness_inject_SOURCES = injector.c ../lib/tsuite_file_data.c ../lib/file.c + exactness_LDADD = @EFL_LIBS@ exactness_inspect_LDADD = @EFL_LIBS@ @@ -18,6 +20,8 @@ exactness_play_LDADD = @EFL_LIBS@ exactness_record_LDADD = @EFL_LIBS@ +exactness_inject_LDADD = @EFL_LIBS@ + exactness_CFLAGS = \ @EFL_CFLAGS@ \ -I$(top_srcdir)/src/lib \ @@ -29,3 +33,6 @@ exactness_inspect_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib exactness_play_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib exactness_record_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib + +exactness_inject_CFLAGS = @EFL_CFLAGS@ -I$(top_srcdir)/src/lib + diff --git a/src/bin/injector.c b/src/bin/injector.c new file mode 100644 index 0000000..b524119 --- /dev/null +++ b/src/bin/injector.c @@ -0,0 +1,464 @@ +#define _GNU_SOURCE 1 +#include +#include +#include +#include + +#include "config.h" +#ifndef EFL_EO_API_SUPPORT +#define EFL_EO_API_SUPPORT +#endif +#include +#include +#include +#include +#include +#include + +#include "exactness_private.h" + +typedef struct +{ + Eina_Debug_Session *session; + int srcid; + void *buffer; + unsigned int size; +} _Main_Loop_Info; + +#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \ +static void \ +_intern_main_loop ## foo(void *data) \ +{ \ + _Main_Loop_Info *info = data; \ + _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \ + free(info->buffer); \ + free(info); \ +} \ +static Eina_Bool \ +foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \ +{ \ + _Main_Loop_Info *info = calloc(1, sizeof(*info)); \ + info->session = session; \ + info->srcid = srcid; \ + info->size = size; \ + if (info->size) \ + { \ + info->buffer = malloc(info->size); \ + memcpy(info->buffer, buffer, info->size); \ + } \ + ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \ + return EINA_TRUE; \ +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SWAP_64(x) x +#define SWAP_32(x) x +#define SWAP_16(x) x +#define SWAP_DBL(x) x +#else +#define SWAP_64(x) eina_swap64(x) +#define SWAP_32(x) eina_swap32(x) +#define SWAP_16(x) eina_swap16(x) +#define SWAP_DBL(x) SWAP_64(x) +#endif + +#define EXTRACT_INT(_buf) \ +({ \ + int __i; \ + memcpy(&__i, _buf, sizeof(int)); \ + _buf += sizeof(int); \ + SWAP_32(__i); \ +}) + +#define STORE_INT(_buf, __i) \ +{ \ + int __i2 = SWAP_32(__i); \ + memcpy(_buf, &__i2, sizeof(int)); \ + _buf += sizeof(int); \ +} + +#define STORE_DOUBLE(_buf, __d) \ +{ \ + double __d2 = SWAP_DBL(__d); \ + memcpy(_buf, &__d2, sizeof(double)); \ + _buf += sizeof(double); \ +} + +#define STORE_STRING(_buf, __s) \ +{ \ + int __len = (__s ? strlen(__s) : 0) + 1; \ + if (__s) memcpy(_buf, __s, __len); \ + else *_buf = '\0'; \ + _buf += __len; \ +} + +static Eina_Stringshare *_src_filename = NULL; +static Exactness_Unit *_src_unit = NULL; +static int _verbose = 0; + +static Eina_Debug_Session *_session = NULL; +static int _cid = -1, _pid = -1; +static Eina_List *_cur_event_list = NULL; +static unsigned int _last_event_time = 0; + +static int _all_apps_get_op = EINA_DEBUG_OPCODE_INVALID; +static int _mouse_in_op = EINA_DEBUG_OPCODE_INVALID; +static int _mouse_out_op = EINA_DEBUG_OPCODE_INVALID; +static int _mouse_wheel_op = EINA_DEBUG_OPCODE_INVALID; +static int _multi_down_op = EINA_DEBUG_OPCODE_INVALID; +static int _multi_up_op = EINA_DEBUG_OPCODE_INVALID; +static int _multi_move_op = EINA_DEBUG_OPCODE_INVALID; +static int _key_down_op = EINA_DEBUG_OPCODE_INVALID; +static int _key_up_op = EINA_DEBUG_OPCODE_INVALID; +static int _take_shot_op = EINA_DEBUG_OPCODE_INVALID; +static int _finish_op = EINA_DEBUG_OPCODE_INVALID; + +static Eina_Bool _all_apps_get_cb(Eina_Debug_Session *, int , void *, int); + +EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops, + {"Daemon/Client/register_observer", &_all_apps_get_op, NULL}, + {"Daemon/Client/added", NULL, &_all_apps_get_cb}, + {"Exactness/Actions/Mouse In", &_mouse_in_op, NULL}, + {"Exactness/Actions/Mouse Out", &_mouse_out_op, NULL}, + {"Exactness/Actions/Mouse Wheel", &_mouse_wheel_op, NULL}, + {"Exactness/Actions/Multi Down", &_multi_down_op, NULL}, + {"Exactness/Actions/Multi Up", &_multi_up_op, NULL}, + {"Exactness/Actions/Multi Move", &_multi_move_op, NULL}, + {"Exactness/Actions/Key Down", &_key_down_op, NULL}, + {"Exactness/Actions/Key Up", &_key_up_op, NULL}, + {"Exactness/Actions/Take Shot", &_take_shot_op, NULL}, + {"Exactness/Actions/Finish", &_finish_op, NULL}, + {NULL, NULL, NULL} + ); + +static void +_printf(int verbose, const char *fmt, ...) +{ + va_list ap; + if (!_verbose || verbose > _verbose) return; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +static void +_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data) +{ + switch (type) + { + case EXACTNESS_ACTION_MOUSE_IN: + { + _printf(1, "Mouse in\n"); + _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas); + eina_debug_session_send(_session, _cid, _mouse_in_op, &n_evas, sizeof(int)); + break; + } + case EXACTNESS_ACTION_MOUSE_OUT: + { + _printf(1, "Mouse out\n"); + _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas); + eina_debug_session_send(_session, _cid, _mouse_out_op, &n_evas, sizeof(int)); + break; + } + case EXACTNESS_ACTION_MOUSE_WHEEL: + { + Exactness_Action_Mouse_Wheel *t = data; + int len = 3*sizeof(int); + char *buf = malloc(len), *tmp = buf; + _printf(1, "Mouse wheel\n"); + _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas); + STORE_INT(tmp, n_evas); + STORE_INT(tmp, t->direction); + STORE_INT(tmp, t->z); + eina_debug_session_send(_session, _cid, _mouse_wheel_op, buf, len); + break; + } + case EXACTNESS_ACTION_MULTI_DOWN: + case EXACTNESS_ACTION_MULTI_UP: + { + Exactness_Action_Multi_Event *t = data; + int len = 5*sizeof(int)+7*sizeof(double)+sizeof(int); + char *buf = malloc(len), *tmp = buf; + _printf(2, "%s %s n_evas=<%d>\n", __func__, + type == EXACTNESS_ACTION_MULTI_DOWN ? "evas_event_feed_multi_down" : + "evas_event_feed_multi_up", n_evas); + STORE_INT(tmp, n_evas); + STORE_INT(tmp, t->d); + STORE_INT(tmp, t->b); + STORE_INT(tmp, t->x); + STORE_INT(tmp, t->y); + STORE_DOUBLE(tmp, t->rad); + STORE_DOUBLE(tmp, t->radx); + STORE_DOUBLE(tmp, t->rady); + STORE_DOUBLE(tmp, t->pres); + STORE_DOUBLE(tmp, t->ang); + STORE_DOUBLE(tmp, t->fx); + STORE_DOUBLE(tmp, t->fy); + STORE_INT(tmp, t->flags); + eina_debug_session_send(_session, _cid, + type == EXACTNESS_ACTION_MULTI_DOWN ? _multi_down_op : _multi_up_op, + buf, len); + break; + } + case EXACTNESS_ACTION_MULTI_MOVE: + { + Exactness_Action_Multi_Move *t = data; + int len = 4*sizeof(int)+7*sizeof(double); + char *buf = malloc(len), *tmp = buf; + _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas); + STORE_INT(tmp, n_evas); + STORE_INT(tmp, t->d); + STORE_INT(tmp, t->x); + STORE_INT(tmp, t->y); + STORE_DOUBLE(tmp, t->rad); + STORE_DOUBLE(tmp, t->radx); + STORE_DOUBLE(tmp, t->rady); + STORE_DOUBLE(tmp, t->pres); + STORE_DOUBLE(tmp, t->ang); + STORE_DOUBLE(tmp, t->fx); + STORE_DOUBLE(tmp, t->fy); + eina_debug_session_send(_session, _cid, _multi_move_op, buf, len); + break; + } + case EXACTNESS_ACTION_KEY_DOWN: + case EXACTNESS_ACTION_KEY_UP: + { + Exactness_Action_Key_Down_Up *t = data; + int len = 2*sizeof(int) + 4; + len += t->keyname ? strlen(t->keyname) : 0; + len += t->key ? strlen(t->key) : 0; + len += t->string ? strlen(t->string) : 0; + len += t->compose ? strlen(t->compose) : 0; + char *buf = malloc(len), *tmp = buf; + _printf(2, "%s %s n_evas=<%d>\n", __func__, + type == EXACTNESS_ACTION_KEY_DOWN ? "evas_event_feed_key_down " : + "evas_event_feed_key_up", n_evas); + STORE_INT(tmp, n_evas); + STORE_STRING(tmp, t->keyname); + STORE_STRING(tmp, t->key); + STORE_STRING(tmp, t->string); + STORE_STRING(tmp, t->compose); + STORE_INT(tmp, t->keycode); + eina_debug_session_send(_session, _cid, + type == EXACTNESS_ACTION_KEY_DOWN ? _key_down_op : _key_up_op, + buf, len); + break; + } + case EXACTNESS_ACTION_TAKE_SHOT: + { + _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas); + eina_debug_session_send(_session, _cid, _take_shot_op, &n_evas, sizeof(int)); + break; + } + default: /* All non-input events are not handeled */ + break; + } +} + +static Eina_Bool +_feed_event_timer_cb(void *data EINA_UNUSED) +{ + Exactness_Action *act = eina_list_data_get(_cur_event_list); + _feed_event(act->type, act->n_evas, act->data); + time_t evt_time = act->timestamp; + + _cur_event_list = eina_list_next(_cur_event_list); + + if (!_cur_event_list) + { /* Finished reading all events */ + eina_debug_session_send(_session, _cid, _finish_op, NULL, 0); + ecore_main_loop_quit(); + } + else + { + double timer_time; + Exactness_Action *cur_act = eina_list_data_get(_cur_event_list); + unsigned int current_event_time = cur_act->timestamp; + _last_event_time = evt_time; + + if (current_event_time < _last_event_time) /* Could happen with refeed event */ + current_event_time = _last_event_time; + + _printf(2, " %s _last_event_time=<%u> current_event_time=<%u>\n", __func__, _last_event_time, current_event_time); + timer_time = (current_event_time - _last_event_time) / 1000.0; + + if (!_last_event_time) timer_time = 0.0; + + _printf(2, " %s timer_time=<%f>\n", __func__, timer_time); + ecore_timer_add(timer_time, _feed_event_timer_cb, NULL); + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_src_open() +{ + double diff_time = 0; /* Time to wait before feeding the first event */ + + _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename); + if (!strcmp(_src_filename + strlen(_src_filename) - 4,".exu")) + { + _src_unit = exactness_unit_file_read(_src_filename); + } + else if (!strcmp(_src_filename + strlen(_src_filename) - 4,".rec")) + { + _src_unit = legacy_rec_file_read(_src_filename); + } + if (!_src_unit) return EINA_FALSE; + _cur_event_list = _src_unit->actions; + Exactness_Action *act = eina_list_data_get(_cur_event_list); + + /* Calculate the time to wait before feeding the first event */ + unsigned int current_event_time = act->timestamp; + + _printf(2, "%s current_event_time=<%u>\n", __func__, current_event_time); + + if (current_event_time) + { + _printf(2, " Waiting <%f>\n", diff_time); + ecore_timer_add(current_event_time / 1000.0, _feed_event_timer_cb, NULL); + } + else + { + _feed_event_timer_cb(NULL); + } + return EINA_TRUE; +} + +static void +_main_loop_all_apps_get_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + int chosen_cid = -1; + if (_cid != -1) return; + while (size > 0) + { + int cid, pid, len; + cid = EXTRACT_INT(buf); + pid = EXTRACT_INT(buf); + if (_pid != -1) + { + if (_pid == pid) + { + _cid = cid; + _src_open(); + return; + } + } + else + { + if (!strcmp(buf, "exactness_play")) + { + if (chosen_cid != -1) + { + fprintf(stderr, "Need to specify a PID - too much choice\n"); + return; + } + chosen_cid = cid; + } + } + len = strlen(buf) + 1; + buf += len; + size -= (2 * sizeof(int) + len); + } + if (chosen_cid != -1) + { + _cid = chosen_cid; + _src_open(); + } +} + +WRAPPER_TO_XFER_MAIN_LOOP(_all_apps_get_cb) + +static void +_ops_ready_cb(void *data EINA_UNUSED, Eina_Bool status) +{ + static Eina_Bool on = EINA_FALSE; + if (status) + { + if (!on) + { + eina_debug_session_send(_session, 0, _all_apps_get_op, NULL, 0); + } + on = EINA_TRUE; + } +} + +static const Ecore_Getopt optdesc = { + "exactness_inject", + "%prog [options] <-v|-p|-t|-h> command", + PACKAGE_VERSION, + "(C) 2018 Enlightenment", + "BSD", + "A scenario events injector for EFL based applications.", + 1, + { + ECORE_GETOPT_STORE_STR('t', "test", "Test to run on the given application"), + ECORE_GETOPT_STORE_INT('p', "pid", "PID of the application to connect to"), + ECORE_GETOPT_STORE_INT('r', "remote-port", "Port to connect remotely to the daemon. Local connection if not specified"), + ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."), + + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +int main(int argc, char **argv) +{ + int opt_args = 0, real__, port = -1; + char *src = NULL; + Eina_Value *ret__; + Eina_Bool want_quit = EINA_FALSE; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_STR(src), + ECORE_GETOPT_VALUE_INT(_pid), + ECORE_GETOPT_VALUE_INT(port), + ECORE_GETOPT_VALUE_INT(_verbose), + + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_BOOL(want_quit), + ECORE_GETOPT_VALUE_NONE + }; + + eina_init(); + eet_init(); + ecore_init(); + + opt_args = ecore_getopt_parse(&optdesc, values, argc, argv); + if (opt_args < 0) + { + fprintf(stderr, "Failed parsing arguments.\n"); + goto end; + } + if (want_quit) goto end; + + if (!src) + { + fprintf(stderr, "no test file specified\n"); + goto end; + } + _src_filename = eina_stringshare_add(src); + + if (port == -1) + _session = eina_debug_local_connect(EINA_TRUE); + else + _session = eina_debug_remote_connect(port); + eina_debug_opcodes_register(_session, _debug_ops(), _ops_ready_cb, NULL); + + elm_init(argc, argv); + ret__ = efl_loop_begin(efl_main_loop_get()); + real__ = efl_loop_exit_code_process(ret__); + elm_shutdown(); +end: + eet_shutdown(); + eina_shutdown(); + return real__; +} + diff --git a/src/bin/player.c b/src/bin/player.c index 95bdaab..31dca53 100644 --- a/src/bin/player.c +++ b/src/bin/player.c @@ -27,12 +27,82 @@ #define MAX_PATH 1024 #define IMAGE_FILENAME_EXT ".png" +typedef struct +{ + Eina_Debug_Session *session; + int srcid; + void *buffer; + unsigned int size; +} _Main_Loop_Info; + +#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \ +static void \ +_intern_main_loop ## foo(void *data) \ +{ \ + _Main_Loop_Info *info = data; \ + _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \ + free(info->buffer); \ + free(info); \ +} \ +static Eina_Bool \ +foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \ +{ \ + _Main_Loop_Info *info = calloc(1, sizeof(*info)); \ + info->session = session; \ + info->srcid = srcid; \ + info->size = size; \ + if (info->size) \ + { \ + info->buffer = malloc(info->size); \ + memcpy(info->buffer, buffer, info->size); \ + } \ + ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \ + return EINA_TRUE; \ +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define SWAP_64(x) x +#define SWAP_32(x) x +#define SWAP_16(x) x +#define SWAP_DBL(x) x +#else +#define SWAP_64(x) eina_swap64(x) +#define SWAP_32(x) eina_swap32(x) +#define SWAP_16(x) eina_swap16(x) +#define SWAP_DBL(x) SWAP_64(x) +#endif + +#define EXTRACT_INT(_buf) \ +({ \ + int __i; \ + memcpy(&__i, _buf, sizeof(int)); \ + _buf += sizeof(int); \ + SWAP_32(__i); \ +}) + +#define EXTRACT_DOUBLE(_buf) \ +({ \ + double __d; \ + memcpy(&__d, _buf, sizeof(double)); \ + _buf += sizeof(double); \ + SWAP_DBL(__d); \ +}) + +#define EXTRACT_STRING(_buf) \ +({ \ + char *__s = _buf ? strdup(_buf) : NULL; \ + int __len = (__s ? strlen(__s) : 0) + 1; \ + _buf += __len; \ + __s; \ +}) + typedef enum { FTYPE_UNKNOWN, FTYPE_DIR, FTYPE_REC = FTYPE_DIR, - FTYPE_EXU + FTYPE_EXU, + FTYPE_REMOTE } File_Type; static File_Type _dest_type = FTYPE_UNKNOWN; @@ -170,17 +240,15 @@ _shot_do(Evas *e) } } -static Eina_Bool -_feed_event(void *data EINA_UNUSED) +static void +_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data) { static Evas_Object *rect = NULL; static unsigned int rect_evas; - Exactness_Action *act = eina_list_data_get(_cur_event_list); - Eo *e = eina_list_nth(_evas_list, act->n_evas); - time_t evt_time = act->timestamp; + Eo *e = eina_list_nth(_evas_list, n_evas); - if (rect && rect_evas != act->n_evas) + if (rect && rect_evas != n_evas) { efl_del(rect); rect = NULL; @@ -193,38 +261,38 @@ _feed_event(void *data EINA_UNUSED) evas_object_resize(rect, 15, 15); evas_object_layer_set(rect, 100); evas_object_show(rect); - rect_evas = act->n_evas; + rect_evas = n_evas; } - switch (act->type) + switch (type) { case EXACTNESS_ACTION_MOUSE_IN: { _printf(1, "Mouse in\n"); - _printf(2, "%s evas_event_feed_mouse_in timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas); if (e) evas_event_feed_mouse_in(e, time(NULL), NULL); break; } case EXACTNESS_ACTION_MOUSE_OUT: { _printf(1, "Mouse out\n"); - _printf(2, "%s evas_event_feed_mouse_out timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp,act->n_evas); + _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas); if (e) evas_event_feed_mouse_out(e, time(NULL), NULL); break; } case EXACTNESS_ACTION_MOUSE_WHEEL: { - Exactness_Action_Mouse_Wheel *t = act->data; + Exactness_Action_Mouse_Wheel *t = data; _printf(1, "Mouse wheel\n"); - _printf(2, "%s evas_event_feed_mouse_wheel timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas); if (e) evas_event_feed_mouse_wheel(e, t->direction, t->z, time(NULL), NULL); break; } case EXACTNESS_ACTION_MULTI_DOWN: { - Exactness_Action_Multi_Event *t = act->data; - _printf(2, "%s evas_event_feed_multi_down timestamp=<%u>, n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + Exactness_Action_Multi_Event *t = data; + _printf(2, "%s evas_event_feed_multi_down n_evas=<%d>\n", __func__, n_evas); if (!t->d) { if (e) evas_event_feed_mouse_down(e, t->b, t->flags, time(NULL), NULL); @@ -242,8 +310,8 @@ _feed_event(void *data EINA_UNUSED) } case EXACTNESS_ACTION_MULTI_UP: { - Exactness_Action_Multi_Event *t = act->data; - _printf(2, "%s evas_event_feed_multi_up timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp,act->n_evas); + Exactness_Action_Multi_Event *t = data; + _printf(2, "%s evas_event_feed_multi_up n_evas=<%d>\n", __func__, n_evas); if (!t->d) { if (e) evas_event_feed_mouse_up(e, t->b, t->flags, time(NULL), NULL); @@ -261,8 +329,8 @@ _feed_event(void *data EINA_UNUSED) } case EXACTNESS_ACTION_MULTI_MOVE: { - Exactness_Action_Multi_Move *t = act->data; - _printf(2, "%s evas_event_feed_multi_move timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + Exactness_Action_Multi_Move *t = data; + _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas); if (!t->d) { if (e) evas_event_feed_mouse_move(e, t->x, t->y, time(NULL), NULL); @@ -284,8 +352,8 @@ _feed_event(void *data EINA_UNUSED) } case EXACTNESS_ACTION_KEY_DOWN: { - Exactness_Action_Key_Down_Up *t = act->data; - _printf(2, "%s evas_event_feed_key_down timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + Exactness_Action_Key_Down_Up *t = data; + _printf(2, "%s evas_event_feed_key_down n_evas=<%d>\n", __func__, n_evas); if (e) evas_event_feed_key_down_with_keycode(e, t->keyname, t->key, t->string, @@ -294,8 +362,8 @@ _feed_event(void *data EINA_UNUSED) } case EXACTNESS_ACTION_KEY_UP: { - Exactness_Action_Key_Down_Up *t = act->data; - _printf(2, "%s evas_event_feed_key_up timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + Exactness_Action_Key_Down_Up *t = data; + _printf(2, "%s evas_event_feed_key_up n_evas=<%d>\n", __func__, n_evas); if (e) evas_event_feed_key_up_with_keycode(e, t->keyname, t->key, t->string, t->compose, time(NULL), NULL, t->keycode); @@ -304,7 +372,7 @@ _feed_event(void *data EINA_UNUSED) } case EXACTNESS_ACTION_TAKE_SHOT: { - _printf(2, "%s take shot timestamp=<%u> n_evas=<%d>\n", __func__, act->timestamp, act->n_evas); + _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas); if (rect) evas_object_color_set(rect, 0, 0, 255, 255); _cur_shot_id++; if (_dest_type != FTYPE_UNKNOWN && e) _shot_do(e); @@ -313,6 +381,14 @@ _feed_event(void *data EINA_UNUSED) default: /* All non-input events are not handeled */ break; } +} + +static Eina_Bool +_feed_event_timer_cb(void *data EINA_UNUSED) +{ + Exactness_Action *act = eina_list_data_get(_cur_event_list); + _feed_event(act->type, act->n_evas, act->data); + time_t evt_time = act->timestamp; _cur_event_list = eina_list_next(_cur_event_list); @@ -336,41 +412,203 @@ _feed_event(void *data EINA_UNUSED) if (!_last_event_time) timer_time = 0.0; _printf(2, " %s timer_time=<%f>\n", __func__, timer_time); - ecore_timer_add(timer_time, _feed_event, NULL); + ecore_timer_add(timer_time, _feed_event_timer_cb, NULL); } return ECORE_CALLBACK_CANCEL; } +static void +_main_loop_mouse_in_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + int n_evas = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_MOUSE_IN, n_evas, NULL); +} + +static void +_main_loop_mouse_out_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + int n_evas = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_MOUSE_OUT, n_evas, NULL); +} + +static void +_main_loop_mouse_wheel_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Mouse_Wheel t; + int n_evas = EXTRACT_INT(buf); + t.direction = EXTRACT_INT(buf); + t.z = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_MOUSE_WHEEL, n_evas, &t); +} + +static void +_main_loop_multi_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Multi_Event t; + int n_evas = EXTRACT_INT(buf); + t.d = EXTRACT_INT(buf); + t.b = EXTRACT_INT(buf); + t.x = EXTRACT_INT(buf); + t.y = EXTRACT_INT(buf); + t.rad = EXTRACT_DOUBLE(buf); + t.radx = EXTRACT_DOUBLE(buf); + t.rady = EXTRACT_DOUBLE(buf); + t.pres = EXTRACT_DOUBLE(buf); + t.ang = EXTRACT_DOUBLE(buf); + t.fx = EXTRACT_DOUBLE(buf); + t.fy = EXTRACT_DOUBLE(buf); + t.flags = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_MULTI_DOWN, n_evas, &t); +} + +static void +_main_loop_multi_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Multi_Event t; + int n_evas = EXTRACT_INT(buf); + t.d = EXTRACT_INT(buf); + t.b = EXTRACT_INT(buf); + t.x = EXTRACT_INT(buf); + t.y = EXTRACT_INT(buf); + t.rad = EXTRACT_DOUBLE(buf); + t.radx = EXTRACT_DOUBLE(buf); + t.rady = EXTRACT_DOUBLE(buf); + t.pres = EXTRACT_DOUBLE(buf); + t.ang = EXTRACT_DOUBLE(buf); + t.fx = EXTRACT_DOUBLE(buf); + t.fy = EXTRACT_DOUBLE(buf); + t.flags = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_MULTI_UP, n_evas, &t); +} + +static void +_main_loop_multi_move_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Multi_Move t; + int n_evas = EXTRACT_INT(buf); + t.d = EXTRACT_INT(buf); + t.x = EXTRACT_INT(buf); + t.y = EXTRACT_INT(buf); + t.rad = EXTRACT_DOUBLE(buf); + t.radx = EXTRACT_DOUBLE(buf); + t.rady = EXTRACT_DOUBLE(buf); + t.pres = EXTRACT_DOUBLE(buf); + t.ang = EXTRACT_DOUBLE(buf); + t.fx = EXTRACT_DOUBLE(buf); + t.fy = EXTRACT_DOUBLE(buf); + _feed_event(EXACTNESS_ACTION_MULTI_MOVE, n_evas, &t); +} + +static void +_main_loop_key_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Key_Down_Up t; + int n_evas = EXTRACT_INT(buf); + t.keyname = EXTRACT_STRING(buf); + t.key = EXTRACT_STRING(buf); + t.string = EXTRACT_STRING(buf); + t.compose = EXTRACT_STRING(buf); + t.keycode = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_KEY_DOWN, n_evas, &t); +} + +static void +_main_loop_key_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + Exactness_Action_Key_Down_Up t; + int n_evas = EXTRACT_INT(buf); + t.keyname = EXTRACT_STRING(buf); + t.key = EXTRACT_STRING(buf); + t.string = EXTRACT_STRING(buf); + t.compose = EXTRACT_STRING(buf); + t.keycode = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_KEY_UP, n_evas, &t); +} + +static void +_main_loop_take_shot_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED) +{ + char *buf = buffer; + int n_evas = EXTRACT_INT(buf); + _feed_event(EXACTNESS_ACTION_TAKE_SHOT, n_evas, NULL); +} + +static void +_main_loop_finish_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +WRAPPER_TO_XFER_MAIN_LOOP(_mouse_in_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_mouse_out_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_mouse_wheel_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_multi_down_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_multi_up_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_multi_move_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_key_down_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_key_up_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_take_shot_cb) +WRAPPER_TO_XFER_MAIN_LOOP(_finish_cb) + +EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops, + {"Exactness/Actions/Mouse In", NULL, &_mouse_in_cb}, + {"Exactness/Actions/Mouse Out", NULL, &_mouse_out_cb}, + {"Exactness/Actions/Mouse Wheel", NULL, &_mouse_wheel_cb}, + {"Exactness/Actions/Multi Down", NULL, &_multi_down_cb}, + {"Exactness/Actions/Multi Up", NULL, &_multi_up_cb}, + {"Exactness/Actions/Multi Move", NULL, &_multi_move_cb}, + {"Exactness/Actions/Key Down", NULL, &_key_down_cb}, + {"Exactness/Actions/Key Up", NULL, &_key_up_cb}, + {"Exactness/Actions/Take Shot", NULL, &_take_shot_cb}, + {"Exactness/Actions/Finish", NULL, &_finish_cb}, + {NULL, NULL, NULL} +); + static Eina_Bool _src_open() { - double diff_time = 0; /* Time to wait before feeding the first event */ - _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename); - if (_src_type == FTYPE_EXU) + if (_src_type != FTYPE_REMOTE) { - _src_unit = exactness_unit_file_read(_src_filename); - } - else if (_src_type == FTYPE_REC) - { - _src_unit = legacy_rec_file_read(_src_filename); - } - if (!_src_unit) return EINA_FALSE; - _cur_event_list = _src_unit->actions; - Exactness_Action *act = eina_list_data_get(_cur_event_list); + double diff_time = 0; /* Time to wait before feeding the first event */ + _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename); + if (_src_type == FTYPE_EXU) + { + _src_unit = exactness_unit_file_read(_src_filename); + } + else if (_src_type == FTYPE_REC) + { + _src_unit = legacy_rec_file_read(_src_filename); + } + if (!_src_unit) return EINA_FALSE; + _cur_event_list = _src_unit->actions; + Exactness_Action *act = eina_list_data_get(_cur_event_list); - /* Calculate the time to wait before feeding the first event */ - unsigned int current_event_time = act->timestamp; + /* Calculate the time to wait before feeding the first event */ + unsigned int current_event_time = act->timestamp; - _printf(2, "%s current_event_time=<%u>\n", __func__, current_event_time); + _printf(2, "%s current_event_time=<%u>\n", __func__, current_event_time); - if (current_event_time) - { - _printf(2, " Waiting <%f>\n", diff_time); - ecore_timer_add(current_event_time / 1000.0, _feed_event, NULL); + if (current_event_time) + { + _printf(2, " Waiting <%f>\n", diff_time); + ecore_timer_add(current_event_time / 1000.0, _feed_event_timer_cb, NULL); + } + else + { + _feed_event_timer_cb(NULL); + } } else { - _feed_event(NULL); + eina_debug_opcodes_register(NULL, _debug_ops(), NULL, NULL); } return EINA_TRUE; } @@ -516,6 +754,7 @@ static const Ecore_Getopt optdesc = { ECORE_GETOPT_STORE_STR('t', "test", "Test to run on the given application"), ECORE_GETOPT_STORE_TRUE('s', "show-on-screen", "Show on screen."), ECORE_GETOPT_STORE_TRUE(0, "scan-objects", "Extract information of all the objects at every shot."), + ECORE_GETOPT_STORE_TRUE(0, "external-injection", "Expect events injection via Eina debug channel."), ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."), ECORE_GETOPT_LICENSE('L', "license"), @@ -531,13 +770,14 @@ int main(int argc, char **argv) int pret = 1, opt_args = 0; char *src = NULL, *dest = NULL, *eq; Eina_Bool show_on_screen = EINA_FALSE; - Eina_Bool want_quit = EINA_FALSE; + Eina_Bool want_quit = EINA_FALSE, external_injection = EINA_FALSE; Ecore_Getopt_Value values[] = { ECORE_GETOPT_VALUE_STR(dest), ECORE_GETOPT_VALUE_STR(src), ECORE_GETOPT_VALUE_BOOL(show_on_screen), ECORE_GETOPT_VALUE_BOOL(_scan_objects), + ECORE_GETOPT_VALUE_BOOL(external_injection), ECORE_GETOPT_VALUE_INT(_verbose), ECORE_GETOPT_VALUE_BOOL(want_quit), @@ -598,12 +838,18 @@ int main(int argc, char **argv) } } } - if (!src) + if (!src && !external_injection) { fprintf(stderr, "no test file specified\n"); goto end; } - else + if (src && external_injection) + { + fprintf(stderr, "Cannot inject events from a source file and from outside simultaneously\n"); + goto end; + } + if (external_injection) _src_type = FTYPE_REMOTE; + if (src) { _src_filename = eina_stringshare_add(src); if (!strcmp(_src_filename + strlen(_src_filename) - 4,".exu")) @@ -669,7 +915,7 @@ int main(int argc, char **argv) if (_dest && _dest_unit) { - _dest_unit->actions = _src_unit->actions; + if (_src_unit) _dest_unit->actions = _src_unit->actions; exactness_unit_file_write(_dest_unit, _dest); }