apps/graphics: Refactor monkey using input generator library

Signed-off-by: liuchan3 <liuchan3@xiaomi.com>
This commit is contained in:
liuchan3 2025-03-19 14:49:56 +08:00 committed by Xiang Xiao
parent 7bfd5e5790
commit 36b117c00a
11 changed files with 112 additions and 206 deletions

View file

@ -41,6 +41,8 @@ if(CONFIG_GRAPHICS_INPUT_MONKEY)
${CONFIG_GRAPHICS_INPUT_MONKEY_STACKSIZE}
MODULE
${CONFIG_GRAPHICS_INPUT_MONKEY}
DEPENDS
input_generator
SRCS
${SRCS})
endif()

View file

@ -4,7 +4,7 @@
#
config GRAPHICS_INPUT_GENERATOR
bool "Input generator library"
bool
default n
---help---
This is a simple input generator library that can be used to
@ -14,6 +14,7 @@ menuconfig GRAPHICS_INPUT_MONKEY
tristate "Monkey test"
select UINPUT_TOUCH
select UINPUT_BUTTONS
select GRAPHICS_INPUT_GENERATOR
select LIBC_PRINT_EXTENSION
default n

View file

@ -25,6 +25,7 @@
****************************************************************************/
#include <nuttx/config.h>
#include <graphics/input_gen.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
@ -41,8 +42,6 @@
#define MONKEY_DEV_PATH_TOUCH "/dev/input0"
#define MONKEY_DEV_PATH_BUTTON "/dev/buttons"
#define MONKEY_DEV_PATH_UTOUCH "/dev/utouch"
#define MONKEY_DEV_PATH_UBUTTON "/dev/ubutton"
#define MONKEY_DEV_CREATE_MATCH(monkey, type_mask, type) \
do { \
@ -60,6 +59,23 @@ do { \
} \
} while (0)
#define MONKEY_DEV_CREATE_UINPUT(monkey, _type) \
do { \
if (input_gen_query_device(monkey->input_gen_ctx, INPUT_GEN_DEV_##_type)) \
{ \
FAR struct monkey_dev_s *dev = calloc(1, sizeof(struct monkey_dev_s)); \
if (!dev) \
{ \
MONKEY_LOG_ERROR("Failed to create virtual device"); \
goto failed; \
} \
dev->type = MONKEY_DEV_TYPE_##_type; \
dev->is_available = true; \
(monkey)->devs[(monkey)->dev_num] = dev; \
(monkey)->dev_num++; \
} \
} while (0)
/****************************************************************************
* Public Functions
****************************************************************************/
@ -75,8 +91,15 @@ FAR struct monkey_s *monkey_create(int dev_type_mask)
if (MONKEY_IS_UINPUT_TYPE(dev_type_mask))
{
MONKEY_DEV_CREATE_MATCH(monkey, dev_type_mask, UTOUCH);
MONKEY_DEV_CREATE_MATCH(monkey, dev_type_mask, UBUTTON);
if (input_gen_create(&monkey->input_gen_ctx,
MONKEY_GET_DEV_TYPE(dev_type_mask)) < 0)
{
MONKEY_LOG_ERROR("input generator create failed");
goto failed;
}
MONKEY_DEV_CREATE_UINPUT(monkey, UTOUCH);
MONKEY_DEV_CREATE_UINPUT(monkey, UBUTTON);
}
else
{
@ -110,6 +133,12 @@ void monkey_delete(FAR struct monkey_s *monkey)
int i;
MONKEY_ASSERT_NULL(monkey);
if (monkey->input_gen_ctx)
{
input_gen_reset_devices(monkey->input_gen_ctx, INPUT_GEN_DEV_ALL);
input_gen_destroy(monkey->input_gen_ctx);
}
for (i = 0; i < monkey->dev_num; i++)
{
monkey_dev_delete(monkey->devs[i]);

View file

@ -27,6 +27,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <graphics/input_gen.h>
#include <nuttx/input/buttons.h>
#include <nuttx/input/touchscreen.h>
#include <poll.h>
@ -48,41 +49,43 @@
* Name: utouch_write
****************************************************************************/
static void utouch_write(int fd, int x, int y, int touch_down)
static void utouch_write(input_gen_ctx_t input_gen_ctx,
FAR const struct monkey_dev_state_s *state)
{
struct touch_sample_s sample;
sample.npoints = 1;
input_gen_fill_point(sample.point, state->data.touch.x,
state->data.touch.y,
state->data.touch.is_pressed ? TOUCH_DOWN : TOUCH_UP);
if (touch_down)
if (input_gen_write_raw(input_gen_ctx, INPUT_GEN_DEV_UTOUCH, &sample,
sizeof(struct touch_sample_s)) < 0)
{
sample.point[0].x = x;
sample.point[0].y = y;
sample.point[0].pressure = 42;
sample.point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID |
TOUCH_POS_VALID | TOUCH_PRESSURE_VALID;
}
else
{
sample.point[0].flags = TOUCH_UP | TOUCH_ID_VALID;
MONKEY_LOG_WARN("unsupported device type: %d", INPUT_GEN_DEV_UTOUCH);
return;
}
sample.npoints = 1;
sample.point[0].h = 1;
sample.point[0].w = 1;
write(fd, &sample, sizeof(struct touch_sample_s));
MONKEY_LOG_INFO("%s at x = %d, y = %d",
touch_down ? "PRESS " : "RELEASE", x, y);
state->data.touch.is_pressed ? "PRESS" : "RELEASE",
state->data.touch.x, state->data.touch.y);
}
/****************************************************************************
* Name: ubutton_write
****************************************************************************/
static void ubutton_write(int fd, uint32_t btn_bits)
static void ubutton_write(input_gen_ctx_t input_gen_ctx,
FAR const struct monkey_dev_state_s *state)
{
btn_buttonset_t buttonset = btn_bits;
write(fd, &buttonset, sizeof(buttonset));
MONKEY_LOG_INFO("btn = 0x%08X", btn_bits);
btn_buttonset_t buttonset = state->data.button.value;
if (input_gen_write_raw(input_gen_ctx, INPUT_GEN_DEV_UBUTTON, &buttonset,
sizeof(buttonset)) < 0)
{
MONKEY_LOG_WARN("unsupported device type: %d", INPUT_GEN_DEV_UBUTTON);
return;
}
MONKEY_LOG_INFO("btn = 0x%08X", state->data.button.value);
}
/****************************************************************************
@ -152,18 +155,12 @@ FAR struct monkey_dev_s *monkey_dev_create(FAR const char *dev_path,
int fd;
MONKEY_ASSERT_NULL(dev_path);
MONKEY_ASSERT(!MONKEY_IS_UINPUT_TYPE(type));
dev = calloc(1, sizeof(struct monkey_dev_s));
MONKEY_ASSERT_NULL(dev);
if (MONKEY_IS_UINPUT_TYPE(type))
{
oflag = O_RDWR | O_NONBLOCK;
}
else
{
oflag = O_RDONLY | O_NONBLOCK;
}
oflag = O_RDONLY | O_NONBLOCK;
fd = open(dev_path, oflag);
if (fd < 0)
@ -204,13 +201,6 @@ void monkey_dev_delete(FAR struct monkey_dev_s *dev)
if (dev->fd > 0)
{
/* Reset input state */
struct monkey_dev_state_s state;
memset(&state, 0, sizeof(state));
state.type = dev->type;
monkey_dev_set_state(dev, &state);
MONKEY_LOG_NOTICE("close fd: %d", dev->fd);
close(dev->fd);
}
@ -222,23 +212,24 @@ void monkey_dev_delete(FAR struct monkey_dev_s *dev)
* Name: monkey_dev_set_state
****************************************************************************/
void monkey_dev_set_state(FAR struct monkey_dev_s *dev,
void monkey_dev_set_state(input_gen_ctx_t input_gen_ctx,
FAR const struct monkey_dev_state_s *state)
{
MONKEY_ASSERT_NULL(dev);
MONKEY_ASSERT_NULL(input_gen_ctx);
switch (MONKEY_GET_DEV_TYPE(dev->type))
switch (MONKEY_GET_DEV_TYPE(state->type))
{
case MONKEY_DEV_TYPE_TOUCH:
utouch_write(dev->fd,
state->data.touch.x,
state->data.touch.y,
state->data.touch.is_pressed);
break;
{
utouch_write(input_gen_ctx, state);
break;
}
case MONKEY_DEV_TYPE_BUTTON:
ubutton_write(dev->fd, state->data.button.value);
break;
{
ubutton_write(input_gen_ctx, state);
break;
}
default:
break;
@ -280,7 +271,7 @@ bool monkey_dev_get_state(FAR struct monkey_dev_s *dev,
}
/****************************************************************************
* Name: monkey_dev_get_state
* Name: monkey_dev_get_type
****************************************************************************/
enum monkey_dev_type_e monkey_dev_get_type(

View file

@ -69,7 +69,7 @@ void monkey_dev_delete(FAR struct monkey_dev_s *dev);
* Name: monkey_dev_set_state
****************************************************************************/
void monkey_dev_set_state(FAR struct monkey_dev_s *dev,
void monkey_dev_set_state(input_gen_ctx_t input_gen_ctx,
FAR const struct monkey_dev_state_s *state);
/****************************************************************************

View file

@ -26,47 +26,12 @@
#include <string.h>
#include <unistd.h>
#include <graphics/input_gen.h>
#include "monkey_dev.h"
#include "monkey_event.h"
#include "monkey_log.h"
#include "monkey_utils.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: monkey_exec_darg
****************************************************************************/
static bool monkey_exec_darg(FAR struct monkey_dev_s *dev,
FAR struct monkey_dev_state_s *state,
FAR const struct monkey_event_param_s *param)
{
int t = 0;
uint32_t start;
state->data.touch.is_pressed = true;
start = monkey_tick_get();
while (t < param->duration)
{
t = monkey_tick_elaps(monkey_tick_get(), start);
state->data.touch.x = monkey_map(t, 0, param->duration,
param->x1, param->x2);
state->data.touch.y = monkey_map(t, 0, param->duration,
param->y1, param->y2);
monkey_dev_set_state(dev, state);
if (usleep(1000) < 0)
{
return false;
}
}
return true;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -143,60 +108,46 @@ bool monkey_event_exec(FAR struct monkey_s *monkey,
FAR const struct monkey_event_param_s *param)
{
bool retval = false;
struct monkey_dev_state_s state;
memset(&state, 0, sizeof(struct monkey_dev_state_s));
state.type = monkey_dev_get_type(dev);
enum monkey_dev_type_e dev_type = monkey_dev_get_type(dev);
MONKEY_LOG_INFO("dev=0x%x event=%d(%s) duration=%d"
" x1=%d y1=%d x2=%d y2=%d",
state.type,
dev_type,
param->event,
monkey_event_type2name(param->event),
param->duration,
param->x1, param->y1,
param->x2, param->y2);
if (state.type & MONKEY_DEV_TYPE_TOUCH)
if (dev_type & MONKEY_DEV_TYPE_TOUCH)
{
state.data.touch.x = param->x1;
state.data.touch.y = param->y1;
state.data.touch.is_pressed = true;
monkey_dev_set_state(dev, &state);
if (param->event == MONKEY_EVENT_DRAG)
{
retval = monkey_exec_darg(dev, &state, param);
retval = !input_gen_drag(monkey->input_gen_ctx,
param->x1, param->y1,
param->x2, param->y2,
param->duration);
}
else
{
retval = usleep(param->duration * 1000) == 0;
}
/* Use swipe with same start and end point to simulate click or
* longpress.
*/
if (!retval)
{
MONKEY_LOG_NOTICE("detect monkey killed");
retval = !input_gen_swipe(monkey->input_gen_ctx,
param->x1, param->y1,
param->x1, param->y1,
param->duration);
}
state.data.touch.is_pressed = false;
monkey_dev_set_state(dev, &state);
}
else if (state.type & MONKEY_DEV_TYPE_BUTTON)
else if (dev_type & MONKEY_DEV_TYPE_BUTTON)
{
/* press button */
state.data.button.value = 1 << monkey->config.btn_bit;
monkey_dev_set_state(dev, &state);
retval = usleep(param->duration * 1000) == 0;
/* release button */
state.data.button.value = 0;
monkey_dev_set_state(dev, &state);
retval = !input_gen_button_longpress(monkey->input_gen_ctx,
1 << monkey->config.btn_bit,
param->duration);
}
else
{
MONKEY_LOG_WARN("unsupport device type: %d", state.type);
MONKEY_LOG_WARN("unsupported device type: %d", dev_type);
}
return retval;

View file

@ -532,7 +532,7 @@ static enum monkey_wait_res_e monkey_wait(uint32_t ms)
}
else
{
MONKEY_LOG_ERROR("Unknow error: %d", errcode);
MONKEY_LOG_ERROR("Unknown error: %d", errcode);
}
}
else if (ret == SIGTSTP)

View file

@ -41,10 +41,10 @@
****************************************************************************/
/****************************************************************************
* Name: monkey_update_uinput_ramdom
* Name: monkey_update_uinput_random
****************************************************************************/
static bool monkey_update_uinput_ramdom(FAR struct monkey_s *monkey)
static bool monkey_update_uinput_random(FAR struct monkey_s *monkey)
{
int i;
bool retval = false;
@ -65,29 +65,15 @@ static bool monkey_update_uinput_ramdom(FAR struct monkey_s *monkey)
return retval;
}
/****************************************************************************
* Name: monkey_search_dev
****************************************************************************/
static FAR struct monkey_dev_s *monkey_search_dev(
FAR struct monkey_s *monkey,
enum monkey_dev_type_e type)
{
int i;
for (i = 0; i < monkey->dev_num; i++)
{
FAR struct monkey_dev_s *dev = monkey->devs[i];
if (type == dev->type)
{
return dev;
}
}
return NULL;
}
/****************************************************************************
* Name: monkey_recorder_get_next
*
* Description:
* Gets the next recorder state
*
* Returned Value:
* 0 on error, 1 on end of file, 2 on success.
*
****************************************************************************/
static int monkey_recorder_get_next(FAR struct monkey_s *monkey,
@ -149,7 +135,6 @@ static bool monkey_update_uinput_playback(FAR struct monkey_s *monkey)
struct monkey_dev_state_s next_state;
uint32_t tick_elaps;
FAR struct monkey_dev_s *dev;
int num_of_get;
@ -168,18 +153,7 @@ static bool monkey_update_uinput_playback(FAR struct monkey_s *monkey)
memset(&monkey->playback_ctx, 0, sizeof(monkey->playback_ctx));
monkey_recorder_reset(monkey->recorder);
case 2:
dev = monkey_search_dev(monkey,
MONKEY_UINPUT_TYPE_MASK | cur_state.type);
if (dev)
{
monkey_dev_set_state(dev, &cur_state);
}
else
{
MONKEY_LOG_WARN("unsupport device type: %d", cur_state.type);
}
monkey_dev_set_state(monkey->input_gen_ctx, &cur_state);
tick_elaps = monkey_tick_elaps(next_time_stamp, cur_time_stamp);
monkey_set_period(monkey, tick_elaps);
break;
@ -203,7 +177,7 @@ static bool monkey_update_uinput(FAR struct monkey_s *monkey)
if (monkey->mode == MONKEY_MODE_RANDOM)
{
retval = monkey_update_uinput_ramdom(monkey);
retval = monkey_update_uinput_random(monkey);
}
else if(monkey->mode == MONKEY_MODE_PLAYBACK)
{

View file

@ -27,6 +27,7 @@
* Included Files
****************************************************************************/
#include <graphics/input_gen.h>
#include <stdint.h>
#include <stdbool.h>
@ -124,6 +125,7 @@ struct monkey_s
FAR struct monkey_dev_s *devs[MONKEY_DEV_MAX_NUM];
int dev_num;
FAR struct monkey_recorder_s *recorder;
input_gen_ctx_t input_gen_ctx;
struct
{
struct monkey_dev_state_s state;

View file

@ -155,44 +155,6 @@ bool monkey_dir_check(FAR const char *dir_path)
return retval;
}
/****************************************************************************
* Name: monkey_map
****************************************************************************/
int monkey_map(int x, int min_in, int max_in, int min_out, int max_out)
{
if (max_in >= min_in && x >= max_in)
{
return max_out;
}
if (max_in >= min_in && x <= min_in)
{
return min_out;
}
if (max_in <= min_in && x <= max_in)
{
return max_out;
}
if (max_in <= min_in && x >= min_in)
{
return min_out;
}
/* The equation should be:
* ((x - min_in) * delta_out) / delta in) + min_out
* To avoid rounding error reorder the operations:
* (x - min_in) * (delta_out / delta_min) + min_out
*/
int delta_in = max_in - min_in;
int delta_out = max_out - min_out;
return ((x - min_in) * delta_out) / delta_in + min_out;
}
/****************************************************************************
* Name: monkey_dev_type2name
****************************************************************************/
@ -210,7 +172,7 @@ FAR const char *monkey_dev_type2name(enum monkey_dev_type_e type)
}
}
return "unknow";
return "unknown";
}
/****************************************************************************
@ -254,5 +216,5 @@ FAR const char *monkey_event_type2name(enum monkey_event_e event)
break;
}
return "unknow";
return "unknown";
}

View file

@ -76,12 +76,6 @@ void monkey_get_localtime_str(FAR char *str_buf, size_t buf_size);
bool monkey_dir_check(FAR const char *dir_path);
/****************************************************************************
* Name: monkey_map
****************************************************************************/
int monkey_map(int x, int min_in, int max_in, int min_out, int max_out);
/****************************************************************************
* Name: monkey_dev_type2name
****************************************************************************/