#define _GNU_SOURCE 1 #define EFL_EO_API_SUPPORT #define EFL_BETA_API_SUPPORT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tsuite_file_data.h" #include "exactness_private.h" #define MAX_PATH 1024 #define SHOT_KEY_STR "F2" #define SAVE_KEY_STR "F3" <<<<<<< HEAD #include #include "exactness_canvas.eo.h" static const char *_rec_filename = NULL; ======= static Evas *(*_evas_new)(void) = NULL; static const char *_out_filename = NULL; >>>>>>> 0cce6b6... SqR static const char *_test_name = NULL; static int _verbose = 0; static Eina_List *_evas_list = NULL; static int _last_evas_id = 0; static Lists_st *_events_list = NULL; static char *_shot_key = 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 Tsuite_Event_Type _event_pointer_type_get(Efl_Pointer_Action t) { switch(t) { case EFL_POINTER_ACTION_IN: return TSUITE_EVENT_MOUSE_IN; case EFL_POINTER_ACTION_OUT: return TSUITE_EVENT_MOUSE_OUT; case EFL_POINTER_ACTION_DOWN: return TSUITE_EVENT_MULTI_DOWN; case EFL_POINTER_ACTION_UP: return TSUITE_EVENT_MULTI_UP; case EFL_POINTER_ACTION_MOVE: return TSUITE_EVENT_MULTI_MOVE; case EFL_POINTER_ACTION_WHEEL: return TSUITE_EVENT_MOUSE_WHEEL; default: return TSUITE_EVENT_NOT_SUPPORTED; } } static const char * _event_name_get(Tsuite_Event_Type type) { switch(type) { case TSUITE_EVENT_MOUSE_IN: return "Mouse In"; case TSUITE_EVENT_MOUSE_OUT: return "Mouse Out"; case TSUITE_EVENT_MOUSE_DOWN: return "Mouse Down"; case TSUITE_EVENT_MOUSE_UP: return "Mouse Up"; case TSUITE_EVENT_MOUSE_MOVE: return "Mouse Move"; case TSUITE_EVENT_MOUSE_WHEEL: return "Mouse Wheel"; case TSUITE_EVENT_MULTI_DOWN: return "Multi Down"; case TSUITE_EVENT_MULTI_UP: return "Multi Up"; case TSUITE_EVENT_MULTI_MOVE: return "Multi Move"; case TSUITE_EVENT_KEY_DOWN: return "Key Down"; case TSUITE_EVENT_KEY_UP: return "Key Up"; case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE: return "Key Down with Keycode"; case TSUITE_EVENT_KEY_UP_WITH_KEYCODE: return "Key Up with Keycode"; case TSUITE_EVENT_TAKE_SHOT: return "Take shot"; default: return NULL; } } static Eina_Bool _is_hook_duplicate(const Variant_st *v, Tsuite_Event_Type ev_type, const void *info, int len) { if (v->t.type == tsuite_event_mapping_type_str_get(ev_type) && !memcmp(v->data, info, len)) return EINA_TRUE; return EINA_FALSE; } /* Adding variant to list, this list is later written to EET file */ #define ADD_TO_LIST(EVT_TYPE, INFO) \ do { /* This macro will add event to EET data list */ \ if (_events_list) \ { \ const Variant_st *prev_v = eina_list_last_data_get(_events_list->variant_list); \ if (!prev_v || !_is_hook_duplicate(prev_v, EVT_TYPE, &INFO, sizeof(INFO))) \ { \ _printf(1, "Recording %s\n", tsuite_event_mapping_type_str_get(EVT_TYPE)); \ Variant_st *v = malloc(sizeof(Variant_st)); \ v->data = malloc(sizeof(INFO)); \ _variant_type_set(tsuite_event_mapping_type_str_get(EVT_TYPE), \ &v->t, EINA_FALSE); \ memcpy(v->data, &INFO, sizeof(INFO)); \ _events_list->variant_list = eina_list_append(_events_list->variant_list, v); \ } \ } \ } while (0) static int _evas_id_get(Evas *e) { return (intptr_t)efl_key_data_get(e, "__evas_id"); } static void _event_pointer_cb(void *data, const Efl_Event *event) { Eo *eo_e = data; Eo *evp = event->info; if (!evp) return; int timestamp = efl_input_timestamp_get(evp); int n_evas = _evas_id_get(eo_e); Efl_Pointer_Action action = efl_input_pointer_action_get(evp); Tsuite_Event_Type evt = _event_pointer_type_get(action); if (!timestamp) return; _printf(2, "Calling \"%s\" timestamp=<%u>\n", _event_name_get(evt), timestamp); switch (action) { case EFL_POINTER_ACTION_MOVE: { double rad = 0, radx = 0, rady = 0, pres = 0, ang = 0, fx = 0, fy = 0; int tool = efl_input_pointer_tool_get(evp); Eina_Position2D pos = efl_input_pointer_position_get(evp); multi_move t = { tool, pos.x, pos.y, rad, radx, rady, pres, ang, fx, fy, timestamp, n_evas }; if (t.n_evas >= 0) ADD_TO_LIST(evt, t); break; } case EFL_POINTER_ACTION_DOWN: case EFL_POINTER_ACTION_UP: { double rad = 0, radx = 0, rady = 0, pres = 0, ang = 0, fx = 0, fy = 0; int b = efl_input_pointer_button_get(evp); int tool = efl_input_pointer_tool_get(evp); Eina_Position2D pos = efl_input_pointer_position_get(evp); Efl_Pointer_Flags flags = efl_input_pointer_button_flags_get(evp); multi_event t = { tool, b, pos.x, pos.y, rad, radx, rady, pres, ang, fx, fy, flags, timestamp, n_evas }; if (t.n_evas >= 0) ADD_TO_LIST(evt, t); break; } case EFL_POINTER_ACTION_IN: case EFL_POINTER_ACTION_OUT: { mouse_in_mouse_out t = { timestamp, n_evas }; if (t.n_evas >= 0) ADD_TO_LIST(evt, t); break; } case EFL_POINTER_ACTION_WHEEL: { Eina_Bool horiz = efl_input_pointer_wheel_horizontal_get(evp); int z = efl_input_pointer_wheel_delta_get(evp); mouse_wheel t = { horiz, z, timestamp, n_evas }; if (t.n_evas >= 0) ADD_TO_LIST(evt, t); break; } default: break; } } static void _event_key_cb(void *data, const Efl_Event *event) { Efl_Input_Key *evk = event->info; Eo *eo_e = data; if (!evk) return; const char *key = efl_input_key_name_get(evk); int timestamp = efl_input_timestamp_get(evk); unsigned int n_evas = _evas_id_get(eo_e); Tsuite_Event_Type evt = TSUITE_EVENT_KEY_UP_WITH_KEYCODE; if (efl_input_key_pressed_get(evk)) { if (!strcmp(key, _shot_key)) { _printf(2, "Take Screenshot: %s timestamp=<%u>\n", __func__, timestamp); take_screenshot t = { timestamp, n_evas }; if (t.n_evas >= 0) ADD_TO_LIST(TSUITE_EVENT_TAKE_SHOT, t); return; } if (!strcmp(key, SAVE_KEY_STR)) { if (_events_list) write_events(_rec_filename, _events_list); _printf(2, "Save events: %s timestamp=<%u>\n", __func__, timestamp); return; } evt = TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE; } else { if (!strcmp(key, _shot_key) || !strcmp(key, SAVE_KEY_STR)) return; } if (_events_list) { /* Construct duplicate strings, free them when list if freed */ key_down_key_up_with_keycode t; t.timestamp = timestamp; t.keyname = eina_stringshare_add(key); t.key = eina_stringshare_add(efl_input_key_get(evk)); t.string = eina_stringshare_add(efl_input_key_string_get(evk)); t.compose = eina_stringshare_add(efl_input_key_compose_get(evk)); t.keycode = efl_input_key_code_get(evk); t.n_evas = n_evas; if (t.n_evas >= 0) ADD_TO_LIST(evt, t); } } // note: "hold" event comes from above (elm), not below (ecore) EFL_CALLBACKS_ARRAY_DEFINE(_event_pointer_callbacks, { EFL_EVENT_POINTER_MOVE, _event_pointer_cb }, { EFL_EVENT_POINTER_DOWN, _event_pointer_cb }, { EFL_EVENT_POINTER_UP, _event_pointer_cb }, { EFL_EVENT_POINTER_IN, _event_pointer_cb }, { EFL_EVENT_POINTER_OUT, _event_pointer_cb }, { EFL_EVENT_POINTER_WHEEL, _event_pointer_cb }, { EFL_EVENT_FINGER_MOVE, _event_pointer_cb }, { EFL_EVENT_FINGER_DOWN, _event_pointer_cb }, { EFL_EVENT_FINGER_UP, _event_pointer_cb }, { EFL_EVENT_KEY_DOWN, _event_key_cb }, { EFL_EVENT_KEY_UP, _event_key_cb } ) static Evas * _my_evas_new(int w EINA_UNUSED, int h EINA_UNUSED) { Evas *e; if (!_evas_new) return NULL; e = _evas_new(); if (e) { _printf(1, "New Evas\n"); _evas_list = eina_list_append(_evas_list, e); efl_key_data_set(e, "__evas_id", (void *)(intptr_t)_last_evas_id++); efl_event_callback_array_add(e, _event_pointer_callbacks(), e); } return e; } static Eina_Bool _prg_invoke(const char *full_path, int argc, char **argv) { Eina_Value *ret__; int real__; void (*efl_main)(void *data, const Efl_Event *ev); int (*elm_main)(int argc, char **argv); int (*c_main)(int argc, char **argv); Eina_Module *h = eina_module_new(full_path); if (!h || !eina_module_load(h)) { fprintf(stderr, "Failed loading %s.\n", full_path); if (h) eina_module_free(h); return EINA_FALSE; } efl_main = eina_module_symbol_get(h, "efl_main"); elm_main = eina_module_symbol_get(h, "elm_main"); c_main = eina_module_symbol_get(h, "main"); _evas_new = eina_module_symbol_get(h, "evas_new"); if (!_evas_new) { fprintf(stderr, "Failed loading symbol 'evas_new' from %s.\n", full_path); eina_module_free(h); return 1; } if (efl_main) { elm_init(argc, argv); efl_event_callback_add(efl_main_loop_get(), EFL_LOOP_EVENT_ARGUMENTS, efl_main, NULL); ret__ = efl_loop_begin(efl_main_loop_get()); real__ = efl_loop_exit_code_process(ret__); elm_shutdown(); } else if (elm_main) { elm_init(argc, argv); real__ = elm_main(argc, argv); elm_shutdown(); } else if (c_main) { real__ = c_main(argc, argv); } else { fprintf(stderr, "Failed loading symbol 'efl_main', 'elm_main' or 'main' from %s.\n", full_path); eina_module_free(h); real__ = 1; } return real__; } static Eina_Stringshare * _prg_full_path_guess(const char *prg) { char full_path[MAX_PATH]; if (strchr(prg, '/')) return eina_stringshare_add(prg); char *paths = strdup(getenv("PATH")); Eina_Stringshare *ret = NULL; while (paths && *paths && !ret) { char *real_path; char *colon = strchr(paths, ':'); if (colon) *colon = '\0'; sprintf(full_path, "%s/%s", paths, prg); real_path = ecore_file_realpath(full_path); if (*real_path) { ret = eina_stringshare_add(real_path); // check if executable } free(real_path); paths += strlen(paths); if (colon) paths++; } return ret; } static void _print_usage(const char *progn, FILE *outf) { fprintf(outf, "Usage: %s [options] [program]\n", progn); fprintf(outf, "Options:\n" " -t file.rec Name of the filename where to store the test\n" " -v Verbose mode\n" " -h Print this message and exit\n" "\n"); } static Eina_Bool _mkdir(const char *dir) { if (!ecore_file_exists(dir)) { const char *cur = dir + 1; do { char *slash = strchr(cur, '/'); if (slash) *slash = '\0'; if (!ecore_file_exists(dir) && !ecore_file_mkdir(dir)) return EINA_FALSE; if (slash) *slash = '/'; if (slash) cur = slash + 1; else cur = NULL; } while (cur); } return EINA_TRUE; } int main(int argc, char **argv) { int pret = 1; eina_init(); opterr = 0; for (int opt; (opt = getopt(argc, argv, "+vt:h")) != -1;) switch (opt) { case 0: break; case 't': { _rec_filename = eina_stringshare_add(optarg); break; } case 'v': { _verbose++; break; } case 'h': { _print_usage(argv[0], stdout); pret = 0; goto end; } default: { _print_usage(argv[0], stderr); goto end; } } if (!argv[optind]) { fprintf(stderr, "no program specified\nUse -h for more information\n"); goto end; } if (!_rec_filename) { fprintf(stderr, "no test file specified\n"); goto end; } else { char *slash = strrchr(_rec_filename, '/'); if (slash) _test_name = strdup(slash + 1); else _test_name = strdup(_rec_filename); char *dot = strrchr(_test_name, '.'); if (dot) *dot = '\0'; if (slash) { *slash = '\0'; if (!_mkdir(_rec_filename)) { fprintf(stderr, "Can't create %s\n", _rec_filename); goto end; } *slash = '/'; } } efl_object_init(); evas_init(); /* Replace the current command line to hide the Exactness part */ int len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[optind]; memcpy(argv[0], argv[optind], len); memset(argv[0] + len, 0, _POSIX_PATH_MAX - len); for (int i = optind; i < argc; i++) { if (i != optind) { argv[i - optind] = argv[0] + (argv[i] - argv[optind]); } _printf(1, "%s ", argv[i - optind]); } _printf(1, "\n"); if (!_shot_key) _shot_key = getenv("TSUITE_SHOT_KEY"); if (!_shot_key) _shot_key = SHOT_KEY_STR; if (!_events_list) { struct sysinfo s_info; sysinfo(&s_info); _events_list = calloc(1, sizeof(*_events_list)); _events_list->first_timestamp = s_info.uptime * 1000; _printf(2, "Uptime=<%u>\n", _events_list->first_timestamp); } ecore_evas_callback_new_set(_my_evas_new); _prg_invoke(_prg_full_path_guess(argv[0]), argc - optind, argv); write_events(_rec_filename, _events_list); free_events(_events_list, EINA_TRUE); _events_list = NULL; end: eina_shutdown(); return pret; }