diff --git a/README.md b/README.md index 2e80606..b8157eb 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,16 @@ add at the moment. To stop the program just kill it in any way you want. Seperate virtual controllers are created for each one plugged into the adapter and hotplugging (both controllers and adapters) is supported. +To calibrate input ranges, first run with the `--calibrate` flag and push your +sticks and shoulder buttons all the way in every direction. Quit the program +and run it again using the given calibration string as the argument for +`--set-calibration-data`. + Quirks ------ * It's new, so there might be bugs! Please report them! * The uinput kernel module is required. If it's not autoloaded, you should do so with `modprobe uinput` -* Input ranges on the sticks/analog triggers are scaled to try to match the - physical ranges of the controls. To remove this scaling run the program with - the `--raw` flag. * If all your controllers start messing with the mouse cursor, you can fix them with this xorg.conf rule. (You can place it in a file in xorg.conf.d) diff --git a/wii-u-gc-adapter.c b/wii-u-gc-adapter.c index cf05b55..e777fe6 100644 --- a/wii-u-gc-adapter.c +++ b/wii-u-gc-adapter.c @@ -65,6 +65,10 @@ const int AXIS_OFFSET_VALUES[6] = { ABS_RZ }; +static uint8_t AXIS_MIN_VALUES[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static uint8_t AXIS_MAX_VALUES[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static bool calibrate = false; + struct ff_event { bool in_use; @@ -98,8 +102,6 @@ struct adapter struct adapter *next; }; -static bool raw_mode; - static volatile int quitting; static struct adapter adapters; @@ -154,23 +156,27 @@ static bool uinput_create(int i, struct ports *port, unsigned char type) ioctl(port->uinput, UI_SET_ABSBIT, ABS_Z); ioctl(port->uinput, UI_SET_ABSBIT, ABS_RZ); - if (raw_mode) - { - uinput_dev.absmin[ABS_X] = 0; uinput_dev.absmax[ABS_X] = 255; - uinput_dev.absmin[ABS_Y] = 0; uinput_dev.absmax[ABS_Y] = 255; - uinput_dev.absmin[ABS_RX] = 0; uinput_dev.absmax[ABS_RX] = 255; - uinput_dev.absmin[ABS_RY] = 0; uinput_dev.absmax[ABS_RY] = 255; - uinput_dev.absmin[ABS_Z] = 0; uinput_dev.absmax[ABS_Z] = 255; - uinput_dev.absmin[ABS_RZ] = 0; uinput_dev.absmax[ABS_RZ] = 255; - } - else - { - uinput_dev.absmin[ABS_X] = 20; uinput_dev.absmax[ABS_X] = 235; - uinput_dev.absmin[ABS_Y] = 20; uinput_dev.absmax[ABS_Y] = 235; - uinput_dev.absmin[ABS_RX] = 30; uinput_dev.absmax[ABS_RX] = 225; - uinput_dev.absmin[ABS_RY] = 30; uinput_dev.absmax[ABS_RY] = 225; - uinput_dev.absmin[ABS_Z] = 25; uinput_dev.absmax[ABS_Z] = 225; - uinput_dev.absmin[ABS_RZ] = 25; uinput_dev.absmax[ABS_RZ] = 225; + if (calibrate) { + uinput_dev.absmin[ABS_X] = 0; uinput_dev.absmax[ABS_X] = 0xFF; + uinput_dev.absmin[ABS_Y] = 0; uinput_dev.absmax[ABS_Y] = 0xFF; + uinput_dev.absmin[ABS_RX] = 0; uinput_dev.absmax[ABS_RX] = 0xFF; + uinput_dev.absmin[ABS_RY] = 0; uinput_dev.absmax[ABS_RY] = 0xFF; + uinput_dev.absmin[ABS_Z] = 0; uinput_dev.absmax[ABS_Z] = 0xFF; + uinput_dev.absmin[ABS_RZ] = 0; uinput_dev.absmax[ABS_RZ] = 0xFF; + } else { + uinput_dev.absmin[ABS_X] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_X]]; + uinput_dev.absmin[ABS_Y] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_Y]]; + uinput_dev.absmin[ABS_RX] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_RX]]; + uinput_dev.absmin[ABS_RY] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_RY]]; + uinput_dev.absmin[ABS_Z] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_Z]]; + uinput_dev.absmin[ABS_RZ] = AXIS_MIN_VALUES[AXIS_OFFSET_VALUES[ABS_RZ]]; + + uinput_dev.absmax[ABS_X] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_X]]; + uinput_dev.absmax[ABS_Y] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_Y]]; + uinput_dev.absmax[ABS_RX] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_RX]]; + uinput_dev.absmax[ABS_RY] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_RY]]; + uinput_dev.absmax[ABS_Z] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_Z]]; + uinput_dev.absmax[ABS_RZ] = AXIS_MAX_VALUES[AXIS_OFFSET_VALUES[ABS_RZ]]; } // rumble @@ -382,6 +388,15 @@ static void handle_payload(int i, struct ports *port, unsigned char *payload, st if (AXIS_OFFSET_VALUES[j] == ABS_Y || AXIS_OFFSET_VALUES[j] == ABS_RY) value ^= 0xFF; // flip from 0 - 255 to 255 - 0 + if (calibrate) { + if (value < AXIS_MIN_VALUES[j]) { + AXIS_MIN_VALUES[j] = value; + } + if (value > AXIS_MAX_VALUES[j]) { + AXIS_MAX_VALUES[j] = value; + } + } + if (port->axis[j] != value) { events[e_count].type = EV_ABS; @@ -461,6 +476,14 @@ static void handle_payload(int i, struct ports *port, unsigned char *payload, st } } +void print_calibration_data() +{ + for (size_t i = 0; i < sizeof(AXIS_MIN_VALUES); i++) { + printf("%d,%d,", AXIS_MIN_VALUES[i], AXIS_MAX_VALUES[i]); + } + printf("\n"); +} + static void *adapter_thread(void *data) { struct adapter *a = (struct adapter *)data; @@ -530,6 +553,10 @@ static void *adapter_thread(void *data) break; } } + + if (calibrate) { + print_calibration_data(); + } } for (int i = 0; i < 4; i++) @@ -637,42 +664,75 @@ enum { }; static struct option options[] = { - { "raw", no_argument, 0, 'r' }, + { "calibrate", no_argument, 0, 'c' }, + { "set-calibration-data", required_argument, 0, 's' }, { "vendor", required_argument, 0, opt_vendor }, { "product", required_argument, 0, opt_product }, { 0, 0, 0, 0 }, }; -int main(int argc, char *argv[]) +void set_calibration_data(char str[]) { - struct udev *udev; - struct udev_device *uinput; - struct sigaction sa; + char *token = strtok(str, ","); + for (size_t i = 0; token && i < sizeof(AXIS_MIN_VALUES); i++) { + AXIS_MIN_VALUES[i] = atoi(token); + token = strtok(NULL, ","); - memset(&sa, 0, sizeof(sa)); + AXIS_MAX_VALUES[i] = atoi(token); + token = strtok(NULL, ","); + } +} - while (1) { +void parse_args(int argc, char *argv[]) +{ + bool has_calibration_data = false; + for (;;) { int option_index = 0; int c = getopt_long(argc, argv, "r", options, &option_index); if (c == -1) break; switch (c) { - case 'r': - fprintf(stderr, "raw mode enabled\n"); - raw_mode = true; - break; - case opt_vendor: - vendor_id = parse_id(optarg); - fprintf(stderr, "vendor_id = %#06x\n", vendor_id); - break; - case opt_product: - product_id = parse_id(optarg); - fprintf(stderr, "product_id = %#06x\n", product_id); - break; + case 'c': + fprintf(stderr, "displaying calibration data, quit to display the results\n"); + calibrate = true; + break; + case 's': + set_calibration_data(optarg); + has_calibration_data = true; + break; + case opt_vendor: + vendor_id = parse_id(optarg); + fprintf(stderr, "vendor_id = %#06x\n", vendor_id); + break; + case opt_product: + product_id = parse_id(optarg); + fprintf(stderr, "product_id = %#06x\n", product_id); + break; } } + if (!has_calibration_data && !calibrate) { + memset(&AXIS_MIN_VALUES, 0, sizeof(AXIS_MIN_VALUES)); + memset(&AXIS_MAX_VALUES, 0xFF, sizeof(AXIS_MAX_VALUES)); + } + + if (!calibrate) { + printf("using calibration data: "); + print_calibration_data(); + } +} + +int main(int argc, char *argv[]) +{ + struct udev *udev; + struct udev_device *uinput; + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + + parse_args(argc, argv); + sa.sa_handler = quitting_signal; sa.sa_flags = SA_RESTART | SA_RESETHAND; sigemptyset(&sa.sa_mask);