Implement controller rumble support in Gamepad (#1739)

* Add SDL rumble

* Fix rumble

* whitespace fixins real (#2)

* whitespacing real.. please!

* nativecffi rumble thing fix lol

* Remove trailing whitespace.

* Use SDL's argument names and order.

* Standardize formatting.

* Make `SDLGamepad` fully static again, for simplicity.

Also, consistently use `find()` instead of array access, to avoid accidentally creating entries.

Also also, consistently use guard clauses instead of indenting.

* Make another guard clause.

* Update CFFI function signature.

* Use `clamp()` instead of `if` statements.

* Include required header for `std::clamp()`.

* Revert "Use `clamp()` instead of `if` statements."

`std::clamp()` was not available until C++17, and we'd like to continue supporting older versions.

This reverts commit 715a270f79.

* Revert "Include required header for `std::clamp()`."

This reverts commit f47aebf640.

* Tidy up.

* Document `Gamepad.rumble()`'s arguments.

* Don't limit rumble duration.

SDL apparently supports the full Uint32 range, so there's no reason for Lime to restrict it.

* Fix whitespace.

* Add rumble support in HTML5 (experimental).

---------

Co-authored-by: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Co-authored-by: player-03 <player3.14@gmail.com>
This commit is contained in:
Regan Green
2025-09-01 00:29:58 -04:00
committed by GitHub
parent 5b05c3f77e
commit c8beb396f6
6 changed files with 129 additions and 46 deletions

View File

@@ -12,6 +12,7 @@ namespace lime {
static void AddMapping (const char* content);
static const char* GetDeviceGUID (int id);
static const char* GetDeviceName (int id);
static void Rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration);
};

View File

@@ -1765,6 +1765,20 @@ namespace lime {
}
void lime_gamepad_rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) {
Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration);
}
HL_PRIM void HL_NAME(hl_gamepad_rumble) (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) {
Gamepad::Rumble (id, lowFrequencyRumble, highFrequencyRumble, duration);
}
value lime_gzip_compress (value buffer, value bytes) {
#ifdef LIME_ZLIB
@@ -4062,6 +4076,7 @@ namespace lime {
DEFINE_PRIME2v (lime_gamepad_event_manager_register);
DEFINE_PRIME1 (lime_gamepad_get_device_guid);
DEFINE_PRIME1 (lime_gamepad_get_device_name);
DEFINE_PRIME4v (lime_gamepad_rumble);
DEFINE_PRIME2 (lime_gzip_compress);
DEFINE_PRIME2 (lime_gzip_decompress);
DEFINE_PRIME2v (lime_haptic_vibrate);
@@ -4255,6 +4270,7 @@ namespace lime {
DEFINE_HL_PRIM (_VOID, hl_gamepad_event_manager_register, _FUN(_VOID, _NO_ARG) _TGAMEPAD_EVENT);
DEFINE_HL_PRIM (_BYTES, hl_gamepad_get_device_guid, _I32);
DEFINE_HL_PRIM (_BYTES, hl_gamepad_get_device_name, _I32);
DEFINE_HL_PRIM (_VOID, hl_gamepad_rumble, _I32 _I32 _F64 _F64);
DEFINE_HL_PRIM (_TBYTES, hl_gzip_compress, _TBYTES _TBYTES);
DEFINE_HL_PRIM (_TBYTES, hl_gzip_decompress, _TBYTES _TBYTES);
DEFINE_HL_PRIM (_VOID, hl_haptic_vibrate, _I32 _I32);

View File

@@ -4,48 +4,40 @@
namespace lime {
std::map<int, SDL_GameController*> gameControllers = std::map<int, SDL_GameController*> ();
std::map<int, int> gameControllerIDs = std::map<int, int> ();
std::map<int, SDL_GameController*> gameControllers;
std::map<int, int> gameControllerIDs;
bool SDLGamepad::Connect (int deviceID) {
if (SDL_IsGameController (deviceID)) {
if (!SDL_IsGameController (deviceID))
return false;
SDL_GameController *gameController = SDL_GameControllerOpen (deviceID);
SDL_GameController *gameController = SDL_GameControllerOpen (deviceID);
if (gameController == nullptr)
return false;
if (gameController) {
SDL_Joystick *joystick = SDL_GameControllerGetJoystick (gameController);
int id = SDL_JoystickInstanceID (joystick);
SDL_Joystick *joystick = SDL_GameControllerGetJoystick (gameController);
int id = SDL_JoystickInstanceID (joystick);
gameControllers[id] = gameController;
gameControllerIDs[deviceID] = id;
gameControllers[id] = gameController;
gameControllerIDs[deviceID] = id;
return true;
}
}
return false;
return true;
}
bool SDLGamepad::Disconnect (int id) {
if (gameControllers.find (id) != gameControllers.end ()) {
auto it = gameControllers.find (id);
if (it == gameControllers.end ())
return false;
SDL_GameController *gameController = gameControllers[id];
SDL_GameControllerClose (gameController);
gameControllers.erase (id);
SDL_GameControllerClose (it->second);
gameControllers.erase (id);
return true;
}
return false;
return true;
}
@@ -66,26 +58,51 @@ namespace lime {
const char* Gamepad::GetDeviceGUID (int id) {
SDL_Joystick* joystick = SDL_GameControllerGetJoystick (gameControllers[id]);
auto it = gameControllers.find (id);
if (it == gameControllers.end ())
return nullptr;
if (joystick) {
SDL_Joystick* joystick = SDL_GameControllerGetJoystick (it->second);
if (joystick == nullptr)
return nullptr;
char* guid = new char[64];
SDL_JoystickGetGUIDString (SDL_JoystickGetGUID (joystick), guid, 64);
return guid;
}
return 0;
char* guid = new char[64];
SDL_JoystickGetGUIDString (SDL_JoystickGetGUID (joystick), guid, 64);
return guid;
}
const char* Gamepad::GetDeviceName (int id) {
return SDL_GameControllerName (gameControllers[id]);
auto it = gameControllers.find (id);
if (it == gameControllers.end ())
return nullptr;
return SDL_GameControllerName (it->second);
}
}
void Gamepad::Rumble (int id, double lowFrequencyRumble, double highFrequencyRumble, int duration) {
auto it = gameControllers.find (id);
if (it == gameControllers.end ())
return;
if (highFrequencyRumble < 0.0f)
highFrequencyRumble = 0.0f;
else if (highFrequencyRumble > 1.0f)
highFrequencyRumble = 1.0f;
if (lowFrequencyRumble < 0.0f)
lowFrequencyRumble = 0.0f;
else if (lowFrequencyRumble > 1.0f)
lowFrequencyRumble = 1.0f;
SDL_GameControllerRumble (it->second, lowFrequencyRumble * 0xFFFF, highFrequencyRumble * 0xFFFF, duration);
}
}