6 #if defined(_WIN32) && defined(VRPN_USE_WINDOWS_XINPUT)
9 vrpn_XInputGamepad::vrpn_XInputGamepad(
const char *name,
vrpn_Connection *c,
unsigned int controllerIndex):
13 _controllerIndex(controllerIndex)
24 fprintf(stderr,
"vrpn_XInputGamepad: Can't register request-single handler\n");
30 fprintf(stderr,
"vrpn_XInputGamepad: Can't register request-multiple handler\n");
37 fprintf(stderr,
"vrpn_XInputGamepad: Can't register connections-dropped handler\n");
42 vrpn_XInputGamepad::~vrpn_XInputGamepad() {
45 void vrpn_XInputGamepad::mainloop() {
50 if ((rv = XInputGetState(_controllerIndex, &state)) != ERROR_SUCCESS) {
54 if (rv == ERROR_DEVICE_NOT_CONNECTED)
55 sprintf(errMsg,
"XInput device %u not connected", _controllerIndex);
57 sprintf(errMsg,
"XInput device %u returned Windows error code %u",
58 _controllerIndex, rv);
66 channel[0] = normalize_axis(state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
67 channel[1] = normalize_axis(state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
68 channel[2] = normalize_axis(state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
69 channel[3] = normalize_axis(state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
70 channel[4] = normalize_dpad(state.Gamepad.wButtons);
71 channel[5] = normalize_trigger(state.Gamepad.bLeftTrigger);
72 channel[6] = normalize_trigger(state.Gamepad.bRightTrigger);
76 buttons[0] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0;
77 buttons[1] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0;
78 buttons[2] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0;
79 buttons[3] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0;
80 buttons[4] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0;
81 buttons[5] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;
82 buttons[6] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0;
83 buttons[7] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0;
84 buttons[8] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;
85 buttons[9] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;
91 vrpn_float64 vrpn_XInputGamepad::normalize_dpad(WORD buttons)
const {
95 if (buttons & XINPUT_GAMEPAD_DPAD_RIGHT)
97 if (buttons & XINPUT_GAMEPAD_DPAD_LEFT)
99 if (buttons & XINPUT_GAMEPAD_DPAD_UP)
101 if (buttons & XINPUT_GAMEPAD_DPAD_DOWN)
104 size_t index = (x + 1) * 3 + (y + 1);
105 vrpn_float64 angles[] = {225, 270, 315, 180, -1, 0, 135, 90, 45};
106 return angles[index];
110 vrpn_float64 vrpn_XInputGamepad::normalize_axis(SHORT axis, SHORT deadzone)
const {
112 if (axis > -deadzone && axis < deadzone)
116 return axis / ((axis < 0) ? 32768.0 : 32767.0);
119 vrpn_float64 vrpn_XInputGamepad::normalize_trigger(BYTE trigger)
const {
121 if (trigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
124 return trigger / 255.0;
127 void vrpn_XInputGamepad::update_vibration() {
128 XINPUT_VIBRATION vibration;
130 vibration.wLeftMotorSpeed = _motorSpeed[0];
131 vibration.wRightMotorSpeed = _motorSpeed[1];
133 DWORD rv = XInputSetState(_controllerIndex, &vibration);
134 if (rv != ERROR_SUCCESS) {
138 if (rv == ERROR_DEVICE_NOT_CONNECTED)
139 sprintf(errMsg,
"XInput device %u not connected", _controllerIndex);
141 sprintf(errMsg,
"XInput device %u returned Windows error code %u",
142 _controllerIndex, rv);
150 void vrpn_XInputGamepad::report(vrpn_uint32 class_of_service) {
158 void vrpn_XInputGamepad::report_changes(vrpn_uint32 class_of_service) {
167 int VRPN_CALLBACK vrpn_XInputGamepad::handle_request_message(
void *selfPtr,
170 const char *bufptr = data.
buffer;
174 vrpn_XInputGamepad *me = (vrpn_XInputGamepad *) selfPtr;
183 if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
184 fprintf(stderr,
"vrpn_Analog_Output_Server::handle_request_message(): Index out of bounds\n");
186 sprintf( msg,
"Error: (handle_request_message): channel %d is not active. Squelching.", chan_num );
190 me->o_channel[chan_num] = value;
192 float magnitude = static_cast<float>(value);
193 magnitude = (magnitude < 0) ? 0 : (magnitude > 1) ? 1 : magnitude;
195 me->_motorSpeed[chan_num] = static_cast<WORD>(magnitude * 65535);
196 me->update_vibration();
202 int VRPN_CALLBACK vrpn_XInputGamepad::handle_request_channels_message(
void *selfPtr,
205 const char *bufptr = data.
buffer;
208 vrpn_XInputGamepad *me = (vrpn_XInputGamepad *) selfPtr;
215 if (chan_num > me->o_num_channel) {
217 sprintf( msg,
"Error: (handle_request_channels_message): channels above %d not active; "
218 "bad request up to channel %d. Squelching.", me->o_num_channel, chan_num );
220 chan_num = me->o_num_channel;
224 sprintf( msg,
"Error: (handle_request_channels_message): invalid channel %d. Squelching.", chan_num );
228 for (i = 0; i < chan_num; i++) {
232 float magnitude = static_cast<float>(value);
233 magnitude = (magnitude < 0) ? 0 : (magnitude > 1) ? 1 : magnitude;
235 me->_motorSpeed[chan_num] = static_cast<WORD>(magnitude * 65535);
238 me->update_vibration();
244 int VRPN_CALLBACK vrpn_XInputGamepad::handle_last_connection_dropped(
void *selfPtr,
247 vrpn_XInputGamepad *me = static_cast<vrpn_XInputGamepad *>(selfPtr);
250 me->_motorSpeed[0] = 0;
251 me->_motorSpeed[1] = 0;
252 me->update_vibration();
257 #endif // _WIN32 && VRPN_USE_DIRECTINPUT