mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-10-26 12:27:44 +00:00 
			
		
		
		
	Added automatic gamepad mapping for the GameInput driver
This commit is contained in:
		| @@ -54,7 +54,6 @@ typedef struct joystick_hwdata | |||||||
| { | { | ||||||
|     GAMEINPUT_InternalDevice *devref; |     GAMEINPUT_InternalDevice *devref; | ||||||
|     GameInputRumbleParams rumbleParams; |     GameInputRumbleParams rumbleParams; | ||||||
|     Uint64 lastTimestamp; |  | ||||||
| } GAMEINPUT_InternalJoystickHwdata; | } GAMEINPUT_InternalJoystickHwdata; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -453,52 +452,39 @@ static int GAMEINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool | |||||||
| static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) | static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) | ||||||
| { | { | ||||||
|     static WORD s_XInputButtons[] = { |     static WORD s_XInputButtons[] = { | ||||||
|         GameInputGamepadA, GameInputGamepadB, GameInputGamepadX, GameInputGamepadY, |         GameInputGamepadA,                  /* SDL_GAMEPAD_BUTTON_SOUTH */ | ||||||
|         GameInputGamepadLeftShoulder, GameInputGamepadRightShoulder, GameInputGamepadView, GameInputGamepadMenu, |         GameInputGamepadB,                  /* SDL_GAMEPAD_BUTTON_EAST */ | ||||||
|         GameInputGamepadLeftThumbstick, GameInputGamepadRightThumbstick, |         GameInputGamepadX,                  /* SDL_GAMEPAD_BUTTON_WEST */ | ||||||
|         0 /* Guide button is not supported on Xbox so ignore that... */ |         GameInputGamepadY,                  /* SDL_GAMEPAD_BUTTON_NORTH */ | ||||||
|  |         GameInputGamepadView,               /* SDL_GAMEPAD_BUTTON_BACK */ | ||||||
|  |         0, /* The guide button is not available */ | ||||||
|  |         GameInputGamepadMenu,               /* SDL_GAMEPAD_BUTTON_START */ | ||||||
|  |         GameInputGamepadLeftThumbstick,     /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ | ||||||
|  |         GameInputGamepadRightThumbstick,    /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ | ||||||
|  |         GameInputGamepadLeftShoulder,       /* SDL_GAMEPAD_BUTTON_LEFT_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; |     GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata; | ||||||
|     IGameInputDevice *device = hwdata->devref->device; |     IGameInputDevice *device = hwdata->devref->device; | ||||||
|     IGameInputReading *reading = NULL; |     IGameInputReading *reading = NULL; | ||||||
|     uint64_t ts = 0; |     Uint64 timestamp = SDL_GetTicksNS(); | ||||||
|     GameInputGamepadState state; |     GameInputGamepadState state; | ||||||
|     HRESULT hR = IGameInput_GetCurrentReading(g_pGameInput, |     HRESULT hR; | ||||||
|         GameInputKindGamepad, |  | ||||||
|         device, |  | ||||||
|         &reading |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     hR = IGameInput_GetCurrentReading(g_pGameInput, GameInputKindGamepad, device, &reading); | ||||||
|     if (FAILED(hR)) { |     if (FAILED(hR)) { | ||||||
|         /* don't SetError here since there can be a legitimate case when there's no reading avail */ |         /* don't SetError here since there can be a legitimate case when there's no reading avail */ | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* GDKX private docs for GetTimestamp: "The microsecond timestamp describing when the input was made." */ |     /* FIXME: See if we can get the delta between the reading timestamp and current time and apply the offset to timestamp */ | ||||||
|     /* SDL expects a nanosecond timestamp, so I guess US_TO_NS should be used here? */ |  | ||||||
|     ts = SDL_US_TO_NS(IGameInputReading_GetTimestamp(reading)); |  | ||||||
|  |  | ||||||
|     if (((!hwdata->lastTimestamp) || (ts != hwdata->lastTimestamp)) && IGameInputReading_GetGamepadState(reading, &state)) { |     if (IGameInputReading_GetGamepadState(reading, &state)) { | ||||||
|         /* `state` is now valid */ |         for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) { | ||||||
|  |             btnstate = (state.buttons & s_XInputButtons[btnidx]) ? SDL_PRESSED : SDL_RELEASED; | ||||||
| #define tosint16(_TheValue) ((Sint16)(((_TheValue) < 0.0f) ? ((_TheValue) * 32768.0f) : ((_TheValue) * 32767.0f))) |             SDL_SendJoystickButton(timestamp, joystick, btnidx, btnstate); | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 0, tosint16(state.leftThumbstickX)); |  | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 1, tosint16(state.leftThumbstickY)); |  | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 2, tosint16(state.leftTrigger)); |  | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 3, tosint16(state.rightThumbstickX)); |  | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 4, tosint16(state.rightThumbstickY)); |  | ||||||
|         SDL_SendJoystickAxis(ts, joystick, 5, tosint16(state.rightTrigger)); |  | ||||||
| #undef tosint16 |  | ||||||
|  |  | ||||||
|         for (btnidx = 0; btnidx < (Uint8)SDL_arraysize(s_XInputButtons); ++btnidx) { |  | ||||||
|             if (s_XInputButtons[btnidx] == 0) { |  | ||||||
|                 btnstate = SDL_RELEASED; |  | ||||||
|             } else { |  | ||||||
|                 btnstate = (state.buttons & s_XInputButtons[btnidx]) ? SDL_PRESSED : SDL_RELEASED; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             SDL_SendJoystickButton(ts, joystick, btnidx, btnstate); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (state.buttons & GameInputGamepadDPadUp) { |         if (state.buttons & GameInputGamepadDPadUp) { | ||||||
| @@ -513,15 +499,32 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) | |||||||
|         if (state.buttons & GameInputGamepadDPadRight) { |         if (state.buttons & GameInputGamepadDPadRight) { | ||||||
|             hat |= SDL_HAT_RIGHT; |             hat |= SDL_HAT_RIGHT; | ||||||
|         } |         } | ||||||
|         SDL_SendJoystickHat(ts, joystick, 0, hat); |         SDL_SendJoystickHat(timestamp, joystick, 0, hat); | ||||||
|  |  | ||||||
|         /* Xbox doesn't let you obtain the power level, pretend we're always full */ | #define CONVERT_AXIS(v) (Sint16)(((v) < 0.0f) ? ((v)*32768.0f) : ((v)*32767.0f)) | ||||||
|         SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL); |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, CONVERT_AXIS(state.leftThumbstickX)); | ||||||
|  |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, CONVERT_AXIS(-state.leftThumbstickY)); | ||||||
|         hwdata->lastTimestamp = ts; |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, CONVERT_AXIS(state.rightThumbstickX)); | ||||||
|  |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, CONVERT_AXIS(-state.rightThumbstickY)); | ||||||
|  | #undef CONVERT_AXIS | ||||||
|  | #define CONVERT_TRIGGER(v) (Sint16)((v)*65535.0f - 32768.0f) | ||||||
|  |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, CONVERT_TRIGGER(state.leftTrigger)); | ||||||
|  |         SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, CONVERT_TRIGGER(state.rightTrigger)); | ||||||
|  | #undef CONVERT_TRIGGER | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     IGameInputReading_Release(reading); |     IGameInputReading_Release(reading); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  |     /* FIXME: We can poll this at a much lower rate */ | ||||||
|  |     GameInputBatteryState battery_state; | ||||||
|  |     SDL_zero(battery_state); | ||||||
|  |     IGameInputDevice_GetBatteryState(device, &battery_state); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /* Xbox doesn't let you obtain the power level, pretend we're always full */ | ||||||
|  |     SDL_SendJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| static void GAMEINPUT_JoystickClose(SDL_Joystick* joystick) | static void GAMEINPUT_JoystickClose(SDL_Joystick* joystick) | ||||||
| @@ -561,7 +564,69 @@ 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) | ||||||
| { | { | ||||||
|     return SDL_FALSE; |     out->a.kind = EMappingKind_Button; | ||||||
|  |     out->a.target = SDL_GAMEPAD_BUTTON_SOUTH; | ||||||
|  |  | ||||||
|  |     out->b.kind = EMappingKind_Button; | ||||||
|  |     out->b.target = SDL_GAMEPAD_BUTTON_EAST; | ||||||
|  |  | ||||||
|  |     out->x.kind = EMappingKind_Button; | ||||||
|  |     out->x.target = SDL_GAMEPAD_BUTTON_WEST; | ||||||
|  |  | ||||||
|  |     out->y.kind = EMappingKind_Button; | ||||||
|  |     out->y.target = SDL_GAMEPAD_BUTTON_NORTH; | ||||||
|  |  | ||||||
|  |     out->back.kind = EMappingKind_Button; | ||||||
|  |     out->back.target = SDL_GAMEPAD_BUTTON_BACK; | ||||||
|  |  | ||||||
|  |     /* The guide button isn't available, so don't map it */ | ||||||
|  |  | ||||||
|  |     out->start.kind = EMappingKind_Button; | ||||||
|  |     out->start.target = SDL_GAMEPAD_BUTTON_START; | ||||||
|  |  | ||||||
|  |     out->leftstick.kind = EMappingKind_Button; | ||||||
|  |     out->leftstick.target = SDL_GAMEPAD_BUTTON_LEFT_STICK; | ||||||
|  |  | ||||||
|  |     out->rightstick.kind = EMappingKind_Button; | ||||||
|  |     out->rightstick.target = SDL_GAMEPAD_BUTTON_RIGHT_STICK; | ||||||
|  |  | ||||||
|  |     out->leftshoulder.kind = EMappingKind_Button; | ||||||
|  |     out->leftshoulder.target = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER; | ||||||
|  |  | ||||||
|  |     out->rightshoulder.kind = EMappingKind_Button; | ||||||
|  |     out->rightshoulder.target = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER; | ||||||
|  |  | ||||||
|  |     out->dpup.kind = EMappingKind_Hat; | ||||||
|  |     out->dpup.target = SDL_HAT_UP; | ||||||
|  |  | ||||||
|  |     out->dpdown.kind = EMappingKind_Hat; | ||||||
|  |     out->dpdown.target = SDL_HAT_DOWN; | ||||||
|  |  | ||||||
|  |     out->dpleft.kind = EMappingKind_Hat; | ||||||
|  |     out->dpleft.target = SDL_HAT_LEFT; | ||||||
|  |  | ||||||
|  |     out->dpright.kind = EMappingKind_Hat; | ||||||
|  |     out->dpright.target = SDL_HAT_RIGHT; | ||||||
|  |  | ||||||
|  |     out->leftx.kind = EMappingKind_Axis; | ||||||
|  |     out->leftx.target = SDL_GAMEPAD_AXIS_LEFTX; | ||||||
|  |  | ||||||
|  |     out->lefty.kind = EMappingKind_Axis; | ||||||
|  |     out->lefty.target = SDL_GAMEPAD_AXIS_LEFTY; | ||||||
|  |  | ||||||
|  |     out->rightx.kind = EMappingKind_Axis; | ||||||
|  |     out->rightx.target = SDL_GAMEPAD_AXIS_RIGHTX; | ||||||
|  |  | ||||||
|  |     out->righty.kind = EMappingKind_Axis; | ||||||
|  |     out->righty.target = SDL_GAMEPAD_AXIS_RIGHTY; | ||||||
|  |  | ||||||
|  |     out->lefttrigger.kind = EMappingKind_Axis; | ||||||
|  |     out->lefttrigger.target = SDL_GAMEPAD_AXIS_LEFT_TRIGGER; | ||||||
|  |  | ||||||
|  |     out->righttrigger.kind = EMappingKind_Axis; | ||||||
|  |     out->righttrigger.target = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER; | ||||||
|  |  | ||||||
|  |     return SDL_TRUE; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sam Lantinga
					Sam Lantinga