support event recorder and replay

This commit is contained in:
lixianjing 2020-05-18 12:32:42 +08:00
parent 926c0c0cd2
commit 6f3a7e3c31
6 changed files with 360 additions and 2 deletions

View File

@ -78,6 +78,7 @@ TOOLS_NAME = ''
COMMON_CCFLAGS=' -DTK_ROOT=\\\"'+TK_ROOT+'\\\" '
#COMMON_CCFLAGS=COMMON_CCFLAGS+' -DENABLE_PERFORMANCE_PROFILE=1 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_EVENT_RECORDER_PLAYER=1 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_ASSET_LOADER -DWITH_FS_RES -DWITH_ASSET_LOADER_ZIP '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DSTBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_VGCANVAS -DWITH_UNICODE_BREAK -DWITH_DESKTOP_STYLE '

View File

@ -25,6 +25,7 @@
#include "awtk.h"
#include "ext_widgets.h"
#include "base/event_recorder_player.h"
static ret_t on_clone_tab(void* ctx, event_t* e);
static ret_t widget_clone_tab(widget_t* widget);
@ -765,6 +766,28 @@ static ret_t on_screen_saver(void* ctx, event_t* e) {
return RET_OK;
}
static ret_t on_key_record_play_events(void* ctx, event_t* e) {
key_event_t* evt = (key_event_t*)e;
#ifdef WITH_EVENT_RECORDER_PLAYER
if (evt->key == TK_KEY_F5) {
event_recorder_player_start_record("event_log.bin");
return RET_STOP;
} else if (evt->key == TK_KEY_F6) {
event_recorder_player_stop_record();
return RET_STOP;
} else if (evt->key == TK_KEY_F7) {
event_recorder_player_start_play("event_log.bin", 0xffff);
return RET_STOP;
} else if (evt->key == TK_KEY_F8) {
event_recorder_player_stop_play();
return RET_STOP;
}
#endif/*WITH_EVENT_RECORDER_PLAYER*/
return RET_OK;
}
static ret_t on_key_back_or_back_to_home(void* ctx, event_t* e) {
key_event_t* evt = (key_event_t*)e;
if (evt->key == TK_KEY_F2) {
@ -821,6 +844,7 @@ ret_t application_init() {
widget_on(wm, EVT_SCREEN_SAVER, on_screen_saver, NULL);
widget_on(wm, EVT_KEY_DOWN, on_key_back_or_back_to_home, wm);
widget_on(wm, EVT_KEY_UP, on_key_record_play_events, wm);
widget_on(wm, EVT_BEFORE_PAINT, wm_on_before_paint, wm);
widget_on(wm, EVT_AFTER_PAINT, wm_on_after_paint, wm);
widget_on(wm, EVT_LOW_MEMORY, wm_on_low_memory, wm);

View File

@ -1,4 +1,7 @@
# 最新动态
* 2020/05/18
* 增加事件录制与重放功能,辅助手动测试和压力测试。
* 2020/05/14
* 修复 clip view 中 type 的问题(感谢尧燊提供补丁)。
* 修复 file browser up 中的问题(感谢瑞安提供补丁)。

View File

@ -0,0 +1,251 @@
/**
* File: event_recorder_player.c
* Author: AWTK Develop Team
* Brief: event_recorder_player
*
* Copyright (c) 2020 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2020-05-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/fs.h"
#include "tkc/types_def.h"
#include "base/main_loop.h"
#include "base/window_manager.h"
#include "base/event_recorder_player.h"
#ifdef WITH_EVENT_RECORDER_PLAYER
typedef union _log_event_t {
key_event_t key_event;
wheel_event_t wheel_event;
pointer_event_t pointer_event;
} log_event_t;
typedef struct _event_recorder_player_t {
fs_file_t* fp;
bool_t playing;
bool_t recording;
uint32_t times;
uint32_t timer_id;
uint64_t last_event_time;
log_event_t pending_event;
} event_recorder_player_t;
static event_recorder_player_t s_event_recorder_player;
static ret_t event_recorder_player_play(event_recorder_player_t* p);
static ret_t dispatch_event_in_timer(const timer_info_t* info) {
event_recorder_player_t* p = (event_recorder_player_t*)(info->ctx);
return event_recorder_player_play(p);
}
static ret_t event_recorder_player_play(event_recorder_player_t* p) {
log_event_t event;
event_t* e = NULL;
int64_t duration = 0;
if (p->fp == NULL) {
return RET_REMOVE;
}
if (p->last_event_time > 0) {
event_queue_req_t req;
memset(&req, 0x00, sizeof(req));
e = (event_t*)&(p->pending_event);
memcpy(&req, e, sizeof(p->pending_event));
main_loop_queue_event(main_loop(), &req);
} else {
log_debug("prepare first event\n");
}
e = (event_t*)&event;
memset(&event, 0x00, sizeof(event));
if (fs_file_read(p->fp, &event, sizeof(event)) == sizeof(event)) {
if (p->last_event_time == 0) {
p->last_event_time = e->time;
}
memcpy(&(p->pending_event), &event, sizeof(event));
duration = e->time - p->last_event_time;
p->last_event_time = e->time;
if (duration < 0) {
duration = 0;
}
timer_modify(p->timer_id, duration);
return RET_REPEAT;
} else {
p->times--;
if (p->times > 0) {
fs_file_seek(p->fp, 0);
p->last_event_time = 0;
log_debug("play event remain times: %d\n", p->times);
return RET_REPEAT;
} else {
p->playing = FALSE;
fs_file_close(p->fp);
p->fp = NULL;
log_debug("play event done\n");
return RET_REMOVE;
}
}
return RET_OK;
}
static ret_t event_recorder_player_record(event_recorder_player_t* p, event_t* e) {
log_event_t event;
memset(&event, 0x00, sizeof(event));
if (p->fp == NULL) {
return RET_REMOVE;
}
switch (e->type) {
case EVT_POINTER_DOWN:
case EVT_POINTER_MOVE:
case EVT_POINTER_UP: {
memcpy(&event, e, sizeof(pointer_event_t));
break;
}
case EVT_KEY_DOWN:
case EVT_KEY_UP: {
memcpy(&event, e, sizeof(key_event_t));
break;
}
case EVT_WHEEL: {
memcpy(&event, e, sizeof(wheel_event_t));
break;
}
default: {
return RET_OK;
}
}
ENSURE(fs_file_write(p->fp, &event, sizeof(log_event_t)) == sizeof(log_event_t));
return RET_OK;
}
static ret_t event_recorder_player_on_input_event(void* ctx, event_t* e) {
event_recorder_player_t* p = (event_recorder_player_t*)ctx;
if (p->recording) {
return event_recorder_player_record(p, e);
}
return RET_REMOVE;
}
ret_t event_recorder_player_start_record(const char* filename) {
event_recorder_player_t* p = &s_event_recorder_player;
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
event_recorder_player_stop();
p->fp = fs_open_file(os_fs(), filename, "wb+");
return_value_if_fail(p->fp != NULL, RET_BAD_PARAMS);
p->recording = TRUE;
widget_on(window_manager(), EVT_POINTER_DOWN, event_recorder_player_on_input_event, p);
widget_on(window_manager(), EVT_POINTER_MOVE, event_recorder_player_on_input_event, p);
widget_on(window_manager(), EVT_POINTER_UP, event_recorder_player_on_input_event, p);
widget_on(window_manager(), EVT_WHEEL, event_recorder_player_on_input_event, p);
widget_on(window_manager(), EVT_KEY_DOWN, event_recorder_player_on_input_event, p);
widget_on(window_manager(), EVT_KEY_UP, event_recorder_player_on_input_event, p);
log_debug("start record events: %s\n", filename);
return RET_OK;
}
ret_t event_recorder_player_start_play(const char* filename, uint32_t times) {
event_recorder_player_t* p = &s_event_recorder_player;
return_value_if_fail(filename != NULL && times > 0, RET_BAD_PARAMS);
event_recorder_player_stop();
p->fp = fs_open_file(os_fs(), filename, "rb");
return_value_if_fail(p->fp != NULL, RET_BAD_PARAMS);
p->times = times;
p->playing = TRUE;
p->timer_id = timer_add(dispatch_event_in_timer, p, 0);
log_debug("start play events: %s\n", filename);
return RET_OK;
}
ret_t event_recorder_player_stop(void) {
event_recorder_player_t* p = &s_event_recorder_player;
if (p->recording || p->playing) {
fs_file_close(p->fp);
p->fp = NULL;
p->playing = FALSE;
p->recording = FALSE;
if (p->timer_id != TK_INVALID_ID) {
timer_remove(p->timer_id);
p->timer_id = TK_INVALID_ID;
}
widget_off_by_ctx(window_manager(), p);
memset(p, 0x00, sizeof(event_recorder_player_t));
}
return RET_OK;
}
ret_t event_recorder_player_stop_play(void) {
event_recorder_player_t* p = &s_event_recorder_player;
return_value_if_fail(p->playing, RET_BAD_PARAMS);
log_debug("event play stop ok\n");
return event_recorder_player_stop();
}
ret_t event_recorder_player_stop_record(void) {
event_recorder_player_t* p = &s_event_recorder_player;
return_value_if_fail(p->recording, RET_BAD_PARAMS);
log_debug("event record stop ok\n");
return event_recorder_player_stop();
}
#else
ret_t event_recorder_player_start_record(const char* filename) {
return RET_NOT_IMPL;
}
ret_t event_recorder_player_start_play(const char* filename, uint32_t times) {
return RET_NOT_IMPL;
}
ret_t event_recorder_player_stop_play(void) {
return RET_NOT_IMPL;
}
ret_t event_recorder_player_stop_record(void) {
return RET_NOT_IMPL;
}
#endif /*WITH_EVENT_RECORDER_PLAYER*/

View File

@ -0,0 +1,79 @@
/**
* File: event_recorder_player.h
* Author: AWTK Develop Team
* Brief: event_recorder_player
*
* Copyright (c) 2020 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2020-05-18 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_EVENT_RECORDER_PLAYER_H
#define TK_EVENT_RECORDER_PLAYER_H
#include "tkc/types_def.h"
BEGIN_C_DECLS
/**
* @class event_recorder_player_t
* @annotation ["fake"]
*
*
*/
/**
* @method event_recorder_player_start_record
*
* @annotation ["static"]
* @param {const char*} filename
*
* @return {ret_t} RET_OK表示成功
*/
ret_t event_recorder_player_start_record(const char* filename);
/**
* @method event_recorder_player_start_play
*
* @annotation ["static"]
* @param {const char*} filename
* @param {uint32_t} times
*
* @return {ret_t} RET_OK表示成功
*/
ret_t event_recorder_player_start_play(const char* filename, uint32_t times);
/**
* @method event_recorder_player_stop_record
*
* @annotation ["static"]
*
* @return {ret_t} RET_OK表示成功
*/
ret_t event_recorder_player_stop_record(void);
/**
* @method event_recorder_player_stop_play
*
* @annotation ["static"]
*
* @return {ret_t} RET_OK表示成功
*/
ret_t event_recorder_player_stop_play(void);
END_C_DECLS
#endif /*TK_EVENT_RECORDER_PLAYER_H*/

View File

@ -99,11 +99,11 @@ typedef struct _event_t {
*/
uint32_t type;
/**
* @property {int32_t} time
* @property {uint64_t} time
* @annotation ["readable", "scriptable"]
*
*/
uint32_t time;
uint64_t time;
/**
* @property {void*} target
* @annotation ["readable", "scriptable"]