diff --git a/src/ial/linux-libinput.c b/src/ial/linux-libinput.c index fd15d03e..b7b685f7 100644 --- a/src/ial/linux-libinput.c +++ b/src/ial/linux-libinput.c @@ -433,6 +433,7 @@ static int translate_libinput_keycode(uint32_t keycode) return 0; scancode = linux_keycode_to_scancode_map[keycode]; + _MG_PRINTF("translate keycode %u to scancode: %u\n", keycode, scancode); return scancode; } @@ -646,9 +647,9 @@ static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, ptr_event = libinput_event_get_pointer_event(event); x = libinput_event_pointer_get_absolute_x_transformed(ptr_event, - my_ctxt.max_x - my_ctxt.min_x + 1); + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; y = libinput_event_pointer_get_absolute_y_transformed(ptr_event, - my_ctxt.max_y - my_ctxt.min_y + 1); + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; if (on_new_mouse_pos(x, y)) retval = IAL_EVENT_MOUSE; break; @@ -744,9 +745,9 @@ static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, tch_event = libinput_event_get_touch_event(event); x = libinput_event_touch_get_x_transformed(tch_event, - my_ctxt.max_x - my_ctxt.min_x + 1); + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; y = libinput_event_touch_get_y_transformed(tch_event, - my_ctxt.max_y - my_ctxt.min_y + 1); + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; retval = 0; // emulate the mouse left button down and mouse move events @@ -783,9 +784,9 @@ static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, tch_event = libinput_event_get_touch_event(event); x = libinput_event_touch_get_x_transformed(tch_event, - my_ctxt.max_x - my_ctxt.min_x + 1); + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; y = libinput_event_touch_get_y_transformed(tch_event, - my_ctxt.max_y - my_ctxt.min_y + 1); + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; retval = 0; // emulate the mouse move event @@ -835,9 +836,9 @@ static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, /* always get x,y for mouse */ mouse_x = libinput_event_tablet_tool_get_x_transformed(tool_event, - my_ctxt.max_x - my_ctxt.min_x + 1); + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; mouse_y = libinput_event_tablet_tool_get_y_transformed(tool_event, - my_ctxt.max_y - my_ctxt.min_y + 1); + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; if (on_new_mouse_pos(mouse_x, mouse_y)) retval = IAL_EVENT_MOUSE; diff --git a/src/ial/random.c b/src/ial/random.c index 7c6e1800..a423a2c1 100644 --- a/src/ial/random.c +++ b/src/ial/random.c @@ -52,8 +52,7 @@ ** ** - mouse: mouse. ** - keyboard: keyboard. -** - joystick: joystick buttons. -** - button: buttons other than joystick. +** - button: buttons. ** - single_touch: touch pen or single touch panel. ** - multi_touch: multiple touch panel. ** - gesture: gesture. @@ -61,16 +60,38 @@ ** - tablet_pad: tablet pad. ** - switch: switch. ** -** The MiniGUI ETC key `random.maxkeycode` specifies the maximal key code -** which can be generated by the engine. +** The MiniGUI ETC key `random.minkeycode` specifies the minimal key code +** which can be generated by the engine if `keyboard` is included. ** -** For invalid `random.eventtyps` and `random.maxkeycord key value, -** use `mouse` and `NR_KEYS` respectively. +** The MiniGUI ETC key `random.maxkeycode` specifies the maximal key code +** which can be generated by the engine if `keyboard` is included. +** +** The MiniGUI ETC key `random.minbtncode` specifies the minimal button code +** which can be generated by the engine if `button` is included. +** +** The MiniGUI ETC key `random.maxbtncode` specifies the maximal key code +** which can be generated by the engine if `button` is included. +** +** For invalid `random.eventtyps`, use `mouse` as default. +** +** For invalid `random.minkeycode`, and/or `random.maxkeycode key values, use +** `SCANCODE_ESCAPE`, and `SCANCODE_MICMUTE` respectively. +** +** For invalid `random.minbtncode`, and/or `random.maxbtncode key values, use +** `0x100` (BTN_MISC defined by Linux kernel), and `0x2ff` (KEY_MAX defined by +** Linux kernel) respectively. ** ** This engine maintains a state machine for each input event type, and ** generates a reasonable event sequence for each type. If and only if ** an event sequence finished or cancelled, the engine switch to another ** event type randomly. +** +** Note that currently, the following event types are not implemented: +** +** - multi_touch +** - tablet_tool +** - tablet_pad +** - switch */ #include @@ -90,32 +111,77 @@ #include "ial.h" #include "random.h" -#define BTN_NONE 0 +#define BTN_NONE 0 #ifdef __LINUX__ #include #else - -/* copied from linux/input-event-codes.h */ -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 #endif +#define MIN_SCANCODE SCANCODE_ESCAPE +#define MAX_SCANCODE SCANCODE_MICMUTE + +#define MIN_BTNCODE 0x100 +#define MAX_BTNCODE 0x2ff + +#define MAX_PRESSED_BTNS 10 + +#define MAX_ABS_X 2048 +#define MAX_ABS_Y 2048 + enum _random_event_type { RANDOM_EVENT_NONE, RANDOM_EVENT_WAIT, RANDOM_EVENT_MOUSE_MOTION, RANDOM_EVENT_MOUSE_BUTTON, + RANDOM_EVENT_MOUSE_WHEEL, RANDOM_EVENT_KEYBOARD_KEY, + RANDOM_EVENT_BUTTON, + RANDOM_EVENT_STOUCH_DOWN, + RANDOM_EVENT_STOUCH_UP, + RANDOM_EVENT_STOUCH_MOTION, + RANDOM_EVENT_MTOUCH_DOWN, + RANDOM_EVENT_MTOUCH_UP, + RANDOM_EVENT_MTOUCH_MOTION, + RANDOM_EVENT_MTOUCH_CANCEL, + RANDOM_EVENT_MTOUCH_FRAME, + RANDOM_EVENT_GESTURE_SWIPE_BEGIN, + RANDOM_EVENT_GESTURE_SWIPE_UPDATE, + RANDOM_EVENT_GESTURE_SWIPE_END, + RANDOM_EVENT_GESTURE_PINCH_BEGIN, + RANDOM_EVENT_GESTURE_PINCH_UPDATE, + RANDOM_EVENT_GESTURE_PINCH_END, }; struct _random_event { enum _random_event_type type; }; -typedef void* (*op_start_event_machine)(void); +struct _event_state_machine; + +#define NR_EVENT_TYPES 10 + +struct _random_input_context { + FILE* log_fp; + int min_x, max_x, min_y, max_y; + int mouse_x, mouse_y, mouse_button; + int min_keycode, max_keycode; + int min_btncode, max_btncode; + + int last_keycode; + char* kbd_state; + + struct _event_state_machine *esm [NR_EVENT_TYPES]; + int nr_machines; + int curr_machine; +}; + +typedef void* (*op_start_event_machine)(const struct _random_input_context* ctxt); typedef void (*op_stop_event_machine)(void* machine); +typedef void (*op_resume_event_machine)(void* machine); typedef const struct _random_event* (*op_generate_event)(void* machine); enum _button_state { @@ -128,12 +194,14 @@ enum _key_state { KEY_STATE_PRESSED, }; -/* state machine for mouse */ +/* implementation of state machine for mouse */ struct _mouse_event { struct _random_event event; uint32_t button; enum _button_state state; int dx, dy; + int sv; // scroll value + int dsv; // discrete scroll value }; enum _mouse_op_type { @@ -141,6 +209,7 @@ enum _mouse_op_type { MOUSE_OP_MOVE, MOUSE_OP_CLICK, MOUSE_OP_PRESSED_MOVE, + MOUSE_OP_WHEEL, MOUSE_OP_COUNT, }; @@ -154,14 +223,11 @@ struct _mouse_event_machine { uint32_t btn_down; }; -static void* start_event_machine_mouse(void) +static void* start_event_machine_mouse(const struct _random_input_context* ctxt) { struct _mouse_event_machine* machine; machine = calloc(1, sizeof (struct _mouse_event_machine)); - machine->op_type = MOUSE_OP_IDLE; - machine->op_sec = random() % 5; - machine->op_start = time(NULL); return machine; } @@ -171,6 +237,16 @@ static void stop_event_machine_mouse(void* machine) free(machine); } +static void resume_event_machine_mouse(void* machine) +{ + struct _mouse_event_machine* my_machine = + (struct _mouse_event_machine*)machine; + + my_machine->op_type = MOUSE_OP_IDLE; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); +} + static const struct _random_event* generate_event_mouse(void* machine) { struct _mouse_event_machine* my_machine = @@ -179,10 +255,9 @@ static const struct _random_event* generate_event_mouse(void* machine) memset(&my_machine->event, 0, sizeof(my_machine->event)); - if ((now - my_machine->op_start) > my_machine->op_sec && - my_machine->btn_down == BTN_NONE) { + if ((now - my_machine->op_start) > my_machine->op_sec) { my_machine->op_type = now % MOUSE_OP_COUNT; - my_machine->op_sec = random() % 5; + my_machine->op_sec = random() % 5 + 1; my_machine->op_start = time(NULL); switch (now % 5) { @@ -197,7 +272,9 @@ static const struct _random_event* generate_event_mouse(void* machine) break; } - __mg_os_time_delay(100); + _DBG_PRINTF("%s: new operation type: %d; time: (%ds)\n", + __FUNCTION__, my_machine->op_type, my_machine->op_sec); + my_machine->event.event.type = RANDOM_EVENT_NONE; goto ret; } @@ -205,7 +282,7 @@ static const struct _random_event* generate_event_mouse(void* machine) /* valid operation */ if ((GetTickCount() % 5)) { // 80% possibility to wait for a new event. - __mg_os_time_delay(10); + __mg_os_time_delay(11); my_machine->event.event.type = RANDOM_EVENT_WAIT; goto ret; } @@ -217,8 +294,10 @@ static const struct _random_event* generate_event_mouse(void* machine) case MOUSE_OP_MOVE: my_machine->event.event.type = RANDOM_EVENT_MOUSE_MOTION; - my_machine->event.dx = random() % 100 - 50; - my_machine->event.dy = random() % 100 - 50; + my_machine->event.dx = (random() % 100) - 50; + my_machine->event.dy = (random() % 100) - 50; + _DBG_PRINTF("MOUSE_OP_MOVE: dx: %d, dy: %d\n", + my_machine->event.dx, my_machine->event.dy); break; case MOUSE_OP_CLICK: @@ -255,8 +334,497 @@ static const struct _random_event* generate_event_mouse(void* machine) } else { my_machine->event.event.type = RANDOM_EVENT_MOUSE_MOTION; - my_machine->event.dx = random() % 100 - 50; - my_machine->event.dy = random() % 100 - 50; + my_machine->event.dx = (random() % 100) - 50; + my_machine->event.dy = (random() % 100) - 50; + } + break; + + case MOUSE_OP_WHEEL: + my_machine->event.event.type = RANDOM_EVENT_MOUSE_WHEEL; + my_machine->event.dsv = (random() % 10) - 5; + my_machine->event.sv = 15 * my_machine->event.dsv; // 15 degrees per tick + break; + + default: + assert(0); + break; + } + +ret: + return &my_machine->event.event; +} + +static inline const +struct _mouse_event* get_mouse_event(const struct _random_event* event) +{ + if (event->type != RANDOM_EVENT_MOUSE_MOTION && + event->type != RANDOM_EVENT_MOUSE_BUTTON && + event->type != RANDOM_EVENT_MOUSE_WHEEL) + return NULL; + + return (struct _mouse_event*)event; +} + +/* implementation of state machine for keyboard */ +struct _keyboard_event { + struct _random_event event; + int keycode; + enum _key_state state; +}; + +enum _keyboard_op_type { + KEYBOARD_OP_IDLE = 0, + KEYBOARD_OP_NORMAL_KEY, + KEYBOARD_OP_SHIFT_KEYS, + KEYBOARD_OP_COUNT, +}; + +struct _keyboard_event_machine { + struct _keyboard_event event; + enum _keyboard_op_type op_type; + int op_sec; + time_t op_start; + + int min_keycode, max_keycode; + uint32_t pressed_shift_keys; + int pressed_normal_key; +}; + +struct _keyboard_shift_key { + int keycode; + uint32_t flag; +} keyboard_shift_keys[] = { + { SCANCODE_CAPSLOCK, KS_CAPSLOCK }, + { SCANCODE_NUMLOCK, KS_NUMLOCK }, + { SCANCODE_SCROLLLOCK, KS_SCROLLLOCK }, + { SCANCODE_LEFTCTRL, KS_LEFTCTRL }, + { SCANCODE_RIGHTCTRL, KS_RIGHTCTRL }, + { SCANCODE_LEFTALT, KS_LEFTALT }, + { SCANCODE_RIGHTALT, KS_RIGHTALT }, + { SCANCODE_LEFTSHIFT, KS_LEFTSHIFT }, + { SCANCODE_RIGHTSHIFT, KS_RIGHTSHIFT }, + { SCANCODE_LEFTMETA, KS_LEFTMETA }, + { SCANCODE_RIGHTMETA, KS_RIGHTMETA }, +}; + +static void* start_event_machine_keyboard(const struct _random_input_context* ctxt) +{ + struct _keyboard_event_machine* machine; + machine = calloc(1, sizeof (struct _keyboard_event_machine)); + + machine->min_keycode = ctxt->min_keycode; + machine->max_keycode = ctxt->max_keycode; + return machine; +} + +static void stop_event_machine_keyboard(void* machine) +{ + if (machine) + free(machine); +} + +static void resume_event_machine_keyboard(void* machine) +{ + struct _keyboard_event_machine* my_machine = + (struct _keyboard_event_machine*)machine; + + my_machine->op_type = KEYBOARD_OP_IDLE; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); +} + +static const struct _random_event* generate_event_keyboard(void* machine) +{ + struct _keyboard_event_machine* my_machine = + (struct _keyboard_event_machine*)machine; + time_t now = time(NULL); + + memset(&my_machine->event, 0, sizeof(my_machine->event)); + + if ((now - my_machine->op_start) > my_machine->op_sec) { + my_machine->op_type = now % KEYBOARD_OP_COUNT; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); + + my_machine->event.event.type = RANDOM_EVENT_NONE; + goto ret; + } + + /* valid operation */ + if ((GetTickCount() % 5)) { + // 80% possibility to wait for a new event. + __mg_os_time_delay(11); + my_machine->event.event.type = RANDOM_EVENT_WAIT; + goto ret; + } + + switch (my_machine->op_type) { + case KEYBOARD_OP_IDLE: + my_machine->event.event.type = RANDOM_EVENT_WAIT; + break; + + case KEYBOARD_OP_NORMAL_KEY: + if (my_machine->pressed_normal_key == SCANCODE_RESERVED) { + my_machine->pressed_normal_key = + (random() % + (my_machine->max_keycode - my_machine->min_keycode + 1)) + + my_machine->min_keycode; + + my_machine->event.event.type = RANDOM_EVENT_KEYBOARD_KEY; + my_machine->event.keycode = my_machine->pressed_normal_key; + my_machine->event.state = KEY_STATE_PRESSED; + } + else { + my_machine->event.event.type = RANDOM_EVENT_KEYBOARD_KEY; + my_machine->event.keycode = my_machine->pressed_normal_key; + my_machine->event.state = KEY_STATE_RELEASED; + + my_machine->pressed_normal_key = SCANCODE_RESERVED; + } + break; + + case KEYBOARD_OP_SHIFT_KEYS: { + int i = random() % (TABLESIZE(keyboard_shift_keys)); + + if (keyboard_shift_keys[i].flag & my_machine->pressed_shift_keys) { + my_machine->event.event.type = RANDOM_EVENT_KEYBOARD_KEY; + my_machine->event.keycode = keyboard_shift_keys[i].keycode; + my_machine->event.state = KEY_STATE_RELEASED; + + my_machine->pressed_shift_keys &= ~keyboard_shift_keys[i].flag; + } + else { + my_machine->event.event.type = RANDOM_EVENT_KEYBOARD_KEY; + my_machine->event.keycode = keyboard_shift_keys[i].keycode; + my_machine->event.state = KEY_STATE_PRESSED; + + my_machine->pressed_shift_keys |= keyboard_shift_keys[i].flag; + } + break; + } + + default: + assert(0); + break; + } + +ret: + return &my_machine->event.event; +} + +static inline const +struct _keyboard_event* get_keyboard_event(const struct _random_event* event) +{ + if (event->type != RANDOM_EVENT_KEYBOARD_KEY) + return NULL; + + return (struct _keyboard_event*)event; +} + +/* implementation of state machine for button */ +struct _button_event { + struct _random_event event; + int btncode; + enum _button_state state; +}; + +enum _button_op_type { + BUTTON_OP_IDLE = 0, + BUTTON_OP_NORMAL, + BUTTON_OP_COUNT, +}; + +struct _button_event_machine { + struct _button_event event; + enum _button_op_type op_type; + int op_sec; + time_t op_start; + + int min_btncode, max_btncode; + int last_btn; + int pressed_btns[MAX_PRESSED_BTNS]; +}; + +static inline +int button_is_pressed(struct _button_event_machine* machine, int btn) +{ + int i; + + for (i = 0; i < MAX_PRESSED_BTNS; i++) { + if (btn == machine->pressed_btns[i]) { + return i; + } + } + + return -1; +} + +static inline +int button_clear(struct _button_event_machine* machine, int btn) +{ + int i; + + for (i = 0; i < MAX_PRESSED_BTNS; i++) { + if (btn == machine->pressed_btns[i]) { + machine->pressed_btns[i] = BTN_NONE; + return i; + } + } + + return -1; +} + +static inline +int button_set(struct _button_event_machine* machine, int btn) +{ + int i; + + for (i = 0; i < MAX_PRESSED_BTNS; i++) { + if (machine->pressed_btns[i] == BTN_NONE) { + machine->pressed_btns[i] = btn; + return i; + } + } + + return -1; +} + +static void* start_event_machine_button(const struct _random_input_context* ctxt) +{ + struct _button_event_machine* machine; + machine = calloc(1, sizeof (struct _button_event_machine)); + + machine->min_btncode = ctxt->min_btncode; + machine->max_btncode = ctxt->max_btncode; + return machine; +} + +static void stop_event_machine_button(void* machine) +{ + if (machine) + free(machine); +} + +static void resume_event_machine_button(void* machine) +{ + struct _button_event_machine* my_machine = + (struct _button_event_machine*)machine; + + my_machine->op_type = BUTTON_OP_IDLE; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); +} + +static const struct _random_event* generate_event_button(void* machine) +{ + struct _button_event_machine* my_machine = + (struct _button_event_machine*)machine; + time_t now = time(NULL); + + memset(&my_machine->event, 0, sizeof(my_machine->event)); + + if ((now - my_machine->op_start) > my_machine->op_sec) { + my_machine->op_type = now % BUTTON_OP_COUNT; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); + + my_machine->event.event.type = RANDOM_EVENT_NONE; + goto ret; + } + + /* valid operation */ + if ((GetTickCount() % 5)) { + // 80% possibility to wait for a new event. + __mg_os_time_delay(11); + my_machine->event.event.type = RANDOM_EVENT_WAIT; + goto ret; + } + + switch (my_machine->op_type) { + case BUTTON_OP_IDLE: + my_machine->event.event.type = RANDOM_EVENT_WAIT; + break; + + case BUTTON_OP_NORMAL: { + if (my_machine->last_btn != BTN_NONE && (GetTickCount() % 5)) { + // 80% possibility to release last button. + int idx = button_clear(my_machine, my_machine->last_btn); + + assert (idx >= 0); + my_machine->event.event.type = RANDOM_EVENT_BUTTON; + my_machine->event.btncode = my_machine->last_btn; + my_machine->event.state = BUTTON_STATE_RELEASED; + + my_machine->last_btn = BTN_NONE; + } + else { + int btn = + (random() % + (my_machine->max_btncode - my_machine->min_btncode + 1)) + + my_machine->min_btncode; + int idx = button_is_pressed(my_machine, btn); + if (idx < 0) { + idx = button_set(my_machine, btn); + if (idx < 0) { + // full pressed buttons; release a random button + idx = random() % MAX_PRESSED_BTNS; + + my_machine->event.event.type = RANDOM_EVENT_BUTTON; + my_machine->event.btncode = my_machine->pressed_btns[idx]; + my_machine->event.state = BUTTON_STATE_RELEASED; + + my_machine->last_btn = BTN_NONE; + } + else { + my_machine->event.event.type = RANDOM_EVENT_BUTTON; + my_machine->event.btncode = btn; + my_machine->event.state = BUTTON_STATE_PRESSED; + + my_machine->last_btn = btn; + } + } + else { + my_machine->event.event.type = RANDOM_EVENT_BUTTON; + my_machine->event.btncode = my_machine->pressed_btns[idx]; + my_machine->event.state = BUTTON_STATE_RELEASED; + + my_machine->last_btn = BTN_NONE; + } + } + break; + } + + default: + assert(0); + break; + } + +ret: + return &my_machine->event.event; +} + +static inline const +struct _button_event* get_button_event(const struct _random_event* event) +{ + if (event->type != RANDOM_EVENT_BUTTON) + return NULL; + + return (struct _button_event*)event; +} + +/* implementation of state machine for stouch */ +struct _stouch_event { + struct _random_event event; + enum _button_state state; + int x, y; +}; + +enum _stouch_op_type { + STOUCH_OP_IDLE = 0, + STOUCH_OP_DOWN, + STOUCH_OP_DOWN_MOVE, + STOUCH_OP_COUNT, +}; + +struct _stouch_event_machine { + struct _stouch_event event; + enum _stouch_op_type op_type; + int op_sec; + time_t op_start; + + int down; +}; + +static void* start_event_machine_stouch(const struct _random_input_context* ctxt) +{ + struct _stouch_event_machine* machine; + machine = calloc(1, sizeof (struct _stouch_event_machine)); + + return machine; +} + +static void stop_event_machine_stouch(void* machine) +{ + if (machine) + free(machine); +} + +static void resume_event_machine_stouch(void* machine) +{ + struct _stouch_event_machine* my_machine = + (struct _stouch_event_machine*)machine; + + my_machine->op_type = STOUCH_OP_IDLE; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); +} + +static const struct _random_event* generate_event_stouch(void* machine) +{ + struct _stouch_event_machine* my_machine = + (struct _stouch_event_machine*)machine; + time_t now = time(NULL); + + memset(&my_machine->event, 0, sizeof(my_machine->event)); + + if ((now - my_machine->op_start) > my_machine->op_sec) { + my_machine->op_type = now % STOUCH_OP_COUNT; + my_machine->op_sec = random() % 5 + 1; + my_machine->op_start = time(NULL); + my_machine->event.event.type = RANDOM_EVENT_NONE; + goto ret; + } + + /* valid operation */ + if ((GetTickCount() % 5)) { + // 80% possibility to wait for a new event. + __mg_os_time_delay(11); + my_machine->event.event.type = RANDOM_EVENT_WAIT; + goto ret; + } + + switch (my_machine->op_type) { + case STOUCH_OP_IDLE: + my_machine->event.event.type = RANDOM_EVENT_WAIT; + break; + + case STOUCH_OP_DOWN: + if (my_machine->down) { + my_machine->event.event.type = RANDOM_EVENT_STOUCH_DOWN; + my_machine->event.state = BUTTON_STATE_RELEASED; + my_machine->down = 0; + } + else { + my_machine->event.event.type = RANDOM_EVENT_STOUCH_DOWN; + my_machine->event.state = BUTTON_STATE_PRESSED; + my_machine->event.x = random() % MAX_ABS_X; + my_machine->event.y = random() % MAX_ABS_Y; + + my_machine->down = 1; + } + break; + + case STOUCH_OP_DOWN_MOVE: + if (my_machine->down == 0) { + my_machine->down = 1; + + my_machine->event.event.type = RANDOM_EVENT_STOUCH_DOWN; + my_machine->event.state = BUTTON_STATE_PRESSED; + + my_machine->event.x = random() % MAX_ABS_X; + my_machine->event.y = random() % MAX_ABS_Y; + } + else if ((GetTickCount() % 5) == 0) { + my_machine->event.event.type = RANDOM_EVENT_STOUCH_DOWN; + my_machine->event.state = BUTTON_STATE_RELEASED; + + my_machine->down = 0; + } + else { + my_machine->event.event.type = RANDOM_EVENT_STOUCH_MOTION; + + my_machine->event.x += (random() % 10) - 5; + my_machine->event.y += (random() % 10) - 5; } break; @@ -269,49 +837,223 @@ ret: return &my_machine->event.event; } -static inline struct _mouse_event* get_mouse_event(struct _random_event* event) +static inline const +struct _stouch_event* get_stouch_event(const struct _random_event* event) { - if (event->type != RANDOM_EVENT_MOUSE_MOTION && - event->type != RANDOM_EVENT_MOUSE_BUTTON) + if (event->type != RANDOM_EVENT_STOUCH_MOTION && + event->type != RANDOM_EVENT_STOUCH_DOWN && + event->type != RANDOM_EVENT_STOUCH_UP) return NULL; - return (struct _mouse_event*)event; + return (struct _stouch_event*)event; +} + +/* implementation of state machine for gesture */ +struct _gesture_event { + struct _random_event event; + int nr_figs; + int dx, dy; + int is_cancelled; + + int scale; + int da; +}; + +enum _gesture_op_type { + GESTURE_OP_IDLE = 0, + GESTURE_OP_SWIPE, + GESTURE_OP_PINCH, + GESTURE_OP_COUNT, +}; + +struct _gesture_event_machine { + struct _gesture_event event; + enum _gesture_op_type op_type; + int op_sec; + time_t op_start; + + int started; +}; + +static void* start_event_machine_gesture(const struct _random_input_context* ctxt) +{ + struct _gesture_event_machine* machine; + machine = calloc(1, sizeof (struct _gesture_event_machine)); + + return machine; +} + +static void stop_event_machine_gesture(void* machine) +{ + if (machine) + free(machine); +} + +static void resume_event_machine_gesture(void* machine) +{ + struct _gesture_event_machine* my_machine = + (struct _gesture_event_machine*)machine; + + my_machine->op_type = GESTURE_OP_IDLE; + my_machine->op_sec = random() % 5; + my_machine->op_start = time(NULL); +} + +static const struct _random_event* generate_event_gesture(void* machine) +{ + struct _gesture_event_machine* my_machine = + (struct _gesture_event_machine*)machine; + time_t now = time(NULL); + + memset(&my_machine->event, 0, sizeof(my_machine->event)); + + if ((now - my_machine->op_start) > my_machine->op_sec && + my_machine->started == 0) { + my_machine->op_type = now % GESTURE_OP_COUNT; + my_machine->op_sec = random() % 5 + 1; + my_machine->op_start = time(NULL); + my_machine->event.event.type = RANDOM_EVENT_NONE; + + memset(&my_machine->event, 0, sizeof(struct _gesture_event)); + goto ret; + } + + /* valid operation */ + if ((GetTickCount() % 2)) { + // 50% possibility to wait for a new event. + __mg_os_time_delay(11); + my_machine->event.event.type = RANDOM_EVENT_WAIT; + goto ret; + } + + switch (my_machine->op_type) { + case GESTURE_OP_IDLE: + my_machine->event.event.type = RANDOM_EVENT_WAIT; + break; + + case GESTURE_OP_SWIPE: + if (my_machine->started == 0) { + my_machine->event.event.type = RANDOM_EVENT_GESTURE_SWIPE_BEGIN; + my_machine->event.nr_figs = random() % 5 + 1; + my_machine->started = 1; + } + else if (GetTickCount() % 10) { + // 90% possibility to wait update + my_machine->event.event.type = RANDOM_EVENT_GESTURE_SWIPE_UPDATE; + my_machine->event.dx = random() % 10 - 5; + my_machine->event.dy = random() % 100 - 50; + } + else { + my_machine->event.event.type = RANDOM_EVENT_GESTURE_SWIPE_END; + if (GetTickCount() % 3) + my_machine->event.is_cancelled = 0; + else + my_machine->event.is_cancelled = 1; + + my_machine->started = 0; + } + break; + + case GESTURE_OP_PINCH: + if (my_machine->started == 0) { + my_machine->event.event.type = RANDOM_EVENT_GESTURE_PINCH_BEGIN; + my_machine->event.nr_figs = random() % 5 + 1; + my_machine->event.scale = 100; + my_machine->started = 1; + } + else if (GetTickCount() % 10) { + // 90% possibility to wait update + my_machine->event.event.type = RANDOM_EVENT_GESTURE_PINCH_UPDATE; + if (GetTickCount() % 2) + my_machine->event.scale *= (random() % 5) + 1; + else + my_machine->event.scale /= (random() % 5) + 1; + if (my_machine->event.scale == 0) + my_machine->event.scale = 1; + + my_machine->event.da = (random() % 10) * 25; + my_machine->event.dx = (random() % 100) - 50; + my_machine->event.dy = (random() % 100) - 50; + } + else { + my_machine->event.event.type = RANDOM_EVENT_GESTURE_PINCH_END; + if (GetTickCount() % 3) + my_machine->event.is_cancelled = 0; + else + my_machine->event.is_cancelled = 1; + + my_machine->started = 0; + } + break; + + default: + assert(0); + break; + } + +ret: + return &my_machine->event.event; +} + +static inline const +struct _gesture_event* get_gesture_event(const struct _random_event* event) +{ + if (event->type < RANDOM_EVENT_GESTURE_SWIPE_BEGIN || + event->type > RANDOM_EVENT_GESTURE_PINCH_END) + return NULL; + + return (struct _gesture_event*)event; } static struct _event_state_machine { const char* name; op_start_event_machine start_machine; - op_stop_event_machine stop_machine; + op_resume_event_machine resume_machine; op_generate_event generate_event; - void* machine; + op_stop_event_machine stop_machine; + void* machine; } event_state_machines [] = { { "mouse", start_event_machine_mouse, + resume_event_machine_mouse, + generate_event_mouse, stop_event_machine_mouse, - generate_event_mouse}, - { "keyboard", }, - { "joystick", }, - { "button", }, - { "single_touch", }, - { "multi_touch", }, - { "gesture", }, - { "tablet_tool", }, - { "tablet_pad", }, - { "switch", }, + }, + { "keyboard", + start_event_machine_keyboard, + resume_event_machine_keyboard, + generate_event_keyboard, + stop_event_machine_keyboard, + }, + { "button", + start_event_machine_button, + resume_event_machine_button, + generate_event_button, + stop_event_machine_button, + }, + { "single_touch", + start_event_machine_stouch, + resume_event_machine_stouch, + generate_event_stouch, + stop_event_machine_stouch, + }, + { "multi_touch", + }, + { "gesture", + start_event_machine_gesture, + resume_event_machine_gesture, + generate_event_gesture, + stop_event_machine_gesture, + }, + { "tablet_tool", + }, + { "tablet_pad", + }, + { "switch", + }, }; -struct _random_input_contxt { - FILE* log_fp; - int min_x, max_x, min_y, max_y; - int mouse_x, mouse_y, mouse_button; - int nr_keys, last_keycode; - char* kbd_state; - - struct _event_state_machine *esm [TABLESIZE(event_state_machines)]; - int nr_machines; -}; - -static struct _random_input_contxt my_ctxt; +static struct _random_input_context my_ctxt; static void mouse_setrange (int newminx, int newminy, int newmaxx, int newmaxy) { @@ -371,7 +1113,6 @@ static const char* keyboard_getstate(void) return my_ctxt.kbd_state; } -#if 0 static void normalize_mouse_pos(int* new_x, int* new_y) { if (*new_x < my_ctxt.min_x) @@ -384,35 +1125,35 @@ static void normalize_mouse_pos(int* new_x, int* new_y) *new_y = my_ctxt.max_y; } -static BOOL on_mouse_moved (double dx, double dy) +static BOOL on_mouse_moved (int dx, int dy) { - int new_x = (int)(my_ctxt.mouse_x + dx + 0.5); - int new_y = (int)(my_ctxt.mouse_y + dy + 0.5); - - _DBG_PRINTF("%s: new mouse position: %d, %d (old: %d, %d; delta: %f, %f)\n", - __FUNCTION__, new_x, new_y, my_ctxt.mouse_x, my_ctxt.mouse_y, dx, dy); + int new_x = my_ctxt.mouse_x + dx; + int new_y = my_ctxt.mouse_y + dy; normalize_mouse_pos(&new_x, &new_y); if (new_x == my_ctxt.mouse_x && new_y == my_ctxt.mouse_y) return FALSE; + _DBG_PRINTF("%s: new mouse position: %d, %d (old: %d, %d; delta: %d, %d)\n", + __FUNCTION__, new_x, new_y, my_ctxt.mouse_x, my_ctxt.mouse_y, dx, dy); + my_ctxt.mouse_x = new_x; my_ctxt.mouse_y = new_y; return TRUE; } -static BOOL on_new_mouse_pos (double x, double y) +static BOOL on_new_mouse_pos (int x, int y) { - int new_x = (int)(x + 0.5); - int new_y = (int)(y + 0.5); - - _DBG_PRINTF("%s: new mouse position: %d, %d (old: %d, %d)\n", - __FUNCTION__, new_x, new_y, my_ctxt.mouse_x, my_ctxt.mouse_y); + int new_x = x; + int new_y = y; normalize_mouse_pos(&new_x, &new_y); if (new_x == my_ctxt.mouse_x && new_y == my_ctxt.mouse_y) return FALSE; + _DBG_PRINTF("%s: new mouse position: %d, %d (old: %d, %d)\n", + __FUNCTION__, new_x, new_y, my_ctxt.mouse_x, my_ctxt.mouse_y); + my_ctxt.mouse_x = new_x; my_ctxt.mouse_y = new_y; return TRUE; @@ -457,18 +1198,46 @@ static BOOL on_mouse_button_changed (uint32_t button, return TRUE; } -#endif -static struct _random_event* get_random_event(struct _random_input_contxt* ctxt) +static const +struct _random_event* get_random_event(struct _random_input_context* ctxt) { - - return NULL; + const struct _random_event* event; + + event = ctxt->esm[ctxt->curr_machine]->generate_event( + ctxt->esm[ctxt->curr_machine]->machine); + + switch (event->type) { + case RANDOM_EVENT_NONE: + ctxt->curr_machine = random() % ctxt->nr_machines; + return NULL; + + case RANDOM_EVENT_WAIT: + return NULL; + + default: + break; + } + + return event; } +static inline +int abs_pos_transformed(int x, int w) +{ + return (x * 2000)/w; +} + +#define LOG_EVENT(fmt, ...) \ + if (my_ctxt.log_fp) { \ + fprintf(my_ctxt.log_fp, fmt, ##__VA_ARGS__); \ + fflush(my_ctxt.log_fp); \ + } + static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, struct timeval *timeout, EXTRA_INPUT_EVENT* extra) { - struct _random_event *event; + const struct _random_event *event; int retval; event = get_random_event(&my_ctxt); @@ -482,7 +1251,172 @@ static int wait_event_ex (int maxfd, fd_set *in, fd_set *out, fd_set *except, } } - return 0; + /* set default return value */ + retval = -1; + switch (event->type) { + case RANDOM_EVENT_MOUSE_MOTION: { + const struct _mouse_event* mouse_event = get_mouse_event(event); + if (mouse_event) { + if (on_mouse_moved(mouse_event->dx, mouse_event->dy)) { + LOG_EVENT("%s: dx (%d), dy (%d)\n", + "RANDOM_EVENT_MOUSE_MOTION", + mouse_event->dx, mouse_event->dy); + } + } + break; + } + + case RANDOM_EVENT_MOUSE_BUTTON: { + const struct _mouse_event* mouse_event = get_mouse_event(event); + if (mouse_event) { + if (on_mouse_button_changed(mouse_event->button, mouse_event->state)) { + LOG_EVENT("%s: %u (%s)\n", + "RANDOM_EVENT_MOUSE_BUTTON", + mouse_event->button, + (mouse_event->state == BUTTON_STATE_PRESSED) ? "PRESSED" : "RELEASED"); + retval = IAL_EVENT_MOUSE; + } + } + break; + } + + case RANDOM_EVENT_MOUSE_WHEEL: { + const struct _mouse_event* mouse_event = get_mouse_event(event); + if (mouse_event) { + extra->event = IAL_EVENT_AXIS; + if (GetTickCount()%2) + extra->wparam = MAKELONG(AXIS_SCROLL_VERTICAL, AXIS_SOURCE_WHEEL); + else + extra->wparam = MAKELONG(AXIS_SCROLL_HORIZONTAL, AXIS_SOURCE_WHEEL); + extra->lparam = MAKELONG(mouse_event->sv, mouse_event->dsv); + retval = IAL_EVENT_EXTRA; + } + break; + } + + case RANDOM_EVENT_KEYBOARD_KEY: { + const struct _keyboard_event* kbd_event; + + kbd_event = get_keyboard_event(event); + if (kbd_event) { + my_ctxt.last_keycode = kbd_event->keycode; + if (my_ctxt.last_keycode) { + switch (kbd_event->state) { + case KEY_STATE_RELEASED: + my_ctxt.kbd_state[my_ctxt.last_keycode] = 0; + break; + case KEY_STATE_PRESSED: + my_ctxt.kbd_state[my_ctxt.last_keycode] = 1; + break; + } + + LOG_EVENT("%s: %u (%s)\n", + "RANDOM_EVENT_KEYBOARD_KEY", + kbd_event->keycode, + (kbd_event->state == KEY_STATE_PRESSED) ? "PRESSED" : "RELEASED"); + retval = IAL_EVENT_KEY; + } + } + break; + } + + case RANDOM_EVENT_BUTTON: { + const struct _button_event* btn_event; + + btn_event = get_button_event(event); + if (btn_event) { + retval = 0; + if (btn_event->btncode >= BTN_LEFT && + btn_event->btncode <= BTN_MIDDLE) { + if (on_mouse_button_changed(btn_event->btncode, btn_event->state)) + retval |= IAL_EVENT_MOUSE; + } + + if (btn_event->state == BUTTON_STATE_PRESSED) + extra->event = IAL_EVENT_BUTTONDOWN; + else + extra->event = IAL_EVENT_BUTTONUP; + extra->wparam = btn_event->btncode; + extra->lparam = 0; + retval |= IAL_EVENT_EXTRA; + } + break; + } + + case RANDOM_EVENT_STOUCH_DOWN: { + const struct _stouch_event* tch_event; + + tch_event = get_stouch_event(event); + if (tch_event) { + int x, y; + x = abs_pos_transformed(tch_event->x, + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; + y = abs_pos_transformed(tch_event->x, + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; + + retval = 0; + // emulate the mouse left button down and mouse move events + if (on_mouse_button_changed(BTN_LEFT, BUTTON_STATE_PRESSED) || + on_new_mouse_pos(x, y)) + retval |= IAL_EVENT_MOUSE; + + extra->event = IAL_EVENT_TOUCH_DOWN; + extra->wparam = 0; + extra->lparam = MAKELONG(my_ctxt.mouse_x, my_ctxt.mouse_y); + retval |= IAL_EVENT_EXTRA; + } + break; + } + + case RANDOM_EVENT_STOUCH_UP: { + const struct _stouch_event* tch_event; + + tch_event = get_stouch_event(event); + if (tch_event) { + retval = 0; + // emulate the mouse left button up and mouse move events + if (on_mouse_button_changed(BTN_LEFT, BUTTON_STATE_RELEASED)) + retval |= IAL_EVENT_MOUSE; + + extra->event = IAL_EVENT_TOUCH_UP; + extra->wparam = 0; + extra->lparam = 0; + retval |= IAL_EVENT_EXTRA; + } + break; + } + + case RANDOM_EVENT_STOUCH_MOTION: { + const struct _stouch_event* tch_event; + + tch_event = get_stouch_event(event); + if (tch_event) { + int x, y; + x = abs_pos_transformed(tch_event->x, + my_ctxt.max_x - my_ctxt.min_x + 1) + my_ctxt.min_x; + y = abs_pos_transformed(tch_event->x, + my_ctxt.max_y - my_ctxt.min_y + 1) + my_ctxt.min_y; + + retval = 0; + // emulate the mouse move event + if (on_new_mouse_pos(x, y)) + retval |= IAL_EVENT_MOUSE; + + extra->event = IAL_EVENT_TOUCH_MOTION; + extra->wparam = 0; + extra->lparam = MAKELONG(my_ctxt.mouse_x, my_ctxt.mouse_y); + retval |= IAL_EVENT_EXTRA; + } + break; + } + + default: + _DBG_PRINTF("IAL>RANDOM: HOW CAN YOU GET HERE? (event->type: %d)\n", + event->type); + break; + } + + return retval; } #define LEN_EVENT_TYPES 127 @@ -504,14 +1438,7 @@ BOOL InitRandomInput (INPUT* input, const char* mdev, const char* mtype) _WRN_PRINTF("No log file defined; log disabled"); } - if (GetMgEtcIntValue ("random", "maxkeycode", &my_ctxt.nr_keys) < 0 || - my_ctxt.nr_keys <= 0) { - _WRN_PRINTF("Bad ETC key value: random.maxkeycode; use default: %d", - NR_KEYS); - my_ctxt.nr_keys = NR_KEYS; - } - - my_ctxt.kbd_state = calloc(my_ctxt.nr_keys, sizeof(char)); + my_ctxt.kbd_state = calloc(my_ctxt.max_keycode + 1, sizeof(char)); if (my_ctxt.kbd_state == NULL) { _ERR_PRINTF("IAL>RANDOM: failed to allocate space for key state\n"); return FALSE; @@ -528,8 +1455,45 @@ BOOL InitRandomInput (INPUT* input, const char* mdev, const char* mtype) if (strstr(eventtypes, event_state_machines[i].name)) { struct _event_state_machine* machine = event_state_machines + i; + if (strcmp(event_state_machines[i].name, "keyboard") == 0) { + if (GetMgEtcIntValue ("random", "minkeycode", &my_ctxt.min_keycode) < 0 || + my_ctxt.min_keycode <= MIN_SCANCODE || + my_ctxt.min_keycode >= MAX_SCANCODE) { + _WRN_PRINTF("Bad ETC key value: random.minkeycode; use default: %d", + MIN_SCANCODE); + my_ctxt.min_keycode = MIN_SCANCODE; + } + + if (GetMgEtcIntValue ("random", "maxkeycode", &my_ctxt.max_keycode) < 0 || + my_ctxt.max_keycode <= MIN_SCANCODE || + my_ctxt.max_keycode <= my_ctxt.min_keycode) { + _WRN_PRINTF("Bad ETC key value: random.maxkeycode; use default: %d", + MAX_SCANCODE); + my_ctxt.max_keycode = MAX_SCANCODE; + } + } + + if (strcmp(event_state_machines[i].name, "button") == 0) { + if (GetMgEtcIntValue ("random", "minbtncode", &my_ctxt.min_btncode) < 0 || + my_ctxt.min_btncode <= MIN_BTNCODE || + my_ctxt.min_btncode >= MAX_BTNCODE) { + _WRN_PRINTF("Bad ETC key value: random.minbtncode; use default: %d", + MIN_BTNCODE); + my_ctxt.min_btncode = MIN_BTNCODE; + } + + if (GetMgEtcIntValue ("random", "maxbtncode", &my_ctxt.max_btncode) < 0 || + my_ctxt.max_btncode <= MIN_SCANCODE || + my_ctxt.max_btncode <= my_ctxt.min_btncode) { + _WRN_PRINTF("Bad ETC key value: random.maxbtncode; use default: %d", + MAX_BTNCODE); + my_ctxt.max_btncode = MAX_BTNCODE; + } + } + if (machine->start_machine && - (machine->machine = machine->start_machine())) { + (machine->machine = machine->start_machine(&my_ctxt))) { + my_ctxt.esm[my_ctxt.nr_machines] = machine; _DBG_PRINTF("IAL>RANDOM: start event machine for %s: %p\n", event_state_machines[i].name, @@ -539,7 +1503,16 @@ BOOL InitRandomInput (INPUT* input, const char* mdev, const char* mtype) } } - assert(my_ctxt.nr_machines > 0); + if (my_ctxt.nr_machines <= 0) { + _ERR_PRINTF("IAL>RANDOM: bad random.eventtypes: %s\n", eventtypes); + free(my_ctxt.kbd_state); + my_ctxt.kbd_state = NULL; + return FALSE; + } + + my_ctxt.curr_machine = 0; + my_ctxt.esm[my_ctxt.curr_machine]->resume_machine( + my_ctxt.esm[my_ctxt.curr_machine]->machine); input->update_mouse = mouse_update; input->get_mouse_xy = mouse_getxy;