mirror of
https://github.com/Ed94/HandmadeHero.git
synced 2024-11-10 03:44:53 -08:00
Day 6 Bonus: Dualsense Edge support!
I had to temporarily make my own binaries for the JoyShockLibrary but it works!
This commit is contained in:
parent
eb1c2b2e57
commit
d7399149bc
2
.gitignore
vendored
2
.gitignore
vendored
@ -19,3 +19,5 @@ bld/
|
|||||||
vc140.pdb
|
vc140.pdb
|
||||||
|
|
||||||
build
|
build
|
||||||
|
|
||||||
|
**/*.dll
|
||||||
|
548
project/dependencies/JoyShockLibrary/InputHelpers.cpp
Normal file
548
project/dependencies/JoyShockLibrary/InputHelpers.cpp
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
#include "JoyShockLibrary.h"
|
||||||
|
#include "JoyShock.cpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
bool handle_input(JoyShock *jc, uint8_t *packet, int len, bool &hasIMU) {
|
||||||
|
hasIMU = true;
|
||||||
|
if (packet[0] == 0) return false; // ignore non-responses
|
||||||
|
// remember last input
|
||||||
|
|
||||||
|
//printf("%d: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
// jc->left_right,
|
||||||
|
// packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[6], packet[7], packet[8], packet[9],
|
||||||
|
// packet[10], packet[11], packet[12], packet[13], packet[14], packet[15], packet[16], packet[17], packet[18], packet[19], packet[20]);
|
||||||
|
|
||||||
|
jc->last_simple_state = jc->simple_state;
|
||||||
|
jc->simple_state.buttons = 0;
|
||||||
|
jc->last_imu_state = jc->imu_state;
|
||||||
|
IMU_STATE imu_state;
|
||||||
|
// delta time
|
||||||
|
auto time_now = std::chrono::steady_clock::now();
|
||||||
|
jc->delta_time = (float)(std::chrono::duration_cast<std::chrono::microseconds>(time_now - jc->last_polled).count() / 1000000.0);
|
||||||
|
jc->last_polled = time_now;
|
||||||
|
if (jc->cue_motion_reset)
|
||||||
|
{
|
||||||
|
//printf("RESET motion\n");
|
||||||
|
jc->cue_motion_reset = false;
|
||||||
|
jc->motion.Reset();
|
||||||
|
}
|
||||||
|
if (jc->motion.GetCalibrationMode() == GamepadMotionHelpers::CalibrationMode::Manual)
|
||||||
|
{
|
||||||
|
if (jc->use_continuous_calibration)
|
||||||
|
{
|
||||||
|
jc->motion.StartContinuousCalibration();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jc->motion.PauseContinuousCalibration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ds4
|
||||||
|
if (jc->controller_type == ControllerType::s_ds4) {
|
||||||
|
int indexOffset = 0;
|
||||||
|
bool isValid = true;
|
||||||
|
if (!jc->is_usb) {
|
||||||
|
isValid = packet[0] == 0x11;
|
||||||
|
indexOffset = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isValid = packet[0] == 0x01;
|
||||||
|
if (isValid && (packet[31] & 0x04) == 0x04)
|
||||||
|
return false; // ignore packets from Dongle with no connected controller
|
||||||
|
}
|
||||||
|
if (isValid) {
|
||||||
|
// Gyroscope:
|
||||||
|
// Gyroscope data is relative (degrees/s)
|
||||||
|
int16_t gyroSampleX = uint16_to_int16(packet[indexOffset+13] | (packet[indexOffset+14] << 8) & 0xFF00);
|
||||||
|
int16_t gyroSampleY = uint16_to_int16(packet[indexOffset+15] | (packet[indexOffset+16] << 8) & 0xFF00);
|
||||||
|
int16_t gyroSampleZ = uint16_to_int16(packet[indexOffset+17] | (packet[indexOffset+18] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleX = uint16_to_int16(packet[indexOffset+19] | (packet[indexOffset+20] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleY = uint16_to_int16(packet[indexOffset+21] | (packet[indexOffset+22] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleZ = uint16_to_int16(packet[indexOffset+23] | (packet[indexOffset+24] << 8) & 0xFF00);
|
||||||
|
|
||||||
|
if ((gyroSampleX | gyroSampleY | gyroSampleZ | accelSampleX | accelSampleY | accelSampleZ) == 0)
|
||||||
|
{
|
||||||
|
// all zero?
|
||||||
|
hasIMU = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to real units
|
||||||
|
imu_state.gyroX = (float)(gyroSampleX) * (2000.0f / 32767.0f);
|
||||||
|
imu_state.gyroY = (float)(gyroSampleY) * (2000.0f / 32767.0f);
|
||||||
|
imu_state.gyroZ = (float)(gyroSampleZ) * (2000.0f / 32767.0f);
|
||||||
|
|
||||||
|
imu_state.accelX = (float)(accelSampleX) / 8192.0f;
|
||||||
|
imu_state.accelY = (float)(accelSampleY) / 8192.0f;
|
||||||
|
imu_state.accelZ = (float)(accelSampleZ) / 8192.0f;
|
||||||
|
|
||||||
|
//printf("DS4 accel: %.4f, %.4f, %.4f\n", imu_state.accelX, imu_state.accelY, imu_state.accelZ);
|
||||||
|
|
||||||
|
//printf("%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%d\n",
|
||||||
|
// jc->gyro.yaw, jc->gyro.pitch, jc->gyro.roll, jc->accel.x, jc->accel.y, jc->accel.z, universal_counter++);
|
||||||
|
|
||||||
|
// Touchpad:
|
||||||
|
jc->last_touch_state = jc->touch_state;
|
||||||
|
|
||||||
|
jc->touch_state.t0Id = (int)(packet[indexOffset+35] & 0x7F);
|
||||||
|
jc->touch_state.t1Id = (int)(packet[indexOffset+39] & 0x7F);
|
||||||
|
jc->touch_state.t0Down = (packet[indexOffset+35] & 0x80) == 0;
|
||||||
|
jc->touch_state.t1Down = (packet[indexOffset+39] & 0x80) == 0;
|
||||||
|
|
||||||
|
jc->touch_state.t0X = (packet[indexOffset+36] | (packet[indexOffset+37] & 0x0F) << 8) / 1920.0f;
|
||||||
|
jc->touch_state.t0Y = ((packet[indexOffset+37] & 0xF0) >> 4 | packet[indexOffset+38] << 4) / 943.0f;
|
||||||
|
jc->touch_state.t1X = (packet[indexOffset+40] | (packet[indexOffset+41] & 0x0F) << 8) / 1920.0f;
|
||||||
|
jc->touch_state.t1Y = ((packet[indexOffset+41] & 0xF0) >> 4 | packet[indexOffset+42] << 4) / 943.0f;
|
||||||
|
|
||||||
|
//printf("DS4 touch: %d, %d, %d, %d, %.4f, %.4f, %.4f, %.4f\n",
|
||||||
|
// jc->touch_state.t0Id, jc->touch_state.t1Id, jc->touch_state.t0Down, jc->touch_state.t1Down,
|
||||||
|
// jc->touch_state.t0X, jc->touch_state.t0Y, jc->touch_state.t1X, jc->touch_state.t1Y);
|
||||||
|
|
||||||
|
// DS4 dpad is a hat... 0x08 is released, 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW
|
||||||
|
// http://eleccelerator.com/wiki/index.php?title=DualShock_4
|
||||||
|
uint8_t hat = packet[indexOffset+5] & 0x0f;
|
||||||
|
|
||||||
|
if ((hat > 2) & (hat < 6)) jc->simple_state.buttons |= JSMASK_DOWN; // down = SE | S | SW
|
||||||
|
if ((hat == 7) | (hat < 2)) jc->simple_state.buttons |= JSMASK_UP; // up = N | NE | NW
|
||||||
|
if ((hat > 0) & (hat < 4)) jc->simple_state.buttons |= JSMASK_RIGHT; // right = NE | E | SE
|
||||||
|
if ((hat > 4) & (hat < 8)) jc->simple_state.buttons |= JSMASK_LEFT; // left = SW | W | NW
|
||||||
|
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+5] >> 4) << JSOFFSET_W) & JSMASK_W;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+5] >> 7) << JSOFFSET_N) & JSMASK_N;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+5] >> 5) << JSOFFSET_S) & JSMASK_S;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+5] >> 6) << JSOFFSET_E) & JSMASK_E;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6] >> 6) << JSOFFSET_LCLICK) & JSMASK_LCLICK;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6] >> 7) << JSOFFSET_RCLICK) & JSMASK_RCLICK;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6] >> 5) << JSOFFSET_OPTIONS) & JSMASK_OPTIONS;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6] >> 4) << JSOFFSET_SHARE) & JSMASK_SHARE;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6] >> 1) << JSOFFSET_R) & JSMASK_R;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+6]) << JSOFFSET_L) & JSMASK_L;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+7]) << JSOFFSET_PS) & JSMASK_PS;
|
||||||
|
jc->simple_state.buttons |= ((int)(packet[indexOffset+7] >> 1) << JSOFFSET_TOUCHPAD_CLICK) & JSMASK_TOUCHPAD_CLICK;
|
||||||
|
//jc->btns.zr = (packet[indexOffset+6] >> 3) & 1;
|
||||||
|
//jc->btns.zl = (packet[indexOffset+6] >> 2) & 1;
|
||||||
|
jc->simple_state.rTrigger = packet[indexOffset+9] / 255.0f;
|
||||||
|
jc->simple_state.lTrigger = packet[indexOffset+8] / 255.0f;
|
||||||
|
|
||||||
|
if (jc->simple_state.rTrigger > 0.0) jc->simple_state.buttons |= JSMASK_ZR;
|
||||||
|
if (jc->simple_state.lTrigger > 0.0) jc->simple_state.buttons |= JSMASK_ZL;
|
||||||
|
|
||||||
|
uint16_t stick_x = packet[indexOffset+1];
|
||||||
|
uint16_t stick_y = packet[indexOffset+2];
|
||||||
|
stick_y = 255 - stick_y;
|
||||||
|
|
||||||
|
uint16_t stick2_x = packet[indexOffset+3];
|
||||||
|
uint16_t stick2_y = packet[indexOffset+4];
|
||||||
|
stick2_y = 255 - stick2_y;
|
||||||
|
|
||||||
|
jc->simple_state.stickLX = (std::fmin)(1.0f, (stick_x - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickLY = (std::fmin)(1.0f, (stick_y - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickRX = (std::fmin)(1.0f, (stick2_x - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickRY = (std::fmin)(1.0f, (stick2_y - 127.0f) / 127.0f);
|
||||||
|
|
||||||
|
jc->modifying_lock.lock();
|
||||||
|
jc->push_sensor_samples(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ,
|
||||||
|
imu_state.accelX, imu_state.accelY, imu_state.accelZ, jc->delta_time);
|
||||||
|
|
||||||
|
jc->get_calibrated_gyro(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ);
|
||||||
|
jc->modifying_lock.unlock();
|
||||||
|
|
||||||
|
jc->imu_state = imu_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Buttons: %d LX: %.5f LY: %.5f RX: %.5f RY: %.5f GX: %.4f GY: %.4f GZ: %.4f\n", \
|
||||||
|
// jc->simple_state.buttons, (jc->simple_state.stickLX + 1), (jc->simple_state.stickLY + 1), (jc->simple_state.stickRX + 1), (jc->simple_state.stickRY + 1), jc->imu_state.gyroX, jc->imu_state.gyroY, jc->imu_state.gyroZ);
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jc->controller_type == ControllerType::s_ds) {
|
||||||
|
//printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
// packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[6], packet[7], packet[8], packet[9],
|
||||||
|
// packet[10], packet[11], packet[12], packet[13], packet[14], packet[15], packet[16], packet[17], packet[18], packet[19], packet[20],
|
||||||
|
// packet[21], packet[22], packet[23], packet[24], packet[25], packet[26], packet[27], packet[28], packet[29], packet[30],
|
||||||
|
// packet[31], packet[32], packet[33], packet[34], packet[35], packet[36], packet[37], packet[38], packet[39], packet[40],
|
||||||
|
// packet[41], packet[42], packet[43], packet[44], packet[45], packet[46], packet[47], packet[48], packet[49], packet[50]);
|
||||||
|
int indexOffset = 1;
|
||||||
|
if(!jc->is_usb) {
|
||||||
|
indexOffset = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gyroscope:
|
||||||
|
// Gyroscope data is relative (degrees/s)
|
||||||
|
int16_t gyroSampleX = uint16_to_int16(packet[indexOffset + 15] | (packet[indexOffset + 16] << 8) & 0xFF00);
|
||||||
|
int16_t gyroSampleY = uint16_to_int16(packet[indexOffset + 17] | (packet[indexOffset + 18] << 8) & 0xFF00);
|
||||||
|
int16_t gyroSampleZ = uint16_to_int16(packet[indexOffset + 19] | (packet[indexOffset + 20] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleX = uint16_to_int16(packet[indexOffset + 21] | (packet[indexOffset + 22] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleY = uint16_to_int16(packet[indexOffset + 23] | (packet[indexOffset + 24] << 8) & 0xFF00);
|
||||||
|
int16_t accelSampleZ = uint16_to_int16(packet[indexOffset + 25] | (packet[indexOffset + 26] << 8) & 0xFF00);
|
||||||
|
|
||||||
|
if ((gyroSampleX | gyroSampleY | gyroSampleZ | accelSampleX | accelSampleY | accelSampleZ) == 0) {
|
||||||
|
// all zero?
|
||||||
|
hasIMU = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to real units
|
||||||
|
imu_state.gyroX = (float) (gyroSampleX) * (2000.0f / 32767.0f);
|
||||||
|
imu_state.gyroY = (float) (gyroSampleY) * (2000.0f / 32767.0f);
|
||||||
|
imu_state.gyroZ = (float) (gyroSampleZ) * (2000.0f / 32767.0f);
|
||||||
|
|
||||||
|
imu_state.accelX = (float) (accelSampleX) / 8192.0f;
|
||||||
|
imu_state.accelY = (float) (accelSampleY) / 8192.0f;
|
||||||
|
imu_state.accelZ = (float) (accelSampleZ) / 8192.0f;
|
||||||
|
|
||||||
|
//printf("DS accel: %.4f, %.4f, %.4f\n", imu_state.accelX, imu_state.accelY, imu_state.accelZ);
|
||||||
|
|
||||||
|
//printf("%.4f,%.4f,%.4f,%.4f,%.4f,%.4f,%d\n",
|
||||||
|
// jc->gyro.yaw, jc->gyro.pitch, jc->gyro.roll, jc->accel.x, jc->accel.y, jc->accel.z, universal_counter++);
|
||||||
|
|
||||||
|
// Touchpad:
|
||||||
|
jc->last_touch_state = jc->touch_state;
|
||||||
|
|
||||||
|
jc->touch_state.t0Id = (int) (packet[indexOffset + 32] & 0x7F);
|
||||||
|
jc->touch_state.t1Id = (int) (packet[indexOffset + 36] & 0x7F);
|
||||||
|
jc->touch_state.t0Down = (packet[indexOffset + 32] & 0x80) == 0;
|
||||||
|
jc->touch_state.t1Down = (packet[indexOffset + 36] & 0x80) == 0;
|
||||||
|
|
||||||
|
jc->touch_state.t0X = (packet[indexOffset + 33] | (packet[indexOffset + 34] & 0x0F) << 8) / 1920.0f;
|
||||||
|
jc->touch_state.t0Y = ((packet[indexOffset + 34] & 0xF0) >> 4 | packet[indexOffset + 35] << 4) / 943.0f;
|
||||||
|
jc->touch_state.t1X = (packet[indexOffset + 37] | (packet[indexOffset + 38] & 0x0F) << 8) / 1920.0f;
|
||||||
|
jc->touch_state.t1Y = ((packet[indexOffset + 38] & 0xF0) >> 4 | packet[indexOffset + 39] << 4) / 943.0f;
|
||||||
|
|
||||||
|
//printf("DS touch: %d, %d, %d, %d, %.4f, %.4f, %.4f, %.4f\n",
|
||||||
|
// jc->touch_state.t0Id, jc->touch_state.t1Id, jc->touch_state.t0Down, jc->touch_state.t1Down,
|
||||||
|
// jc->touch_state.t0X, jc->touch_state.t0Y, jc->touch_state.t1X, jc->touch_state.t1Y);
|
||||||
|
|
||||||
|
// DS dpad is a hat... 0x08 is released, 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW
|
||||||
|
// http://eleccelerator.com/wiki/index.php?title=DualShock_4
|
||||||
|
uint8_t hat = packet[indexOffset + 7] & 0x0f;
|
||||||
|
|
||||||
|
if ((hat > 2) & (hat < 6)) jc->simple_state.buttons |= JSMASK_DOWN; // down = SE | S | SW
|
||||||
|
if ((hat == 7) | (hat < 2)) jc->simple_state.buttons |= JSMASK_UP; // up = N | NE | NW
|
||||||
|
if ((hat > 0) & (hat < 4)) jc->simple_state.buttons |= JSMASK_RIGHT; // right = NE | E | SE
|
||||||
|
if ((hat > 4) & (hat < 8)) jc->simple_state.buttons |= JSMASK_LEFT; // left = SW | W | NW
|
||||||
|
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 4) << JSOFFSET_W) & JSMASK_W;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 7) << JSOFFSET_N) & JSMASK_N;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 5) << JSOFFSET_S) & JSMASK_S;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 7] >> 6) << JSOFFSET_E) & JSMASK_E;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 6) << JSOFFSET_LCLICK) & JSMASK_LCLICK;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 7) << JSOFFSET_RCLICK) & JSMASK_RCLICK;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 5) << JSOFFSET_OPTIONS) & JSMASK_OPTIONS;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 4) << JSOFFSET_SHARE) & JSMASK_SHARE;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8] >> 1) << JSOFFSET_R) & JSMASK_R;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 8]) << JSOFFSET_L) & JSMASK_L;
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 9]) << JSOFFSET_PS) & JSMASK_PS;
|
||||||
|
// The DS5 has a mute button that is normally ignored on PC. We can use this.
|
||||||
|
jc->simple_state.buttons |= ((int) (packet[indexOffset + 9] >> 2) << JSOFFSET_MIC) & JSMASK_MIC;
|
||||||
|
jc->simple_state.buttons |=
|
||||||
|
((int) (packet[indexOffset + 9] >> 1) << JSOFFSET_TOUCHPAD_CLICK) & JSMASK_TOUCHPAD_CLICK;
|
||||||
|
//jc->btns.zr = (packet[indexOffset+6] >> 3) & 1;
|
||||||
|
//jc->btns.zl = (packet[indexOffset+6] >> 2) & 1;
|
||||||
|
jc->simple_state.rTrigger = packet[indexOffset + 5] / 255.0f;
|
||||||
|
jc->simple_state.lTrigger = packet[indexOffset + 4] / 255.0f;
|
||||||
|
|
||||||
|
if (jc->simple_state.rTrigger > 0.0) jc->simple_state.buttons |= JSMASK_ZR;
|
||||||
|
if (jc->simple_state.lTrigger > 0.0) jc->simple_state.buttons |= JSMASK_ZL;
|
||||||
|
|
||||||
|
uint16_t stick_x = packet[indexOffset + 0];
|
||||||
|
uint16_t stick_y = packet[indexOffset + 1];
|
||||||
|
|
||||||
|
stick_y = 255 - stick_y;
|
||||||
|
|
||||||
|
uint16_t stick2_x = packet[indexOffset + 2];
|
||||||
|
uint16_t stick2_y = packet[indexOffset + 3];
|
||||||
|
stick2_y = 255 - stick2_y;
|
||||||
|
|
||||||
|
jc->simple_state.stickLX = (std::fmin)(1.0f, (stick_x - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickLY = (std::fmin)(1.0f, (stick_y - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickRX = (std::fmin)(1.0f, (stick2_x - 127.0f) / 127.0f);
|
||||||
|
jc->simple_state.stickRY = (std::fmin)(1.0f, (stick2_y - 127.0f) / 127.0f);
|
||||||
|
|
||||||
|
jc->modifying_lock.lock();
|
||||||
|
jc->push_sensor_samples(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ,
|
||||||
|
imu_state.accelX, imu_state.accelY, imu_state.accelZ, jc->delta_time);
|
||||||
|
|
||||||
|
jc->get_calibrated_gyro(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ);
|
||||||
|
jc->modifying_lock.unlock();
|
||||||
|
|
||||||
|
jc->imu_state = imu_state;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// most of this JoyCon and Pro Controller stuff is adapted from MFosse's Joycon driver.
|
||||||
|
|
||||||
|
// bluetooth button pressed packet:
|
||||||
|
if (packet[0] == 0x3F) {
|
||||||
|
|
||||||
|
//uint16_t old_buttons = jc->buttons;
|
||||||
|
//int8_t old_dstick = jc->dstick;
|
||||||
|
|
||||||
|
jc->dstick = packet[3];
|
||||||
|
// todo: get button states here aswell:
|
||||||
|
}
|
||||||
|
|
||||||
|
int buttons_pressed = 0;
|
||||||
|
|
||||||
|
// input update packet:
|
||||||
|
// 0x21 is just buttons, 0x30 includes gyro, 0x31 includes NFC (large packet size)
|
||||||
|
if (packet[0] == 0x21 || packet[0] == 0x30 || packet[0] == 0x31) {
|
||||||
|
|
||||||
|
// offset for usb or bluetooth data:
|
||||||
|
/*int offset = settings.usingBluetooth ? 0 : 10;*/
|
||||||
|
int offset = 0;
|
||||||
|
//int offset = !jc->is_usb ? 0 : 10;
|
||||||
|
|
||||||
|
uint8_t *btn_data = packet + offset + 3;
|
||||||
|
|
||||||
|
// get button states:
|
||||||
|
{
|
||||||
|
uint16_t states = 0;
|
||||||
|
uint16_t states2 = 0;
|
||||||
|
|
||||||
|
// Left JoyCon:
|
||||||
|
if (jc->left_right == 1) {
|
||||||
|
states = (btn_data[1] << 8) | (btn_data[2] & 0xFF);
|
||||||
|
// Right JoyCon:
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 2) {
|
||||||
|
states = (btn_data[1] << 8) | (btn_data[0] & 0xFF);
|
||||||
|
// Pro Controller:
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 3) {
|
||||||
|
states = (btn_data[1] << 8) | (btn_data[2] & 0xFF);
|
||||||
|
states2 = (btn_data[1] << 8) | (btn_data[0] & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons_pressed = states;
|
||||||
|
// Pro Controller:
|
||||||
|
if (jc->left_right == 3) {
|
||||||
|
buttons_pressed |= states2 << 16;
|
||||||
|
|
||||||
|
// fix some non-sense the Pro Controller does
|
||||||
|
// clear nth bit
|
||||||
|
//num &= ~(1UL << n);
|
||||||
|
buttons_pressed &= ~(1L << 9);
|
||||||
|
buttons_pressed &= ~(1L << 12);
|
||||||
|
buttons_pressed &= ~(1L << 14);
|
||||||
|
|
||||||
|
buttons_pressed &= ~(1UL << (8 + 16));
|
||||||
|
buttons_pressed &= ~(1UL << (11 + 16));
|
||||||
|
buttons_pressed &= ~(1UL << (13 + 16));
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 2) {
|
||||||
|
buttons_pressed = buttons_pressed << 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get stick data:
|
||||||
|
uint8_t *stick_data = packet + offset;
|
||||||
|
if (jc->left_right == 1) {
|
||||||
|
stick_data += 6;
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 2) {
|
||||||
|
stick_data += 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t stick_x = stick_data[0] | ((stick_data[1] & 0xF) << 8);
|
||||||
|
uint16_t stick_y = (stick_data[1] >> 4) | (stick_data[2] << 4);
|
||||||
|
|
||||||
|
// use calibration data:
|
||||||
|
if (jc->left_right == 1) {
|
||||||
|
jc->CalcAnalogStick2(jc->simple_state.stickLX, jc->simple_state.stickLY,
|
||||||
|
stick_x,
|
||||||
|
stick_y,
|
||||||
|
jc->stick_cal_x_l,
|
||||||
|
jc->stick_cal_y_l);
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 2) {
|
||||||
|
jc->CalcAnalogStick2(jc->simple_state.stickRX, jc->simple_state.stickRY,
|
||||||
|
stick_x,
|
||||||
|
stick_y,
|
||||||
|
jc->stick_cal_x_r,
|
||||||
|
jc->stick_cal_y_r);
|
||||||
|
}
|
||||||
|
else if (jc->left_right == 3) {
|
||||||
|
// pro controller
|
||||||
|
stick_data += 6;
|
||||||
|
//printf("%d, %d\n",
|
||||||
|
// jc->stick_cal_x_l,
|
||||||
|
// jc->stick_cal_y_l);
|
||||||
|
uint16_t stick_x = stick_data[0] | ((stick_data[1] & 0xF) << 8);
|
||||||
|
uint16_t stick_y = (stick_data[1] >> 4) | (stick_data[2] << 4);
|
||||||
|
jc->CalcAnalogStick2(jc->simple_state.stickLX, jc->simple_state.stickLY,
|
||||||
|
stick_x,
|
||||||
|
stick_y,
|
||||||
|
jc->stick_cal_x_l,
|
||||||
|
jc->stick_cal_y_l);
|
||||||
|
stick_data += 3;
|
||||||
|
uint16_t stick_x2 = stick_data[0] | ((stick_data[1] & 0xF) << 8);
|
||||||
|
uint16_t stick_y2 = (stick_data[1] >> 4) | (stick_data[2] << 4);
|
||||||
|
jc->CalcAnalogStick2(jc->simple_state.stickRX, jc->simple_state.stickRY,
|
||||||
|
stick_x2,
|
||||||
|
stick_y2,
|
||||||
|
jc->stick_cal_x_r,
|
||||||
|
jc->stick_cal_y_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
jc->battery = (stick_data[1] & 0xF0) >> 4;
|
||||||
|
//printf("JoyCon battery: %d\n", jc->battery);
|
||||||
|
|
||||||
|
// Accelerometer:
|
||||||
|
// Accelerometer data is absolute
|
||||||
|
{
|
||||||
|
// get accelerometer X:
|
||||||
|
float accelSampleZ = (float)uint16_to_int16(packet[13] | (packet[14] << 8) & 0xFF00) * jc->acc_cal_coeff[0];
|
||||||
|
float accelSampleX = (float)uint16_to_int16(packet[15] | (packet[16] << 8) & 0xFF00) * jc->acc_cal_coeff[1];
|
||||||
|
float accelSampleY = (float)uint16_to_int16(packet[17] | (packet[18] << 8) & 0xFF00) * jc->acc_cal_coeff[2];
|
||||||
|
float gyroSampleX = (float)uint16_to_int16(packet[19] | (packet[20] << 8) & 0xFF00) * jc->gyro_cal_coeff[0];
|
||||||
|
float gyroSampleY = (float)uint16_to_int16(packet[21] | (packet[22] << 8) & 0xFF00) * jc->gyro_cal_coeff[1];
|
||||||
|
float gyroSampleZ = (float)uint16_to_int16(packet[23] | (packet[24] << 8) & 0xFF00) * jc->gyro_cal_coeff[2];
|
||||||
|
|
||||||
|
if (gyroSampleX == 0.f && gyroSampleY == 0.f && gyroSampleZ == 0.f && accelSampleX == 0.f && accelSampleY == 0.f && accelSampleZ == 0.f)
|
||||||
|
{
|
||||||
|
// all zero?
|
||||||
|
hasIMU = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//jc->push_sensor_samples(accelSampleX, accelSampleY, accelSampleZ, gyroSampleX, gyroSampleY, gyroSampleZ);
|
||||||
|
float accelX = accelSampleX;
|
||||||
|
float accelY = accelSampleY;
|
||||||
|
float accelZ = accelSampleZ;
|
||||||
|
float totalGyroX = gyroSampleX - jc->sensor_cal[1][0];
|
||||||
|
float totalGyroY = gyroSampleY - jc->sensor_cal[1][1];
|
||||||
|
float totalGyroZ = gyroSampleZ - jc->sensor_cal[1][2];
|
||||||
|
// each packet actually has 3 samples worth of data, so collect sample 2
|
||||||
|
accelSampleZ = (float)uint16_to_int16(packet[25] | (packet[26] << 8) & 0xFF00) * jc->acc_cal_coeff[0];
|
||||||
|
accelSampleX = (float)uint16_to_int16(packet[27] | (packet[28] << 8) & 0xFF00) * jc->acc_cal_coeff[1];
|
||||||
|
accelSampleY = (float)uint16_to_int16(packet[29] | (packet[30] << 8) & 0xFF00) * jc->acc_cal_coeff[2];
|
||||||
|
gyroSampleX = (float)uint16_to_int16(packet[31] | (packet[32] << 8) & 0xFF00) * jc->gyro_cal_coeff[0];
|
||||||
|
gyroSampleY = (float)uint16_to_int16(packet[33] | (packet[34] << 8) & 0xFF00) * jc->gyro_cal_coeff[1];
|
||||||
|
gyroSampleZ = (float)uint16_to_int16(packet[35] | (packet[36] << 8) & 0xFF00) * jc->gyro_cal_coeff[2];
|
||||||
|
//jc->push_sensor_samples(accelSampleX, accelSampleY, accelSampleZ, gyroSampleX, gyroSampleY, gyroSampleZ);
|
||||||
|
accelX += accelSampleX;
|
||||||
|
accelY += accelSampleY;
|
||||||
|
accelZ += accelSampleZ;
|
||||||
|
totalGyroX += gyroSampleX - jc->sensor_cal[1][0];
|
||||||
|
totalGyroY += gyroSampleY - jc->sensor_cal[1][1];
|
||||||
|
totalGyroZ += gyroSampleZ - jc->sensor_cal[1][2];
|
||||||
|
// ... and sample 3
|
||||||
|
accelSampleZ = (float)uint16_to_int16(packet[37] | (packet[38] << 8) & 0xFF00) * jc->acc_cal_coeff[0];
|
||||||
|
accelSampleX = (float)uint16_to_int16(packet[39] | (packet[40] << 8) & 0xFF00) * jc->acc_cal_coeff[1];
|
||||||
|
accelSampleY = (float)uint16_to_int16(packet[41] | (packet[42] << 8) & 0xFF00) * jc->acc_cal_coeff[2];
|
||||||
|
gyroSampleX = (float)uint16_to_int16(packet[43] | (packet[44] << 8) & 0xFF00) * jc->gyro_cal_coeff[0];
|
||||||
|
gyroSampleY = (float)uint16_to_int16(packet[45] | (packet[46] << 8) & 0xFF00) * jc->gyro_cal_coeff[1];
|
||||||
|
gyroSampleZ = (float)uint16_to_int16(packet[47] | (packet[48] << 8) & 0xFF00) * jc->gyro_cal_coeff[2];
|
||||||
|
//jc->push_sensor_samples(accelSampleX, accelSampleY, accelSampleZ, gyroSampleX, gyroSampleY, gyroSampleZ);
|
||||||
|
accelX += accelSampleX;
|
||||||
|
accelY += accelSampleY;
|
||||||
|
accelZ += accelSampleZ;
|
||||||
|
totalGyroX += gyroSampleX - jc->sensor_cal[1][0];
|
||||||
|
totalGyroY += gyroSampleY - jc->sensor_cal[1][1];
|
||||||
|
totalGyroZ += gyroSampleZ - jc->sensor_cal[1][2];
|
||||||
|
// average the 3 samples
|
||||||
|
accelX /= 3;
|
||||||
|
accelY /= 3;
|
||||||
|
accelZ /= 3;
|
||||||
|
totalGyroX /= 3;
|
||||||
|
totalGyroY /= 3;
|
||||||
|
totalGyroZ /= 3;
|
||||||
|
imu_state.accelX = -accelX;
|
||||||
|
imu_state.accelY = accelY;
|
||||||
|
imu_state.accelZ = -accelZ;
|
||||||
|
imu_state.gyroX = -totalGyroY;
|
||||||
|
imu_state.gyroY = totalGyroZ;
|
||||||
|
imu_state.gyroZ = totalGyroX;
|
||||||
|
|
||||||
|
//printf("Switch accel: %.4f, %.4f, %.4f\n", imu_state.accelX, imu_state.accelY, imu_state.accelZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle buttons
|
||||||
|
{
|
||||||
|
// left:
|
||||||
|
if (jc->left_right == 1) {
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 1) << JSOFFSET_UP) & JSMASK_UP;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed) << JSOFFSET_DOWN) & JSMASK_DOWN;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 3) << JSOFFSET_LEFT) & JSMASK_LEFT;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 2) << JSOFFSET_RIGHT) & JSMASK_RIGHT;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 11) << JSOFFSET_LCLICK) & JSMASK_LCLICK;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 8) << JSOFFSET_MINUS) & JSMASK_MINUS;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 6) << JSOFFSET_L) & JSMASK_L;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 13) << JSOFFSET_CAPTURE) & JSMASK_CAPTURE;
|
||||||
|
jc->simple_state.lTrigger = (float)((buttons_pressed >> 7) & 1);
|
||||||
|
jc->simple_state.buttons |= ((int)(jc->simple_state.lTrigger) << JSOFFSET_ZL) & JSMASK_ZL;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 5) << JSOFFSET_SL) & JSMASK_SL;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 4) << JSOFFSET_SR) & JSMASK_SR;
|
||||||
|
|
||||||
|
// just need to negate gyroZ
|
||||||
|
imu_state.gyroZ = -imu_state.gyroZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right:
|
||||||
|
if (jc->left_right == 2) {
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 16) << JSOFFSET_W) & JSMASK_W;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 17) << JSOFFSET_N) & JSMASK_N;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 18) << JSOFFSET_S) & JSMASK_S;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 19) << JSOFFSET_E) & JSMASK_E;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 26) << JSOFFSET_RCLICK) & JSMASK_RCLICK;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 25) << JSOFFSET_PLUS) & JSMASK_PLUS;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 22) << JSOFFSET_R) & JSMASK_R;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 28) << JSOFFSET_HOME) & JSMASK_HOME;
|
||||||
|
jc->simple_state.rTrigger = (float)((buttons_pressed >> 23) & 1);
|
||||||
|
jc->simple_state.buttons |= ((int)(jc->simple_state.rTrigger) << JSOFFSET_ZR) & JSMASK_ZR;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 21) << JSOFFSET_SL) & JSMASK_SL;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 20) << JSOFFSET_SR) & JSMASK_SR;
|
||||||
|
|
||||||
|
// for some reason we need to negate x and y, and z on the right joycon
|
||||||
|
imu_state.gyroX = -imu_state.gyroX;
|
||||||
|
imu_state.gyroY = -imu_state.gyroY;
|
||||||
|
imu_state.gyroZ = -imu_state.gyroZ;
|
||||||
|
|
||||||
|
imu_state.accelX = -imu_state.accelX;
|
||||||
|
imu_state.accelY = -imu_state.accelY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// pro controller:
|
||||||
|
if (jc->left_right == 3) {
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 1) << JSOFFSET_UP) & JSMASK_UP;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed) << JSOFFSET_DOWN) & JSMASK_DOWN;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 3) << JSOFFSET_LEFT) & JSMASK_LEFT;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 2) << JSOFFSET_RIGHT) & JSMASK_RIGHT;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 16) << JSOFFSET_W) & JSMASK_W;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 17) << JSOFFSET_N) & JSMASK_N;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 18) << JSOFFSET_S) & JSMASK_S;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 19) << JSOFFSET_E) & JSMASK_E;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 11) << JSOFFSET_LCLICK) & JSMASK_LCLICK;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 26) << JSOFFSET_RCLICK) & JSMASK_RCLICK;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 25) << JSOFFSET_PLUS) & JSMASK_PLUS;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 8) << JSOFFSET_MINUS) & JSMASK_MINUS;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 22) << JSOFFSET_R) & JSMASK_R;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 6) << JSOFFSET_L) & JSMASK_L;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 28) << JSOFFSET_HOME) & JSMASK_HOME;
|
||||||
|
jc->simple_state.buttons |= ((buttons_pressed >> 13) << JSOFFSET_CAPTURE) & JSMASK_CAPTURE;
|
||||||
|
jc->simple_state.rTrigger = (float)((buttons_pressed >> 23) & 1);
|
||||||
|
jc->simple_state.lTrigger = (float)((buttons_pressed >> 7) & 1);
|
||||||
|
jc->simple_state.buttons |= ((int)(jc->simple_state.lTrigger) << JSOFFSET_ZL) & JSMASK_ZL;
|
||||||
|
jc->simple_state.buttons |= ((int)(jc->simple_state.rTrigger) << JSOFFSET_ZR) & JSMASK_ZR;
|
||||||
|
|
||||||
|
// just need to negate gyroZ
|
||||||
|
imu_state.gyroZ = -imu_state.gyroZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jc->modifying_lock.lock();
|
||||||
|
jc->push_sensor_samples(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ,
|
||||||
|
imu_state.accelX, imu_state.accelY, imu_state.accelZ, jc->delta_time);
|
||||||
|
|
||||||
|
jc->get_calibrated_gyro(imu_state.gyroX, imu_state.gyroY, imu_state.gyroZ);
|
||||||
|
jc->modifying_lock.unlock();
|
||||||
|
|
||||||
|
jc->imu_state = imu_state;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
1564
project/dependencies/JoyShockLibrary/JoyShock.cpp
Normal file
1564
project/dependencies/JoyShockLibrary/JoyShock.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1164
project/dependencies/JoyShockLibrary/JoyShockLibrary.cpp
Normal file
1164
project/dependencies/JoyShockLibrary/JoyShockLibrary.cpp
Normal file
File diff suppressed because it is too large
Load Diff
248
project/dependencies/JoyShockLibrary/JoyShockLibrary.h
Normal file
248
project/dependencies/JoyShockLibrary/JoyShockLibrary.h
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
// JoyShockLibrary.h - Contains declarations of functions
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if _MSC_VER // this is defined when compiling with Visual Studio
|
||||||
|
#define JOY_SHOCK_API __declspec(dllexport) // Visual Studio needs annotating exported functions with this
|
||||||
|
#else
|
||||||
|
#define JOY_SHOCK_API // XCode does not need annotating exported functions, so define is empty
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JS_TYPE_JOYCON_LEFT 1
|
||||||
|
#define JS_TYPE_JOYCON_RIGHT 2
|
||||||
|
#define JS_TYPE_PRO_CONTROLLER 3
|
||||||
|
#define JS_TYPE_DS4 4
|
||||||
|
#define JS_TYPE_DS 5
|
||||||
|
|
||||||
|
#define JS_SPLIT_TYPE_LEFT 1
|
||||||
|
#define JS_SPLIT_TYPE_RIGHT 2
|
||||||
|
#define JS_SPLIT_TYPE_FULL 3
|
||||||
|
|
||||||
|
#define JSMASK_UP 0x00001
|
||||||
|
#define JSMASK_DOWN 0x00002
|
||||||
|
#define JSMASK_LEFT 0x00004
|
||||||
|
#define JSMASK_RIGHT 0x00008
|
||||||
|
#define JSMASK_PLUS 0x00010
|
||||||
|
#define JSMASK_OPTIONS 0x00010
|
||||||
|
#define JSMASK_MINUS 0x00020
|
||||||
|
#define JSMASK_SHARE 0x00020
|
||||||
|
#define JSMASK_LCLICK 0x00040
|
||||||
|
#define JSMASK_RCLICK 0x00080
|
||||||
|
#define JSMASK_L 0x00100
|
||||||
|
#define JSMASK_R 0x00200
|
||||||
|
#define JSMASK_ZL 0x00400
|
||||||
|
#define JSMASK_ZR 0x00800
|
||||||
|
#define JSMASK_S 0x01000
|
||||||
|
#define JSMASK_E 0x02000
|
||||||
|
#define JSMASK_W 0x04000
|
||||||
|
#define JSMASK_N 0x08000
|
||||||
|
#define JSMASK_HOME 0x10000
|
||||||
|
#define JSMASK_PS 0x10000
|
||||||
|
#define JSMASK_CAPTURE 0x20000
|
||||||
|
#define JSMASK_TOUCHPAD_CLICK 0x20000
|
||||||
|
#define JSMASK_MIC 0x40000
|
||||||
|
#define JSMASK_SL 0x40000
|
||||||
|
#define JSMASK_SR 0x80000
|
||||||
|
|
||||||
|
#define JSOFFSET_UP 0
|
||||||
|
#define JSOFFSET_DOWN 1
|
||||||
|
#define JSOFFSET_LEFT 2
|
||||||
|
#define JSOFFSET_RIGHT 3
|
||||||
|
#define JSOFFSET_PLUS 4
|
||||||
|
#define JSOFFSET_OPTIONS 4
|
||||||
|
#define JSOFFSET_MINUS 5
|
||||||
|
#define JSOFFSET_SHARE 5
|
||||||
|
#define JSOFFSET_LCLICK 6
|
||||||
|
#define JSOFFSET_RCLICK 7
|
||||||
|
#define JSOFFSET_L 8
|
||||||
|
#define JSOFFSET_R 9
|
||||||
|
#define JSOFFSET_ZL 10
|
||||||
|
#define JSOFFSET_ZR 11
|
||||||
|
#define JSOFFSET_S 12
|
||||||
|
#define JSOFFSET_E 13
|
||||||
|
#define JSOFFSET_W 14
|
||||||
|
#define JSOFFSET_N 15
|
||||||
|
#define JSOFFSET_HOME 16
|
||||||
|
#define JSOFFSET_PS 16
|
||||||
|
#define JSOFFSET_CAPTURE 17
|
||||||
|
#define JSOFFSET_TOUCHPAD_CLICK 17
|
||||||
|
#define JSOFFSET_MIC 18
|
||||||
|
#define JSOFFSET_SL 18
|
||||||
|
#define JSOFFSET_SR 19
|
||||||
|
|
||||||
|
// PS5 Player maps for the DS Player Lightbar
|
||||||
|
#define DS5_PLAYER_1 4
|
||||||
|
#define DS5_PLAYER_2 10
|
||||||
|
#define DS5_PLAYER_3 21
|
||||||
|
#define DS5_PLAYER_4 27
|
||||||
|
#define DS5_PLAYER_5 31
|
||||||
|
|
||||||
|
typedef struct JOY_SHOCK_STATE {
|
||||||
|
int buttons = 0;
|
||||||
|
float lTrigger = 0.f;
|
||||||
|
float rTrigger = 0.f;
|
||||||
|
float stickLX = 0.f;
|
||||||
|
float stickLY = 0.f;
|
||||||
|
float stickRX = 0.f;
|
||||||
|
float stickRY = 0.f;
|
||||||
|
} JOY_SHOCK_STATE;
|
||||||
|
|
||||||
|
typedef struct IMU_STATE {
|
||||||
|
float accelX = 0.f;
|
||||||
|
float accelY = 0.f;
|
||||||
|
float accelZ = 0.f;
|
||||||
|
float gyroX = 0.f;
|
||||||
|
float gyroY = 0.f;
|
||||||
|
float gyroZ = 0.f;
|
||||||
|
} IMU_STATE;
|
||||||
|
|
||||||
|
typedef struct MOTION_STATE {
|
||||||
|
float quatW = 0.f;
|
||||||
|
float quatX = 0.f;
|
||||||
|
float quatY = 0.f;
|
||||||
|
float quatZ = 0.f;
|
||||||
|
float accelX = 0.f;
|
||||||
|
float accelY = 0.f;
|
||||||
|
float accelZ = 0.f;
|
||||||
|
float gravX = 0.f;
|
||||||
|
float gravY = 0.f;
|
||||||
|
float gravZ = 0.f;
|
||||||
|
} MOTION_STATE;
|
||||||
|
|
||||||
|
typedef struct TOUCH_STATE {
|
||||||
|
int t0Id = 0;
|
||||||
|
int t1Id = 0;
|
||||||
|
bool t0Down = false;
|
||||||
|
bool t1Down = false;
|
||||||
|
float t0X = 0.f;
|
||||||
|
float t0Y = 0.f;
|
||||||
|
float t1X = 0.f;
|
||||||
|
float t1Y = 0.f;
|
||||||
|
} TOUCH_STATE;
|
||||||
|
|
||||||
|
typedef struct JSL_AUTO_CALIBRATION {
|
||||||
|
float confidence = 0.f;
|
||||||
|
bool autoCalibrationEnabled = false;
|
||||||
|
bool isSteady = false;
|
||||||
|
} JSL_AUTO_CALIBRATION;
|
||||||
|
|
||||||
|
typedef struct JSL_SETTINGS {
|
||||||
|
int gyroSpace = 0;
|
||||||
|
int colour = 0;
|
||||||
|
int playerNumber = 0;
|
||||||
|
int controllerType = 0;
|
||||||
|
int splitType = 0;
|
||||||
|
bool isCalibrating = false;
|
||||||
|
bool autoCalibrationEnabled = false;
|
||||||
|
bool isConnected = false;
|
||||||
|
} JSL_SETTINGS;
|
||||||
|
|
||||||
|
extern "C" JOY_SHOCK_API int JslConnectDevices();
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetConnectedDeviceHandles(int* deviceHandleArray, int size);
|
||||||
|
extern "C" JOY_SHOCK_API void JslDisconnectAndDisposeAll();
|
||||||
|
extern "C" JOY_SHOCK_API bool JslStillConnected(int deviceId);
|
||||||
|
|
||||||
|
// get buttons as bits in the following order, using North South East West to name face buttons to avoid ambiguity between Xbox and Nintendo layouts:
|
||||||
|
// 0x00001: up
|
||||||
|
// 0x00002: down
|
||||||
|
// 0x00004: left
|
||||||
|
// 0x00008: right
|
||||||
|
// 0x00010: plus
|
||||||
|
// 0x00020: minus
|
||||||
|
// 0x00040: left stick click
|
||||||
|
// 0x00080: right stick click
|
||||||
|
// 0x00100: L
|
||||||
|
// 0x00200: R
|
||||||
|
// ZL and ZR are reported as analogue inputs (GetLeftTrigger, GetRightTrigger), because DS4 and XBox controllers use analogue triggers, but we also have them as raw buttons
|
||||||
|
// 0x00400: ZL
|
||||||
|
// 0x00800: ZR
|
||||||
|
// 0x01000: S
|
||||||
|
// 0x02000: E
|
||||||
|
// 0x04000: W
|
||||||
|
// 0x08000: N
|
||||||
|
// 0x10000: home / PS
|
||||||
|
// 0x20000: capture / touchpad-click
|
||||||
|
// 0x40000: SL
|
||||||
|
// 0x80000: SR
|
||||||
|
// These are the best way to get all the buttons/triggers/sticks, gyro/accelerometer (IMU), orientation/acceleration/gravity (Motion), or touchpad
|
||||||
|
extern "C" JOY_SHOCK_API JOY_SHOCK_STATE JslGetSimpleState(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API IMU_STATE JslGetIMUState(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API MOTION_STATE JslGetMotionState(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API TOUCH_STATE JslGetTouchState(int deviceId, bool previous = false);
|
||||||
|
extern "C" JOY_SHOCK_API bool JslGetTouchpadDimension(int deviceId, int &sizeX, int &sizeY);
|
||||||
|
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetButtons(int deviceId);
|
||||||
|
|
||||||
|
// get thumbsticks
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetLeftX(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetLeftY(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetRightX(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetRightY(int deviceId);
|
||||||
|
|
||||||
|
// get triggers. Switch controllers don't have analogue triggers, but will report 0.0 or 1.0 so they can be used in the same way as others
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetLeftTrigger(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetRightTrigger(int deviceId);
|
||||||
|
|
||||||
|
// get gyro
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetGyroX(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetGyroY(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetGyroZ(int deviceId);
|
||||||
|
|
||||||
|
// get accumulated average gyro since this function was last called or last flushed values
|
||||||
|
extern "C" JOY_SHOCK_API void JslGetAndFlushAccumulatedGyro(int deviceId, float& gyroX, float& gyroY, float& gyroZ);
|
||||||
|
|
||||||
|
// set gyro space. JslGetGyro*, JslGetAndFlushAccumulatedGyro, JslGetIMUState, and the IMU_STATEs reported in the callback functions will use one of 3 transformations:
|
||||||
|
// 0 = local space -> no transformation is done on gyro input
|
||||||
|
// 1 = world space -> gyro input is transformed based on the calculated gravity direction to account for the player's preferred controller orientation
|
||||||
|
// 2 = player space -> a simple combination of local and world space that is as adaptive as world space but is as robust as local space
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetGyroSpace(int deviceId, int gyroSpace);
|
||||||
|
|
||||||
|
// get accelerometor
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetAccelX(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetAccelY(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetAccelZ(int deviceId);
|
||||||
|
|
||||||
|
// get touchpad
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetTouchId(int deviceId, bool secondTouch = false);
|
||||||
|
extern "C" JOY_SHOCK_API bool JslGetTouchDown(int deviceId, bool secondTouch = false);
|
||||||
|
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetTouchX(int deviceId, bool secondTouch = false);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetTouchY(int deviceId, bool secondTouch = false);
|
||||||
|
|
||||||
|
// analog parameters have different resolutions depending on device
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetStickStep(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetTriggerStep(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetPollRate(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API float JslGetTimeSinceLastUpdate(int deviceId);
|
||||||
|
|
||||||
|
// calibration
|
||||||
|
extern "C" JOY_SHOCK_API void JslResetContinuousCalibration(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API void JslStartContinuousCalibration(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API void JslPauseContinuousCalibration(int deviceId);
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetAutomaticCalibration(int deviceId, bool enabled);
|
||||||
|
extern "C" JOY_SHOCK_API void JslGetCalibrationOffset(int deviceId, float& xOffset, float& yOffset, float& zOffset);
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset);
|
||||||
|
extern "C" JOY_SHOCK_API JSL_AUTO_CALIBRATION JslGetAutoCalibrationStatus(int deviceId);
|
||||||
|
|
||||||
|
// this function will get called for each input event from each controller
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetCallback(void(*callback)(int, JOY_SHOCK_STATE, JOY_SHOCK_STATE, IMU_STATE, IMU_STATE, float));
|
||||||
|
// this function will get called for each input event, even if touch data didn't update
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetTouchCallback(void(*callback)(int, TOUCH_STATE, TOUCH_STATE, float));
|
||||||
|
// this function will get called for each device when it is newly connected
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetConnectCallback(void(*callback)(int));
|
||||||
|
// this function will get called for each device when it is disconnected
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetDisconnectCallback(void(*callback)(int, bool));
|
||||||
|
|
||||||
|
// super-getter for reading a whole lot of state at once
|
||||||
|
extern "C" JOY_SHOCK_API JSL_SETTINGS JslGetControllerInfoAndSettings(int deviceId);
|
||||||
|
// what kind of controller is this?
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetControllerType(int deviceId);
|
||||||
|
// is this a left, right, or full controller?
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetControllerSplitType(int deviceId);
|
||||||
|
// what colour is the controller (not all controllers support this; those that don't will report white)
|
||||||
|
extern "C" JOY_SHOCK_API int JslGetControllerColour(int deviceId);
|
||||||
|
// set controller light colour (not all controllers have a light whose colour can be set, but that just means nothing will be done when this is called -- no harm)
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetLightColour(int deviceId, int colour);
|
||||||
|
// set controller rumble
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetRumble(int deviceId, int smallRumble, int bigRumble);
|
||||||
|
// set controller player number indicator (not all controllers have a number indicator which can be set, but that just means nothing will be done when this is called -- no harm)
|
||||||
|
extern "C" JOY_SHOCK_API void JslSetPlayerNumber(int deviceId, int number);
|
391
project/dependencies/JoyShockLibrary/hidapi/hidapi.h
Normal file
391
project/dependencies/JoyShockLibrary/hidapi/hidapi.h
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/*******************************************************
|
||||||
|
HIDAPI - Multi-Platform library for
|
||||||
|
communication with HID devices.
|
||||||
|
|
||||||
|
Alan Ott
|
||||||
|
Signal 11 Software
|
||||||
|
|
||||||
|
8/22/2009
|
||||||
|
|
||||||
|
Copyright 2009, All Rights Reserved.
|
||||||
|
|
||||||
|
At the discretion of the user of this library,
|
||||||
|
this software may be licensed under the terms of the
|
||||||
|
GNU General Public License v3, a BSD-Style license, or the
|
||||||
|
original HIDAPI license as outlined in the LICENSE.txt,
|
||||||
|
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||||
|
files located at the root of the source distribution.
|
||||||
|
These files may also be found in the public source
|
||||||
|
code repository located at:
|
||||||
|
http://github.com/signal11/hidapi .
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @defgroup API hidapi API
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HIDAPI_H__
|
||||||
|
#define HIDAPI_H__
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define HID_API_EXPORT __declspec(dllexport)
|
||||||
|
#define HID_API_CALL
|
||||||
|
#else
|
||||||
|
#define HID_API_EXPORT /**< API export macro */
|
||||||
|
#define HID_API_CALL /**< API call macro */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
struct hid_device_;
|
||||||
|
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
|
||||||
|
|
||||||
|
/** hidapi info structure */
|
||||||
|
struct hid_device_info {
|
||||||
|
/** Platform-specific device path */
|
||||||
|
char *path;
|
||||||
|
/** Device Vendor ID */
|
||||||
|
unsigned short vendor_id;
|
||||||
|
/** Device Product ID */
|
||||||
|
unsigned short product_id;
|
||||||
|
/** Serial Number */
|
||||||
|
wchar_t *serial_number;
|
||||||
|
/** Device Release Number in binary-coded decimal,
|
||||||
|
also known as Device Version Number */
|
||||||
|
unsigned short release_number;
|
||||||
|
/** Manufacturer String */
|
||||||
|
wchar_t *manufacturer_string;
|
||||||
|
/** Product string */
|
||||||
|
wchar_t *product_string;
|
||||||
|
/** Usage Page for this Device/Interface
|
||||||
|
(Windows/Mac only). */
|
||||||
|
unsigned short usage_page;
|
||||||
|
/** Usage for this Device/Interface
|
||||||
|
(Windows/Mac only).*/
|
||||||
|
unsigned short usage;
|
||||||
|
/** The USB interface which this logical device
|
||||||
|
represents. Valid on both Linux implementations
|
||||||
|
in all cases, and valid on the Windows implementation
|
||||||
|
only if the device contains more than one interface. */
|
||||||
|
int interface_number;
|
||||||
|
|
||||||
|
/** Pointer to the next device */
|
||||||
|
struct hid_device_info *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Initialize the HIDAPI library.
|
||||||
|
|
||||||
|
This function initializes the HIDAPI library. Calling it is not
|
||||||
|
strictly necessary, as it will be called automatically by
|
||||||
|
hid_enumerate() and any of the hid_open_*() functions if it is
|
||||||
|
needed. This function should be called at the beginning of
|
||||||
|
execution however, if there is a chance of HIDAPI handles
|
||||||
|
being opened by different threads simultaneously.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_init(void);
|
||||||
|
|
||||||
|
/** @brief Finalize the HIDAPI library.
|
||||||
|
|
||||||
|
This function frees all of the static data associated with
|
||||||
|
HIDAPI. It should be called at the end of execution to avoid
|
||||||
|
memory leaks.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_exit(void);
|
||||||
|
|
||||||
|
/** @brief Enumerate the HID Devices.
|
||||||
|
|
||||||
|
This function returns a linked list of all the HID devices
|
||||||
|
attached to the system which match vendor_id and product_id.
|
||||||
|
If @p vendor_id is set to 0 then any vendor matches.
|
||||||
|
If @p product_id is set to 0 then any product matches.
|
||||||
|
If @p vendor_id and @p product_id are both set to 0, then
|
||||||
|
all HID devices will be returned.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param vendor_id The Vendor ID (VID) of the types of device
|
||||||
|
to open.
|
||||||
|
@param product_id The Product ID (PID) of the types of
|
||||||
|
device to open.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns a pointer to a linked list of type
|
||||||
|
struct #hid_device, containing information about the HID devices
|
||||||
|
attached to the system, or NULL in the case of failure. Free
|
||||||
|
this linked list by calling hid_free_enumeration().
|
||||||
|
*/
|
||||||
|
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
|
||||||
|
|
||||||
|
/** @brief Free an enumeration Linked List
|
||||||
|
|
||||||
|
This function frees a linked list created by hid_enumerate().
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param devs Pointer to a list of struct_device returned from
|
||||||
|
hid_enumerate().
|
||||||
|
*/
|
||||||
|
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
|
||||||
|
|
||||||
|
/** @brief Open a HID device using a Vendor ID (VID), Product ID
|
||||||
|
(PID) and optionally a serial number.
|
||||||
|
|
||||||
|
If @p serial_number is NULL, the first device with the
|
||||||
|
specified VID and PID is opened.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param vendor_id The Vendor ID (VID) of the device to open.
|
||||||
|
@param product_id The Product ID (PID) of the device to open.
|
||||||
|
@param serial_number The Serial Number of the device to open
|
||||||
|
(Optionally NULL).
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns a pointer to a #hid_device object on
|
||||||
|
success or NULL on failure.
|
||||||
|
*/
|
||||||
|
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
|
||||||
|
|
||||||
|
/** @brief Open a HID device by its path name.
|
||||||
|
|
||||||
|
The path name be determined by calling hid_enumerate(), or a
|
||||||
|
platform-specific path name can be used (eg: /dev/hidraw0 on
|
||||||
|
Linux).
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param path The path name of the device to open
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns a pointer to a #hid_device object on
|
||||||
|
success or NULL on failure.
|
||||||
|
*/
|
||||||
|
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
|
||||||
|
|
||||||
|
/** @brief Write an Output report to a HID device.
|
||||||
|
|
||||||
|
The first byte of @p data[] must contain the Report ID. For
|
||||||
|
devices which only support a single report, this must be set
|
||||||
|
to 0x0. The remaining bytes contain the report data. Since
|
||||||
|
the Report ID is mandatory, calls to hid_write() will always
|
||||||
|
contain one more byte than the report contains. For example,
|
||||||
|
if a hid report is 16 bytes long, 17 bytes must be passed to
|
||||||
|
hid_write(), the Report ID (or 0x0, for devices with a
|
||||||
|
single report), followed by the report data (16 bytes). In
|
||||||
|
this example, the length passed in would be 17.
|
||||||
|
|
||||||
|
hid_write() will send the data on the first OUT endpoint, if
|
||||||
|
one exists. If it does not, it will send the data through
|
||||||
|
the Control Endpoint (Endpoint 0).
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param data The data to send, including the report number as
|
||||||
|
the first byte.
|
||||||
|
@param length The length in bytes of the data to send.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns the actual number of bytes written and
|
||||||
|
-1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
|
||||||
|
|
||||||
|
/** @brief Read an Input report from a HID device with timeout.
|
||||||
|
|
||||||
|
Input reports are returned
|
||||||
|
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||||
|
contain the Report number if the device uses numbered reports.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param data A buffer to put the read data into.
|
||||||
|
@param length The number of bytes to read. For devices with
|
||||||
|
multiple reports, make sure to read an extra byte for
|
||||||
|
the report number.
|
||||||
|
@param milliseconds timeout in milliseconds or -1 for blocking wait.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns the actual number of bytes read and
|
||||||
|
-1 on error. If no packet was available to be read within
|
||||||
|
the timeout period, this function returns 0.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
|
||||||
|
|
||||||
|
/** @brief Read an Input report from a HID device.
|
||||||
|
|
||||||
|
Input reports are returned
|
||||||
|
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||||
|
contain the Report number if the device uses numbered reports.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param data A buffer to put the read data into.
|
||||||
|
@param length The number of bytes to read. For devices with
|
||||||
|
multiple reports, make sure to read an extra byte for
|
||||||
|
the report number.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns the actual number of bytes read and
|
||||||
|
-1 on error. If no packet was available to be read and
|
||||||
|
the handle is in non-blocking mode, this function returns 0.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
|
||||||
|
|
||||||
|
/** @brief Set the device handle to be non-blocking.
|
||||||
|
|
||||||
|
In non-blocking mode calls to hid_read() will return
|
||||||
|
immediately with a value of 0 if there is no data to be
|
||||||
|
read. In blocking mode, hid_read() will wait (block) until
|
||||||
|
there is data to read before returning.
|
||||||
|
|
||||||
|
Nonblocking can be turned on and off at any time.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param nonblock enable or not the nonblocking reads
|
||||||
|
- 1 to enable nonblocking
|
||||||
|
- 0 to disable nonblocking.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
|
||||||
|
|
||||||
|
/** @brief Send a Feature report to the device.
|
||||||
|
|
||||||
|
Feature reports are sent over the Control endpoint as a
|
||||||
|
Set_Report transfer. The first byte of @p data[] must
|
||||||
|
contain the Report ID. For devices which only support a
|
||||||
|
single report, this must be set to 0x0. The remaining bytes
|
||||||
|
contain the report data. Since the Report ID is mandatory,
|
||||||
|
calls to hid_send_feature_report() will always contain one
|
||||||
|
more byte than the report contains. For example, if a hid
|
||||||
|
report is 16 bytes long, 17 bytes must be passed to
|
||||||
|
hid_send_feature_report(): the Report ID (or 0x0, for
|
||||||
|
devices which do not use numbered reports), followed by the
|
||||||
|
report data (16 bytes). In this example, the length passed
|
||||||
|
in would be 17.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param data The data to send, including the report number as
|
||||||
|
the first byte.
|
||||||
|
@param length The length in bytes of the data to send, including
|
||||||
|
the report number.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns the actual number of bytes written and
|
||||||
|
-1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
|
||||||
|
|
||||||
|
/** @brief Get a feature report from a HID device.
|
||||||
|
|
||||||
|
Set the first byte of @p data[] to the Report ID of the
|
||||||
|
report to be read. Make sure to allow space for this
|
||||||
|
extra byte in @p data[]. Upon return, the first byte will
|
||||||
|
still contain the Report ID, and the report data will
|
||||||
|
start in data[1].
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param data A buffer to put the read data into, including
|
||||||
|
the Report ID. Set the first byte of @p data[] to the
|
||||||
|
Report ID of the report to be read, or set it to zero
|
||||||
|
if your device does not use numbered reports.
|
||||||
|
@param length The number of bytes to read, including an
|
||||||
|
extra byte for the report ID. The buffer can be longer
|
||||||
|
than the actual report.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns the number of bytes read plus
|
||||||
|
one for the report ID (which is still in the first
|
||||||
|
byte), or -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
|
||||||
|
|
||||||
|
/** @brief Close a HID device.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
*/
|
||||||
|
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
|
||||||
|
|
||||||
|
/** @brief Get The Manufacturer String from a HID device.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param string A wide string buffer to put the data into.
|
||||||
|
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
|
||||||
|
|
||||||
|
/** @brief Get The Product String from a HID device.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param string A wide string buffer to put the data into.
|
||||||
|
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
|
||||||
|
|
||||||
|
/** @brief Get The Serial Number String from a HID device.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param string A wide string buffer to put the data into.
|
||||||
|
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
|
||||||
|
|
||||||
|
/** @brief Get a string from a HID device, based on its string index.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
@param string_index The index of the string to get.
|
||||||
|
@param string A wide string buffer to put the data into.
|
||||||
|
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns 0 on success and -1 on error.
|
||||||
|
*/
|
||||||
|
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
|
||||||
|
|
||||||
|
/** @brief Get a string describing the last error which occurred.
|
||||||
|
|
||||||
|
@ingroup API
|
||||||
|
@param device A device handle returned from hid_open().
|
||||||
|
|
||||||
|
@returns
|
||||||
|
This function returns a string containing the last error
|
||||||
|
which occurred or NULL if none has occurred.
|
||||||
|
*/
|
||||||
|
HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
BIN
project/dependencies/JoyShockLibrary/stdafx.cpp
Normal file
BIN
project/dependencies/JoyShockLibrary/stdafx.cpp
Normal file
Binary file not shown.
BIN
project/dependencies/JoyShockLibrary/stdafx.h
Normal file
BIN
project/dependencies/JoyShockLibrary/stdafx.h
Normal file
Binary file not shown.
BIN
project/dependencies/JoyShockLibrary/targetver.h
Normal file
BIN
project/dependencies/JoyShockLibrary/targetver.h
Normal file
Binary file not shown.
109
project/dependencies/JoyShockLibrary/tools.cpp
Normal file
109
project/dependencies/JoyShockLibrary/tools.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
//#include <curl/curl.h>
|
||||||
|
|
||||||
|
#pragma warning(disable: 4996)
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef int8_t s8;
|
||||||
|
typedef int16_t s16;
|
||||||
|
typedef int32_t s32;
|
||||||
|
typedef int64_t s64;
|
||||||
|
|
||||||
|
int16_t unsignedToSigned16(uint16_t n) {
|
||||||
|
uint16_t A = n;
|
||||||
|
uint16_t B = 0xFFFF - A;
|
||||||
|
if (A < B) {
|
||||||
|
return (int16_t)A;
|
||||||
|
} else {
|
||||||
|
return (int16_t)(-1 * B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t uint16_to_int16(uint16_t a) {
|
||||||
|
int16_t b;
|
||||||
|
char* aPointer = (char*)&a, *bPointer = (char*)&b;
|
||||||
|
memcpy(bPointer, aPointer, sizeof(a));
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t combine_uint8_t(uint8_t a, uint8_t b) {
|
||||||
|
uint16_t c = ((uint16_t)a << 8) | b;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t combine_gyro_data(uint8_t a, uint8_t b) {
|
||||||
|
uint16_t c = combine_uint8_t(a, b);
|
||||||
|
int16_t d = uint16_to_int16(c);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
float clamp(float a, float min, float max) {
|
||||||
|
if (a < min) {
|
||||||
|
return min;
|
||||||
|
} else if (a > max) {
|
||||||
|
return max;
|
||||||
|
} else {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t clamp(uint16_t a, uint16_t min, uint16_t max) {
|
||||||
|
if (a < min) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
else if (a > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned createMask(unsigned a, unsigned b) {
|
||||||
|
unsigned r = 0;
|
||||||
|
for (unsigned i = a; i <= b; i++)
|
||||||
|
r |= 1 << i;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hex_dump(unsigned char *buf, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void hex_dump2(unsigned char *buf, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hex_dump_0(unsigned char *buf, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (buf[i] != 0) {
|
||||||
|
printf("%02x ", buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void int_dump(unsigned char *buf, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
printf("%i ", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
|
|
||||||
|
// Using this to get dualsense controllers
|
||||||
|
#include "JoyShockLibrary/JoyShockLibrary.h"
|
||||||
|
|
||||||
|
|
||||||
NS_WIN32_BEGIN
|
NS_WIN32_BEGIN
|
||||||
|
|
||||||
// TODO(Ed) : This is a global for now.
|
// TODO(Ed) : This is a global for now.
|
||||||
@ -301,7 +305,17 @@ WinMain(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
using namespace win32;
|
using namespace win32;
|
||||||
xinput_load_library_bindings();
|
// xinput_load_library_bindings();
|
||||||
|
|
||||||
|
using JSL_DeviceHandle = int;
|
||||||
|
u32 jsl_num_devices = JslConnectDevices();
|
||||||
|
|
||||||
|
JSL_DeviceHandle device_handles[4] {};
|
||||||
|
u32 jsl_getconnected_found = JslGetConnectedDeviceHandles( device_handles, jsl_num_devices );
|
||||||
|
if ( jsl_getconnected_found != jsl_num_devices )
|
||||||
|
{
|
||||||
|
OutputDebugStringA( "Error: JSLGetConnectedDeviceHandles didn't find as many as were stated with JslConnectDevices\n");
|
||||||
|
}
|
||||||
|
|
||||||
// MessageBox( 0, L"First message!", L"Handmade Hero", MB_Ok_Btn | MB_Icon_Information );
|
// MessageBox( 0, L"First message!", L"Handmade Hero", MB_Ok_Btn | MB_Icon_Information );
|
||||||
|
|
||||||
@ -374,6 +388,7 @@ WinMain(
|
|||||||
DispatchMessage( & msg_info );
|
DispatchMessage( & msg_info );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XInput Polling
|
||||||
// TODO(Ed) : Should we poll this more frequently?
|
// TODO(Ed) : Should we poll this more frequently?
|
||||||
for ( DWORD controller_index = 0; controller_index < XUSER_MAX_COUNT; ++ controller_index )
|
for ( DWORD controller_index = 0; controller_index < XUSER_MAX_COUNT; ++ controller_index )
|
||||||
{
|
{
|
||||||
@ -406,6 +421,30 @@ WinMain(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSL Input Polling
|
||||||
|
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
||||||
|
{
|
||||||
|
if ( ! JslStillConnected( device_handles[ jsl_device_index ] ) )
|
||||||
|
{
|
||||||
|
OutputDebugStringA( "Error: JSLStillConnected returned false\n" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JOY_SHOCK_STATE state = JslGetSimpleState( device_handles[ jsl_device_index ] );
|
||||||
|
dpad_up = state.buttons & JSMASK_UP;
|
||||||
|
dpad_down = state.buttons & JSMASK_DOWN;
|
||||||
|
dpad_left = state.buttons & JSMASK_LEFT;
|
||||||
|
dpad_right = state.buttons & JSMASK_RIGHT;
|
||||||
|
start = state.buttons & JSMASK_PLUS;
|
||||||
|
back = state.buttons & JSMASK_MINUS;
|
||||||
|
left_shoulder = state.buttons & JSMASK_L;
|
||||||
|
right_shoulder = state.buttons & JSMASK_R;
|
||||||
|
btn_a_button = state.buttons & JSMASK_S;
|
||||||
|
btn_b_button = state.buttons & JSMASK_E;
|
||||||
|
btn_x_button = state.buttons & JSMASK_W;
|
||||||
|
btn_y_button = state.buttons & JSMASK_N;
|
||||||
|
}
|
||||||
|
|
||||||
x_offset += dpad_right;
|
x_offset += dpad_right;
|
||||||
x_offset -= dpad_left;
|
x_offset -= dpad_left;
|
||||||
y_offset += dpad_up;
|
y_offset += dpad_up;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#pragma region Platform Detection
|
#pragma region Platform Detection
|
||||||
|
|
||||||
/* Platform architecture */
|
/* Platform architecture */
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
|
|
||||||
#define global static // Global variables
|
#define global static // Global variables
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#pragma region Basic Types
|
#pragma region Basic Types
|
||||||
|
|
||||||
#define U8_MIN 0u
|
#define U8_MIN 0u
|
||||||
|
@ -338,10 +338,15 @@ $includes = @(
|
|||||||
$path_deps,
|
$path_deps,
|
||||||
$path_platform
|
$path_platform
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Microsoft
|
||||||
$lib_gdi32 = 'Gdi32.lib'
|
$lib_gdi32 = 'Gdi32.lib'
|
||||||
$lib_xinput = 'Xinput.lib'
|
$lib_xinput = 'Xinput.lib'
|
||||||
$lib_user32 = 'User32.lib'
|
$lib_user32 = 'User32.lib'
|
||||||
|
|
||||||
|
# Github
|
||||||
|
$lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib'
|
||||||
|
|
||||||
$unit = Join-Path $path_project 'handmade_win32.cpp'
|
$unit = Join-Path $path_project 'handmade_win32.cpp'
|
||||||
$executable = Join-Path $path_build 'handmade_win32.exe'
|
$executable = Join-Path $path_build 'handmade_win32.exe'
|
||||||
|
|
||||||
@ -351,6 +356,9 @@ $linker_args = @(
|
|||||||
$lib_gdi32,
|
$lib_gdi32,
|
||||||
# $lib_xinput,
|
# $lib_xinput,
|
||||||
$lib_user32,
|
$lib_user32,
|
||||||
|
|
||||||
|
$lib_jsl,
|
||||||
|
|
||||||
$flag_link_win_subsystem_windows
|
$flag_link_win_subsystem_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Binary file not shown.
@ -1,28 +1,65 @@
|
|||||||
clear-host
|
clear-host
|
||||||
$path_root = & git rev-parse --show-toplevel
|
$path_root = & git rev-parse --show-toplevel
|
||||||
|
|
||||||
|
$path_data = Join-Path $path_root "data"
|
||||||
$path_project = Join-Path $path_root "project"
|
$path_project = Join-Path $path_root "project"
|
||||||
$path_deps = Join-Path $path_project "dependencies"
|
$path_deps = Join-Path $path_project "dependencies"
|
||||||
$path_deps_windows = Join-Path $path_deps "windows"
|
$path_deps_windows = Join-Path $path_deps "windows"
|
||||||
$path_temp = Join-Path $path_deps "temp"
|
$path_temp = Join-Path $path_deps "temp"
|
||||||
$path_platform = Join-Path $path_project "platform"
|
$path_platform = Join-Path $path_project "platform"
|
||||||
|
|
||||||
# Define the URL of the zip file and the destination directory
|
# Clear out the current content first
|
||||||
$url = "https://github.com/Ed94/gencpp/releases/download/latest/gencpp_singleheader.zip"
|
if (Test-Path $path_deps) {
|
||||||
$destinationZip = Join-Path $path_temp "gencpp_singleheader.zip"
|
Remove-Item $path_deps -Recurse -Force
|
||||||
|
|
||||||
# Create directories if they don't exist
|
|
||||||
if (-not (Test-Path $path_deps)) {
|
|
||||||
New-Item -ItemType Directory -Path $path_deps
|
New-Item -ItemType Directory -Path $path_deps
|
||||||
}
|
}
|
||||||
if (-not (Test-Path $path_temp)) {
|
New-Item -ItemType Directory -Path $path_temp
|
||||||
New-Item -ItemType Directory -Path $path_temp
|
|
||||||
}
|
$url_gencpp = "https://github.com/Ed94/gencpp/releases/download/latest/gencpp_singleheader.zip"
|
||||||
|
$path_gencpp_zip = Join-Path $path_temp "gencpp_singleheader.zip"
|
||||||
|
|
||||||
#region gencpp
|
#region gencpp
|
||||||
Invoke-WebRequest -Uri $url -OutFile $destinationZip
|
Invoke-WebRequest -Uri $url_gencpp -OutFile $path_gencpp_zip
|
||||||
Expand-Archive -Path $destinationZip -DestinationPath $path_temp
|
Expand-Archive -Path $path_gencpp_zip -DestinationPath $path_temp
|
||||||
Move-Item -Path (Join-Path $path_temp "gen.hpp") -Destination $path_deps -Force
|
Move-Item -Path (Join-Path $path_temp "gen.hpp") -Destination $path_deps -Force
|
||||||
#endregion gencpp
|
#endregion gencpp
|
||||||
|
|
||||||
|
#region JoyShockLibrary
|
||||||
|
$url_jsl_repo = "https://github.com/JibbSmart/JoyShockLibrary.git"
|
||||||
|
# $url_jsl_zip = "https://github.com/JibbSmart/JoyShockLibrary/releases/download/v3.0/JSL_3_0.zip"
|
||||||
|
$url_jsl_zip = "https://github.com/Ed94/JoyShockLibrary/releases/download/not_for_public_use/JSL.zip"
|
||||||
|
$path_jsl_repo = Join-Path $path_temp "JoyShockLibraryRepo"
|
||||||
|
$path_jsl_repo_code = Join-Path $path_jsl_repo "JoyShockLibrary"
|
||||||
|
$path_jsl_lib_zip = Join-Path $path_temp "JSL_3_0.zip"
|
||||||
|
$path_jsl = Join-Path $path_deps "JoyShockLibrary"
|
||||||
|
$path_jsl_hidapi = Join-Path $path_jsl "hidapi"
|
||||||
|
$path_jsl_lib = Join-Path $path_jsl "x64"
|
||||||
|
|
||||||
|
# Grab code from repo
|
||||||
|
& git clone $url_jsl_repo $path_jsl_repo
|
||||||
|
Move-Item -Path $path_jsl_repo_code -Destination $path_deps -Force
|
||||||
|
|
||||||
|
# Clean up the junk
|
||||||
|
@( $path_jsl, $path_jsl_hidapi ) | ForEach-Object {
|
||||||
|
Get-ChildItem -Path $path_jsl -Recurse -File | Where-Object {
|
||||||
|
($_.Extension -ne ".h" -and $_.Extension -ne ".cpp")
|
||||||
|
} | Remove-Item -Force
|
||||||
|
}
|
||||||
|
Remove-Item (join-path $path_jsl_hidapi 'objs') -Recurse -Force
|
||||||
|
|
||||||
|
# Get precompiled binaries
|
||||||
|
Invoke-WebRequest -Uri $url_jsl_zip -OutFile $path_jsl_lib_zip
|
||||||
|
Expand-Archive -Path $path_jsl_lib_zip -DestinationPath $path_temp
|
||||||
|
|
||||||
|
if (-not (Test-Path $path_jsl_lib)) {
|
||||||
|
New-Item -ItemType Directory -Path $path_jsl_lib
|
||||||
|
}
|
||||||
|
|
||||||
|
$jsl_lib_files = (Get-ChildItem (Join-Path $path_temp "JSL\x64") -Recurse -Include *.dll, *.lib)
|
||||||
|
Move-Item $jsl_lib_files -Destination $path_jsl_lib -Force
|
||||||
|
|
||||||
|
$path_jsl_dll = Join-Path $path_jsl_lib "JoyShockLibrary.dll"
|
||||||
|
Move-Item $path_jsl_dll $path_data -Force
|
||||||
|
#endregion JoyShockLibrary
|
||||||
|
|
||||||
Remove-Item $path_temp -Recurse -Force
|
Remove-Item $path_temp -Recurse -Force
|
||||||
|
Loading…
Reference in New Issue
Block a user