mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-30 06:23:22 +08:00
1671 lines
48 KiB
C
1671 lines
48 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMPORTANT NOTICE
|
|
//
|
|
// The following open source license statement does not apply to any
|
|
// entity in the Exception List published by FMSoft.
|
|
//
|
|
// For more information, please visit:
|
|
//
|
|
// https://www.fmsoft.cn/exception-list
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
* This file is part of MiniGUI, a mature cross-platform windowing
|
|
* and Graphics User Interface (GUI) support system for embedded systems
|
|
* and smart IoT devices.
|
|
*
|
|
* Copyright (C) 2002~2019, Beijing FMSoft Technologies Co., Ltd.
|
|
* Copyright (C) 1998~2002, WEI Yongming
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Or,
|
|
*
|
|
* As this program is a library, any link to this program must follow
|
|
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
|
* GPLv3, you need to be licensed from FMSoft.
|
|
*
|
|
* If you have got a commercial license of this program, please use it
|
|
* under the terms and conditions of the commercial license.
|
|
*
|
|
* For more information about the commercial license, please refer to
|
|
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
|
|
*/
|
|
/*
|
|
** random.c: the random IAL Engine.
|
|
**
|
|
** Created by WEI Yongming, 2005/06/08
|
|
**
|
|
** Enhanced by WEI Yongming to support extra input events in June, 2019.
|
|
**
|
|
** The MiniGUI runtime configuration key `random.logfile` specifies
|
|
** the log file which will store the input events generated by this engine.
|
|
** If MiniGUI failed to open the log file, the log feature will be disabled.
|
|
**
|
|
** The MiniGUI runtime configuration key `random.eventtypes` specifies
|
|
** the input event types which will be generated by this IAL engine,
|
|
** in the following pattern:
|
|
**
|
|
** <event-type>[-<event-type>]*
|
|
**
|
|
** The <event-type> can be one of the following values:
|
|
**
|
|
** - mouse: mouse.
|
|
** - keyboard: keyboard.
|
|
** - button: buttons.
|
|
** - single_touch: touch pen or single touch panel.
|
|
** - multi_touch: multiple touch panel.
|
|
** - gesture: gesture.
|
|
** - tablet_tool: tablet tool.
|
|
** - tablet_pad: tablet pad.
|
|
** - switch: switch.
|
|
**
|
|
** The MiniGUI ETC key `random.minkeycode` specifies the minimal key code
|
|
** which can be generated by the engine if `keyboard` is included.
|
|
**
|
|
** 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
//#define _DEBUG
|
|
#include "common.h"
|
|
|
|
#ifdef _MGIAL_RANDOM
|
|
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "minigui.h"
|
|
#include "misc.h"
|
|
#include "ial.h"
|
|
#include "random.h"
|
|
|
|
#define BTN_NONE 0
|
|
|
|
#ifdef __LINUX__
|
|
#include <linux/input-event-codes.h>
|
|
#else
|
|
#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;
|
|
};
|
|
|
|
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 {
|
|
BUTTON_STATE_RELEASED,
|
|
BUTTON_STATE_PRESSED,
|
|
};
|
|
|
|
enum _key_state {
|
|
KEY_STATE_RELEASED,
|
|
KEY_STATE_PRESSED,
|
|
};
|
|
|
|
/* 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 {
|
|
MOUSE_OP_IDLE = 0,
|
|
MOUSE_OP_MOVE,
|
|
MOUSE_OP_CLICK,
|
|
MOUSE_OP_PRESSED_MOVE,
|
|
MOUSE_OP_WHEEL,
|
|
MOUSE_OP_COUNT,
|
|
};
|
|
|
|
struct _mouse_event_machine {
|
|
struct _mouse_event event;
|
|
enum _mouse_op_type op_type;
|
|
int op_sec;
|
|
time_t op_start;
|
|
|
|
uint32_t btn_sel;
|
|
uint32_t btn_down;
|
|
};
|
|
|
|
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));
|
|
|
|
return machine;
|
|
}
|
|
|
|
static void stop_event_machine_mouse(void* machine)
|
|
{
|
|
if (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 =
|
|
(struct _mouse_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 % MOUSE_OP_COUNT;
|
|
my_machine->op_sec = random() % 5 + 1;
|
|
my_machine->op_start = time(NULL);
|
|
|
|
switch (now % 5) {
|
|
case 0:
|
|
my_machine->btn_sel = BTN_RIGHT;
|
|
break;
|
|
case 1:
|
|
my_machine->btn_sel = BTN_MIDDLE;
|
|
break;
|
|
default: /* 60% possibility to choose the left button. */
|
|
my_machine->btn_sel = BTN_LEFT;
|
|
break;
|
|
}
|
|
|
|
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 MOUSE_OP_IDLE:
|
|
my_machine->event.event.type = RANDOM_EVENT_WAIT;
|
|
break;
|
|
|
|
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;
|
|
break;
|
|
|
|
case MOUSE_OP_CLICK:
|
|
if (my_machine->btn_down == BTN_NONE) {
|
|
my_machine->btn_down = my_machine->btn_sel;
|
|
|
|
my_machine->event.event.type = RANDOM_EVENT_MOUSE_BUTTON;
|
|
my_machine->event.button = my_machine->btn_down;
|
|
my_machine->event.state = BUTTON_STATE_PRESSED;
|
|
}
|
|
else {
|
|
my_machine->event.event.type = RANDOM_EVENT_MOUSE_BUTTON;
|
|
my_machine->event.button = my_machine->btn_down;
|
|
my_machine->event.state = BUTTON_STATE_RELEASED;
|
|
|
|
my_machine->btn_down = BTN_NONE;
|
|
}
|
|
break;
|
|
|
|
case MOUSE_OP_PRESSED_MOVE:
|
|
if (my_machine->btn_down == BTN_NONE) {
|
|
my_machine->btn_down = my_machine->btn_sel;
|
|
|
|
my_machine->event.event.type = RANDOM_EVENT_MOUSE_BUTTON;
|
|
my_machine->event.button = my_machine->btn_down;
|
|
my_machine->event.state = BUTTON_STATE_PRESSED;
|
|
}
|
|
else if ((GetTickCount() % 5) == 0) {
|
|
my_machine->event.event.type = RANDOM_EVENT_MOUSE_BUTTON;
|
|
my_machine->event.button = my_machine->btn_down;
|
|
my_machine->event.state = BUTTON_STATE_RELEASED;
|
|
|
|
my_machine->btn_down = BTN_NONE;
|
|
}
|
|
else {
|
|
my_machine->event.event.type = RANDOM_EVENT_MOUSE_MOTION;
|
|
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;
|
|
};
|
|
|
|
static 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;
|
|
int nr_down;
|
|
};
|
|
|
|
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_pressed_count(struct _button_event_machine* machine)
|
|
{
|
|
int i, n = 0;
|
|
|
|
for (i = 0; i < MAX_PRESSED_BTNS; i++) {
|
|
if (machine->pressed_btns[i]) {
|
|
n++;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
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;
|
|
my_machine->pressed_btns[idx] = 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;
|
|
my_machine->pressed_btns[idx] = BTN_NONE;
|
|
}
|
|
}
|
|
|
|
my_machine->event.nr_down = button_pressed_count(my_machine);
|
|
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;
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
ret:
|
|
return &my_machine->event.event;
|
|
}
|
|
|
|
static inline const
|
|
struct _stouch_event* get_stouch_event(const struct _random_event* event)
|
|
{
|
|
if (event->type != RANDOM_EVENT_STOUCH_MOTION &&
|
|
event->type != RANDOM_EVENT_STOUCH_DOWN &&
|
|
event->type != RANDOM_EVENT_STOUCH_UP)
|
|
return NULL;
|
|
|
|
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() % 100) - 50;
|
|
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;
|
|
my_machine->event.scale = (random() % 1000) + 1;
|
|
if (my_machine->event.scale == 0)
|
|
my_machine->event.scale = 1;
|
|
|
|
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_resume_event_machine resume_machine;
|
|
op_generate_event generate_event;
|
|
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,
|
|
},
|
|
{ "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",
|
|
},
|
|
};
|
|
|
|
static struct _random_input_context my_ctxt;
|
|
|
|
static void mouse_setrange (int newminx, int newminy, int newmaxx, int newmaxy)
|
|
{
|
|
my_ctxt.min_x = newminx;
|
|
my_ctxt.max_x = newmaxx;
|
|
my_ctxt.min_y = newminy;
|
|
my_ctxt.max_y = newmaxy;
|
|
|
|
my_ctxt.mouse_x = (my_ctxt.min_x + my_ctxt.max_x) / 2;
|
|
my_ctxt.mouse_y = (my_ctxt.min_y + my_ctxt.max_y) / 2;
|
|
}
|
|
|
|
static void mouse_setxy (int newx, int newy)
|
|
{
|
|
if (newx < my_ctxt.min_x)
|
|
newx = my_ctxt.min_x;
|
|
if (newx > my_ctxt.max_x)
|
|
newx = my_ctxt.max_x;
|
|
if (newy < my_ctxt.min_y)
|
|
newy = my_ctxt.min_y;
|
|
if (newy > my_ctxt.max_y)
|
|
newy = my_ctxt.max_y;
|
|
|
|
if (newx == my_ctxt.mouse_x && newy == my_ctxt.mouse_y)
|
|
return;
|
|
|
|
my_ctxt.mouse_x = newx;
|
|
my_ctxt.mouse_x = newy;
|
|
}
|
|
|
|
static int mouse_update(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void mouse_getxy (int* x, int* y)
|
|
{
|
|
*x = my_ctxt.mouse_x;
|
|
*y = my_ctxt.mouse_y;
|
|
}
|
|
|
|
static int mouse_getbutton(void)
|
|
{
|
|
return my_ctxt.mouse_button;
|
|
}
|
|
|
|
static int keyboard_update(void)
|
|
{
|
|
if (my_ctxt.last_keycode == 0)
|
|
return 0;
|
|
|
|
return my_ctxt.last_keycode + 1;
|
|
}
|
|
|
|
static const char* keyboard_getstate(void)
|
|
{
|
|
return my_ctxt.kbd_state;
|
|
}
|
|
|
|
static void normalize_mouse_pos(int* new_x, int* new_y)
|
|
{
|
|
if (*new_x < my_ctxt.min_x)
|
|
*new_x = my_ctxt.min_x;
|
|
if (*new_x > my_ctxt.max_x)
|
|
*new_x = my_ctxt.max_x;
|
|
if (*new_y < my_ctxt.min_y)
|
|
*new_y = my_ctxt.min_y;
|
|
if (*new_y > my_ctxt.max_y)
|
|
*new_y = my_ctxt.max_y;
|
|
}
|
|
|
|
static BOOL on_mouse_moved (int dx, int 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 (int x, int 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;
|
|
}
|
|
|
|
static BOOL on_mouse_button_changed (uint32_t button,
|
|
enum _button_state state)
|
|
{
|
|
int old_mouse_button = my_ctxt.mouse_button;
|
|
|
|
switch (button) {
|
|
case BTN_LEFT:
|
|
if (state == BUTTON_STATE_RELEASED)
|
|
my_ctxt.mouse_button &= ~IAL_MOUSE_LEFTBUTTON;
|
|
else
|
|
my_ctxt.mouse_button |= IAL_MOUSE_LEFTBUTTON;
|
|
break;
|
|
|
|
case BTN_RIGHT:
|
|
if (state == BUTTON_STATE_RELEASED)
|
|
my_ctxt.mouse_button &= ~IAL_MOUSE_RIGHTBUTTON;
|
|
else
|
|
my_ctxt.mouse_button |= IAL_MOUSE_RIGHTBUTTON;
|
|
break;
|
|
|
|
case BTN_MIDDLE:
|
|
if (state == BUTTON_STATE_RELEASED)
|
|
my_ctxt.mouse_button &= ~IAL_MOUSE_MIDDLEBUTTON;
|
|
else
|
|
my_ctxt.mouse_button |= IAL_MOUSE_MIDDLEBUTTON;
|
|
break;
|
|
|
|
default:
|
|
// not a standard mouse button.
|
|
return FALSE;
|
|
}
|
|
|
|
_DBG_PRINTF("%s: new mouse button: 0x%x (old: 0x%x)\n",
|
|
__FUNCTION__, my_ctxt.mouse_button, old_mouse_button);
|
|
if (old_mouse_button == my_ctxt.mouse_button)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const
|
|
struct _random_event* get_random_event(struct _random_input_context* ctxt)
|
|
{
|
|
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)
|
|
{
|
|
const struct _random_event *event;
|
|
int retval;
|
|
|
|
event = get_random_event(&my_ctxt);
|
|
if (event == NULL) {
|
|
retval = select (maxfd + 1, in, out, except, timeout);
|
|
if (retval >= 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* 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 = btn_event->nr_down;
|
|
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;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_SWIPE_BEGIN: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_SWIPE_BEGIN;
|
|
extra->wparam = my_event->nr_figs;
|
|
extra->lparam = 0;
|
|
retval = IAL_EVENT_EXTRA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_SWIPE_UPDATE: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_SWIPE_UPDATE;
|
|
extra->wparam = my_event->nr_figs;
|
|
extra->lparam = MAKELONG(my_event->dx, my_event->dy);
|
|
retval = IAL_EVENT_EXTRA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_SWIPE_END: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_SWIPE_END;
|
|
extra->wparam = my_event->nr_figs;
|
|
extra->lparam = my_event->is_cancelled;
|
|
retval = IAL_EVENT_EXTRA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_PINCH_BEGIN: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_PINCH_BEGIN;
|
|
extra->wparam = my_event->nr_figs;
|
|
extra->lparam = my_event->scale;
|
|
retval = IAL_EVENT_EXTRA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_PINCH_UPDATE: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_PINCH_UPDATE;
|
|
extra->wparam = MAKELONG(my_event->scale, my_event->da);
|
|
extra->lparam = MAKELONG(my_event->dx, my_event->dy);
|
|
retval = IAL_EVENT_EXTRA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case RANDOM_EVENT_GESTURE_PINCH_END: {
|
|
const struct _gesture_event* my_event;
|
|
|
|
my_event = get_gesture_event(event);
|
|
if (my_event) {
|
|
extra->event = IAL_EVENT_GESTURE_PINCH_END;
|
|
extra->wparam = my_event->nr_figs;
|
|
extra->lparam = my_event->is_cancelled;
|
|
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
|
|
|
|
BOOL ial_InitRandomInput (INPUT* input, const char* mdev, const char* mtype)
|
|
{
|
|
char logfile[MAX_PATH + 1];
|
|
char eventtypes[LEN_EVENT_TYPES + 1];
|
|
int i;
|
|
|
|
if (GetMgEtcValue ("random", "logfile", logfile, MAX_PATH) == ETC_OK) {
|
|
my_ctxt.log_fp = fopen(logfile, "a");
|
|
if (my_ctxt.log_fp == NULL) {
|
|
_WRN_PRINTF("Failed to open file %s for logging; log disabled\n",
|
|
logfile);
|
|
}
|
|
}
|
|
else {
|
|
_WRN_PRINTF("No log file defined; log disabled\n");
|
|
}
|
|
|
|
if (GetMgEtcValue ("random", "eventtypes", eventtypes, LEN_EVENT_TYPES) < 0) {
|
|
_WRN_PRINTF("Bad ETC key value: random.eventtypes; use default: mouse\n");
|
|
strcpy(eventtypes, "mouse");
|
|
}
|
|
|
|
my_ctxt.nr_machines = 0;
|
|
for (i = 0; i < TABLESIZE(event_state_machines); i++) {
|
|
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\n",
|
|
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\n",
|
|
MAX_SCANCODE);
|
|
my_ctxt.max_keycode = MAX_SCANCODE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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\n",
|
|
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\n",
|
|
MAX_BTNCODE);
|
|
my_ctxt.max_btncode = MAX_BTNCODE;
|
|
}
|
|
}
|
|
|
|
if (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,
|
|
my_ctxt.esm[my_ctxt.nr_machines]->machine);
|
|
my_ctxt.nr_machines++;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
input->set_mouse_xy = mouse_setxy;
|
|
input->get_mouse_button = mouse_getbutton;
|
|
input->set_mouse_range = mouse_setrange;
|
|
input->suspend_mouse= NULL;
|
|
input->resume_mouse = NULL;
|
|
|
|
input->update_keyboard = keyboard_update;
|
|
input->get_keyboard_state = keyboard_getstate;
|
|
input->suspend_keyboard = NULL;
|
|
input->resume_keyboard = NULL;
|
|
input->set_leds = NULL;
|
|
input->wait_event_ex = wait_event_ex;
|
|
|
|
srand (__mg_os_get_random_seed ());
|
|
return TRUE;
|
|
}
|
|
|
|
void TermRandomInput (void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < TABLESIZE(event_state_machines); i++) {
|
|
if (my_ctxt.esm[i]->machine) {
|
|
if (my_ctxt.esm[i]->stop_machine)
|
|
my_ctxt.esm[i]->stop_machine(my_ctxt.esm[i]->machine);
|
|
else
|
|
free (my_ctxt.esm[i]->machine);
|
|
|
|
my_ctxt.esm[i]->machine = NULL;
|
|
}
|
|
}
|
|
|
|
if (my_ctxt.log_fp) {
|
|
fclose(my_ctxt.log_fp);
|
|
my_ctxt.log_fp = NULL;
|
|
}
|
|
|
|
if (my_ctxt.kbd_state) {
|
|
free(my_ctxt.kbd_state);
|
|
my_ctxt.kbd_state = NULL;
|
|
}
|
|
}
|
|
|
|
#endif /* _MGIAL_RANDOM */
|
|
|