diff --git a/src/pc/controller/controller_api.h b/src/pc/controller/controller_api.h index 6e55c846..d4a9d86c 100644 --- a/src/pc/controller/controller_api.h +++ b/src/pc/controller/controller_api.h @@ -16,18 +16,24 @@ #include struct ControllerAPI { - const u32 vkbase; // base number in the virtual keyspace (e.g. keyboard is 0x0000-0x1000) - void (*init)(void); // call once, also calls reconfig() - void (*read)(OSContPad *pad); // read controller and update N64 pad values - u32 (*rawkey)(void); // returns last pressed virtual key or VK_INVALID if none - void (*reconfig)(void); // (optional) call when bindings have changed - void (*shutdown)(void); // (optional) call in osContReset + const u32 vkbase; // base number in the virtual keyspace (e.g. keyboard is 0x0000-0x1000) + void (*init)(void); // call once, also calls reconfig() + void (*read)(OSContPad *pad); // read controller and update N64 pad values + u32 (*rawkey)(void); // returns last pressed virtual key or VK_INVALID if none + void (*rumble_play)(float str, float time); // (optional) rumble with intensity `str` (0 - 1) for `time` seconds + void (*rumble_stop)(void); // (optional) stop any ongoing haptic feedback + void (*reconfig)(void); // (optional) call when bindings have changed + void (*shutdown)(void); // (optional) call in osContReset }; // used for binding keys u32 controller_get_raw_key(void); void controller_reconfigure(void); +// rumbles all controllers with rumble support +void controller_rumble_play(float str, float time); +void controller_rumble_stop(void); + // calls the shutdown() function of all controller subsystems void controller_shutdown(void); diff --git a/src/pc/controller/controller_entry_point.c b/src/pc/controller/controller_entry_point.c index b8b54ad3..fae9d657 100644 --- a/src/pc/controller/controller_entry_point.c +++ b/src/pc/controller/controller_entry_point.c @@ -31,15 +31,18 @@ s32 osContInit(OSMesgQueue *mq, u8 *controllerBits, OSContStatus *status) { s32 osMotorStart(void *pfs) { // Since rumble stops by osMotorStop, its duration is not nessecary. - return controller_rumble_play(configRumbleStrength / 100.0, 50); + // Set it to 5 seconds and hope osMotorStop() is called in time. + controller_rumble_play(configRumbleStrength / 100.0f, 5.0f); + return 0; } s32 osMotorStop(void *pfs) { - return controller_rumble_stop(); + controller_rumble_stop(); + return 0; } u32 osMotorInit(OSMesgQueue *mq, void *pfs, s32 port) { - return controller_rumble_init(); + return 0; // rumble is initialized in the specific backend's init function } s32 osContStartReadData(OSMesgQueue *mesg) { @@ -93,3 +96,17 @@ void controller_reconfigure(void) { controller_implementations[i]->reconfig(); } } + +void controller_rumble_play(float str, float time) { + for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) { + if (controller_implementations[i]->rumble_play) + controller_implementations[i]->rumble_play(str, time); + } +} + +void controller_rumble_stop(void) { + for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) { + if (controller_implementations[i]->rumble_stop) + controller_implementations[i]->rumble_stop(); + } +} diff --git a/src/pc/controller/controller_recorded_tas.c b/src/pc/controller/controller_recorded_tas.c index 2fcd5b54..73b507dc 100644 --- a/src/pc/controller/controller_recorded_tas.c +++ b/src/pc/controller/controller_recorded_tas.c @@ -39,6 +39,8 @@ struct ControllerAPI controller_recorded_tas = { tas_init, tas_read, tas_rawkey, + NULL, // no rumble_play + NULL, // no rumble_stop NULL, // no rebinding tas_shutdown }; diff --git a/src/pc/controller/controller_sdl.c b/src/pc/controller/controller_sdl.c index 683eefbb..368179f3 100644 --- a/src/pc/controller/controller_sdl.c +++ b/src/pc/controller/controller_sdl.c @@ -113,6 +113,24 @@ static void controller_sdl_init(void) { init_ok = true; } +static SDL_Haptic *controller_sdl_init_haptics(const int joy) { + SDL_Haptic *hap = SDL_HapticOpen(joy); + if (!hap) return NULL; + + if (SDL_HapticRumbleSupported(hap) != SDL_TRUE) { + SDL_HapticClose(hap); + return NULL; + } + + if (SDL_HapticRumbleInit(hap) != 0) { + SDL_HapticClose(hap); + return NULL; + } + + printf("controller %s has haptics support, rumble enabled\n", SDL_JoystickNameForIndex(joy)); + return hap; +} + static void controller_sdl_read(OSContPad *pad) { if (!init_ok) { return; @@ -138,15 +156,18 @@ static void controller_sdl_read(OSContPad *pad) { SDL_GameControllerUpdate(); if (sdl_cntrl != NULL && !SDL_GameControllerGetAttached(sdl_cntrl)) { + SDL_HapticClose(sdl_haptic); SDL_GameControllerClose(sdl_cntrl); sdl_cntrl = NULL; + sdl_haptic = NULL; } + if (sdl_cntrl == NULL) { for (int i = 0; i < SDL_NumJoysticks(); i++) { if (SDL_IsGameController(i)) { sdl_cntrl = SDL_GameControllerOpen(i); - sdl_haptic = SDL_HapticOpen(i); if (sdl_cntrl != NULL) { + sdl_haptic = controller_sdl_init_haptics(i); break; } } @@ -220,6 +241,16 @@ static void controller_sdl_read(OSContPad *pad) { } } +static void controller_sdl_rumble_play(f32 strength, u32 length) { + if (sdl_haptic) + SDL_HapticRumblePlay(sdl_haptic, strength, length); +} + +static void controller_sdl_rumble_stop(void) { + if (sdl_haptic) + SDL_HapticRumbleStop(sdl_haptic); +} + static u32 controller_sdl_rawkey(void) { if (last_joybutton != VK_INVALID) { const u32 ret = last_joybutton; @@ -252,42 +283,13 @@ static void controller_sdl_shutdown(void) { init_ok = false; } -u32 controller_rumble_init(void) { - if (SDL_HapticRumbleSupported(sdl_haptic) != SDL_TRUE) { - // printf("Controller does not support haptics! %s\n", SDL_GetError()); - return 1; - } - if (SDL_HapticRumbleInit(sdl_haptic) != 0) { - printf("Unable to initialize rumble! %s\n", SDL_GetError()); - return 1; - } - return 0; -} - - -s32 controller_rumble_play(f32 strength, u32 length) { - if (SDL_HapticRumblePlay(sdl_haptic, strength, length) != 0) { - printf("Unable to start rumble! %s\n", SDL_GetError()); - return -1; - } else { - return 0; - } -} - -s32 controller_rumble_stop(void) { - if (SDL_HapticRumbleStop(sdl_haptic) != 0) { - printf("Unable to stop rumble! %s\n", SDL_GetError()); - return -1; - } else { - return 0; - } -} - struct ControllerAPI controller_sdl = { VK_BASE_SDL_GAMEPAD, controller_sdl_init, controller_sdl_read, controller_sdl_rawkey, + controller_sdl_rumble_play, + controller_sdl_rumble_stop, controller_sdl_bind, controller_sdl_shutdown }; diff --git a/src/pc/controller/controller_sdl.h b/src/pc/controller/controller_sdl.h index c1a43cec..bbe8a62c 100644 --- a/src/pc/controller/controller_sdl.h +++ b/src/pc/controller/controller_sdl.h @@ -7,8 +7,4 @@ extern struct ControllerAPI controller_sdl; -u32 controller_rumble_init(void); -s32 controller_rumble_play(f32 strength, u32 length); -s32 controller_rumble_stop(void); - #endif