Use SDL-style mapping for input

This commit is contained in:
Iwan Timmer
2017-04-08 14:25:20 +02:00
parent 0a5b4ec5cc
commit 9f43712fc8
3 changed files with 213 additions and 174 deletions

View File

@@ -49,6 +49,9 @@ struct input_abs_parms {
struct input_device {
struct libevdev *dev;
struct mapping map;
int key_map[KEY_MAX];
int abs_map[ABS_MAX];
int hats_state[3][2];
int fd;
char modifiers;
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
@@ -59,9 +62,16 @@ struct input_device {
short rightStickX, rightStickY;
bool gamepadModified;
struct input_abs_parms xParms, yParms, rxParms, ryParms, zParms, rzParms;
struct input_abs_parms dpadxParms, dpadyParms;
};
#define HAT_UP 1
#define HAT_RIGHT 2
#define HAT_DOWN 4
#define HAT_LEFT 8
static const int hat_constants[3][3] = {{HAT_UP | HAT_LEFT, HAT_UP, HAT_UP | HAT_RIGHT}, {HAT_LEFT, 0, HAT_RIGHT}, {HAT_LEFT | HAT_DOWN, HAT_DOWN, HAT_RIGHT}};
#define set_hat(flags, flag, hat, hat_flag) flags = (-((hat & hat_flag) > 0) ^ flags) & flag
static struct input_device* devices = NULL;
static int numDevices = 0;
static int assignedControllerIds = 0;
@@ -78,9 +88,9 @@ static bool grabbingDevices;
static bool (*handler) (struct input_event*, struct input_device*);
static void evdev_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
parms->flat = libevdev_get_abs_flat(dev->dev, code);
parms->min = libevdev_get_abs_minimum(dev->dev, code);
parms->max = libevdev_get_abs_maximum(dev->dev, code);
parms->flat = libevdev_get_abs_flat(dev->dev, dev->abs_map[code]);
parms->min = libevdev_get_abs_minimum(dev->dev, dev->abs_map[code]);
parms->max = libevdev_get_abs_maximum(dev->dev, dev->abs_map[code]);
parms->avg = (parms->min+parms->max)/2;
parms->range = parms->max - parms->avg;
parms->diff = parms->max - parms->min;
@@ -120,15 +130,6 @@ static char evdev_convert_value_byte(struct input_event *ev, struct input_device
return (ev->value - parms->flat - parms->min) * UCHAR_MAX / (parms->diff - parms->flat);
}
static int evdev_convert_value_direction(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) {
if (ev->value > (parms->avg+parms->range/4))
return reverse?-1:1;
else if (ev->value < (parms->avg-parms->range/4))
return reverse?1:-1;
else
return 0;
}
static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) {
bool gamepadModified = false;
@@ -195,6 +196,8 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
} else {
int mouseCode = 0;
short gamepadCode = 0;
int index = dev->key_map[ev->code - BTN_MISC];
switch (ev->code) {
case BTN_LEFT:
mouseCode = BUTTON_LEFT;
@@ -206,35 +209,35 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
mouseCode = BUTTON_RIGHT;
break;
default:
if (ev->code == dev->map.btn_south)
if (index == dev->map.btn_a)
gamepadCode = A_FLAG;
else if (ev->code == dev->map.btn_west)
else if (index == dev->map.btn_x)
gamepadCode = X_FLAG;
else if (ev->code == dev->map.btn_north)
else if (index == dev->map.btn_y)
gamepadCode = Y_FLAG;
else if (ev->code == dev->map.btn_east)
else if (index == dev->map.btn_b)
gamepadCode = B_FLAG;
else if (ev->code == dev->map.btn_dpad_up)
else if (index == dev->map.btn_dpup)
gamepadCode = UP_FLAG;
else if (ev->code == dev->map.btn_dpad_down)
else if (index == dev->map.btn_dpdown)
gamepadCode = DOWN_FLAG;
else if (ev->code == dev->map.btn_dpad_right)
else if (index == dev->map.btn_dpright)
gamepadCode = RIGHT_FLAG;
else if (ev->code == dev->map.btn_dpad_left)
else if (index == dev->map.btn_dpleft)
gamepadCode = LEFT_FLAG;
else if (ev->code == dev->map.btn_thumbl)
else if (index == dev->map.btn_leftstick)
gamepadCode = LS_CLK_FLAG;
else if (ev->code == dev->map.btn_thumbr)
else if (index == dev->map.btn_rightstick)
gamepadCode = RS_CLK_FLAG;
else if (ev->code == dev->map.btn_tl)
else if (index == dev->map.btn_leftshoulder)
gamepadCode = LB_FLAG;
else if (ev->code == dev->map.btn_tr)
else if (index == dev->map.btn_rightshoulder)
gamepadCode = RB_FLAG;
else if (ev->code == dev->map.btn_start)
else if (index == dev->map.btn_start)
gamepadCode = PLAY_FLAG;
else if (ev->code == dev->map.btn_select)
else if (index == dev->map.btn_back)
gamepadCode = BACK_FLAG;
else if (ev->code == dev->map.btn_mode)
else if (index == dev->map.btn_guide)
gamepadCode = SPECIAL_FLAG;
}
@@ -248,9 +251,9 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
dev->buttonFlags |= gamepadCode;
else
dev->buttonFlags &= ~gamepadCode;
} else if (ev->code == dev->map.btn_tl2)
} else if (index == dev->map.btn_lefttrigger)
dev->leftTrigger = ev->value?UCHAR_MAX:0;
else if (ev->code == dev->map.btn_tr2)
else if (index == dev->map.btn_righttrigger)
dev->rightTrigger = ev->value?UCHAR_MAX:0;
else {
fprintf(stderr, "Unmapped button: %d\n", ev->code);
@@ -274,46 +277,46 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
break;
case EV_ABS:
gamepadModified = true;
if (ev->code == dev->map.abs_x)
dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x);
else if (ev->code == dev->map.abs_y)
dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y);
else if (ev->code == dev->map.abs_rx)
dev->rightStickX = evdev_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx);
else if (ev->code == dev->map.abs_ry)
dev->rightStickY = evdev_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry);
else if (ev->code == dev->map.abs_z)
dev->leftTrigger = evdev_convert_value_byte(ev, dev, &dev->zParms);
else if (ev->code == dev->map.abs_rz)
dev->rightTrigger = evdev_convert_value_byte(ev, dev, &dev->rzParms);
else if (ev->code == dev->map.abs_dpad_x) {
int dir = evdev_convert_value_direction(ev, dev, &dev->dpadxParms, dev->map.reverse_dpad_x);
if (dir == 1) {
dev->buttonFlags |= RIGHT_FLAG;
dev->buttonFlags &= ~LEFT_FLAG;
} else if (dir == 0) {
dev->buttonFlags &= ~RIGHT_FLAG;
dev->buttonFlags &= ~LEFT_FLAG;
} else {
dev->buttonFlags &= ~RIGHT_FLAG;
dev->buttonFlags |= LEFT_FLAG;
}
} else if (ev->code == dev->map.abs_dpad_y) {
int dir = evdev_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y);
if (dir == 1) {
dev->buttonFlags |= DOWN_FLAG;
dev->buttonFlags &= ~UP_FLAG;
} else if (dir == 0) {
dev->buttonFlags &= ~DOWN_FLAG;
dev->buttonFlags &= ~UP_FLAG;
} else {
dev->buttonFlags &= ~DOWN_FLAG;
dev->buttonFlags |= UP_FLAG;
}
} else
gamepadModified = false;
int index = dev->abs_map[ev->code];
int hat_index = (ev->code - ABS_HAT0X) / 2;
int har_dir_index = (ev->code - ABS_HAT0X) % 2;
break;
switch (ev->code) {
case ABS_HAT0X:
case ABS_HAT0Y:
case ABS_HAT1X:
case ABS_HAT1Y:
case ABS_HAT2X:
case ABS_HAT2Y:
case ABS_HAT3X:
case ABS_HAT3Y:
dev->hats_state[hat_index][har_dir_index] = ev->value < 0 ? 0 : (ev->value == 0 ? 1 : 2);
int hat_state = hat_constants[dev->hats_state[hat_index][0]][dev->hats_state[hat_index][1]];
if (hat_index == dev->map.hat_dpup)
set_hat(dev->buttonFlags, UP_FLAG, hat_state, dev->map.hat_dir_dpup);
if (hat_index == dev->map.hat_dpdown)
set_hat(dev->buttonFlags, DOWN_FLAG, hat_state, dev->map.hat_dir_dpdown);
if (hat_index == dev->map.hat_dpright)
set_hat(dev->buttonFlags, HAT_RIGHT, hat_state, dev->map.hat_dir_dpright);
if (hat_index == dev->map.hat_dpleft)
set_hat(dev->buttonFlags, HAT_LEFT, hat_state, dev->map.hat_dir_dpleft);
break;
}
default:
if (index == dev->map.abs_leftx)
dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map.reverse_leftx);
else if (index == dev->map.abs_lefty)
dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, !dev->map.reverse_lefty);
else if (index == dev->map.abs_rightx)
dev->rightStickX = evdev_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rightx);
else if (index == dev->map.abs_righty)
dev->rightStickY = evdev_convert_value(ev, dev, &dev->ryParms, !dev->map.reverse_righty);
else if (index == dev->map.abs_lefttrigger)
dev->leftTrigger = evdev_convert_value_byte(ev, dev, &dev->zParms);
else if (index == dev->map.abs_righttrigger)
dev->rightTrigger = evdev_convert_value_byte(ev, dev, &dev->rzParms);
else
gamepadModified = false;
}
dev->gamepadModified |= gamepadModified;
@@ -410,15 +413,32 @@ void evdev_create(const char* device, char* mapFile) {
if (mapFile != NULL)
mapping_load(mapFile, &(devices[dev].map));
int nbuttons = 0;
for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
if (libevdev_has_event_code(devices[dev].dev, EV_KEY, i))
devices[dev].key_map[i - BTN_MISC] = nbuttons++;
}
for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
if (libevdev_has_event_code(devices[dev].dev, EV_KEY, i))
devices[dev].key_map[i - BTN_MISC] = nbuttons++;
}
int naxes = 0;
for (int i = 0; i < ABS_MAX; ++i) {
/* Skip hats */
if (i == ABS_HAT0X)
i = ABS_HAT3Y;
else if (libevdev_has_event_code(devices[dev].dev, EV_ABS, i))
devices[dev].abs_map[i] = naxes++;
}
devices[dev].controllerId = -1;
evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_x);
evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_y);
evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_z);
evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rx);
evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_ry);
evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_rz);
evdev_init_parms(&devices[dev], &(devices[dev].dpadxParms), devices[dev].map.abs_dpad_x);
evdev_init_parms(&devices[dev], &(devices[dev].dpadyParms), devices[dev].map.abs_dpad_y);
evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_leftx);
evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_lefty);
evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_lefttrigger);
evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rightx);
evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_righty);
evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_righttrigger);
if (grabbingDevices) {
if (ioctl(fd, EVIOCGRAB, 1) < 0) {

View File

@@ -33,89 +33,104 @@ void mapping_load(char* fileName, struct mapping* map) {
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, fd) != -1) {
char *key = NULL, *value = NULL;
if (sscanf(line, "%ms = %ms", &key, &value) == 2) {
long int_value = strtol(value, NULL, 10);
if (strcmp("abs_x", key) == 0)
map->abs_x = int_value;
else if (strcmp("abs_y", key) == 0)
map->abs_y = int_value;
else if (strcmp("abs_z", key) == 0)
map->abs_z = int_value;
else if (strcmp("abs_rx", key) == 0)
map->abs_rx = int_value;
else if (strcmp("abs_ry", key) == 0)
map->abs_ry = int_value;
else if (strcmp("abs_rz", key) == 0)
map->abs_rz = int_value;
else if (strcmp("abs_deadzone", key) == 0)
map->abs_deadzone = int_value;
else if (strcmp("hat_dpad_right", key) == 0)
map->hat_dpad_right = int_value;
else if (strcmp("hat_dpad_left", key) == 0)
map->hat_dpad_left = int_value;
else if (strcmp("hat_dpad_up", key) == 0)
map->hat_dpad_up = int_value;
else if (strcmp("hat_dpad_down", key) == 0)
map->hat_dpad_down = int_value;
else if (strcmp("hat_dpad_dir_right", key) == 0)
map->hat_dpad_dir_right = int_value;
else if (strcmp("hat_dpad_dir_left", key) == 0)
map->hat_dpad_dir_left = int_value;
else if (strcmp("hat_dpad_dir_up", key) == 0)
map->hat_dpad_dir_up = int_value;
else if (strcmp("hat_dpad_dir_down", key) == 0)
map->hat_dpad_dir_down = int_value;
else if (strcmp("btn_south", key) == 0)
map->btn_south = int_value;
else if (strcmp("btn_north", key) == 0)
map->btn_north = int_value;
else if (strcmp("btn_east", key) == 0)
map->btn_east = int_value;
else if (strcmp("btn_west", key) == 0)
map->btn_west = int_value;
else if (strcmp("btn_select", key) == 0)
map->btn_select = int_value;
else if (strcmp("btn_start", key) == 0)
map->btn_start = int_value;
else if (strcmp("btn_mode", key) == 0)
map->btn_mode = int_value;
else if (strcmp("btn_thumbl", key) == 0)
map->btn_thumbl = int_value;
else if (strcmp("btn_thumbr", key) == 0)
map->btn_thumbr = int_value;
else if (strcmp("btn_tl", key) == 0)
map->btn_tl = int_value;
else if (strcmp("btn_tr", key) == 0)
map->btn_tr = int_value;
else if (strcmp("btn_tl2", key) == 0)
map->btn_tl2 = int_value;
else if (strcmp("btn_tr2", key) == 0)
map->btn_tr2 = int_value;
else if (strcmp("btn_dpad_up", key) == 0)
map->btn_dpad_up = int_value;
else if (strcmp("btn_dpad_down", key) == 0)
map->btn_dpad_down = int_value;
else if (strcmp("btn_dpad_left", key) == 0)
map->btn_dpad_left = int_value;
else if (strcmp("btn_dpad_right", key) == 0)
map->btn_dpad_right = int_value;
else if (strcmp("reverse_x", key) == 0)
map->reverse_x = strcmp("true", value) == 0;
else if (strcmp("reverse_y", key) == 0)
map->reverse_y = strcmp("true", value) == 0;
else if (strcmp("reverse_rx", key) == 0)
map->reverse_rx = strcmp("true", value) == 0;
else if (strcmp("reverse_ry", key) == 0)
map->reverse_ry = strcmp("true", value) == 0;
else
fprintf(stderr, "Can't map (%s)\n", key);
}
if (key != NULL)
free(key);
char* strpoint;
char* guid = strtok_r(line, ",", &strpoint);
char* name = strtok_r(NULL, ",", &strpoint);
if (guid == NULL || name == NULL)
continue;
if (value != NULL)
free(value);
strncpy(map->guid, guid, sizeof(map->guid));
strncpy(map->name, name, sizeof(map->name));
char* option;
while ((option = strtok_r(NULL, ",", &strpoint)) != NULL) {
char *key = NULL, *value = NULL;
int ret;
if ((ret = sscanf(option, "%m[^:]:%ms", &key, &value)) == 2) {
int int_value, direction_value;
char flag = NULL;
if (strcmp("platform", key) == 0)
strncpy(map->platform, value, sizeof(map->platform));
else if (sscanf(value, "b%d", &int_value) == 1) {
if (strcmp("a", key) == 0)
map->btn_a = int_value;
else if (strcmp("y", key) == 0)
map->btn_y = int_value;
else if (strcmp("x", key) == 0)
map->btn_x = int_value;
else if (strcmp("b", key) == 0)
map->btn_b = int_value;
else if (strcmp("back", key) == 0)
map->btn_back = int_value;
else if (strcmp("start", key) == 0)
map->btn_start = int_value;
else if (strcmp("guide", key) == 0)
map->btn_guide = int_value;
else if (strcmp("dpup", key) == 0)
map->btn_dpup = int_value;
else if (strcmp("dpdown", key) == 0)
map->btn_dpdown = int_value;
else if (strcmp("dpleft", key) == 0)
map->btn_dpleft = int_value;
else if (strcmp("dpright", key) == 0)
map->btn_dpright = int_value;
else if (strcmp("leftstick", key) == 0)
map->btn_leftstick = int_value;
else if (strcmp("rightstick", key) == 0)
map->btn_rightstick = int_value;
else if (strcmp("leftshoulder", key) == 0)
map->btn_leftshoulder = int_value;
else if (strcmp("rightshoulder", key) == 0)
map->btn_rightshoulder = int_value;
else if (strcmp("lefttrigger", key) == 0)
map->btn_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->btn_righttrigger = int_value;
} else if (sscanf(value, "a%d%c", &int_value, &flag) >= 1) {
if (strcmp("leftx", key) == 0) {
map->abs_leftx = int_value;
map->reverse_leftx = flag == '~';
} else if (strcmp("lefty", key) == 0) {
map->abs_lefty = int_value;
map->reverse_lefty = flag == '~';
} else if (strcmp("rightx", key) == 0) {
map->abs_rightx = int_value;
map->reverse_rightx = flag == '~';
} else if (strcmp("righty", key) == 0) {
map->abs_righty = int_value;
map->reverse_righty = flag == '~';
} else if (strcmp("lefttrigger", key) == 0)
map->abs_lefttrigger = int_value;
else if (strcmp("righttrigger", key) == 0)
map->abs_righttrigger = int_value;
} else if (sscanf(value, "h%d.%d", &int_value, &direction_value) == 2) {
if (strcmp("dpright", key) == 0) {
map->hat_dpright = int_value;
map->hat_dir_dpright = direction_value;
} else if (strcmp("dpleft", key) == 0) {
map->hat_dpleft = int_value;
map->hat_dir_dpleft = direction_value;
} else if (strcmp("dpup", key) == 0) {
map->hat_dpup = int_value;
map->hat_dir_dpup = direction_value;
} else if (strcmp("dpdown", key) == 0) {
map->hat_dpdown = int_value;
map->hat_dir_dpdown = direction_value;
}
} else
fprintf(stderr, "Can't map (%s)\n", option);
} else if (ret == 0 && option[0] != '\n')
fprintf(stderr, "Can't map (%s)\n", option);
if (key != NULL)
free(key);
if (value != NULL)
free(value);
}
map->guid[32] = '\0';
map->name[256] = '\0';
map->platform[32] = '\0';
}
free(line);
}

View File

@@ -20,23 +20,27 @@
#include <stdbool.h>
struct mapping {
short abs_x, abs_y, abs_z;
short abs_rx, abs_ry, abs_rz;
char guid[33];
char platform[33];
char name[257];
bool reverse_x, reverse_y;
bool reverse_rx, reverse_ry;
bool reverse_leftx, reverse_lefty;
bool reverse_rightx, reverse_righty;
short abs_leftx, abs_lefty;
short abs_rightx, abs_righty;
short abs_deadzone;
short abs_dpad_x, abs_dpad_y;
bool reverse_dpad_x, reverse_dpad_y;
short btn_south, btn_east, btn_north, btn_west;
short btn_select, btn_start, btn_mode;
short btn_thumbl, btn_thumbr;
short btn_tl, btn_tr, btn_tl2, btn_tr2;
short btn_dpad_up, btn_dpad_down, btn_dpad_left, btn_dpad_right;
short hat_dpright, hat_dpleft, hat_dpup, hat_dpdown;
short hat_dir_dpright, hat_dir_dpleft, hat_dir_dpup, hat_dir_dpdown;
short btn_dpup, btn_dpdown, btn_dpleft, btn_dpright;
short btn_a, btn_x, btn_y, btn_b;
short btn_back, btn_start, btn_guide;
short btn_leftstick, btn_rightstick;
short btn_leftshoulder, btn_rightshoulder;
short abs_lefttrigger, abs_righttrigger;
short btn_lefttrigger, btn_righttrigger;
};
void mapping_load(char* fileName, struct mapping* map);