From a9ebc30ea7b96bfa542c226ed04be066e2cb819a Mon Sep 17 00:00:00 2001 From: Will Xyen Date: Sat, 26 Sep 2020 18:46:17 -0700 Subject: [PATCH] vigem-sdvxio: Add relative mode and address comments --- doc/sdvxhook/vigem-sdvxio.md | 20 ++--- src/main/vigem-sdvxio/config-vigem-sdvxio.c | 25 +++++- src/main/vigem-sdvxio/config-vigem-sdvxio.h | 3 +- src/main/vigem-sdvxio/main.c | 89 ++++++++++++++++++++- src/main/vigemstub/Module.mk | 1 + src/main/vigemstub/helper.c | 9 ++- 6 files changed, 126 insertions(+), 21 deletions(-) diff --git a/doc/sdvxhook/vigem-sdvxio.md b/doc/sdvxhook/vigem-sdvxio.md index 8eed331..4098ab4 100644 --- a/doc/sdvxhook/vigem-sdvxio.md +++ b/doc/sdvxhook/vigem-sdvxio.md @@ -1,24 +1,24 @@ -This application allows you to use any sdvxio backend to drive an XB360 controller. +This application allows you to use any sdvxio backend, e.g. `sdvxio-kfca.dll`, to be available as a XBOX 360 game controller on windows. Thus, it allows you to use a real cab with *any* game that supports xinput. # Setup -* Install ViGEmBus (https://github.com/ViGEm/ViGEmBus/releases) +* Install [ViGEmBus](https://github.com/ViGEm/ViGEmBus/releases) * Place the following in the same folder as vigem-sdvxio: - * Get a copy of ViGEmClient.dll (https://bin.jvnv.net/file/ZgMJK/ViGEmClient.zip) - * Rename your corresponding sdvxio-device.dll to sdvxio.dll. -* Run vigem-sdvxio.exe so that the config file gets created -* Edit vigem-sdvxio.conf so that the config file gets created as needed + * Get a copy of [ViGEmClient.dll](https://bin.jvnv.net/file/ZgMJK/ViGEmClient.zip) (or from bemanitools-supplements) + * Rename your corresponding `sdvxio-XXX.dll`, e.g. `sdvxio-kfca.dll`, to `sdvxio.dll`. +* Run `vigem-sdvxio.exe` so that the config file gets created +* Edit `vigem-sdvxio.conf` so that the config file gets created as needed # Usage -* Run vigem-sdvxio.exe +* Run `vigem-sdvxio.exe` * To quit the program, hit the TEST + SERVICE button at the same time # Mapping * BT ABCD are mapped to ABXY * FX LR are mapped to LB/RB -* VOL LR are mapped to L/R thumbstick X +* VOL LR are mapped to L thumbstick X/Y (either in absolute or relative mode depending on the config) -# Additional Notes For Cabinets: -* Make sure that you follow the instructions exactly from the release page (Prerequisites for Windows 7) +# Additional Notes For Cabinets (Running on embedded Windows 7): +* Make sure that you follow the instructions exactly from the release page ([Prerequisites for Windows 7](https://github.com/ViGEm/ViGEmBus/wiki/Prerequisites-for-Windows-7)) * If you get an error while trying to install KB3033929, re-enable windows update * Make sure to ewfmgr C: -commit and reboot after installing the drivers (this only needs to be done once) diff --git a/src/main/vigem-sdvxio/config-vigem-sdvxio.c b/src/main/vigem-sdvxio/config-vigem-sdvxio.c index 1060351..2d86878 100644 --- a/src/main/vigem-sdvxio/config-vigem-sdvxio.c +++ b/src/main/vigem-sdvxio/config-vigem-sdvxio.c @@ -6,11 +6,13 @@ #include "util/log.h" #define VIGEM_SDVXIO_CONFIG_ENABLE_KEYLIGHT_KEY "sdvxio.enable_keylight" +#define VIGEM_SDVXIO_CONFIG_RELATIVE_ANALOG_KEY "sdvxio.use_relative_analog" #define VIGEM_SDVXIO_CONFIG_PWM_WINGS_KEY "sdvxio.pwm_wings" #define VIGEM_SDVXIO_CONFIG_PWM_CONTROLLER_KEY "sdvxio.pwm_controller" #define VIGEM_SDVXIO_CONFIG_AMP_VOLUME_KEY "sdvxio.amp_volume" #define VIGEM_SDVXIO_CONFIG_DEFAULT_ENABLE_KEYLIGHT_VALUE true +#define VIGEM_SDVXIO_CONFIG_DEFAULT_RELATIVE_ANALOG_VALUE false #define VIGEM_SDVXIO_CONFIG_DEFAULT_PWM_WINGS_VALUE 128 #define VIGEM_SDVXIO_CONFIG_DEFAULT_PWM_CONTROLLER_VALUE 64 #define VIGEM_SDVXIO_CONFIG_DEFAULT_AMP_VOLUME_VALUE 48 @@ -23,6 +25,12 @@ void vigem_sdvxio_config_init(struct cconfig *config) VIGEM_SDVXIO_CONFIG_DEFAULT_ENABLE_KEYLIGHT_VALUE, "Enable input based key lighting"); + cconfig_util_set_bool( + config, + VIGEM_SDVXIO_CONFIG_RELATIVE_ANALOG_KEY, + VIGEM_SDVXIO_CONFIG_DEFAULT_RELATIVE_ANALOG_VALUE, + "Use relative mode analog mapping"); + cconfig_util_set_int( config, VIGEM_SDVXIO_CONFIG_PWM_WINGS_KEY, @@ -57,6 +65,18 @@ void vigem_sdvxio_config_get( VIGEM_SDVXIO_CONFIG_DEFAULT_ENABLE_KEYLIGHT_VALUE); } + if (!cconfig_util_get_bool( + config, + VIGEM_SDVXIO_CONFIG_RELATIVE_ANALOG_KEY, + &vigem_config->relative_analog, + VIGEM_SDVXIO_CONFIG_DEFAULT_RELATIVE_ANALOG_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + VIGEM_SDVXIO_CONFIG_RELATIVE_ANALOG_KEY, + VIGEM_SDVXIO_CONFIG_DEFAULT_RELATIVE_ANALOG_VALUE); + } + if (!cconfig_util_get_int( config, VIGEM_SDVXIO_CONFIG_PWM_WINGS_KEY, @@ -94,7 +114,7 @@ void vigem_sdvxio_config_get( } } -void get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out) +bool get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out) { struct cconfig *config; @@ -111,7 +131,7 @@ void get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out) "vigem-sdvxio", CCONFIG_CMD_USAGE_OUT_STDOUT)) { cconfig_finit(config); - exit(EXIT_FAILURE); + return false; } vigem_sdvxio_config_get(config_out, config); @@ -125,4 +145,5 @@ void get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out) if (config_out->pwm_wings > 255) { config_out->pwm_wings = 255; } + return true; } diff --git a/src/main/vigem-sdvxio/config-vigem-sdvxio.h b/src/main/vigem-sdvxio/config-vigem-sdvxio.h index 359fe29..b689735 100644 --- a/src/main/vigem-sdvxio/config-vigem-sdvxio.h +++ b/src/main/vigem-sdvxio/config-vigem-sdvxio.h @@ -7,11 +7,12 @@ struct vigem_sdvxio_config { bool enable_keylight; + bool relative_analog; int32_t pwm_wings; int32_t pwm_controller; int32_t amp_volume; }; -void get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out); +bool get_vigem_sdvxio_config(struct vigem_sdvxio_config *config_out); #endif \ No newline at end of file diff --git a/src/main/vigem-sdvxio/main.c b/src/main/vigem-sdvxio/main.c index 796dd4b..ee9c17c 100644 --- a/src/main/vigem-sdvxio/main.c +++ b/src/main/vigem-sdvxio/main.c @@ -15,12 +15,74 @@ #include "vigem-sdvxio/config-vigem-sdvxio.h" -int64_t convert_analog_to_s16(uint16_t val) +#define ANALOG_FIXED_SENSITIVITY 1024 + +int16_t convert_analog_to_s16(uint16_t val) { // val is 10 bit return (int64_t)(val * 64); } +int16_t get_relative_delta(int16_t val, int16_t last) +{ + // val is 10 bit + const int16_t half_point = 512; // 2^9 + + int16_t delta = val - last; + + if (delta > half_point) { + delta -= 1024; + } + + if (delta < -half_point) { + delta += 1024; + } + + // delta is now between (-512 - 512) + return delta; +} + +int16_t filter_floor(int32_t value, int16_t floor) { + if (abs(value) < floor) { + return 0; + } + if (value > INT16_MAX) { + value = INT16_MAX; + } + if (value < INT16_MIN) { + value = INT16_MIN; + } + + return value; +} + +int32_t convert_relative_analog( + uint16_t val, uint16_t last, int32_t buffered_last, int16_t multiplier) +{ + int16_t delta = get_relative_delta(val, last); + + if (delta == 0) { + // ease the stick back to 0 like a real stick would + return buffered_last / 2.f; + } else { + int64_t result = buffered_last; + result += delta * multiplier; + + // we use an i32 to store the buffered value + // so that we can overshoot an i16 by up to 1.5x + // this allows users to stay at the min/max stick positions + // without perfect knob turning + if (result > INT16_MAX*1.5) { + result = INT16_MAX*1.5; + } + if (result < INT16_MIN*1.5) { + result = INT16_MIN*1.5; + } + + return result; + } +} + bool check_key(uint16_t input, size_t idx_in) { if ((input >> idx_in) & 1) { @@ -87,7 +149,9 @@ int main(int argc, char **argv) log_to_writer(log_writer_stdout, NULL); struct vigem_sdvxio_config config; - get_vigem_sdvxio_config(&config); + if (!get_vigem_sdvxio_config(&config)) { + exit(EXIT_FAILURE); + } sdvx_io_set_loggers( log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal); @@ -100,12 +164,14 @@ int main(int argc, char **argv) sdvx_io_set_amp_volume(config.amp_volume, config.amp_volume, config.amp_volume); PVIGEM_CLIENT client = vigem_helper_setup(); + if (!client) { log_warning("client failed to connect failed"); return -1; } PVIGEM_TARGET pad = vigem_helper_add_pad(client); + if (!pad) { log_warning("vigem_alloc pad 1 failed"); return -1; @@ -117,10 +183,14 @@ int main(int argc, char **argv) uint16_t gpio0; uint16_t gpio1; uint16_t vol[2] = {0, 0}; + uint16_t last_vol[2] = {0, 0}; + + int32_t buffered_vol[2] = {0, 0}; XUSB_REPORT state; log_info("vigem init succeeded, beginning poll loop"); + while (loop) { sdvx_io_read_input(); @@ -133,8 +203,19 @@ int main(int argc, char **argv) memset(&state, 0, sizeof(state)); - state.sThumbLX = convert_analog_to_s16(vol[0]); - state.sThumbRX = convert_analog_to_s16(vol[1]); + if (config.relative_analog) { + buffered_vol[0] = convert_relative_analog(vol[0], last_vol[0], buffered_vol[0], ANALOG_FIXED_SENSITIVITY); + buffered_vol[1] = convert_relative_analog(vol[1], last_vol[1], buffered_vol[1], ANALOG_FIXED_SENSITIVITY); + + state.sThumbLX = filter_floor(buffered_vol[0], ANALOG_FIXED_SENSITIVITY/2); + state.sThumbLY = filter_floor(buffered_vol[1], ANALOG_FIXED_SENSITIVITY/2); + + last_vol[0] = vol[0]; + last_vol[1] = vol[1]; + } else { + state.sThumbLX = convert_analog_to_s16(vol[0]); + state.sThumbLY = convert_analog_to_s16(vol[1]); + } state.wButtons |= check_assign_key( gpio0, SDVX_IO_IN_GPIO_0_START, XUSB_GAMEPAD_START); diff --git a/src/main/vigemstub/Module.mk b/src/main/vigemstub/Module.mk index cdb94fb..f1c8479 100644 --- a/src/main/vigemstub/Module.mk +++ b/src/main/vigemstub/Module.mk @@ -5,6 +5,7 @@ cppflags_vigemstub := \ -I src/imports \ libs_vigemstub := \ + util \ src_vigemstub := \ helper.c \ diff --git a/src/main/vigemstub/helper.c b/src/main/vigemstub/helper.c index 9f2df6c..47ba018 100644 --- a/src/main/vigemstub/helper.c +++ b/src/main/vigemstub/helper.c @@ -4,6 +4,7 @@ #include "ViGEm/Client.h" +#include "util/log.h" #include "vigemstub/helper.h" PVIGEM_CLIENT vigem_helper_setup(void) @@ -11,14 +12,14 @@ PVIGEM_CLIENT vigem_helper_setup(void) PVIGEM_CLIENT client = vigem_alloc(); if (client == NULL) { - printf("vigem_alloc failed\n"); + log_warning("vigem_alloc failed\n"); return NULL; } VIGEM_ERROR retval = vigem_connect(client); if (!VIGEM_SUCCESS(retval)) { - printf("ViGEm Bus connection failed with error code: 0x%x\n", retval); + log_warning("ViGEm Bus connection failed with error code: 0x%x\n", retval); return NULL; } @@ -30,14 +31,14 @@ PVIGEM_TARGET vigem_helper_add_pad(PVIGEM_CLIENT client) PVIGEM_TARGET pad = vigem_target_x360_alloc(); if (pad == NULL) { - printf("vigem_target_x360_alloc failed\n"); + log_warning("vigem_target_x360_alloc failed\n"); return NULL; } VIGEM_ERROR pir = vigem_target_add(client, pad); if (!VIGEM_SUCCESS(pir)) { - printf("Target plugin failed with error code: 0x%x\n", pir); + log_warning("Target plugin failed with error code: 0x%x\n", pir); return NULL; }