/* * Joystick remapper for the input driver suite. * by Alexandre Hardy * * 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 2 of the License, or * (at your option) any later version. */ #include <fcntl.h> #include <sys/types.h> #include <linux/input.h> #include <unistd.h> #include <poll.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "config.h" #include "mapper.h" #define MAX_SIGNALS 16 #define MAX_EVENTS 1024 #define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) #define TIMEOUT 20 //(50 times a second) #undef press #undef release struct shift_map { struct program_button_remap *button_press[KEY_MAX+1]; struct program_button_remap *button_release[KEY_MAX+1]; struct program_axis_remap *axes[ABS_MAX+1]; }; struct mapping { int fd; /* /dev/input/event* file descriptor */ __uint16_t vendor; __uint16_t product; int jsnum; int mapped; int duplicate; //two maps, one for shifted, and one for not shifted struct shift_map map[2]; }; static int shifted=0; static __uint16_t shift_vendor; static __uint16_t shift_product; static __uint16_t shift_button; struct mapping *events[MAX_EVENTS]; //install after creating joysticks and code joystick //our joysticks are vendor 0xff and product 0x01 and must not be handled //our mice are vendor 0xff and product 0x02 and must not be handled //our kbd are vendor 0xff and product 0x03 and must not be handled //the code joystick is 0xff and product 0x00 //the code joystick must be handled by our code void install_event_handlers() { int i, j, r, d; char name[256]; struct input_id id; for (i=0; i<=MAX_EVENTS; i++) { sprintf(name, "%s%d", get_config(EVENT_DEV), i); int fd=open(name, O_RDONLY|O_NONBLOCK); if (fd<0) { events[i]=NULL; } else { r = ioctl(fd, EVIOCGID, &id); if (r < 0) { perror("Failed to get vendor and product id"); exit(1); } if ((id.vendor==0x00ff)&&(id.product!=0x0000)) { close(fd); events[i]=NULL; continue; } char devname[256]; memset(devname, 0, 256); r = ioctl(fd, EVIOCGNAME(255), devname); if (r < 0) { perror("Failed to get input device name"); exit(1); } fprintf(stderr, "Found device %s (vendor=0x%04x, product=0x%04x)\n", devname, id.vendor, id.product); events[i]=(struct mapping *)malloc(sizeof(struct mapping)); events[i]->fd=fd; events[i]->vendor=id.vendor; events[i]->product=id.product; events[i]->jsnum=-1; events[i]->mapped=0; events[i]->duplicate=0; for (d=0; d<i; d++) { if (events[d] && events[d]->vendor==id.vendor && events[d]->product==id.product) { events[i]->duplicate = events[i]->duplicate + 1; } } for (j=0; j<KEY_MAX+1; j++) { events[i]->map[0].button_press[j]=NULL; events[i]->map[0].button_release[j]=NULL; events[i]->map[1].button_press[j]=NULL; events[i]->map[1].button_release[j]=NULL; } for (j=0; j<ABS_MAX+1; j++) { events[i]->map[0].axes[j]=NULL; events[i]->map[1].axes[j]=NULL; } } } } static void process_key(struct mapping *mapper, int key, int value); static void process_axis(struct mapping *mapper, int axis, int value); void poll_joystick_loop() { int i, j, n=0; struct pollfd polled_fds[MAX_EVENTS]; struct mapping *poll_mapper[MAX_EVENTS]; struct input_event ev[16]; int rb; for (i=0; i<MAX_EVENTS; i++) { if (events[i] && (events[i]->mapped)) { poll_mapper[n]=events[i]; polled_fds[n].fd=events[i]->fd; polled_fds[n++].events=POLLIN; } } poll(polled_fds, n, TIMEOUT); /* TODO: We may return early, we should indicate to program_run if a timertick is required */ /* http://man7.org/linux/man-pages/man2/clock_gettime.2.html */ for (i=0; i<n; i++) { if (polled_fds[i].revents&POLLIN) { rb=1; while (rb>0) { rb=read(polled_fds[i].fd, ev, sizeof(struct input_event)*16); if (rb>0) for (j=0; j<(int)(rb/sizeof(struct input_event)); j++) { if (ev[j].type==EV_KEY) { if ((ev[j].code >= BTN_MISC) && (ev[j].value != 2)) process_key(poll_mapper[i], ev[j].code, ev[j].value); } if (ev[j].type==EV_ABS) process_axis(poll_mapper[i], ev[j].code, ev[j].value); } } } } program_run(); repeat_mouse_move(); } static int nsignals=0; static int signals[MAX_SIGNALS]; static int sighead=0; static int sigtail=0; int no_signal(void) { return (nsignals==0); } int goto_next_signal(void) { int r=signals[sighead]; nsignals--; sighead++; sighead=sighead%MAX_SIGNALS; return r; } void push_signal(int signal) { //silently drop signals if too many are sent if (nsignals>=MAX_SIGNALS) return; nsignals++; signals[sigtail]=signal; sigtail++; sigtail=sigtail%MAX_SIGNALS; } static void process_key(struct mapping *mapper, int key, int value) { int button=0; int i, j; struct program_button_remap **button_remap; if ((mapper->vendor==shift_vendor)||(mapper->product==shift_product)) { if (key==shift_button) { shifted=value; if (shifted!=0) shifted=1; } } if ((mapper->vendor!=0x00ff)||(mapper->product!=0x0000)) code_notify_button(mapper->jsnum, key, value); if (value==1) button_remap=mapper->map[shifted].button_press; else if (value==0) button_remap=mapper->map[shifted].button_release; else return; if (button_remap==NULL) return; if (button_remap[key]==NULL) return; j=button_remap[key]->device&0x0F; switch (button_remap[key]->device&0xF0) { case DEVICE_JOYSTICK: if (button_remap[key]->type==TYPE_BUTTON) { for (i=0; (i<MAX_SEQUENCE) && (button_remap[key]->sequence[i]!=SEQUENCE_DONE); i++) { button=button_remap[key]->sequence[i]&KEYMASK; if (button_remap[key]->sequence[i]&RELEASEMASK) value=0; else value=1; press_joy_button(j, button, value); if ((button_remap[key]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_joy_button(j, button, 0); } } } else if (button_remap[key]->type==TYPE_AXIS) { //it is an axis if (value==1) value=32767; if (button_remap[key]->flags&FLAG_INVERT) value=-value; set_joy_axis(j, button_remap[key]->sequence[0], value); } break; case DEVICE_MOUSE: if (button_remap[key]->type==TYPE_BUTTON) { for (i=0; (i<MAX_SEQUENCE) && (button_remap[key]->sequence[i]!=SEQUENCE_DONE); i++) { button=button_remap[key]->sequence[i]&KEYMASK; if (button_remap[key]->sequence[i]&RELEASEMASK) value=0; else value=1; press_mouse_button(button, value); if ((button_remap[key]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_mouse_button(button, 0); } } } else if (button_remap[key]->type==TYPE_AXIS) { //it is an axis if (button_remap[key]->flags&FLAG_INVERT) value=-value; if (button_remap[key]->sequence[0]==ABS_X) move_mouse_x(value * button_remap[key]->speed); if (button_remap[key]->sequence[0]==ABS_Y) move_mouse_y(value * button_remap[key]->speed); if (button_remap[key]->sequence[0]==ABS_WHEEL) move_mouse_wheel(value * button_remap[key]->speed); } break; case DEVICE_KBD: if (button_remap[key]->type==TYPE_BUTTON) { for (i=0; (i<MAX_SEQUENCE) && (button_remap[key]->sequence[i]!=SEQUENCE_DONE); i++) { button=button_remap[key]->sequence[i]&KEYMASK; if (button_remap[key]->sequence[i]&RELEASEMASK) value=0; else value=1; press_key(button, value); if ((button_remap[key]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_key(button, 0); } } } break; } } static void process_axis(struct mapping *mapper, int axis, int value) { int button=0; int i, j; struct program_axis_remap **axes_remap; __uint16_t *sequence, *off; int release = 0; if ((mapper->vendor!=0x00ff)||(mapper->product!=0x0000)) code_notify_axis(mapper->jsnum, axis, value); axes_remap=mapper->map[shifted].axes; if (axes_remap==NULL) return; if (axes_remap[axis]==NULL) return; if (axes_remap[axis]->min != axes_remap[axis]->max) { if (axes_remap[axis]->min < axes_remap[axis]->max) { if (value < axes_remap[axis]->min) value = axes_remap[axis]->min; if (value > axes_remap[axis]->max) value = axes_remap[axis]->max; } else { if (value > axes_remap[axis]->min) value = axes_remap[axis]->min; if (value < axes_remap[axis]->max) value = axes_remap[axis]->max; } // sigh. use floating point because I am too lazy (right now) to work out an overflow free integer version value = ((value - axes_remap[axis]->min) * 65536.0) / (axes_remap[axis]->max - axes_remap[axis]->min) - 32767; if (value < -32767) value = -32767; if (value > 32767) value = 32767; } if ((value >= -axes_remap[axis]->deadzone) && (value <= axes_remap[axis]->deadzone)) { value = 0; } else if (axes_remap[axis]->deadzone) { // we don't want a sudden jump in values. rescale it. if (value < 0) value = (value + axes_remap[axis]->deadzone) * 32767.0 / (32767 - axes_remap[axis]->deadzone); else value = (value - axes_remap[axis]->deadzone) * 32767.0 / (32767 - axes_remap[axis]->deadzone); } if (axes_remap[axis]->flags&FLAG_BINARY) { // only process the event if there is a binary change (differs in sign and non-zero) if ((axes_remap[axis]->saved_value<0) && (value<=0)) { return; } if ((axes_remap[axis]->saved_value>0) && (value>=0)) { return; } if ((axes_remap[axis]->saved_value==0) && (value==0)) { return; } axes_remap[axis]->saved_value=value; if (value == 0) //release any keys pressed release = 1; } if (axes_remap[axis]->flags&FLAG_TRINARY) { // only process the event if there is a binary change (differs in sign and non-zero) if ((axes_remap[axis]->saved_value<0) && (value<0)) { return; } if ((axes_remap[axis]->saved_value>0) && (value>0)) { return; } axes_remap[axis]->saved_value=value; if (value == 0) //release any keys pressed release = 1; } j=axes_remap[axis]->device&0x0F; if (axes_remap[axis]->type==TYPE_BUTTON) { if (value<0) { sequence=axes_remap[axis]->minus; off=axes_remap[axis]->plus; } else { sequence=axes_remap[axis]->plus; off=axes_remap[axis]->minus; } } switch (axes_remap[axis]->device&0xF0) { case DEVICE_JOYSTICK: if (axes_remap[axis]->type==TYPE_BUTTON) { //a joystick button for (i=0; (i<MAX_SEQUENCE) && (off[i]!=SEQUENCE_DONE); i++) { button=off[i]&KEYMASK; press_joy_button(j, button, 0); } for (i=0; (i<MAX_SEQUENCE) && (sequence[i]!=SEQUENCE_DONE); i++) { button=sequence[i]&KEYMASK; if ((release) || (sequence[i]&RELEASEMASK)) value=0; else value=1; press_joy_button(j, button, value); if ((axes_remap[axis]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_joy_button(j, button, 0); } } } else if (axes_remap[axis]->type==TYPE_AXIS) { //it is an axis if (axes_remap[axis]->flags&FLAG_INVERT) value=-value; set_joy_axis(j, axes_remap[axis]->axis, value); } break; case DEVICE_MOUSE: if (axes_remap[axis]->type==TYPE_BUTTON) { //a mouse button for (i=0; (i<MAX_SEQUENCE) && (off[i]!=SEQUENCE_DONE); i++) { button=off[i]&KEYMASK; press_mouse_button(button, 0); } for (i=0; (i<MAX_SEQUENCE) && (sequence[i]!=SEQUENCE_DONE); i++) { button=sequence[i]&KEYMASK; if ((release) || (sequence[i]&RELEASEMASK)) value=0; else value=1; press_mouse_button(button, value); if ((axes_remap[axis]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_mouse_button(button, 0); } } } else if (axes_remap[axis]->type==TYPE_AXIS) { //it is an axis, assume -32767 to 32767. Use min and max if that is not the case // make it a lot smaller value = value * ((float)(axes_remap[axis]->speed) / 32767.0); if (axes_remap[axis]->flags&FLAG_INVERT) value=-value; //if (value>0) value=1; //if (value<0) value=-1; if (axes_remap[axis]->axis==ABS_X) move_mouse_x(value); if (axes_remap[axis]->axis==ABS_Y) move_mouse_y(value); if (axes_remap[axis]->axis==ABS_WHEEL) move_mouse_wheel(value); } break; case DEVICE_KBD: if (axes_remap[axis]->type==TYPE_BUTTON) { //a keypress for (i=0; (i<MAX_SEQUENCE) && (off[i]!=SEQUENCE_DONE); i++) { button=off[i]&KEYMASK; press_key(button, 0); } for (i=0; (i<MAX_SEQUENCE) && (sequence[i]!=SEQUENCE_DONE); i++) { button=sequence[i]&KEYMASK; if ((release) || (sequence[i]&RELEASEMASK)) value=0; else value=1; press_key(button, value); if ((axes_remap[axis]->flags&FLAG_AUTO_RELEASE)&&(value==1)) { press_key(button, 0); } } } break; } } void remap_axis(struct program_axis_remap *axis) { struct mapping *mapper; int i, shifted, r; if (axis->program!=PROGRAM_AXIS_REMAP) return; if (axis->srcaxis>ABS_MAX) return; mapper=NULL; for (i=0; i<MAX_EVENTS; i++) { if (events[i]) if ((events[i]->vendor==axis->vendor)&& (events[i]->product==axis->product)) mapper=events[i]; } if (mapper==NULL) return; if (mapper->mapped) r = 0; else r = ioctl(mapper->fd, EVIOCGRAB, 1); mapper->mapped=1; if (r < 0) { perror("Failed to grab device"); fprintf(stderr, "Failed to lock device with vendor=0x%04x, product=0x%04x. Continuing anyway...\n", axis->vendor, axis->product); } shifted=0; if (axis->flags&FLAG_SHIFT) shifted=1; mapper->map[shifted].axes[axis->srcaxis]=axis; } void remap_button(struct program_button_remap *btn) { struct mapping *mapper; int i, shifted, r; if (btn->program!=PROGRAM_BUTTON_REMAP) return; if (btn->srcbutton>KEY_MAX) return; mapper=NULL; for (i=0; i<MAX_EVENTS; i++) { if (events[i]) if ((events[i]->vendor==btn->vendor)&& (events[i]->product==btn->product)) { if (btn->joystick != 255) { if (btn->joystick == events[i]->duplicate) mapper=events[i]; } else { mapper=events[i]; } } } if (mapper==NULL) return; if (mapper->mapped) r = 0; else r = ioctl(mapper->fd, EVIOCGRAB, 1); mapper->mapped=1; if (r < 0) { perror("Failed to grab device"); fprintf(stderr, "Failed to lock device with vendor=0x%04x, product=0x%04x. Continuing anyway...\n", btn->vendor, btn->product); } shifted=0; if (btn->flags&FLAG_SHIFT) shifted=1; if (btn->type==TYPE_SHIFT) { shift_vendor=btn->vendor; shift_product=btn->product; shift_button=btn->srcbutton; } else { if (btn->flags&FLAG_RELEASE) mapper->map[shifted].button_release[btn->srcbutton]=btn; else mapper->map[shifted].button_press[btn->srcbutton]=btn; } } void set_joystick_number(__uint16_t vendor, __uint16_t product, int device) { struct mapping *mapper; int i; mapper=NULL; for (i=0; i<MAX_EVENTS; i++) { if (events[i]) if ((events[i]->vendor==vendor)&& (events[i]->product==product)) mapper=events[i]; } if (mapper==NULL) return; mapper->mapped=1; mapper->jsnum=device; }