Add map function to create controller mappings

This commit is contained in:
Iwan Timmer 2017-10-24 20:51:08 +02:00
parent a0c43053e7
commit f08b701223
6 changed files with 185 additions and 4 deletions

View File

@ -31,6 +31,10 @@ List all available games and application on host.
Quit the current running game or application on host. Quit the current running game or application on host.
=item B<map>
Create a mapping for the specified I<INPUT> device.
=item B<help> =item B<help>
Show help for all available commands. Show help for all available commands.

View File

@ -84,6 +84,8 @@ static int numDevices = 0;
static int assignedControllerIds = 0; static int assignedControllerIds = 0;
static short* currentKey; static short* currentKey;
static short* currentHat;
static short* currentHatDir;
static short* currentAbs; static short* currentAbs;
static bool* currentReverse; static bool* currentReverse;
@ -366,28 +368,42 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
} }
static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) { static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) {
int index, hat_index;
switch (ev->type) { switch (ev->type) {
case EV_KEY: case EV_KEY:
index = ev->code > BTN_MISC && ev->code < (BTN_MISC + KEY_MAX) ? dev->key_map[ev->code - BTN_MISC] : -1;
if (currentKey != NULL) { if (currentKey != NULL) {
if (ev->value) if (ev->value)
*currentKey = ev->code; *currentKey = index;
else if (ev->code == *currentKey) else if (*currentKey != -1 && index == *currentKey)
return false; return false;
} }
break; break;
case EV_ABS: case EV_ABS:
hat_index = (ev->code - ABS_HAT0X) / 2;
if (hat_index >= 0 && hat_index < 4) {
int hat_dir_index = (ev->code - ABS_HAT0X) % 2;
dev->hats_state[hat_index][hat_dir_index] = ev->value < 0 ? -1 : (ev->value == 0 ? 0 : 1);
}
if (currentAbs != NULL) { if (currentAbs != NULL) {
struct input_abs_parms parms; struct input_abs_parms parms;
evdev_init_parms(dev, &parms, ev->code); evdev_init_parms(dev, &parms, ev->code);
printf("%d: %d >< %d / %d\n", ev->code, ev->value, parms.avg + parms.range/2, parms.avg - parms.range/2);
if (ev->value > parms.avg + parms.range/2) { if (ev->value > parms.avg + parms.range/2) {
*currentAbs = ev->code; *currentAbs = dev->abs_map[ev->code];
*currentReverse = false; *currentReverse = false;
} else if (ev->value < parms.avg - parms.range/2) { } else if (ev->value < parms.avg - parms.range/2) {
*currentAbs = ev->code; *currentAbs = dev->abs_map[ev->code];
*currentReverse = true; *currentReverse = true;
} else if (ev->code == *currentAbs) } else if (ev->code == *currentAbs)
return false; return false;
} else if (currentHat != NULL) {
if (hat_index >= 0 && hat_index < 4) {
*currentHat = hat_index;
*currentHatDir = hat_constants[dev->hats_state[hat_index][1] + 1][dev->hats_state[hat_index][0] + 1];
return false;
}
} }
break; break;
} }
@ -537,6 +553,117 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) {
loop_add_fd(devices[dev].fd, &evdev_handle, POLLIN); loop_add_fd(devices[dev].fd, &evdev_handle, POLLIN);
} }
static void evdev_map_key(char* keyName, short* key) {
printf("Press %s\n", keyName);
currentKey = key;
currentHat = NULL;
currentAbs = NULL;
*key = -1;
loop_main();
usleep(250000);
evdev_drain();
}
static void evdev_map_abs(char* keyName, short* abs, bool* reverse) {
printf("Move %s\n", keyName);
currentKey = NULL;
currentHat = NULL;
currentAbs = abs;
currentReverse = reverse;
*abs = -1;
loop_main();
usleep(250000);
evdev_drain();
}
static void evdev_map_hatkey(char* keyName, short* hat, short* hat_dir, short* key) {
printf("Press %s\n", keyName);
currentKey = key;
currentHat = hat;
currentHatDir = hat_dir;
currentAbs = NULL;
*key = -1;
*hat = -1;
*hat_dir = -1;
*currentReverse = false;
loop_main();
usleep(250000);
evdev_drain();
}
static void evdev_map_abskey(char* keyName, short* abs, short* key, bool* reverse) {
printf("Press %s\n", keyName);
currentKey = key;
currentHat = NULL;
currentAbs = abs;
currentReverse = reverse;
*key = -1;
*abs = -1;
*currentReverse = false;
loop_main();
usleep(250000);
evdev_drain();
}
void evdev_map(char* device) {
int fd = open(device, O_RDONLY|O_NONBLOCK);
struct libevdev *evdev = libevdev_new();
libevdev_set_fd(evdev, fd);
const char* name = libevdev_get_name(evdev);
int16_t guid[8] = {0};
guid[0] = int16_to_le(libevdev_get_id_bustype(evdev));
guid[2] = int16_to_le(libevdev_get_id_vendor(evdev));
guid[4] = int16_to_le(libevdev_get_id_product(evdev));
guid[6] = int16_to_le(libevdev_get_id_version(evdev));
char str_guid[33];
char* buf = str_guid;
for (int i = 0; i < 16; i++)
buf += sprintf(buf, "%02x", ((unsigned char*) guid)[i]);
struct mapping map;
strncpy(map.name, libevdev_get_name(evdev), sizeof(map.name));
strncpy(map.guid, str_guid, sizeof(map.name));
libevdev_free(evdev);
close(fd);
handler = evdev_handle_mapping_event;
evdev_map_abs("Left Stick Right", &(map.abs_leftx), &(map.reverse_leftx));
evdev_map_abs("Left Stick Up", &(map.abs_lefty), &(map.reverse_lefty));
evdev_map_key("Left Stick Button", &(map.btn_leftstick));
evdev_map_abs("Right Stick Right", &(map.abs_rightx), &(map.reverse_rightx));
evdev_map_abs("Right Stick Up", &(map.abs_righty), &(map.reverse_righty));
evdev_map_key("Right Stick Button", &(map.btn_rightstick));
evdev_map_hatkey("D-Pad Right", &(map.hat_dpright), &(map.hat_dir_dpright), &(map.btn_dpright));
evdev_map_hatkey("D-Pad Left", &(map.hat_dpleft), &(map.hat_dir_dpleft), &(map.btn_dpleft));
evdev_map_hatkey("D-Pad Up", &(map.hat_dpup), &(map.hat_dir_dpup), &(map.btn_dpup));
evdev_map_hatkey("D-Pad Down", &(map.hat_dpdown), &(map.hat_dir_dpdown), &(map.btn_dpdown));
evdev_map_key("Button X (1)", &(map.btn_x));
evdev_map_key("Button A (2)", &(map.btn_a));
evdev_map_key("Button B (3)", &(map.btn_b));
evdev_map_key("Button Y (4)", &(map.btn_y));
evdev_map_key("Back Button", &(map.btn_back));
evdev_map_key("Start Button", &(map.btn_start));
evdev_map_key("Special Button", &(map.btn_guide));
bool ignored;
evdev_map_abskey("Left Trigger", &(map.abs_lefttrigger), &(map.btn_lefttrigger), &ignored);
evdev_map_abskey("Right Trigger", &(map.abs_righttrigger), &(map.btn_righttrigger), &ignored);
evdev_map_key("Left Bumper", &(map.btn_leftshoulder));
evdev_map_key("Right Bumper", &(map.btn_rightshoulder));
mapping_print(&map);
}
void evdev_start() { void evdev_start() {
// After grabbing, the only way to quit via the keyboard // After grabbing, the only way to quit via the keyboard
// is via the special key combo that the input handling // is via the special key combo that the input handling

View File

@ -25,3 +25,4 @@ void evdev_loop();
void evdev_init(); void evdev_init();
void evdev_start(); void evdev_start();
void evdev_stop(); void evdev_stop();
void evdev_map(char* device);

View File

@ -155,3 +155,39 @@ struct mapping* mapping_load(char* fileName, bool verbose) {
return mappings; return mappings;
} }
#define print_btn(btn, code) if (code > -1) printf("%s:b%d,", btn, code)
#define print_abs(abs, code) if (code > -1) printf("%s:a%d,", abs, code)
#define print_hat(hat, code, dir) if (code > -1) printf("%s:h%d.%d,", hat, code, dir)
void mapping_print(struct mapping* map) {
printf("%s,%s,", map->guid, map->name);
print_btn("a", map->btn_a);
print_btn("b", map->btn_b);
print_btn("x", map->btn_x);
print_btn("y", map->btn_y);
print_btn("start", map->btn_start);
print_btn("guide", map->btn_guide);
print_btn("back", map->btn_back);
print_btn("leftstick", map->btn_leftstick);
print_btn("rightstick", map->btn_rightstick);
print_btn("leftshoulder", map->btn_leftshoulder);
print_btn("rightshoulder", map->btn_rightshoulder);
print_btn("dpup", map->btn_dpup);
print_btn("dpleft", map->btn_dpleft);
print_btn("dpdown", map->btn_dpdown);
print_btn("dpright", map->btn_dpright);
print_hat("dpup", map->hat_dpup, map->hat_dir_dpup);
print_hat("dpleft", map->hat_dpleft, map->hat_dir_dpleft);
print_hat("dpdown", map->hat_dpdown, map->hat_dir_dpdown);
print_hat("dpright", map->hat_dpright, map->hat_dir_dpright);
print_abs("leftx", map->abs_leftx);
print_abs("lefty", map->abs_lefty);
print_abs("rightx", map->abs_rightx);
print_abs("righty", map->abs_righty);
print_abs("lefttrigger", map->abs_lefttrigger);
print_abs("righttrigger", map->abs_righttrigger);
print_btn("lefttrigger", map->btn_lefttrigger);
print_btn("righttrigger", map->btn_righttrigger);
printf("platform:Linux\n");
}

View File

@ -49,3 +49,4 @@ struct mapping {
struct mapping* mapping_parse(char* mapping); struct mapping* mapping_parse(char* mapping);
struct mapping* mapping_load(char* fileName, bool verbose); struct mapping* mapping_load(char* fileName, bool verbose);
void mapping_print(struct mapping*);

View File

@ -139,6 +139,7 @@ static void help() {
printf("\tstream\t\t\tStream computer to device\n"); printf("\tstream\t\t\tStream computer to device\n");
printf("\tlist\t\t\tList available games and applications\n"); printf("\tlist\t\t\tList available games and applications\n");
printf("\tquit\t\t\tQuit the application or game being streamed\n"); printf("\tquit\t\t\tQuit the application or game being streamed\n");
printf("\tmap\t\t\tCreate mapping file for gamepad\n");
printf("\thelp\t\t\tShow this help\n"); printf("\thelp\t\t\tShow this help\n");
printf("\n Global Options\n\n"); printf("\n Global Options\n\n");
printf("\t-config <config>\tLoad configuration file\n"); printf("\t-config <config>\tLoad configuration file\n");
@ -194,6 +195,17 @@ int main(int argc, char* argv[]) {
if (config.debug_level > 0) if (config.debug_level > 0)
printf("Moonlight Embedded %d.%d.%d (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMPILE_OPTIONS); printf("Moonlight Embedded %d.%d.%d (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMPILE_OPTIONS);
if (strcmp("map", config.action) == 0) {
if (config.inputsCount != 1) {
printf("You need to specify one input device using -input.\n");
exit(-1);
}
evdev_create(config.inputs[0], NULL, config.debug_level > 0);
evdev_map(config.inputs[0]);
exit(0);
}
if (config.address == NULL) { if (config.address == NULL) {
config.address = malloc(MAX_ADDRESS_SIZE); config.address = malloc(MAX_ADDRESS_SIZE);
if (config.address == NULL) { if (config.address == NULL) {