/*
* 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)) {
if (axis->joystick != 255) {
if (axis->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", 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;
}