1
/* Mednafen - Multi-system Emulator
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "Joystick_XInput.h"
30
struct XInputFuncPointers
32
void WINAPI (*p_XInputEnable)(BOOL);
33
DWORD WINAPI (*p_XInputSetState)(DWORD, XINPUT_VIBRATION*);
34
DWORD WINAPI (*p_XInputGetState)(DWORD, XINPUT_STATE*);
35
DWORD WINAPI (*p_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
38
class Joystick_XInput : public Joystick
42
Joystick_XInput(unsigned index, const XINPUT_CAPABILITIES &caps_in, const XInputFuncPointers* xfps_in);
45
virtual void SetRumble(uint8 weak_intensity, uint8 strong_intensity);
46
virtual bool IsAxisButton(unsigned axis);
47
void UpdateInternal(void);
50
const unsigned joy_index;
51
const XINPUT_CAPABILITIES caps;
52
const XInputFuncPointers *xfps;
55
Joystick_XInput::Joystick_XInput(unsigned index, const XINPUT_CAPABILITIES &caps_in, const XInputFuncPointers* xfps_in) : joy_index(index), caps(caps_in), xfps(xfps_in)
57
num_buttons = sizeof(((XINPUT_GAMEPAD*)0)->wButtons) * 8;
61
button_state.resize(num_buttons);
62
axis_state.resize(num_axes);
64
id = (caps.Type << 24) | (caps.SubType << 16); // Don't include the XInput index in the id, it'll just cause problems, especially when multiple different subtypes of controllers are connected. | (index << 8);
66
snprintf(name, sizeof(name), "XInput Unknown Controller");
67
if(caps.Type == XINPUT_DEVTYPE_GAMEPAD)
72
case XINPUT_DEVSUBTYPE_GAMEPAD: snprintf(name, sizeof(name), "XInput Gamepad"); break;
73
case XINPUT_DEVSUBTYPE_WHEEL: snprintf(name, sizeof(name), "XInput Wheel"); break;
74
case XINPUT_DEVSUBTYPE_ARCADE_STICK: snprintf(name, sizeof(name), "XInput Arcade Stick"); break;
75
#ifdef XINPUT_DEVSUBTYPE_FLIGHT_STICK
76
case XINPUT_DEVSUBTYPE_FLIGHT_STICK: snprintf(name, sizeof(name), "XInput Flight Stick"); break;
78
case XINPUT_DEVSUBTYPE_DANCE_PAD: snprintf(name, sizeof(name), "XInput Dance Pad"); break;
80
#ifdef XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE
81
case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
83
#ifdef XINPUT_DEVSUBTYPE_GUITAR_BASS
84
case XINPUT_DEVSUBTYPE_GUITAR_BASS:
86
case XINPUT_DEVSUBTYPE_GUITAR: snprintf(name, sizeof(name), "XInput Guitar"); break;
88
case XINPUT_DEVSUBTYPE_DRUM_KIT: snprintf(name, sizeof(name), "XInput Drum Kit"); break;
89
#ifdef XINPUT_DEVSUBTYPE_ARCADE_PAD
90
case XINPUT_DEVSUBTYPE_ARCADE_PAD: snprintf(name, sizeof(name), "XInput Arcade Pad"); break;
97
Joystick_XInput::~Joystick_XInput()
102
bool Joystick_XInput::IsAxisButton(unsigned axis)
110
void Joystick_XInput::UpdateInternal(void)
112
XINPUT_STATE joy_state;
113
memset(&joy_state, 0, sizeof(XINPUT_STATE));
115
xfps->p_XInputGetState(joy_index, &joy_state);
117
for(unsigned b = 0; b < num_buttons; b++)
118
button_state[b] = (joy_state.Gamepad.wButtons >> b) & 1;
120
axis_state[0] = std::max<int>(-32767, joy_state.Gamepad.sThumbLX);
121
axis_state[1] = std::max<int>(-32767, joy_state.Gamepad.sThumbLY);
122
axis_state[2] = std::max<int>(-32767, joy_state.Gamepad.sThumbRX);
123
axis_state[3] = std::max<int>(-32767, joy_state.Gamepad.sThumbRY);
125
axis_state[4] = (((unsigned)joy_state.Gamepad.bLeftTrigger * 32767) + 127) / 255;
126
axis_state[5] = (((unsigned)joy_state.Gamepad.bRightTrigger * 32767) + 127) / 255;
129
void Joystick_XInput::SetRumble(uint8 weak_intensity, uint8 strong_intensity)
131
XINPUT_VIBRATION vib;
133
memset(&vib, 0, sizeof(XINPUT_VIBRATION));
134
vib.wLeftMotorSpeed = (((unsigned int)strong_intensity * 65535) + 127) / 255;
135
vib.wRightMotorSpeed = (((unsigned int)weak_intensity * 65535) + 127) / 255;
136
xfps->p_XInputSetState(joy_index, &vib);
139
class JoystickDriver_XInput : public JoystickDriver
143
JoystickDriver_XInput();
144
virtual ~JoystickDriver_XInput();
146
virtual unsigned NumJoysticks(); // Cached internally on JoystickDriver instantiation.
147
virtual Joystick *GetJoystick(unsigned index);
148
virtual void UpdateJoysticks(void);
151
Joystick_XInput *joys[XUSER_MAX_COUNT];
156
XInputFuncPointers xfps;
160
bool GetXIPA(HMODULE dll_handle, T& pf, const char *name)
162
pf = (T)GetProcAddress(dll_handle, name);
166
JoystickDriver_XInput::JoystickDriver_XInput() : joy_count(0), dll_handle(NULL)
168
if((dll_handle = LoadLibrary("xinput1_3.dll")) == NULL)
170
if((dll_handle = LoadLibrary("xinput1_4.dll")) == NULL)
172
if((dll_handle = LoadLibrary("xinput9_1_0.dll")) == NULL)
179
// 9.1.0 supposedly lacks XInputEnable()
180
xfps.p_XInputEnable = NULL;
181
GetXIPA(dll_handle, xfps.p_XInputEnable, "XInputEnable");
183
if(!GetXIPA(dll_handle, xfps.p_XInputSetState, "XInputSetState") ||
184
!GetXIPA(dll_handle, xfps.p_XInputGetState, "XInputGetState") ||
185
!GetXIPA(dll_handle, xfps.p_XInputGetCapabilities, "XInputGetCapabilities"))
187
FreeLibrary(dll_handle);
191
if(xfps.p_XInputEnable)
192
xfps.p_XInputEnable(TRUE);
194
for(unsigned i = 0; i < XUSER_MAX_COUNT; i++)
199
XINPUT_CAPABILITIES caps;
201
if(xfps.p_XInputGetCapabilities(i, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS)
203
joys[joy_count] = new Joystick_XInput(i, caps, &xfps);
204
joy_count++; // joys[joy_count++] would not be exception-safe.
207
catch(std::exception &e)
209
MDFND_PrintError(e.what());
214
JoystickDriver_XInput::~JoystickDriver_XInput()
216
if(xfps.p_XInputEnable)
217
xfps.p_XInputEnable(FALSE);
219
for(unsigned i = 0; i < joy_count; i++)
229
if(dll_handle != NULL)
231
FreeLibrary(dll_handle);
236
unsigned JoystickDriver_XInput::NumJoysticks(void)
241
Joystick *JoystickDriver_XInput::GetJoystick(unsigned index)
246
void JoystickDriver_XInput::UpdateJoysticks(void)
248
for(unsigned i = 0; i < joy_count; i++)
249
joys[i]->UpdateInternal();
252
JoystickDriver *JoystickDriver_XInput_New(void)
254
JoystickDriver_XInput* jdxi = new JoystickDriver_XInput();
256
if(!jdxi->NumJoysticks())