mirror of
				https://github.com/Ed94/HandmadeHero.git
				synced 2025-10-31 06:50:54 -07: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:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -19,3 +19,5 @@ bld/ | ||||
| vc140.pdb | ||||
|  | ||||
| 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" | ||||
|  | ||||
| // Using this to get dualsense controllers | ||||
| #include "JoyShockLibrary/JoyShockLibrary.h" | ||||
|  | ||||
|  | ||||
| NS_WIN32_BEGIN | ||||
|  | ||||
| // TODO(Ed) : This is a global for now. | ||||
| @@ -301,7 +305,17 @@ WinMain( | ||||
| ) | ||||
| { | ||||
| 	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 ); | ||||
|  | ||||
| @@ -374,6 +388,7 @@ WinMain( | ||||
| 					DispatchMessage( & msg_info ); | ||||
| 				} | ||||
|  | ||||
| 				// XInput Polling | ||||
| 				// TODO(Ed) : Should we poll this more frequently? | ||||
| 				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_left; | ||||
| 				y_offset += dpad_up; | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| #pragma region Platform Detection | ||||
|  | ||||
| /* Platform architecture */ | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| // Keywords | ||||
|  | ||||
| #define global        static    // Global variables | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| #pragma region Basic Types | ||||
|  | ||||
| #define U8_MIN 0u | ||||
|   | ||||
| @@ -338,10 +338,15 @@ $includes = @( | ||||
| 	$path_deps, | ||||
| 	$path_platform | ||||
| ) | ||||
|  | ||||
| # Microsoft | ||||
| $lib_gdi32  = 'Gdi32.lib' | ||||
| $lib_xinput = 'Xinput.lib' | ||||
| $lib_user32 = 'User32.lib' | ||||
|  | ||||
| # Github | ||||
| $lib_jsl = Join-Path $path_deps 'JoyShockLibrary/x64/JoyShockLibrary.lib' | ||||
|  | ||||
| $unit       = Join-Path $path_project 'handmade_win32.cpp' | ||||
| $executable = Join-Path $path_build   'handmade_win32.exe' | ||||
|  | ||||
| @@ -351,6 +356,9 @@ $linker_args = @( | ||||
| 	$lib_gdi32, | ||||
| 	# $lib_xinput, | ||||
| 	$lib_user32, | ||||
|  | ||||
| 	$lib_jsl, | ||||
|  | ||||
| 	$flag_link_win_subsystem_windows | ||||
| ) | ||||
|  | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,28 +1,65 @@ | ||||
| clear-host | ||||
| $path_root = & git rev-parse --show-toplevel | ||||
|  | ||||
| $path_data         = Join-Path $path_root         "data" | ||||
| $path_project      = Join-Path $path_root         "project" | ||||
| $path_deps         = Join-Path $path_project      "dependencies" | ||||
| $path_deps_windows = Join-Path $path_deps         "windows" | ||||
| $path_temp         = Join-Path $path_deps         "temp" | ||||
| $path_platform     = Join-Path $path_project      "platform" | ||||
|  | ||||
| # Define the URL of the zip file and the destination directory | ||||
| $url            = "https://github.com/Ed94/gencpp/releases/download/latest/gencpp_singleheader.zip" | ||||
| $destinationZip = Join-Path $path_temp "gencpp_singleheader.zip" | ||||
|  | ||||
| # Create directories if they don't exist | ||||
| if (-not (Test-Path $path_deps)) { | ||||
| # Clear out the current content first | ||||
| if (Test-Path $path_deps) { | ||||
| 	Remove-Item $path_deps -Recurse -Force | ||||
| 	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 | ||||
| Invoke-WebRequest -Uri $url -OutFile $destinationZip | ||||
| Expand-Archive    -Path $destinationZip                  -DestinationPath $path_temp | ||||
| Invoke-WebRequest -Uri  $url_gencpp                      -OutFile         $path_gencpp_zip | ||||
| Expand-Archive    -Path $path_gencpp_zip                 -DestinationPath $path_temp | ||||
| Move-Item         -Path (Join-Path $path_temp "gen.hpp") -Destination     $path_deps -Force | ||||
| #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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user