/*
* 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 <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "config.h"
#include "mapper.h"
#define MAX_SIGNALS 16
#define MAX_EVENTS 512
#define MAX_DEVICES 512
#define MAX_IDENTICAL_DEVICES 5
#define MAX_EFFECTS FF_MAX_EFFECTS
#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 event_device;
struct mapping {
int fd; /* /dev/input/event* file descriptor */
uint16_t vendor;
uint16_t product;
int event_id;
int jsnum;
int mapped;
int removed;
int locked;
int instance;
int used;
//two maps, one for shifted, and one for not shifted
struct shift_map map[2];
struct program_force_remap *ff[MAX_FF];
int effect_map[MAX_EFFECTS];
int inverse_effect_map[MAX_EFFECTS];
struct event_device *event_device;
uint16_t shift_button;
uint16_t shift_bit;
};
struct calibration {
int min;
int max;
int fuzz;
int flat;
int resolution;
};
struct event_device {
int fd;
int removed;
int scanned;
int skip;
struct mapping *mapping;
struct calibration calibration[ABS_MAX+1];
};
static int nograb=0;
static int shifted=0;
static uint32_t next_shift_bit=1;
static uint32_t shift_bits=0;
static int event_calibrate=0;
static int fake_ff_constant=0;
struct mapping *devices[MAX_DEVICES];
struct event_device event_devices[MAX_EVENTS] = {0};
int clamp_int(int value, int min, int max) {
if (value < min) value = min;
else if (value > max) value = max;
return value;
}
void set_event_input_calibrate(int set) {
event_calibrate = set;
}
void set_nograb() {
nograb = 1;
}
void set_fake_ff_constant() {
fake_ff_constant = 1;
}
struct mapping *get_device_by_id(uint16_t event_id, int create) {
struct mapping *mapper;
int i, j;
mapper = NULL;
for (i=0; i<MAX_DEVICES; i++) {
if (devices[i])
if (devices[i]->event_id==event_id)
mapper=devices[i];
}
if (mapper)
return mapper;
if (!create)
return NULL;
for (i=0; (mapper==NULL) && (i<MAX_DEVICES); i++) {
if (!devices[i]) {
mapper = devices[i] = (struct mapping *)malloc(sizeof(struct mapping));
mapper->fd = -1;
mapper->vendor = 0;
mapper->product = 0;
mapper->jsnum = -1;
mapper->mapped = 0;
mapper->removed = 1;
mapper->locked = 0;
mapper->event_id = event_id;
mapper->instance = 0;
mapper->used = 0;
for (j=0; j<KEY_MAX+1; j++) {
mapper->map[0].button_press[j]=NULL;
mapper->map[0].button_release[j]=NULL;
mapper->map[1].button_press[j]=NULL;
mapper->map[1].button_release[j]=NULL;
}
for (j=0; j<ABS_MAX+1; j++) {
mapper->map[0].axes[j]=NULL;
mapper->map[1].axes[j]=NULL;
}
}
}
if (mapper == NULL) {
fprintf(stderr, "No allocated device for id=%d\n", event_id);
}
return mapper;
}
struct mapping *get_device_by_vendor(uint16_t vendor, uint16_t product, int instance, int create) {
struct mapping *mapper;
int i, j;
mapper = NULL;
for (i=0; i<MAX_DEVICES; i++) {
if (devices[i])
if ((devices[i]->vendor==vendor)&&
(devices[i]->product==product)&&
(devices[i]->instance==instance))
mapper=devices[i];
}
if (mapper)
return mapper;
if (!create)
return NULL;
for (i=0; (mapper==NULL) && (i<MAX_DEVICES); i++) {
if (!devices[i]) {
mapper = devices[i] = (struct mapping *)malloc(sizeof(struct mapping));
mapper->fd = -1;
mapper->vendor = vendor;
mapper->product = product;
mapper->jsnum = -1;
mapper->mapped = 0;
mapper->removed = 1;
mapper->locked = 0;
mapper->event_id = -1;
mapper->instance = instance;
mapper->used = 0;
for (j=0; j<KEY_MAX+1; j++) {
mapper->map[0].button_press[j]=NULL;
mapper->map[0].button_release[j]=NULL;
mapper->map[1].button_press[j]=NULL;
mapper->map[1].button_release[j]=NULL;
}
for (j=0; j<ABS_MAX+1; j++) {
mapper->map[0].axes[j]=NULL;
mapper->map[1].axes[j]=NULL;
}
}
}
if (mapper == NULL) {
fprintf(stderr, "No allocated device for vendor=0x%04x product=0x%04x\n", vendor, product);
}
return mapper;
}
struct mapping *get_device(uint16_t vendor, uint16_t product, uint16_t event_id, int instance, int create) {
struct mapping *map;
if (create) {
if (vendor || product) {
return get_device_by_vendor(vendor, product, instance, create);
}
return get_device_by_id(event_id, create);
} else {
map = get_device_by_id(event_id, create);
if ((map == NULL) && (vendor || product)) {
map = get_device_by_vendor(vendor, product, instance, create);
}
return map;
}
}
void grab_device(struct mapping *device) {
int r;
if (!device->mapped) {
return;
}
if (device->removed) {
return;
}
if (device->locked) {
return;
}
if (!nograb) {
r = ioctl(device->fd, EVIOCGRAB, 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", device->vendor, device->product);
} else {
fprintf(stderr, "Locked device, vendor=0x%04x, product=0x%04x\n", device->vendor, device->product);
}
}
device->locked = 1;
}
void update_event_handlers() {
int i, j, r;
struct input_id id;
struct mapping *device;
struct input_absinfo info;
int number;
for (i=0; i<MAX_EVENTS; i++) {
if (!event_devices[i].fd)
continue;
if (event_devices[i].skip)
continue;
r = ioctl(event_devices[i].fd, EVIOCGID, &id);
device = event_devices[i].mapping;
if (r < 0) {
if (device != NULL) {
fprintf(stderr, "Device removed (vendor=0x%04x, product=0x%04x)\n", device->vendor, device->product);
device->removed = 1;
device->locked = 0;
device->fd = 0;
device->event_id = -1;
device->used = 0;
}
event_devices[i].mapping = NULL;
event_devices[i].removed = 1;
event_devices[i].scanned = 0;
close(event_devices[i].fd);
event_devices[i].fd = 0;
} else if (device != NULL) {
if ((id.vendor != device->vendor) || (id.product != device->product)) {
fprintf(stderr, "Device removed (vendor=0x%04x, product=0x%04x)\n", device->vendor, device->product);
device->removed = 1;
device->locked = 0;
device->fd = 0;
device->event_id = -1;
device->used = 0;
event_devices[i].mapping = NULL;
event_devices[i].removed = 1;
event_devices[i].scanned = 0;
close(event_devices[i].fd);
event_devices[i].fd = 0;
}
} else {
char devname[256];
memset(devname, 0, 256);
r = ioctl(event_devices[i].fd, EVIOCGNAME(255), devname);
if (r < 0) {
continue;
}
if (event_devices[i].scanned) {
continue;
}
fprintf(stderr, "Found device %s (vendor=0x%04x, product=0x%04x)\n", devname, id.vendor, id.product);
event_devices[i].removed = 0;
event_devices[i].mapping = NULL;
for (number=0; number < MAX_IDENTICAL_DEVICES; number++) {
device = get_device(id.vendor, id.product, i, number, 0);
if ((device != NULL) && (!(device->used))) {
fprintf(stderr, "Mapping device %s (vendor=0x%04x, product=0x%04x)\n", devname, id.vendor, id.product);
device->fd = event_devices[i].fd;
device->removed = 0;
device->locked = 0;
device->event_device = event_devices + i;
device->event_id = i;
device->vendor = id.vendor;
device->product = id.product;
device->used = 1;
for (j = 0; j < MAX_EFFECTS; j++) {
device->effect_map[j] = -1;
device->inverse_effect_map[j] = -1;
}
grab_device(device);
if (event_calibrate) {
for (j = 0; j < ABS_MAX + 1; j++) {
r = ioctl(event_devices[i].fd, EVIOCGABS(j), &info);
if (r == 0) {
event_devices[i].calibration[j].min = info.minimum;
event_devices[i].calibration[j].max = info.maximum;
event_devices[i].calibration[j].fuzz = info.fuzz;
event_devices[i].calibration[j].flat = info.flat;
event_devices[i].calibration[j].resolution = info.resolution;
} else {
event_devices[i].calibration[j].min = 0;
event_devices[i].calibration[j].max = 0;
event_devices[i].calibration[j].fuzz = 0;
event_devices[i].calibration[j].flat = 0;
event_devices[i].calibration[j].resolution = 0;
}
}
}
event_devices[i].mapping = device;
break;
}
}
event_devices[i].scanned = 1;
}
}
}
//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;
char name[256];
struct input_id id;
struct mapping *mapping;
struct input_absinfo info;
int number;
for (i=0; i<MAX_EVENTS; i++) {
if (event_devices[i].fd != 0) {
continue;
}
if (event_devices[i].skip) {
continue;
}
sprintf(name, "%s%d", get_config(EVENT_DEV), i);
int fd=open(name, O_RDWR|O_NONBLOCK);
if (fd<0) {
event_devices[i].fd = 0;
event_devices[i].removed = 1;
event_devices[i].scanned = 0;
event_devices[i].mapping = 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);
event_devices[i].fd = 0;
event_devices[i].removed = 1;
event_devices[i].scanned = 1;
event_devices[i].skip = 1;
event_devices[i].mapping = 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);
event_devices[i].fd = fd;
event_devices[i].removed = 0;
event_devices[i].scanned = 1;
event_devices[i].mapping = NULL;
for (number=0; number < MAX_IDENTICAL_DEVICES; number++) {
mapping = get_device(id.vendor, id.product, i, number, 0);
if ((mapping != NULL) && (!(mapping->used))) {
fprintf(stderr, "Mapping device %s (vendor=0x%04x, product=0x%04x)\n", devname, id.vendor, id.product);
mapping->fd = fd;
mapping->removed = 0;
mapping->locked = 0;
mapping->event_device = event_devices + i;
mapping->event_id = i;
mapping->vendor = id.vendor;
mapping->product = id.product;
mapping->used = 1;
for (j = 0; j < MAX_EFFECTS; j++) {
mapping->effect_map[j] = -1;
mapping->inverse_effect_map[j] = -1;
}
grab_device(mapping);
if (event_calibrate) {
for (j = 0; j < ABS_MAX + 1; j++) {
r = ioctl(event_devices[i].fd, EVIOCGABS(j), &info);
if (r == 0) {
event_devices[i].calibration[j].min = info.minimum;
event_devices[i].calibration[j].max = info.maximum;
event_devices[i].calibration[j].fuzz = info.fuzz;
event_devices[i].calibration[j].flat = info.flat;
event_devices[i].calibration[j].resolution = info.resolution;
} else {
event_devices[i].calibration[j].min = 0;
event_devices[i].calibration[j].max = 0;
event_devices[i].calibration[j].fuzz = 0;
event_devices[i].calibration[j].flat = 0;
event_devices[i].calibration[j].resolution = 0;
}
}
}
event_devices[i].mapping = mapping;
break;
} else {
if (id.vendor==0x00ff) {
event_devices[i].skip = 1;
}
}
}
}
}
}
/*static int input_defuzz_abs_event(int value, int old_val, int fuzz) {
if (fuzz) {
if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
return old_val;
if (value > old_val - fuzz && value < old_val + fuzz)
return (old_val * 3 + value) / 4;
if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
return (old_val + value) / 2;
}
return value;
}*/
static inline int recalibrate(struct event_device *device, int axis, int value) {
int middle;
int dead_min, dead_max;
if (device == NULL) {
return value;
}
struct calibration calibration = device->calibration[axis];
if (calibration.min == calibration.max) {
return value;
}
middle = (calibration.min + calibration.max) / 2;
dead_min = middle - calibration.flat;
dead_max = middle + calibration.flat;
if ((dead_min <= value) && (value <= dead_max)) {
return 0;
}
if (calibration.min < calibration.max) {
if (value < calibration.min)
value = calibration.min;
if (value > calibration.max)
value = calibration.max;
} else {
if (value > calibration.min)
value = calibration.min;
if (value < calibration.max)
value = calibration.max;
}
// sigh. use floating point because I am too lazy (right now) to work out an overflow free integer version
if (value < dead_min) {
value = -((value - dead_min) * 32767.0) / (calibration.min - dead_min);
} else {
value = ((value - dead_max) * 32767.0) / (calibration.max - dead_max);
}
if (value < -32767) value = -32767;
if (value > 32767) value = 32767;
return value;
}
static void process_key(struct mapping *mapper, int key, int value);
static void process_axis(struct mapping *mapper, int axis, int value);
static void process_ff(struct mapping *mapper, int effect, int value);
void poll_joystick_loop() {
int i, j, n=0;
struct pollfd polled_fds[MAX_DEVICES];
struct mapping *poll_mapper[MAX_DEVICES];
struct input_event ev[16];
int rb;
int value;
for (i=0; i<MAX_DEVICES; i++) {
if (devices[i] && (devices[i]->mapped) && (!devices[i]->removed)) {
poll_mapper[n]=devices[i];
polled_fds[n].fd=devices[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) {
value = recalibrate(poll_mapper[i]->event_device, ev[j].code, ev[j].value);
process_axis(poll_mapper[i], ev[j].code, value);
}
if (ev[j].type==EV_FF_STATUS) {
/* code is the force feedback identifier */
/* value is one of FF_STATUS_STOPPED or FF_STATUS_PLAYING */
process_ff(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 (key==mapper->shift_button) {
if (value==0) {
shift_bits&=~(mapper->shift_bit);
} else {
shift_bits|=mapper->shift_bit;
}
shifted=(shift_bits)?1:0;
}
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]->input_min != axes_remap[axis]->input_max) {
if (axes_remap[axis]->input_min < axes_remap[axis]->input_max) {
if (value < axes_remap[axis]->input_min)
value = axes_remap[axis]->input_min;
if (value > axes_remap[axis]->input_max)
value = axes_remap[axis]->input_max;
} else {
if (value > axes_remap[axis]->input_min)
value = axes_remap[axis]->input_min;
if (value < axes_remap[axis]->input_max)
value = axes_remap[axis]->input_max;
}
// sigh. use floating point because I am too lazy (right now) to work out an overflow free integer version
value = round(((value - axes_remap[axis]->input_min) * 65534.0) / (axes_remap[axis]->input_max - axes_remap[axis]->input_min) - 32767);
value = clamp_int(value, -32767, 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 = round((value + axes_remap[axis]->deadzone) * 32767.0 / (32767 - axes_remap[axis]->deadzone));
else
value = round((value - axes_remap[axis]->deadzone) * 32767.0 / (32767 - axes_remap[axis]->deadzone));
value = clamp_int(value, -32767, 32767);
}
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;
}
}
int get_uinput_effect_code(struct mapping *mapper, int effect_code);
static void process_ff(struct mapping *mapper, int effect, int status) {
int i;
int uinput_effect = get_uinput_effect_code(mapper, effect);
for (i=0; i<MAX_FF; i++) {
if (mapper->ff[i]) {
set_joy_ff_status(mapper->ff[i]->device, uinput_effect, status);
}
}
}
void remap_axis(struct program_axis_remap *axis) {
struct mapping *mapper;
int shifted;
if (axis->program!=PROGRAM_AXIS_REMAP) return;
if (axis->srcaxis>ABS_MAX) return;
mapper = get_device(axis->vendor, axis->product, axis->joystick, axis->instance, 1);
if (mapper==NULL) return;
mapper->mapped=1;
grab_device(mapper);
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 shifted;
if (btn->program!=PROGRAM_BUTTON_REMAP) return;
if (btn->srcbutton>KEY_MAX) return;
mapper = get_device(btn->vendor, btn->product, btn->joystick, btn->instance, 1);
if (mapper==NULL) return;
mapper->mapped=1;
grab_device(mapper);
shifted=0;
if (btn->flags&FLAG_SHIFT) shifted=1;
if (btn->type==TYPE_SHIFT) {
mapper->shift_button=btn->srcbutton;
mapper->shift_bit = next_shift_bit;
if (next_shift_bit > (1 << 30)) {
fprintf(stderr, "Too many shift buttons, some shift buttons will not work correctly when pressed simulaneously with other shift buttons\n");
} else {
next_shift_bit *= 2;
}
} else {
if (btn->flags&FLAG_RELEASE)
mapper->map[shifted].button_release[btn->srcbutton]=btn;
else
mapper->map[shifted].button_press[btn->srcbutton]=btn;
}
}
void remap_ff(struct program_force_remap *force) {
int i;
struct mapping *mapper;
if (force->program!=PROGRAM_FORCE_REMAP) return;
mapper = get_device(force->vendor, force->product, force->joystick, force->instance, 1);
if (mapper==NULL) return;
mapper->mapped=1;
grab_device(mapper);
force->allocated = (void *)mapper;
for (i=0; i<MAX_FF; i++) {
if (mapper->ff[i] == NULL) {
mapper->ff[i] = force;
return;
}
}
}
void remap_empty(uint16_t vendor, uint16_t product, int instance) {
struct mapping *mapper;
mapper = get_device(vendor, product, 0, instance, 1);
if (mapper==NULL) return;
mapper->mapped=1;
}
void set_joystick_number(uint16_t vendor, uint16_t product, uint16_t event_id, int instance, int device) {
struct mapping *mapper;
mapper = get_device(vendor, product, event_id, instance, 1);
if (mapper==NULL) return;
mapper->mapped=1;
mapper->jsnum=device;
}
int get_effect_code(struct mapping *mapper, int effect_code) {
if (effect_code < 0) {
return -1;
}
if (effect_code >= MAX_EFFECTS) {
return -1;
}
return mapper->effect_map[effect_code];
}
int get_uinput_effect_code(struct mapping *mapper, int effect_code) {
if (effect_code < 0) {
return -1;
}
if (effect_code >= MAX_EFFECTS) {
return -1;
}
return mapper->inverse_effect_map[effect_code];
}
void set_effect_code(struct mapping *mapper, int effect_code, int device_code) {
if (effect_code < 0) {
return;
}
if (effect_code >= MAX_EFFECTS) {
return;
}
if (device_code < 0) {
return;
}
if (device_code >= MAX_EFFECTS) {
return;
}
mapper->effect_map[effect_code] = device_code;
mapper->inverse_effect_map[device_code] = effect_code;
}
void remove_effect_code(struct mapping *mapper, int effect_code) {
int device_code;
if (effect_code < 0) {
return;
}
if (effect_code >= MAX_EFFECTS) {
return;
}
device_code = mapper->effect_map[effect_code];
mapper->effect_map[effect_code] = -1;
if (device_code < 0) {
return;
}
if (device_code >= MAX_EFFECTS) {
return;
}
mapper->inverse_effect_map[device_code] = -1;
}
int forward_ff_event(void *handle, struct input_event ev) {
struct mapping *mapper;
int r;
if (handle == NULL) {
return -EINVAL;
}
mapper = (struct mapping *)handle;
if ((!mapper->mapped) || (mapper->removed)) {
return 0;
}
if (ev.type == EV_FF) {
if (ev.code < FF_MAX_EFFECTS) {
ev.code = get_effect_code(mapper, ev.code);
if (ev.code == -1) {
return -EINVAL;
}
}
}
r = write(mapper->fd, &ev, sizeof(ev));
if (r < 0) {
perror("Failed FF write");
return -errno;
}
return 0;
}
int forward_ff_upload(void *handle, struct ff_effect *effect) {
struct mapping *mapper;
int r, uinput_id;
struct ff_effect original;
if (handle == NULL) {
return -EINVAL;
}
mapper = (struct mapping *)handle;
if ((!mapper->mapped) || (mapper->removed)) {
return 0;
}
uinput_id = effect->id;
if (fake_ff_constant) {
if (effect->type == FF_CONSTANT) {
original = *effect;
effect->type = FF_PERIODIC;
effect->u.periodic.envelope = original.u.constant.envelope;
effect->u.periodic.waveform = FF_SINE;
effect->u.periodic.period = 50;
effect->u.periodic.magnitude = original.u.constant.level;
effect->u.periodic.offset = 0;
effect->u.periodic.phase = 0;
}
}
// remap to device id
effect->id = get_effect_code(mapper, uinput_id);
r = ioctl(mapper->fd, EVIOCSFF, effect);
if (r < 0) {
// restore the id
perror("Failed FF upload");
effect->id = uinput_id;
return -errno;
}
set_effect_code(mapper, uinput_id, effect->id);
// restore the id
effect->id = uinput_id;
return 0;
}
int forward_ff_erase(void *handle, int effect_id) {
struct mapping *mapper;
int r, uinput_id;
if (handle == NULL) {
return -EINVAL;
}
mapper = (struct mapping *)handle;
if ((!mapper->mapped) || (mapper->removed)) {
return 0;
}
uinput_id = effect_id;
effect_id = get_effect_code(mapper, uinput_id);
if (effect_id < 0) {
return -EINVAL;
}
r = ioctl(mapper->fd, EVIOCRMFF, effect_id);
if (r < 0) {
perror("Failed FF erase");
return -errno;
}
remove_effect_code(mapper, uinput_id);
return 0;
}