6#if defined(_WIN32) && defined(VRPN_USE_WINDOWS_XINPUT)
9vrpn_XInputGamepad::vrpn_XInputGamepad(
const char *name,
vrpn_Connection *c,
unsigned int controllerIndex):
13 _controllerIndex(controllerIndex)
22 if (register_autodeleted_handler(request_m_id,
23 handle_request_message,
this, d_sender_id)) {
24 fprintf(stderr,
"vrpn_XInputGamepad: Can't register request-single handler\n");
28 if (register_autodeleted_handler(request_channels_m_id,
29 handle_request_channels_message,
this, d_sender_id)) {
30 fprintf(stderr,
"vrpn_XInputGamepad: Can't register request-multiple handler\n");
34 if (register_autodeleted_handler(
36 handle_last_connection_dropped,
this)) {
37 fprintf(stderr,
"vrpn_XInputGamepad: Can't register connections-dropped handler\n");
42vrpn_XInputGamepad::~vrpn_XInputGamepad() {
45void 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;
91vrpn_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];
110vrpn_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);
119vrpn_float64 vrpn_XInputGamepad::normalize_trigger(BYTE trigger)
const {
121 if (trigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
124 return trigger / 255.0;
127void 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);
150void vrpn_XInputGamepad::report(vrpn_uint32 class_of_service) {
158void vrpn_XInputGamepad::report_changes(vrpn_uint32 class_of_service) {
167int 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();
202int 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();
244int 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();
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Generic connection class not specific to the transport mechanism.
This structure is what is passed to a vrpn_Connection message callback.
const char * vrpn_dropped_last_connection
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
#define vrpn_gettimeofday