diff --git a/Makefile b/Makefile index 9ce7120..6fdf515 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,19 @@ -main: main.c - gcc -Wall main.c -lpthread -o DelayDaemon +TARGET = DelayDaemon + +CFLAGS = -Wall -pedantic -O3 -std=gnu11 $(shell pkg-config --cflags libevdev) +LDFLAGS = $(shell pkg-config --libs libevdev) +LIBS = -pthread -lm + +OBJECTS = \ + log.o \ + args.o \ + main.o + +$(TARGET) : $(OBJECTS) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +%.o : %.c + $(CC) $(CFLAGS) -o $@ -c $< + +clean : + rm -f $(TARGET) *.o diff --git a/README.md b/README.md index d05f434..1d2d2c2 100644 --- a/README.md +++ b/README.md @@ -5,41 +5,55 @@ It grabs all input events from the specified input device and blocks them from b A new virtual input device is created and grabbed events are passed to this device after a certain delay. It is possible to add a fixed delay to all events (by using the same value for **min** and **max**) or a range of possible delay times which leads to a distribution. -For now, only an even distribution is implemented. +Delays within range can distributed linearly or normally. The delays for click events and movement events can be set separately. Note that a varying delay for movement events leads to stuttering mouse movement. The delay times can also be changed during runtime using a FIFO. -## Usage: +This program must be run as superuser, unless your user has permissions to access uinput. +## Usage: +``` +DelayDaemon [OPTION...] + --input --min_key_delay --max_key_delay +``` ``` -DelayDaemon [event_handle] [min_delay_click] [max_delay_click] [min_delay_move] [max_delay_move] [fifo_path] +-0, --min_key_delay=NUM Minimum delay for keys/clicks +-1, --max_key_delay=NUM Maximum delay for keys/clicks +-2, --min_move_delay=NUM Minimum delay for mouse movement +-3, --max_move_delay=NUM Maximum delay for mouse movement +-d, --distribution[=STRING] [linear] (default) or [normal] distributed + random values +-f, --fifo[=FILE] path to the fifo file +-i, --input=FILE /dev/input/eventX +-m, --mean[=NUM] target mean value for normal distribution +-s, --std[=NUM] target standard distribution for normal + distribution +-v, --verbose turn on debug prints +-?, --help Give this help list + --usage Give a short usage message +-V, --version Print program version +``` +Example: +``` +sudo ./DelayDaemon -0 0 -1 100 -2 0 -3 200 -i /dev/input/event6 ``` - * **event_handle**: path to input device, e.g. `/dev/input/event5` - * **min_delay_click**: minimum delay to be added to mouse clicks (in milliseconds) - * **max_delay_click**: maximum delay to be added to mouse clicks (in milliseconds) - * **min_delay_move**: minimum delay to be added to mouse movement (in milliseconds) - * **max_delay_move**: maximum delay to be added to mouse movement (in milliseconds) - * **fifo_path**: path to a FIFO used to remotely set delay times during runtime (optional) +This will set each click delay to a random value between 0 and 100 and each mouse movement to a random value between 0 and 200 for the input device corresponding to event6. ## Remotely Controlling Delay Times -If **fifo_path** is set, a FIFO is created at this path. +If `--fifo` is set, a FIFO is created at this path. By writing into this FIFO (which can be done with normal file operations), delay times can be changed during runtime. The new values have to be written to the FIFO seperated by whitespaces and all four values have to be set. **Example:** ``` -./DelayDaemon /dev/input/event5 100 200 0 0 /tmp/delaydaemon +sudo ./DelayDaemon -i /dev/input/event6 -0 100 -1 200 -2 0 -3 0 -f /tmp/delaydaemon echo "200 300 0 0" > /tmp/delaydaemon ``` This would start the program with a click delay of 100-200 ms and then increase the delay to 200-300 ms. - -## Future Work: - - * add the possibility to use different distributions (like gaussian) diff --git a/args.c b/args.c new file mode 100644 index 0000000..12a91e1 --- /dev/null +++ b/args.c @@ -0,0 +1,101 @@ +#include "args.h" + +static char doc[] = + "DelayDaemon 1.1 -- A GNU/Linux tool to add (varying) latency to input devices\n" + "Run as superuser\n"; + +const char *argp_program_version = + "DelayDaemon 1.1"; + +static char args_doc[] = + "--input --min_key_delay --max_key_delay "; + +static struct argp_option options[] = +{ + {"input", 'i', "FILE", 0, "/dev/input/eventX"}, + {"min_key_delay", '0', "NUM", 0, "Minimum delay for keys/clicks"}, + {"max_key_delay", '1', "NUM", 0, "Maximum delay for keys/clicks"}, + {"min_move_delay", '2', "NUM", 0, "Minimum delay for mouse movement"}, + {"max_move_delay", '3', "NUM", 0, "Maximum delay for mouse movement"}, + {"distribution", 'd', "STRING", OPTION_ARG_OPTIONAL, "[linear] (default) or [normal] distributed random values"}, + {"mean", 'm', "NUM", OPTION_ARG_OPTIONAL, "target mean value for normal distribution"}, + {"std", 's', "NUM", OPTION_ARG_OPTIONAL, "target standard distribution for normal distribution"}, + {"fifo", 'f', "FILE", OPTION_ARG_OPTIONAL, "path to the fifo file"}, + {"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, "turn on debug prints"}, + {0} +}; + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct arguments *args = state->input; + + switch (key) { + case 'i': + args->device_file = arg; + break; + case '0': + args->min_key_delay = strtol(arg, NULL, 10); + break; + case '1': + args->max_key_delay = strtol(arg, NULL, 10); + break; + case '2': + args->min_move_delay = strtol(arg, NULL, 10); + break; + case '3': + args->max_move_delay = strtol(arg, NULL, 10); + break; + case 'd': + args->distribution = arg + 1; // skip the '=' character + break; + case 'm': + args->mean = strtol(arg, NULL, 10); + break; + case 's': + args->std = strtol(arg, NULL, 10); + break; + case 'f': + args->fifo_path = arg +1; + break; + case 'v': + args->verbose = 1; + break; + case ARGP_KEY_END: + + /* Check if file is specified. */ + if (args->device_file == NULL) + { + argp_state_help(state, stdout, ARGP_HELP_STD_HELP); + } + + if(args->min_key_delay > 0 && args->max_key_delay == 0) + { + args->max_key_delay = args->min_key_delay; + } + // set default values if none specified + if(strcmp(args->distribution, "normal") == 0) + { + if(args->mean == 0) args->mean = (args->max_key_delay + args->min_key_delay) / 2; + if(args->std == 0) args->std = args->mean / 10; + + if(args->mean > args->max_key_delay + || args->mean < args->min_key_delay + ||(args->mean > args->max_move_delay && args->max_move_delay > 0) // since move delay is optional and can be 0 + || args->mean < args->min_move_delay) + { + printf("Illegal value for mu. Average must be between min and max delay!\n"); + return 1; + } + } + break; + } + + return 0; +} + +error_t parse_args(int argc, char **argv, struct arguments *args) +{ + struct argp argp = {options, parse_opt, args_doc, doc}; + + return argp_parse(&argp, argc, argv, 0, 0, args); +} \ No newline at end of file diff --git a/args.h b/args.h new file mode 100644 index 0000000..5d09fe6 --- /dev/null +++ b/args.h @@ -0,0 +1,24 @@ +#ifndef _ARGS_H_ +#define _ARGS_H_ + +#include +#include +#include + +struct arguments +{ + char* device_file; + int min_key_delay; + int max_key_delay; + int min_move_delay; + int max_move_delay; + char* distribution; + float mean; + float std; + char* fifo_path; + int verbose; +}; + +error_t parse_args(int argc, char **argv, struct arguments *arg); + +#endif \ No newline at end of file diff --git a/log.c b/log.c new file mode 100644 index 0000000..92957d7 --- /dev/null +++ b/log.c @@ -0,0 +1,56 @@ +#include "log.h" + +const char* log_file = "event_log.csv"; + +// https://stackoverflow.com/a/3536261 +void init_vector(event_vector *ev, size_t size) +{ + ev->events = malloc(size * sizeof(delayed_event)); + ev->used = 0; + ev->size = size; +} + +void append_to_vector(event_vector *ev, delayed_event event) +{ + // upgrade allocated memory if necessary + if(ev->used >= ev->size) + { + ev->size *= 2; + ev->events = realloc(ev->events, ev->size * sizeof(delayed_event)); + } + ev->events[ev->used++] = event; +} + +void free_vector(event_vector *ev) +{ + free(ev->events); + ev->events = NULL; + ev->used = ev->size = 0; +} + +void write_event_log(event_vector *ev) +{ + // write header if file doesn't exist + if(access(log_file, F_OK) != 0) + { + FILE *file = fopen(log_file, "w+"); + const char* header = "timestamp;delay;type;value;code\n"; + fwrite(header, 1, strlen(header), file); + fclose(file); + } + + FILE *file = fopen(log_file, "a"); + for(int i=0; iused; ++i) + { + delayed_event evnt = ev->events[i]; + fprintf(file, + "%lu;%i;%i;%i;%i\n", + evnt.timestamp, + evnt.delay, + evnt.type, + evnt.value, + evnt.code); + } + fclose(file); + free_vector(ev); +} \ No newline at end of file diff --git a/log.h b/log.h new file mode 100644 index 0000000..db8662f --- /dev/null +++ b/log.h @@ -0,0 +1,30 @@ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include +#include +#include +#include + +typedef struct +{ + int type; // event type (e.g. key press, relative movement, ...) + int code; // event code (e.g. for key pressses the key/button code) + int value; // event value (e.g. 0/1 for button up/down, coordinates for absolute movement, ...) + int delay; // delay time for the event in milliseconds + unsigned long timestamp; // time the event occured +} delayed_event; + +typedef struct +{ + size_t size; + size_t used; + delayed_event* events; +} event_vector; + +void init_vector(event_vector *ev, size_t size); +void append_to_vector(event_vector *ev, delayed_event event); +void free_vector(event_vector *ev); +void write_event_log(event_vector *ev); + +#endif \ No newline at end of file diff --git a/main.c b/main.c index 4e2b3f1..890bc7c 100644 --- a/main.c +++ b/main.c @@ -1,86 +1,105 @@ // created by Andreas Schmid, 2019 -// this software is released into the public domain, do whatever you want with it +// edited by Thomas Fischer, 2022 +// partly based on evlag by Filip Aláč // -// Usage: latency_daemon [event_handle] [min_delay_move] [max_delay_move] [fifo_path] -// event_handle: path to input device you want to delay (e.g. /dev/input/event5) -// min_delay_click: minimum delay to be added to click events (in milliseconds) -// max_delay_click: maximum delay to be added to click events (in milliseconds) -// min_delay_move: minimum delay to be added to mouse movement (in milliseconds) -// max_delay_move: maximum delay to be added to mouse movement (in milliseconds) -// fifo_path: path to a FIFO used to remotely set delay times during runtime (optional) // Use the same value for min and max to achieve constant delays. -#include -#include #include -#include -#include -#include #include -#include #include #include #include -#include #include #include +#include +#include "args.h" +#include "log.h" +#include -// set to 1 for more verbose console output -#define DEBUG 0 +struct arguments args; +int DEBUG = 0; -typedef struct -{ - int fd; // file descriptor of the input device - int type; // event type (e.g. key press, relative movement, ...) - int code; // event code (e.g. for key pressses the key/button code) - int value; // event value (e.g. 0/1 for button up/down, coordinates for absolute movement, ...) - int delay; // delay time for the event in milliseconds -} delayed_event; - -int input_fd = -1; // actual input device -int virtual_fd = -1; // virtual device for delayed events -int fifo_fd = -1; // path to FIFO for remotely controlled delay times +event_vector ev; // vector of all input events char* event_handle; // event handle of the input event we want to add delay to (normally somewhere in /dev/input/) +int fifo_fd = -1; // path to FIFO for remotely controlled delay times char* fifo_path; pthread_t fifo_thread; // use attributes to create threads in a detached state -pthread_attr_t invoked_event_thread_attr; +pthread_attr_t invoked_event_thread_attr, log_delay_val_thread_attr; + +enum{ + linear, + normal +} distribution; + +// normal distribution variables +double mu = -1.0; +double sigma = -1.0; -// delay range for mouse clicks -int min_delay_click = -1; -int max_delay_click = -1; +// delay range for key events +int min_delay_key = -1; +int max_delay_key = -1; // delay range for mouse movement // note that variance here causes the movement to stutter int min_delay_move = -1; int max_delay_move = -1; +struct libevdev *event_dev = NULL; +struct libevdev *uinput_dev = NULL; +int polling_rate = 8192; + +// returns a normally distributed value around an average mu with std sigma +// source: https://phoxis.org/2013/05/04/generating-random-numbers-from-normal-distribution-in-c/ +int randn (double mu, double sigma) +{ + double U1, U2, W, mult; + static double X1, X2; + static int call = 0; + + if (call == 1) + { + call = !call; + return (mu + sigma * (double) X2); + } + + do + { + U1 = -1 + ((double) rand () / RAND_MAX) * 2; + U2 = -1 + ((double) rand () / RAND_MAX) * 2; + W = pow (U1, 2) + pow (U2, 2); + } + while (W >= 1 || W == 0); + + mult = sqrt ((-2 * log (W)) / W); + X1 = U1 * mult; + X2 = U2 * mult; + + call = !call; + + return (mu + sigma * (double) X1); +} + // generate a delay time for an input event // this function uses a linear distribution between min_delay_move and max_delay_move // other distributions (e.g. gaussian) may be added in the future int calculate_delay(int min, int max) { if(min == max) return min; // add constant delay if no range is specified - else return min + (rand() % (max - min)); -} - -// creates an input event for the specified device -// source: https://www.kernel.org/doc/html/v4.12/input/uinput.html -void emit(int fd, int type, int code, int val) -{ - struct input_event ie; - - ie.type = type; - ie.code = code; - ie.value = val; - - ie.time.tv_sec = 0; - ie.time.tv_usec = 0; - - write(fd, &ie, sizeof(ie)); + else if(distribution == linear) return min + (rand() % (max - min)); + else if(distribution == normal) + { + int x = -1; + while(x < min || x > max) + { + x = randn(mu, sigma); + } + return x; + } + else return 0; } // wait for some time, then emit an input event to a virtual input device @@ -88,21 +107,18 @@ void *invoke_delayed_event(void *args) { delayed_event *event = args; - int eventFd = event->fd; - int eventType = event->type; - int eventCode = event->code; - int eventValue = event->value; - int eventDelay = event->delay; + usleep(event->delay * 1000); // wait for the specified delay time (in milliseconds) - free(event); + int rc = libevdev_uinput_write_event( + uinput_dev, event->type, + event->code, event->value); - usleep(eventDelay * 1000); // wait for the specified delay time (in milliseconds) + if(rc != 0) printf("Failed to write uinput event: %s\n", strerror(-rc)); - emit(eventFd, eventType, eventCode, eventValue); // this is the actual delayed input event (eg. mouse move or click) - emit(eventFd, EV_SYN, SYN_REPORT, 0); // EV_SYN events have to come in time so we trigger them manually + rc = libevdev_uinput_write_event(uinput_dev, EV_SYN, SYN_REPORT, 0); pthread_exit(NULL); -} +} // thread to handle external modification of delay times using a FIFO void *handle_fifo(void *args) @@ -110,7 +126,7 @@ void *handle_fifo(void *args) char buffer[80]; // needed so we don't lose our old delay times in case something goes wrong - int buffer_min_delay_click, buffer_max_delay_click, buffer_min_delay_move, buffer_max_delay_move; + int buffer_min_delay_key, buffer_max_delay_key, buffer_min_delay_move, buffer_max_delay_move; while(1) { @@ -121,19 +137,19 @@ void *handle_fifo(void *args) // parse new values from the FIFO // only set the delay times if all four values could be read correctly - if(sscanf(buffer, "%d %d %d %d", &buffer_min_delay_click, &buffer_max_delay_click, &buffer_min_delay_move, &buffer_max_delay_move) == 4) + if(sscanf(buffer, "%d %d %d %d", &buffer_min_delay_key, &buffer_max_delay_key, &buffer_min_delay_move, &buffer_max_delay_move) == 4) { // set delay times - min_delay_click = buffer_min_delay_click; - max_delay_click = buffer_max_delay_click; + min_delay_key = buffer_min_delay_key; + max_delay_key = buffer_max_delay_key; min_delay_move = buffer_min_delay_move; max_delay_move = buffer_max_delay_move; // make sure max >= min - if(max_delay_click < min_delay_click) max_delay_click = min_delay_click; + if(max_delay_key < min_delay_key) max_delay_key = min_delay_key; if(max_delay_move < min_delay_move) max_delay_move = min_delay_move; - if(DEBUG) printf("set new values: %d %d %d %d\n", min_delay_click, max_delay_click, min_delay_move, max_delay_move); + if(DEBUG) printf("set new values: %d %d %d %d\n", min_delay_key, max_delay_key, min_delay_move, max_delay_move); } else { @@ -146,7 +162,7 @@ void *handle_fifo(void *args) // create a FIFO for inter process communication at the path defined by the 6th command line parameter (recommended: somewhere in /tmp) // this can be used to adjust the delay values with an external program during runtime -// simply write (or echo) four numbers (min_delay_click max_delay_click min_delay_move max_delay move) separated by whitespaces into the FIFO +// simply write (or echo) four numbers (min_delay_key max_delay_key min_delay_move max_delay move) separated by whitespaces into the FIFO int init_fifo() { unlink(fifo_path); // unlink the FIFO if it already exists @@ -159,152 +175,179 @@ int init_fifo() return 1; } +// open the input device we want to "enhance" with delay +int init_input_device() +{ + /* Open device. */ + int fd_event = open(event_handle, O_RDONLY); + if (fd_event < 0) + { + perror("Failed to open input device"); + exit(EXIT_FAILURE); + } + + /* Create libevdev device and grab it. */ + if (libevdev_new_from_fd(fd_event, &event_dev) < 0) + { + perror("Failed to init libevdev"); + exit(EXIT_FAILURE); + } + + if (libevdev_grab(event_dev, LIBEVDEV_GRAB) < 0) + { + perror("Failed to grab device"); + exit(EXIT_FAILURE); + } + + return 1; +} + // create a virtual input device // this device is used to trigger delayed input events -// source: https://www.kernel.org/doc/html/v4.12/input/uinput.html +// source: https://www.freedesktop.org/software/libevdev/doc/latest/group__uinput.html#gaf14b21301bac9d79c20e890172873b96 int init_virtual_input() { - struct uinput_setup usetup; - - virtual_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); - - if(!virtual_fd) + /* Create uinput clone of device. */ + int fd_uinput = open("/dev/uinput", O_WRONLY); + if (fd_uinput < 0) { - printf("Error - Could not open virtual device\n"); - return 0; - } + perror("Failed to open uinput device"); + exit(EXIT_FAILURE); + } - // enable mouse buttons and relative events - // for devices other than mice, change this block - // possible events of input devices can be found using the program evtest - // the meaning of those key codes can be found here: https://www.kernel.org/doc/html/v4.15/input/event-codes.html - ioctl(virtual_fd, UI_SET_EVBIT, EV_KEY); - ioctl(virtual_fd, UI_SET_KEYBIT, BTN_LEFT); - ioctl(virtual_fd, UI_SET_KEYBIT, BTN_RIGHT); - - ioctl(virtual_fd, UI_SET_EVBIT, EV_REL); - ioctl(virtual_fd, UI_SET_RELBIT, REL_X); - ioctl(virtual_fd, UI_SET_RELBIT, REL_Y); - ioctl(virtual_fd, UI_SET_RELBIT, REL_WHEEL); - - // some metadata for the input device... - memset(&usetup, 0, sizeof(usetup)); - usetup.id.bustype = BUS_USB; - usetup.id.vendor = 0x1234; // sample vendor - usetup.id.product = 0x5678; // sample product - strcpy(usetup.name, "DelayDaemon"); - - // actually create the device... - ioctl(virtual_fd, UI_DEV_SETUP, &usetup); - ioctl(virtual_fd, UI_DEV_CREATE); + if (libevdev_uinput_create_from_device(event_dev, fd_uinput, &uinput_dev) < 0) + { + perror("Failed to create uinput device"); + exit(EXIT_FAILURE); + } return 1; } -// open the input device we want to "enhance" with delay -int init_input_device() +// get the next input event from libevdev +int get_event(struct input_event *event) { - if(DEBUG) printf("input event: %s\n", event_handle); + struct timeval current_time; + gettimeofday(¤t_time, NULL); - input_fd = open(event_handle, O_RDONLY | O_NONBLOCK); + int rc = LIBEVDEV_READ_STATUS_SUCCESS; - if(DEBUG) printf("input device fd: %d\n", input_fd); + rc = libevdev_next_event(event_dev, + LIBEVDEV_READ_FLAG_NORMAL | + LIBEVDEV_READ_FLAG_BLOCKING, event); - if(!input_fd) + /* Handle dropped SYN. */ + if (rc == LIBEVDEV_READ_STATUS_SYNC) { - printf("Error - Device not found: %d\n", input_fd); - return 0; - } + printf("Warning, syn dropped: (%d) %s\n", -rc, strerror(-rc)); - // this line reserves the device for this program so its events do not arrive at other applications - ioctl(input_fd, EVIOCGRAB, 1); + while (rc == LIBEVDEV_READ_STATUS_SYNC) + { + rc = libevdev_next_event(event_dev, + LIBEVDEV_READ_FLAG_SYNC, event); + } + } + if (rc == -ENODEV) + { + printf("Device disconnected: (%d) %s\n", -rc, strerror(-rc)); + return -1; + } return 1; } // make sure to clean up when the program ends void onExit(int signum) { + printf("\n"); + write_event_log(&ev); + // end inter process communication pthread_cancel(fifo_thread); unlink(fifo_path); - // close virtual input device - ioctl(virtual_fd, UI_DEV_DESTROY); - close(virtual_fd); - exit(EXIT_SUCCESS); } int main(int argc, char* argv[]) { signal(SIGINT, onExit); - - // check arguments - // event_handle is mandatory - // if only one delay value is passed, the added delay is constant - if(argc <= 2) - { - printf("Too few arguments!\n" - "Usage: latency_daemon [event_handle] [min_delay_move] [max_delay_move] [fifo_path]\n" - "event_handle: path to input device you want to delay (e.g. /dev/input/event5)\n" - "min_delay_click: minimum delay to be added to click events (in milliseconds)\n" - "max_delay_click: maximum delay to be added to click events (in milliseconds)\n" - "min_delay_move: minimum delay to be added to mouse movement (in milliseconds)\n" - "max_delay_move: maximum delay to be added to mouse movement (in milliseconds)\n" - "fifo_path: path to a FIFO used to remotely set delay times during runtime (optional)\n" - "Use the same value for min and max to achieve constant delays.\n"); - return 1; - } - - event_handle = argv[1]; - + // defaults + args.device_file = NULL; + args.min_key_delay = 0; + args.max_key_delay = 0; + args.min_move_delay = 0; + args.max_move_delay = 0; + args.fifo_path = NULL; + args.distribution = ""; + + if (parse_args(argc, argv, &args) < 0) { + perror("Failed to parse arguments"); + exit(EXIT_FAILURE); + } + + // set global variables + event_handle = args.device_file; + min_delay_key = args.min_key_delay; + max_delay_key = args.max_key_delay; + min_delay_move = args.min_move_delay; + max_delay_move = args.max_move_delay; + mu = args.mean; + sigma = args.std; + if(strcmp(args.distribution, "normal") == 0) distribution = normal; + else distribution = linear; + if(args.fifo_path) fifo_path = args.fifo_path; + DEBUG = args.verbose; + + // prevents Keydown events for KEY_Enter from never being released when grabbing the input device + // after running the program in a terminal by pressing Enter + // https://stackoverflow.com/questions/41995349 + sleep(1); + + init_vector(&ev, 10); if(!init_input_device()) return 1; if(!init_virtual_input()) return 1; - - if(sscanf(argv[2], "%d", &min_delay_click) == EOF) min_delay_click = 0; - if(sscanf(argv[3], "%d", &max_delay_click) == EOF) max_delay_click = min_delay_click; - if(sscanf(argv[4], "%d", &min_delay_move) == EOF) min_delay_move = 0; - if(sscanf(argv[5], "%d", &max_delay_move) == EOF) max_delay_move = min_delay_move; - - // path to a FIFO to enable inter process communication for remotely controlling the delay times (optional) - if(argc > 6) + if(fifo_path != NULL && fifo_path[0] != '\0') { - fifo_path = argv[6]; if(!init_fifo()) return 1; } - if(DEBUG) printf("click delay: %d - %d\nmove delay: %d - %d\n", min_delay_click, max_delay_click, min_delay_move, max_delay_move); + if(distribution==normal && DEBUG) printf("Normal distribution: mean: %lf, std: %lf\n", mu, sigma); - srand(time(0)); + if(DEBUG) printf("key delay: %d - %d\nmove delay: %d - %d\n", min_delay_key, max_delay_key, min_delay_move, max_delay_move); - struct input_event inputEvent; - int err = -1; + srand(time(0)); pthread_attr_setdetachstate(&invoked_event_thread_attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setdetachstate(&log_delay_val_thread_attr, PTHREAD_CREATE_DETACHED); // wait for new input events of the actual device // when new event arrives, generate a delay value and create a thread waiting for this delay time // the thread then generates an input event for a virtual input device // note EV_SYN events are NOT delayed, they are automatically generated when the delayed event is executed + struct input_event inputEvent; + int err = -1; + while(1) { - err = read(input_fd, &inputEvent, sizeof(struct input_event)); - if(err > -1 && inputEvent.type != EV_SYN && inputEvent.type != EV_MSC) // I have no idea what EV_MSC is but it freezes the application (MSC_SCAN!) when moving fast - { + err = get_event(&inputEvent); + if(err > -1 && inputEvent.type != EV_SYN && inputEvent.type != EV_MSC) + { delayed_event *event = malloc(sizeof(delayed_event)); - event->fd = virtual_fd; event->type = inputEvent.type; event->code = inputEvent.code; event->value = inputEvent.value; - if(inputEvent.type == EV_KEY) event->delay = calculate_delay(min_delay_click, max_delay_click); + if(inputEvent.type == EV_KEY) event->delay = calculate_delay(min_delay_key, max_delay_key); else if(inputEvent.type == EV_REL) event->delay = calculate_delay(min_delay_move, max_delay_move); pthread_t delayed_event_thread; - pthread_create(&delayed_event_thread, &invoked_event_thread_attr, invoke_delayed_event, event); + pthread_create(&delayed_event_thread, &invoked_event_thread_attr, invoke_delayed_event, event); + + event->timestamp = inputEvent.time.tv_sec * 1000 + inputEvent.time.tv_usec / 1000; + append_to_vector(&ev, *event); } } - + return 0; }