void vrpn_Griffin_PowerMate::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // Decode all full reports, each of which is 8 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. // XXX Check to see that this works with HIDAPI, there may be two smaller reports. if (bytes == 6) { if (vrpn_Dial::num_dials > 0) { // dial (2nd byte) // Do the unsigned/signed conversion at the last minute so the // signed values work properly. dials[0] = static_cast<vrpn_int8>(buffer[1]); } else { // dial (2nd byte) normalize_axis(buffer[1], 5, 1.0f, channel[0]); } vrpn_uint8 value; // switches (1st byte): value = buffer[0]; // button #0: 01 button for (int btn = 0; btn < 1; btn++) { vrpn_uint8 mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn] = ((value & mask) != 0); } } else { fprintf(stderr, "vrpn_Griffin_PowerMate: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes)); } }
void vrpn_Contour_ShuttleXpress::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // Decode all full reports, each of which is 5 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. if (bytes == 5) { if (!_gotDial) { _gotDial = true; } else { dials[0] = static_cast<vrpn_int8>(buffer[1] - _lastDial) / 10.0; } _lastDial = buffer[1]; // analog (1st byte): 0 center, 1..7 right, -1..-7 left normalize_axis((unsigned int)((static_cast<float>(static_cast<vrpn_int8>(buffer[0])) * 128.0f / 7.0f) + 128.0f), 0, 1.0f, channel[0]); // Second analog integrates the dial value. channel[1] += dials[0]; vrpn_uint8 value; // buttons (4th byte): value = buffer[3]; for (int btn = 0; btn < 4; btn++) { vrpn_uint8 mask = static_cast<vrpn_uint8>((1 << (btn % 8)) << 4); buttons[btn] = ((value & mask) != 0); } // buttons (5th byte): value = buffer[4]; for (int btn = 0; btn < 1; btn++) { vrpn_uint8 mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn + 4] = ((value & mask) != 0); } } else { fprintf(stderr, "vrpn_Contour_ShuttleXpress: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes)); } }
void vrpn_XInputGamepad::mainloop() { XINPUT_STATE state; DWORD rv; server_mainloop(); if ((rv = XInputGetState(_controllerIndex, &state)) != ERROR_SUCCESS) { char errMsg[256]; struct timeval now; if (rv == ERROR_DEVICE_NOT_CONNECTED) sprintf(errMsg, "XInput device %u not connected", _controllerIndex); else sprintf(errMsg, "XInput device %u returned Windows error code %u", _controllerIndex, rv); vrpn_gettimeofday(&now, NULL); send_text_message(errMsg, now, vrpn_TEXT_ERROR); return; } // Set device state in VRPN_Analog channel[0] = normalize_axis(state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); channel[1] = normalize_axis(state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); channel[2] = normalize_axis(state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); channel[3] = normalize_axis(state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); channel[4] = normalize_dpad(state.Gamepad.wButtons); channel[5] = normalize_trigger(state.Gamepad.bLeftTrigger); channel[6] = normalize_trigger(state.Gamepad.bRightTrigger); // Set device state in VRPN_Button // Buttons are listed in DirectInput ordering buttons[0] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0; buttons[1] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; buttons[2] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0; buttons[3] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0; buttons[4] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; buttons[5] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; buttons[6] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0; buttons[7] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0; buttons[8] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; buttons[9] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; vrpn_gettimeofday(&_timestamp, NULL); report_changes(); }
void vrpn_Contour_ShuttleXpress::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // Decode all full reports, each of which is 5 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. // XXX Check to see that this works with HIDAPI, there may be two smaller reports. if (bytes == 5) { static bool set = false; // analog (1st byte): 0 center, 1..7 right, -1..-7 left normalize_axis((unsigned int) ((static_cast<float>(static_cast<vrpn_int8>(buffer[0])) * 128.0f / 7.0f) + 128.0f), 0, 1.0f, channel[0]); if (vrpn_Dial::num_dials > 0) { // dial (2nd byte) // Do the unsigned/signed conversion at the last minute so the signed values work properly. dials[0] = static_cast<vrpn_int8>(buffer[1] - _lastDial); _lastDial = buffer[1]; } else { // dial (2nd byte) normalize_axis((unsigned int) (static_cast<float>(static_cast<vrpn_int8>(buffer[1])) + 128.0f), 0, 1.0f, channel[1]); } vrpn_uint8 value; // buttons (4th byte): value = buffer[3]; for (int btn = 0; btn < 4; btn++) { vrpn_uint8 mask = static_cast<vrpn_uint8>((1 << (btn % 8)) << 4); buttons[btn] = ((value & mask) != 0); } // buttons (5th byte): value = buffer[4]; for (int btn = 0; btn < 1; btn++) { vrpn_uint8 mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn + 4] = ((value & mask) != 0); } } else { fprintf(stderr, "vrpn_Contour_ShuttleXpress: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes)); } }
static void normalize_axes(const unsigned int x, const unsigned int y, const short deadzone, const vrpn_float64 scale, vrpn_float64& channelX, vrpn_float64& channelY, int wordSize = 16) { #ifdef FUTURE // adapted from: http://msdn.microsoft.com/en-us/library/windows/desktop/ee417001%28v=vs.85%29.aspx // determine how far the controller is pushed float magnitude = (float) sqrt((double) ((x * x) + (y * y))); // determine the direction the controller is pushed float normalizedX = ((magnitude > 0.0f) ? (x / magnitude) : 0.0f); float normalizedY = ((magnitude > 0.0f) ? (y / magnitude) : 0.0f); float normalizedMagnitude = 0.0f; // check if the controller is outside a circular dead zone if (magnitude > deadzone) { // clip the magnitude at its expected maximum value if (magnitude > 32767) { magnitude = 32767; } // adjust magnitude relative to the end of the dead zone magnitude -= deadzone; // optionally normalize the magnitude with respect to its // expected range giving a magnitude value of 0.0 to 1.0 normalizedMagnitude = magnitude / (32767.0f - deadzone); } else { // if the controller is in the deadzone zero out the magnitude magnitude = 0.0f; normalizedMagnitude = 0.0f; } #else normalize_axis(x, deadzone, scale, channelX, wordSize); normalize_axis(y, deadzone, scale, channelY, wordSize); #endif // FUTURE }
void vrpn_Contour_ShuttlePROv2::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // Print the report so we can figure out what is going on. /* for (size_t i = 0; i < bytes; i++) { printf("%02x ", buffer[i]); } printf("\n"); return; */ // Decode all full reports, each of which is 5 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. if (bytes == 5) { if (!_gotDial) { _gotDial = true; } else { dials[0] = static_cast<vrpn_int8>(buffer[1] - _lastDial) / 10.0; } _lastDial = buffer[1]; // analog (1st byte): 0 center, 1..7 right, -1..-7 left normalize_axis((unsigned int)((static_cast<float>(static_cast<vrpn_int8>(buffer[0])) * 128.0f / 7.0f) + 128.0f), 0, 1.0f, channel[0]); // Second analog integrates the dial value. channel[1] += dials[0]; // Top row of four buttons, from left to right: index[bit] // 3[0], 3[1], 3[2], 3[3] // Second row of 5 buttons, from left to right: // 3[4], 3[5], 3[6], 3[7], 4[0] // Four lower buttons, from left to right and then down to next row: // 4[1], 4[2], 4[3], 4[4] // Two black buttons, from left to right: // 4[5], 4[6] for (int btn = 0; btn <= 15; btn++) { vrpn_uint8 *offset, mask; offset = buffer + btn / 8 + 3; mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn] = (*offset & mask) != 0; } } else { fprintf(stderr, "vrpn_Contour_ShuttlePROv2: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes)); } }
static void normalize_axes(const unsigned int x, const unsigned int y, const short deadzone, const vrpn_float64 scale, vrpn_float64& channelX, vrpn_float64& channelY, int wordSize = 16) { normalize_axis(x, deadzone, scale, channelX, wordSize); normalize_axis(y, deadzone, scale, channelY, wordSize); }
void vrpn_Logitech_Extreme_3D_Pro::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // SideWinder Precision 2 joystick // Decode all full reports, each of which is 40 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. /* ? [0]: X-axis (left=00, right=ff) [1]: Y-axis - lower byte (up=00, down=ff) [2]: POV Hat high nibble (none=0x80, N=0x00, NE=0x10, ... NW=0x80), Y-axis upper nibble in low nibble of this byte [3]: Z-rotate (left=00, right=ff) [4]: buttons (bit flags: none=0x00, "1" (trigger)=0x01, "2"=0x02, "3"=0x04, ..., "8"=0x80 [5]: Slider (up=00, down=ff) [6]: buttons (bit flags: none=0x00, "9"=0x01, "10"=0x02, "11"=0x04, "12"=0x08 */ // XXX Check to see that this works with HIDAPI, there may be two smaller reports. if (bytes == 7) { unsigned int x, y; x = buffer[0]; y = ((buffer[2] & 0x0f) << 8) + buffer[1]; normalize_axes(x, y, 0x16, 1.0f, channel[0], channel[1], 12); normalize_axis(buffer[3], 0x12, 1.0f, channel[2], 8); normalize_axis(buffer[5], 0x0e, 1.0f, channel[3], 8); vrpn_uint8 value, mask; value = buffer[4]; for (int btn = 0; btn < 8; btn++) { mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn] = ((value & mask) != 0); } // Point of View Hat buttons[8] = buttons[9] = buttons[10] = buttons[11] = 0; switch (buffer[2] >> 4) { case 0: // up buttons[8] = true; break; case 1: buttons[8] = buttons[9] = true; break; case 2: // right buttons[9] = true; break; case 3: buttons[9] = buttons[10] = true; break; case 4: // down buttons[10] = true; break; case 5: buttons[10] = buttons[11] = true; break; case 6: // left buttons[11] = true; break; case 7: buttons[11] = buttons[8] = true; break; case 8: default: // nothing to do break; } channel[4] = normalize_dpad(buttons[8], buttons[9], buttons[10], buttons[11]); }
void vrpn_Retrolink_GameCube::decodePacket(size_t bytes, vrpn_uint8 *buffer) { /* // Print the report so we can figure out what is going on. for (size_t i = 0; i < bytes; i++) { printf("%02x ", buffer[i]); } printf("\n"); return; */ // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. // Reports should be 8 bytes. They are encoded as follows: // 0 = Left joystick X axis, goes from 0 (left) to 255 (right) // 1 = Left joystick Y axis, goes from 0 (up) to 255 (down) // 2 = Uncontrolled jibberish, must be from an unconnected channel // 3 = Left joystick X axis, goes from 0 (left) to 255 (right) // 4 = Left joystick Y axis, goes from 0 (left) to 255 (right) // 5 upper nybble = bit 0 (Y), 1 (X), 2 (A), 3 (B) // 5 lower nybble = rocker: 255 when nothing; 0 (up), 1 (UR), 2 (right), .. 7 (UL) // 6 = bit # 0 (left trigger), 1 (right trigger), 2 (Z), 5 (Start/pause) // 7 = always 0x20 (maybe unconnected buttons; probably safest to ignore) // Controls for the Nintendo 64 classic // 0 = Left joystick X axis, goes from 0 (left) to 255 (right) // 1 = Left joystick Y axis, goes from 0 (up) to 255 (down) // 2 = Uncontrolled jibberish, must be from an unconnected channel // 5 upper nybble = bit 0 (C up), 1 (C right), 2 (C down), 3 (C Left) // 5 lower nybble = rocker: 255 when nothing; 0 (up), 1 (UR), 2 (right), .. 7 (UL) // 6 = bit # 0 (left trigger), 1 (right trigger), 2 (A), 3 (Z), 4 (B), 5 (Start) // 7 = always 0x20 (maybe unconnected buttons; probably safest to ignore) if (bytes == 8) { // Figure out the joystick axes. channel[0] = normalize_axis(buffer[0]); channel[1] = normalize_axis(buffer[1]); channel[2] = normalize_axis(buffer[3]); channel[3] = normalize_axis(buffer[4]); // Figure out the buttons. buttons[0] = (buffer[5] & (1 << 4)) != 0; buttons[1] = (buffer[5] & (1 << 5)) != 0; buttons[2] = (buffer[5] & (1 << 6)) != 0; buttons[3] = (buffer[5] & (1 << 7)) != 0; buttons[4] = (buffer[6] & (1 << 0)) != 0; buttons[5] = (buffer[6] & (1 << 1)) != 0; buttons[6] = (buffer[6] & (1 << 2)) != 0; buttons[7] = (buffer[6] & (1 << 5)) != 0; // Figure out the rocker. vrpn_uint8 rocker = buffer[5] & 0x0f; vrpn_float64 angle; bool up, right, down, left; angle_and_buttons_from_rocker_byte(rocker, &angle, &up, &right, &down, &left); channel[4] = angle; buttons[8] = up; buttons[9] = right; buttons[10] = down; buttons[11] = left; } else { fprintf(stderr, "vrpn_Retrolink_GameCube: Found a corrupted report; # total bytes = %u\n", static_cast<unsigned>(bytes)); } }
void vrpn_Microsoft_SideWinder_Precision_2::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // SideWinder Precision 2 joystick // Decode all full reports, each of which is 40 bytes long. // Because there is only one type of report, the initial "0" report-type // byte is removed by the HIDAPI driver. /* Byte : Bit 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 [0]: X-axis (left=00, right=ff) [1]: Y-axis (up=00, down=ff) [2]: Z-rotate (left=00, right=ff) [3]: Slider (up=00, down=ff) [4]: buttons (bit flags: none=0x00, "1" (trigger)=0x01, "2"=0x02, "3"=0x04, ..., "8"=0x80 [5]: POV Hat high nibble (none=0x80, N=0x00, NE=0x10, ... NW=0x80) */ // XXX Check to see that this works with HIDAPI, there may be two smaller reports. if (bytes == 6) { normalize_axes(buffer[0], buffer[1], 0x08, 1.0f, channel[0], channel[1], 8); normalize_axis(buffer[2], 0x08, 1.0f, channel[2], 8); normalize_axis(buffer[3], 0x08, 1.0f, channel[3], 8); vrpn_uint8 value, mask; value = buffer[4]; for (int btn = 0; btn < 8; btn++) { mask = static_cast<vrpn_uint8>(1 << (btn % 8)); buttons[btn] = ((value & mask) != 0); } // Point of View Hat buttons[8] = buttons[9] = buttons[10] = buttons[11] = 0; switch (buffer[5] >> 4) { case 0: // up buttons[8] = true; break; case 1: buttons[8] = buttons[9] = true; break; case 2: // right buttons[9] = true; break; case 3: buttons[9] = buttons[10] = true; break; case 4: // down buttons[10] = true; break; case 5: buttons[10] = buttons[11] = true; break; case 6: // left buttons[11] = true; break; case 7: buttons[11] = buttons[8] = true; break; case 8: default: // nothing to do break; } channel[4] = normalize_dpad(buttons[8], buttons[9], buttons[10], buttons[11]); }