diff --git a/config_functions.h b/config_functions.h index 60b795d..acd467c 100644 --- a/config_functions.h +++ b/config_functions.h @@ -1,6 +1,15 @@ #ifndef H_CONFIG_FUNCTIONS #define H_CONFIG_FUNCTIONS +#define ADD_INPUT_PATH(INPUT_PATH, NUM) \ + /* Open input and uinput */ \ + in[NUM] = open(INPUT_PATH, O_RDONLY); \ + if(in[NUM] < 0) { \ + perror("Could not open: " INPUT_PATH); \ + return 1; \ + } + + #define JOYSTICK_SET_OPT(opt, bit, device) \ if (device == j) { \ if (ioctl(js[device], bit, opt) < 0) { \ diff --git a/confs/mouse_map.h b/confs/mouse_map.h index 6c32cef..902000e 100644 --- a/confs/mouse_map.h +++ b/confs/mouse_map.h @@ -6,11 +6,24 @@ /* Set up amount of joysticks here */ #define JOYCOUNT 1 -/* Set up event to read from */ -#define INPUT_PATH "/dev/input/by-path/platform-i8042-serio-0-event-kbd" +/* Set up amount of input devices here */ +#define INPUT_DEVICE_COUNT 1 #endif +/* -------------------------------------------------------------------------- */ +/* ------------------- FIRST AND A HALF SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifdef H_CONFIGURE_EVENTS +#ifndef H_CONFIGURE_EVENTS_SEEN +#define H_CONFIGURE_EVENTS_SEEN + +ADD_INPUT_PATH("/dev/input/by-path/platform-i8042-serio-0-event-kbd", 0) + +#endif +#endif + /* -------------------------------------------------------------------------- */ /* ----------------------------- SECOND SECTION ----------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/confs/mulitput.h b/confs/mulitput.h new file mode 100644 index 0000000..6a7f64d --- /dev/null +++ b/confs/mulitput.h @@ -0,0 +1,192 @@ +/* + * Copyright Merlijn Wajer 2012 + * + * This is the uinput-mapper configuration file. + * + * We are still working out all the details, but it basically boils down to the + * following: You write the configuration entirely in the C preprocessor by + * adding the right commands (macros) to the right sections. + * + * + * As of now, there are three sections: + * + * - GLOBAL_MAP; + * This is where you set the amount of devices to be emulated (currently + * called JOYCOUNT) and the INPUT_PATH. + * + * - CONFIGURE_JOYSTICKS: + * This is where you tell uinput-mapper what buttons your new joysticks (or + * other devices) should expose. Any button not exposed here will never be + * send. + * + * Macros that make sense to use here: + * - JOYSTICK_SET_OPT(, , ) + * - JOYSTICK_ADD_KEY(, , ) + * - JOYSTICK_SET_LIM(, , ) + * + * JOYSTICK_SET_LIM is mostly used for ABS_HATs. + * + * - JOYMAP: + * + * Set the key mappings here. + * + * Macros that make sense here: + * - KEYMAP(, , , , ) + * + * + * Notes: + * - To expose a joystick device, expose the BTN_JOYSTICK ``button'' with + * JOYSTICK_ADD_KEY + * - To expose a mouse device, expose (at least) the BTN_LEFT button with + * JOYSTICK_ADD_KEY + * + * ---------------------------------------------------------------------------- + * + * TODO: + * - For KEYMAPs, add parameter that species the INPUT_PATH to map from + * - Add support for multiple INPUT_PATH + * - Figure out more details. There's probably a lot missing. + * - Remove EV_KEY constraint in map.c and use it as arg to KEY_MAP + * + * ---------------------------------------------------------------------------- + */ + +#include "config_functions.h" + +/* -------------------------------------------------------------------------- */ +/* ----------------------------- FIRST SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifndef H_GLOBAL_MAP +#define H_GLOBAL_MAP + +/* Set up amount of joysticks here */ +#define JOYCOUNT 2 + +/* Set up amount of input devices here */ +#define INPUT_DEVICE_COUNT 2 + +#endif + +/* -------------------------------------------------------------------------- */ +/* ------------------- FIRST AND A HALF SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifdef H_CONFIGURE_EVENTS +#ifndef H_CONFIGURE_EVENTS_SEEN +#define H_CONFIGURE_EVENTS_SEEN + +ADD_INPUT_PATH("/dev/input/event4", 0) +ADD_INPUT_PATH("/dev/input/event5", 1) + +#endif +#endif + +/* -------------------------------------------------------------------------- */ +/* ----------------------------- SECOND SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifdef H_CONFIGURE_JOYSTICKS +#ifndef H_CONFIGURE_JOYSTICKS_SEEN +#define H_CONFIGURE_JOYSTICKS_SEEN + + +/* Configure first joystick. + * + * Here we just tell the program what keys event we will expose and what + * keys we want to use. + * + * If a key is not enabled here, it will never be passed. + */ + +/* We want to send ABS and KEY events */ +JOYSTICK_SET_OPT(EV_ABS, UI_SET_EVBIT, 0) +JOYSTICK_SET_OPT(EV_KEY, UI_SET_EVBIT, 0) + +/* Hats: + * We set the absmax and absmin; otherwise the hats make no sense. + */ +JOYSTICK_ADD_KEY(ABS_HAT0X, UI_SET_ABSBIT, 0) +JOYSTICK_SET_LIM(absmax, 1, ABS_HAT0X) +JOYSTICK_SET_LIM(absmin, -1, ABS_HAT0X) +JOYSTICK_ADD_KEY(ABS_HAT0Y, UI_SET_ABSBIT, 0) +JOYSTICK_SET_LIM(absmax, 1, ABS_HAT0Y) +JOYSTICK_SET_LIM(absmin, -1, ABS_HAT0Y) + +/* XXX: ALWAYS SET BTN_JOYSTICK TO EXPOSE A JOYSTICK DEVICE */ +JOYSTICK_ADD_KEY(BTN_JOYSTICK, UI_SET_KEYBIT, 0) + +/* Buttons. */ +JOYSTICK_ADD_KEY(BTN_0, UI_SET_KEYBIT, 0) +JOYSTICK_ADD_KEY(BTN_1, UI_SET_KEYBIT, 0) +JOYSTICK_ADD_KEY(BTN_2, UI_SET_KEYBIT, 0) +JOYSTICK_ADD_KEY(BTN_3, UI_SET_KEYBIT, 0) + +/* Second joystick ; same comments as first one */ +JOYSTICK_SET_OPT(EV_ABS, UI_SET_EVBIT, 1) +JOYSTICK_SET_OPT(EV_KEY, UI_SET_EVBIT, 1) + +JOYSTICK_ADD_KEY(ABS_HAT0X, UI_SET_ABSBIT, 1) +JOYSTICK_SET_LIM(absmax, 1, ABS_HAT0X) +JOYSTICK_SET_LIM(absmin, -1, ABS_HAT0X) + +JOYSTICK_ADD_KEY(ABS_HAT0Y, UI_SET_ABSBIT, 1) +JOYSTICK_SET_LIM(absmax, 1, ABS_HAT0X) +JOYSTICK_SET_LIM(absmin, -1, ABS_HAT0X) + +JOYSTICK_ADD_KEY(BTN_JOYSTICK, UI_SET_KEYBIT, 1) + +JOYSTICK_ADD_KEY(BTN_0, UI_SET_KEYBIT, 1) +JOYSTICK_ADD_KEY(BTN_1, UI_SET_KEYBIT, 1) +JOYSTICK_ADD_KEY(BTN_2, UI_SET_KEYBIT, 1) +JOYSTICK_ADD_KEY(BTN_3, UI_SET_KEYBIT, 1) + +#endif +#endif + +/* -------------------------------------------------------------------------- */ +/* ----------------------------- THIRD SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifdef H_JOYMAP +#ifndef H_JOYMAP_SEEN +#define H_JOYMAP_SEEN + +/* First joystick */ + +LEGAL_VALUE(e.value == 1 || e.value == 0, + /* HAT */ + KEYMAP(EV_KEY, KEY_UP, ABS_HAT0Y, EV_ABS, 0, -) + KEYMAP(EV_KEY, KEY_DOWN, ABS_HAT0Y, EV_ABS, 0, +) + KEYMAP(EV_KEY, KEY_LEFT, ABS_HAT0X, EV_ABS, 0, -) + KEYMAP(EV_KEY, KEY_RIGHT, ABS_HAT0X, EV_ABS, 0, +) + + /* Red buttons */ + KEYMAP(EV_KEY, KEY_LEFTCTRL, BTN_0, EV_KEY, 0, +) + KEYMAP(EV_KEY, KEY_LEFTALT, BTN_1, EV_KEY, 0, +) + KEYMAP(EV_KEY, KEY_SPACE, BTN_2, EV_KEY, 0, +) + + /* Yellow button */ + KEYMAP(EV_KEY, KEY_1, BTN_3, EV_KEY, 0, +) +) + +/* Second joystick */ + +LEGAL_VALUE(e.value == 1 || e.value == 0, + /* HAT */ + KEYMAP(EV_KEY, KEY_R, ABS_HAT0Y, EV_ABS, 1, -) + KEYMAP(EV_KEY, KEY_F, ABS_HAT0Y, EV_ABS, 1, +) + KEYMAP(EV_KEY, KEY_D, ABS_HAT0X, EV_ABS, 1, -) + KEYMAP(EV_KEY, KEY_G, ABS_HAT0X, EV_ABS, 1, +) + + /* Red buttons */ + KEYMAP(EV_KEY, KEY_A, BTN_0, EV_KEY, 1, +) + KEYMAP(EV_KEY, KEY_S, BTN_1, EV_KEY, 1, +) + KEYMAP(EV_KEY, KEY_Q, BTN_2, EV_KEY, 1, +) + + /* Yellow button */ + KEYMAP(EV_KEY, KEY_2, BTN_3, EV_KEY, 1, +) +) + +#endif +#endif diff --git a/confs/techinc_arcade.h b/confs/techinc_arcade.h index 8520dc9..3a86ff6 100644 --- a/confs/techinc_arcade.h +++ b/confs/techinc_arcade.h @@ -63,11 +63,24 @@ /* Set up amount of joysticks here */ #define JOYCOUNT 2 -/* Set up event to read from */ -#define INPUT_PATH "/dev/input/by-path/platform-i8042-serio-0-event-kbd" +/* Set up amount of input devices here */ +#define INPUT_DEVICE_COUNT 1 #endif +/* -------------------------------------------------------------------------- */ +/* ------------------- FIRST AND A HALF SECTION ----------------------------- */ +/* -------------------------------------------------------------------------- */ + +#ifdef H_CONFIGURE_EVENTS +#ifndef H_CONFIGURE_EVENTS_SEEN +#define H_CONFIGURE_EVENTS_SEEN + +ADD_INPUT_PATH("/dev/input/by-path/platform-i8042-serio-0-event-kbd", 0) + +#endif +#endif + /* -------------------------------------------------------------------------- */ /* ----------------------------- SECOND SECTION ----------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/map.c b/map.c index 93dccfc..de9268a 100644 --- a/map.c +++ b/map.c @@ -25,6 +25,10 @@ #include #include +#include +#include +#include + #include "config.h" #define UINPUT_PATH "/dev/uinput" @@ -71,8 +75,9 @@ void free_js(int sig) { } int main(int argc, char** argv) { - int j, nowrite; - int in; /* fds */ + int j, nowrite, rfds, fdrr = 0; + int in[INPUT_DEVICE_COUNT]; /* fds */ + struct pollfd pin[INPUT_DEVICE_COUNT]; struct input_event e, je; struct uinput_user_dev uidev; @@ -82,15 +87,19 @@ int main(int argc, char** argv) { (void)get_key_num; - if(signal(SIGINT, free_js)) { - printf("SIGINT handler registration failed\n"); - return 1; + /* Open required input devices */ + #define H_CONFIGURE_EVENTS + #include "config.h" + + /* Now setup poll structure */ + for (j = 0; j < INPUT_DEVICE_COUNT; j++) + { + pin[j].fd = in[j]; + pin[j].events = POLLIN; } - /* Open input and uinput */ - in = open(INPUT_PATH, O_RDONLY); - if(in < 0) { - perror("Could not open: " INPUT_PATH); + if(signal(SIGINT, free_js) == SIG_ERR) { + printf("SIGINT handler registration failed\n"); return 1; } @@ -116,51 +125,91 @@ int main(int argc, char** argv) { if (write(js[j], &uidev, sizeof(uidev)) < 0) { perror("write"); - return -1; + return EXIT_FAILURE; } if (ioctl(js[j], UI_DEV_CREATE)) { perror("ioctl create"); - return 1; + return EXIT_FAILURE; } } /* Do it! */ while (1) { - if (read(in, &e, sizeof(struct input_event))) { - printf("Event: (Type: %d, Code: %d, Value %d)\n", e.type, e.code, e.value); + printf("Entering poll..\n"); + /* Any data available? */ + if ((rfds = poll(pin, INPUT_DEVICE_COUNT, -1)) < 0) { + /* Interrupted by signal */ + if (errno == EINTR) + continue; + perror("poll"); + return EXIT_FAILURE; } + printf("Leaving poll..\n"); - memset(&je, '\0', sizeof(struct input_event)); - nowrite = 1; - j = 0; + /* Round-robin check readers */ + while (rfds) { + if (pin[fdrr].revents & POLLIN) { + printf("Device %d has input\n", fdrr); + /* XXX: Need checking for complete read? */ + if (read(in[fdrr], &e, sizeof(struct input_event)) < 0) { + /* Interrupted by singal? Retry */ + if (errno == EINTR) + continue; - #define H_JOYMAP - #include "config.h" +#if 0 + if (errno == EWOULDBLOCK || errno == EAGAIN) { + printf("poll tells us device %d is readable.. it is not\n", fdrr); + rfds -= 1; + fdrr = (fdrr + 1) % INPUT_DEVICE_COUNT; + continue; + } +#endif - if (nowrite == 0) { - printf("Writing %d to %d\n", e.code, j); - if(write(js[j], &je, sizeof(struct input_event)) < 0) { - perror("Event write event"); - return -1; + err(EXIT_FAILURE, "reading input device nr. %d failed", fdrr); + } + + printf("Event: (Type: %d, Code: %d, Value %d)\n", e.type, e.code, e.value); } - } - /* Synchronisation events */ - if (e.type == EV_SYN) { + /* Update poll read mechanism */ + fdrr = (fdrr + 1) % INPUT_DEVICE_COUNT; + rfds -= 1; + + /* Now handle received event */ memset(&je, '\0', sizeof(struct input_event)); - printf("SYN event\n"); + nowrite = 1; + j = 0; - je.type = EV_SYN; - je.code = 0; - je.value = 0; + #define H_JOYMAP + #include "config.h" - if (write(js[j], &je, sizeof(struct input_event)) < 0) { - perror("SYN write event"); - return -1; + if (nowrite == 0) { + printf("Writing %d to %d\n", e.code, j); + if(write(js[j], &je, sizeof(struct input_event)) < 0) { + perror("Event write event"); + return EXIT_FAILURE; + } } - } - } + /* Synchronisation events */ + if (e.type == EV_SYN) { + memset(&je, '\0', sizeof(struct input_event)); + printf("SYN event\n"); + je.type = EV_SYN; + je.code = 0; + je.value = 0; + + if (write(js[j], &je, sizeof(struct input_event)) < 0) { + perror("SYN write event"); + return EXIT_FAILURE; + } + } + + } /* End reader check loop */ + + } /* End main loop */ + + return 0; }