From 9f43712fc89ab6e56a5a6f777deeb5a7c5fc7192 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 8 Apr 2017 14:25:20 +0200 Subject: [PATCH] Use SDL-style mapping for input --- src/input/evdev.c | 174 +++++++++++++++++++++++------------------- src/input/mapping.c | 179 ++++++++++++++++++++++++-------------------- src/input/mapping.h | 34 +++++---- 3 files changed, 213 insertions(+), 174 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index b241d21..441c770 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -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) { diff --git a/src/input/mapping.c b/src/input/mapping.c index d88a616..2260c12 100644 --- a/src/input/mapping.c +++ b/src/input/mapping.c @@ -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); } diff --git a/src/input/mapping.h b/src/input/mapping.h index 2701b9f..44e2c10 100644 --- a/src/input/mapping.h +++ b/src/input/mapping.h @@ -20,23 +20,27 @@ #include 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);