Files
MiniGUI/src/ial/random.c
T

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 */