Added support for non-gamepad controllers to the GameInput driver

This commit is contained in:
Sam Lantinga
2024-02-17 22:32:44 -08:00
parent f63f99bd2d
commit bb4ec5250f

View File

@@ -63,6 +63,14 @@ static IGameInput *g_pGameInput = NULL;
static GameInputCallbackToken g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE; static GameInputCallbackToken g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
static SDL_bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info)
{
if (info->supportedInput & GameInputKindGamepad) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) static int GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
{ {
GAMEINPUT_InternalDevice **devicelist = NULL; GAMEINPUT_InternalDevice **devicelist = NULL;
@@ -234,7 +242,7 @@ static int GAMEINPUT_JoystickInit(void)
hR = IGameInput_RegisterDeviceCallback(g_pGameInput, hR = IGameInput_RegisterDeviceCallback(g_pGameInput,
NULL, NULL,
GameInputKindGamepad, GameInputKindController,
GameInputDeviceConnected, GameInputDeviceConnected,
GameInputBlockingEnumeration, GameInputBlockingEnumeration,
NULL, NULL,
@@ -360,6 +368,7 @@ static void CALLBACK GAMEINPUT_InternalGuideButtonCallback(GameInputCallbackToke
static int GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index) static int GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
{ {
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index); GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
const GameInputDeviceInfo *info = elem->info;
GAMEINPUT_InternalJoystickHwdata *hwdata = NULL; GAMEINPUT_InternalJoystickHwdata *hwdata = NULL;
if (!elem) { if (!elem) {
@@ -374,34 +383,40 @@ static int GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
hwdata->devref = elem; hwdata->devref = elem;
joystick->hwdata = hwdata; joystick->hwdata = hwdata;
if (GAMEINPUT_InternalIsGamepad(info)) {
joystick->naxes = 6; joystick->naxes = 6;
joystick->nbuttons = 11; joystick->nbuttons = 11;
joystick->nhats = 1; joystick->nhats = 1;
} else {
joystick->naxes = info->controllerAxisCount;
joystick->nbuttons = info->controllerButtonCount;
joystick->nhats = info->controllerSwitchCount;
}
if (elem->info->supportedInput & GameInputKindGamepad) { if (GAMEINPUT_InternalIsGamepad(info)) {
#if 0 /* The actual signature for this function is GameInputClient::RegisterSystemButtonCallback(struct IGameInputDevice *,enum GameInputSystemButtons,void *,void (*)(unsigned __int64,void *,struct IGameInputDevice *,unsigned __int64,enum GameInputSystemButtons,enum GameInputSystemButtons),unsigned __int64 *) */ #if 0 /* The actual signature for this function is GameInputClient::RegisterSystemButtonCallback(struct IGameInputDevice *,enum GameInputSystemButtons,void *,void (*)(unsigned __int64,void *,struct IGameInputDevice *,unsigned __int64,enum GameInputSystemButtons,enum GameInputSystemButtons),unsigned __int64 *) */
IGameInput_RegisterGuideButtonCallback(g_pGameInput, elem->device, joystick, GAMEINPUT_InternalGuideButtonCallback, &hwdata->guide_button_callback_token); IGameInput_RegisterGuideButtonCallback(g_pGameInput, elem->device, joystick, GAMEINPUT_InternalGuideButtonCallback, &hwdata->guide_button_callback_token);
#endif #endif
} }
if (elem->info->supportedRumbleMotors & (GameInputRumbleLowFrequency | GameInputRumbleHighFrequency)) { if (info->supportedRumbleMotors & (GameInputRumbleLowFrequency | GameInputRumbleHighFrequency)) {
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, SDL_TRUE); SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, SDL_TRUE);
} }
if (elem->info->supportedRumbleMotors & (GameInputRumbleLeftTrigger | GameInputRumbleRightTrigger)) { if (info->supportedRumbleMotors & (GameInputRumbleLeftTrigger | GameInputRumbleRightTrigger)) {
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, SDL_TRUE); SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, SDL_TRUE);
} }
if (elem->info->supportedInput & GameInputKindTouch) { if (info->supportedInput & GameInputKindTouch) {
SDL_PrivateJoystickAddTouchpad(joystick, elem->info->touchPointCount); SDL_PrivateJoystickAddTouchpad(joystick, info->touchPointCount);
} }
if (elem->info->supportedInput & GameInputKindMotion) { if (info->supportedInput & GameInputKindMotion) {
/* FIXME: What's the sensor update rate? */ /* FIXME: What's the sensor update rate? */
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
} }
if (elem->info->capabilities & GameInputDeviceCapabilityWireless) { if (info->capabilities & GameInputDeviceCapabilityWireless) {
joystick->epowerlevel = GAMEINPUT_InternalGetPowerLevel(elem->device); joystick->epowerlevel = GAMEINPUT_InternalGetPowerLevel(elem->device);
} else { } else {
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
@@ -449,6 +464,23 @@ static int GAMEINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool
static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
{ {
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
IGameInputDevice *device = hwdata->devref->device;
const GameInputDeviceInfo *info = hwdata->devref->info;
IGameInputReading *reading = NULL;
Uint64 timestamp = SDL_GetTicksNS();
GameInputGamepadState state;
HRESULT hR;
hR = IGameInput_GetCurrentReading(g_pGameInput, info->supportedInput, device, &reading);
if (FAILED(hR)) {
/* don't SetError here since there can be a legitimate case when there's no reading avail */
return;
}
/* FIXME: See if we can get the delta between the reading timestamp and current time and apply the offset to timestamp */
if (GAMEINPUT_InternalIsGamepad(info)) {
static WORD s_XInputButtons[] = { static WORD s_XInputButtons[] = {
GameInputGamepadA, /* SDL_GAMEPAD_BUTTON_SOUTH */ GameInputGamepadA, /* SDL_GAMEPAD_BUTTON_SOUTH */
GameInputGamepadB, /* SDL_GAMEPAD_BUTTON_EAST */ GameInputGamepadB, /* SDL_GAMEPAD_BUTTON_EAST */
@@ -463,22 +495,6 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
GameInputGamepadRightShoulder, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ GameInputGamepadRightShoulder, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */
}; };
Uint8 btnidx = 0, btnstate = 0, hat = 0; Uint8 btnidx = 0, btnstate = 0, hat = 0;
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
IGameInputDevice *device = hwdata->devref->device;
const GameInputDeviceInfo *info = hwdata->devref->info;
IGameInputReading *reading = NULL;
Uint64 timestamp = SDL_GetTicksNS();
GameInputGamepadState state;
HRESULT hR;
hR = IGameInput_GetCurrentReading(g_pGameInput, GameInputKindGamepad, device, &reading);
if (FAILED(hR)) {
/* don't SetError here since there can be a legitimate case when there's no reading avail */
return;
}
/* FIXME: See if we can get the delta between the reading timestamp and current time and apply the offset to timestamp */
if (IGameInputReading_GetGamepadState(reading, &state)) { if (IGameInputReading_GetGamepadState(reading, &state)) {
for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) { for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) {
@@ -515,6 +531,30 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, CONVERT_TRIGGER(state.rightTrigger)); SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, CONVERT_TRIGGER(state.rightTrigger));
#undef CONVERT_TRIGGER #undef CONVERT_TRIGGER
} }
} else {
bool *button_state = SDL_stack_alloc(bool, info->controllerButtonCount);
float *axis_state = SDL_stack_alloc(float, info->controllerAxisCount);
if (button_state) {
uint32_t i;
uint32_t button_count = IGameInputReading_GetControllerButtonState(reading, info->controllerButtonCount, button_state);
for (i = 0; i < button_count; ++i) {
SDL_SendJoystickButton(timestamp, joystick, i, button_state[i]);
}
SDL_stack_free(button_state);
}
#define CONVERT_AXIS(v) (Sint16)((v)*65535.0f - 32768.0f)
if (axis_state) {
uint32_t i;
uint32_t axis_count = IGameInputReading_GetControllerAxisState(reading, info->controllerAxisCount, axis_state);
for (i = 0; i < axis_count; ++i) {
SDL_SendJoystickAxis(timestamp, joystick, i, CONVERT_AXIS(axis_state[i]));
}
SDL_stack_free(axis_state);
}
#undef CONVERT_AXIS
}
if (info->supportedInput & GameInputKindTouch) { if (info->supportedInput & GameInputKindTouch) {
GameInputTouchState *touch_state = SDL_stack_alloc(GameInputTouchState, info->touchPointCount); GameInputTouchState *touch_state = SDL_stack_alloc(GameInputTouchState, info->touchPointCount);
@@ -582,6 +622,12 @@ static void GAMEINPUT_JoystickQuit(void)
static SDL_bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) static SDL_bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{ {
GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index);
if (!GAMEINPUT_InternalIsGamepad(elem->info)) {
return SDL_FALSE;
}
out->a.kind = EMappingKind_Button; out->a.kind = EMappingKind_Button;
out->a.target = SDL_GAMEPAD_BUTTON_SOUTH; out->a.target = SDL_GAMEPAD_BUTTON_SOUTH;