- Added Joycon Support

- Further gyro changes
- Updated hidapi
This commit is contained in:
David Khachaturov 2018-03-05 17:55:04 +00:00
parent 334b71d78e
commit e850051957
4 changed files with 136 additions and 61 deletions

View file

@ -10,10 +10,13 @@ using System.Threading.Tasks;
namespace BetterJoyForCemu {
public class Joycon {
float timing = 60.0f;
float timing = 120.0f;
bool isPro = false;
public bool isPro = false;
bool isUSB = false;
public Joycon other;
public bool send = true;
public enum DebugType : int {
NONE,
@ -210,7 +213,7 @@ namespace BetterJoyForCemu {
// For UdpServer
public int PadId = 0;
public int battery = 2;
public int battery = 4;
public int model = 2;
public int constate = 2;
public int connection = 3;
@ -262,9 +265,6 @@ namespace BetterJoyForCemu {
public int Attach(byte leds_ = 0x0) {
state = state_.ATTACHED;
// Make sure command is received
HIDapi.hid_set_nonblocking(handle, 0);
byte[] a = { 0x0 };
// Connect
@ -315,8 +315,6 @@ namespace BetterJoyForCemu {
DebugPrint("Done with init.", DebugType.COMMS);
HIDapi.hid_set_nonblocking(handle, 1);
return 0;
}
@ -349,10 +347,10 @@ namespace BetterJoyForCemu {
private byte ts_en;
private int ReceiveRaw() {
if (handle == IntPtr.Zero) return -2;
HIDapi.hid_set_nonblocking(handle, 0);
HIDapi.hid_set_nonblocking(handle, 1);
byte[] raw_buf = new byte[report_len];
int ret = HIDapi.hid_read(handle, raw_buf, new UIntPtr(report_len));
if (ret > 0) {
if (ret > 0 && Program.server != null) {
// Process packets as soon as they come
for (int n = 0; n < 3; n++) {
ExtractIMUValues(raw_buf, n);
@ -362,7 +360,7 @@ namespace BetterJoyForCemu {
Timestamp += (ulong)lag * 5000; // add lag once
ProcessButtonsAndStick(raw_buf);
}
Timestamp += (ulong)(2 - n) * 5000; // 5ms difference
Timestamp += 5000; // 5ms difference
packetCounter++;
Program.server.NewReportIncoming(this);
@ -382,19 +380,19 @@ namespace BetterJoyForCemu {
private void Poll() {
int attempts = 0;
while (!stop_polling & state > state_.NO_JOYCONS) {
SendRumble(rumble_obj.GetData());
//SendRumble(rumble_obj.GetData());
int a = ReceiveRaw();
//a = ReceiveRaw();
if (a > 0) {
state = state_.IMU_DATA_OK;
attempts = 0;
} else if (attempts > 1000) {
} else if (attempts > 10000) {
state = state_.DROPPED;
DebugPrint("Connection lost. Is the Joy-Con connected?", DebugType.ALL);
break;
} else {
DebugPrint("Pause 5ms", DebugType.THREADING);
Thread.Sleep((Int32)5);
Thread.Sleep((Int32)(!isPro ? 1 : 5));
}
++attempts;
}
@ -412,6 +410,9 @@ namespace BetterJoyForCemu {
}
}
}
public float[] otherStick = { 0, 0 };
private int ProcessButtonsAndStick(byte[] report_buf) {
if (report_buf[0] == 0x00) return -1;
@ -427,14 +428,27 @@ namespace BetterJoyForCemu {
stick_precal[0] = (UInt16)(stick_raw[0] | ((stick_raw[1] & 0xf) << 8));
stick_precal[1] = (UInt16)((stick_raw[1] >> 4) | (stick_raw[2] << 4));
stick = CenterSticks(stick_precal);
stick = CenterSticks(stick_precal, stick_cal, deadzone);
if (isPro) {
stick2_precal[0] = (UInt16)(stick2_raw[0] | ((stick2_raw[1] & 0xf) << 8));
stick2_precal[1] = (UInt16)((stick2_raw[1] >> 4) | (stick2_raw[2] << 4));
stick2 = CenterSticks(stick2_precal, true);
stick2 = CenterSticks(stick2_precal, stick2_cal, deadzone2);
}
// Read other Joycon's sticks
if (isLeft && other != null) {
stick2 = otherStick;
other.otherStick = stick;
}
if (!isLeft && other != null) {
Array.Copy(stick, stick2, 2);
stick = otherStick;
other.otherStick = stick2;
}
//
lock (buttons) {
lock (down_) {
for (int i = 0; i < buttons.Length; ++i) {
@ -465,6 +479,33 @@ namespace BetterJoyForCemu {
buttons[(int)Button.SHOULDER2_2] = (report_buf[3 + (!isLeft ? 2 : 0)] & 0x80) != 0;
}
if (isLeft && other != null) {
buttons[(int)Button.B] = other.buttons[(int)Button.DPAD_DOWN];
buttons[(int)Button.A] = other.buttons[(int)Button.DPAD_RIGHT];
buttons[(int)Button.X] = other.buttons[(int)Button.DPAD_UP];
buttons[(int)Button.Y] = other.buttons[(int)Button.DPAD_LEFT];
buttons[(int)Button.STICK2] = other.buttons[(int)Button.STICK];
buttons[(int)Button.SHOULDER2_1] = other.buttons[(int)Button.SHOULDER_1];
buttons[(int)Button.SHOULDER2_2] = other.buttons[(int)Button.SHOULDER_2];
buttons[(int)Button.HOME] = other.buttons[(int)Button.HOME];
buttons[(int)Button.PLUS] = other.buttons[(int)Button.PLUS];
}
if (!isLeft && other != null) {
buttons[(int)Button.B] = other.buttons[(int)Button.DPAD_DOWN];
buttons[(int)Button.A] = other.buttons[(int)Button.DPAD_RIGHT];
buttons[(int)Button.X] = other.buttons[(int)Button.DPAD_UP];
buttons[(int)Button.Y] = other.buttons[(int)Button.DPAD_LEFT];
buttons[(int)Button.STICK2] = other.buttons[(int)Button.STICK];
buttons[(int)Button.SHOULDER2_1] = other.buttons[(int)Button.SHOULDER_1];
buttons[(int)Button.SHOULDER2_2] = other.buttons[(int)Button.SHOULDER_2];
buttons[(int)Button.MINUS] = other.buttons[(int)Button.MINUS];
}
lock (buttons_up) {
lock (buttons_down) {
for (int i = 0; i < buttons.Length; ++i) {
@ -500,13 +541,13 @@ namespace BetterJoyForCemu {
break;
case 1:
acc_g.Y = (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
gyr_g.Y = -(gyr_r[i] - gyr_neutral[i] * 0.5f) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
acc_g.Y = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
gyr_g.Y = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i] * 0.5f) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
break;
case 2:
acc_g.Z = (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
gyr_g.Z = -(gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
acc_g.Z = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
gyr_g.Z = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i] * 0.5f) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
break;
}
@ -526,16 +567,13 @@ namespace BetterJoyForCemu {
first_imu_packet = true;
}
private float[] CenterSticks(UInt16[] vals, bool special = false) {
ushort[] t = stick_cal;
if (special)
t = stick2_cal;
private float[] CenterSticks(UInt16[] vals, ushort[] cal, ushort dz) {
ushort[] t = cal;
float[] s = { 0, 0 };
for (uint i = 0; i < 2; ++i) {
float diff = vals[i] - t[2 + i];
if (Math.Abs(diff) < deadzone) vals[i] = 0;
if (Math.Abs(diff) < dz) vals[i] = 0;
else if (diff > 0) // if axis is above center
{
s[i] = diff / t[i];

View file

@ -18,9 +18,6 @@ namespace BetterJoyForCemu {
public bool EnableIMU = true;
public bool EnableLocalize = false;
// Different operating systems either do or don't like the trailing zero
private const ushort vendor_id = 0x57e;
private const ushort vendor_id_ = 0x057e;
private const ushort product_l = 0x2006;
@ -53,7 +50,6 @@ namespace BetterJoyForCemu {
}
}
string path = "";
hid_device_info enumerate;
while (ptr != IntPtr.Zero) {
enumerate = (hid_device_info)Marshal.PtrToStructure(ptr, typeof(hid_device_info));
@ -73,7 +69,12 @@ namespace BetterJoyForCemu {
}
IntPtr handle = HIDapi.hid_open_path(enumerate.path);
HIDapi.hid_set_nonblocking(handle, 1);
try {
HIDapi.hid_set_nonblocking(handle, 1);
} catch (Exception e) {
Console.WriteLine("Unable to open path to device - are you using the correct (64 vs 32-bit) version for your PC?");
break;
}
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
@ -87,6 +88,39 @@ namespace BetterJoyForCemu {
ptr = enumerate.next;
}
int found = 0;
foreach (Joycon v in j) {
if (v.isLeft && !v.isPro)
found++;
if (!v.isLeft && !v.isPro)
found++;
}
if (found == 2) {
Console.WriteLine("Both joycons successfully found.");
Joycon temp = null;
foreach (Joycon v in j) {
if (v.isLeft && !v.isPro) {
if (temp == null)
temp = v;
else {
temp.other = v;
v.other = temp;
}
}
if (!v.isLeft && !v.isPro) {
if (temp == null)
temp = v;
else {
temp.other = v;
v.other = temp;
}
}
} // Join up the two joycons
} else if (found != 0)
Console.WriteLine("Only one joycon found. Please connect both and then restart the program.");
HIDapi.hid_free_enumeration(top_ptr);
}

View file

@ -292,7 +292,8 @@ namespace BetterJoyForCemu {
udpSock.Close();
udpSock = null;
throw ex;
Console.WriteLine("Could not start server. Make sure that only one instance of the program is running at a time and no other CemuHook applications are running.");
return;
}
byte[] randomBuf = new byte[4];
@ -315,27 +316,29 @@ namespace BetterJoyForCemu {
private bool ReportToBuffer(Joycon hidReport, byte[] outputData, ref int outIdx) {
outputData[outIdx] = 0;
if (hidReport.GetButton(Joycon.Button.DPAD_LEFT)) outputData[outIdx] |= 0x80;
if (hidReport.GetButton(Joycon.Button.DPAD_DOWN)) outputData[outIdx] |= 0x40;
if (hidReport.GetButton(Joycon.Button.DPAD_RIGHT)) outputData[outIdx] |= 0x20;
if (hidReport.GetButton(Joycon.Button.DPAD_UP)) outputData[outIdx] |= 0x10;
bool isLeft = hidReport.isLeft;
if (hidReport.GetButton(Joycon.Button.PLUS)) outputData[outIdx] |= 0x08;
if (hidReport.GetButton(Joycon.Button.STICK2)) outputData[outIdx] |= 0x04;
if (hidReport.GetButton(Joycon.Button.STICK)) outputData[outIdx] |= 0x02;
if (hidReport.GetButton(Joycon.Button.MINUS)) outputData[outIdx] |= 0x01;
if (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_LEFT : Joycon.Button.A)) outputData[outIdx] |= 0x80;
if (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_DOWN : Joycon.Button.B)) outputData[outIdx] |= 0x40;
if (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_RIGHT : Joycon.Button.Y)) outputData[outIdx] |= 0x20;
if (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_UP : Joycon.Button.X)) outputData[outIdx] |= 0x10;
if (hidReport.GetButton(Joycon.Button.PLUS)) outputData[outIdx] |= 0x08;
if (hidReport.GetButton(isLeft ? Joycon.Button.STICK2 : Joycon.Button.STICK)) outputData[outIdx] |= 0x04;
if (hidReport.GetButton(isLeft ? Joycon.Button.STICK : Joycon.Button.STICK2)) outputData[outIdx] |= 0x02;
if (hidReport.GetButton(Joycon.Button.MINUS)) outputData[outIdx] |= 0x01;
outputData[++outIdx] = 0;
if (hidReport.GetButton(Joycon.Button.Y)) outputData[outIdx] |= 0x80;
if (hidReport.GetButton(Joycon.Button.B)) outputData[outIdx] |= 0x40;
if (hidReport.GetButton(Joycon.Button.A)) outputData[outIdx] |= 0x20;
if (hidReport.GetButton(Joycon.Button.X)) outputData[outIdx] |= 0x10;
if (hidReport.GetButton(isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT)) outputData[outIdx] |= 0x80;
if (hidReport.GetButton(isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN)) outputData[outIdx] |= 0x40;
if (hidReport.GetButton(isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT)) outputData[outIdx] |= 0x20;
if (hidReport.GetButton(isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP)) outputData[outIdx] |= 0x10;
if (hidReport.GetButton(Joycon.Button.SHOULDER2_1)) outputData[outIdx] |= 0x08;
if (hidReport.GetButton(Joycon.Button.SHOULDER_1)) outputData[outIdx] |= 0x04;
if (hidReport.GetButton(Joycon.Button.SHOULDER2_2)) outputData[outIdx] |= 0x02;
if (hidReport.GetButton(Joycon.Button.SHOULDER_2)) outputData[outIdx] |= 0x01;
if (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER2_1 : Joycon.Button.SHOULDER_1)) outputData[outIdx] |= 0x08;
if (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER_1 : Joycon.Button.SHOULDER2_1)) outputData[outIdx] |= 0x04;
if (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER2_2 : Joycon.Button.SHOULDER_2)) outputData[outIdx] |= 0x02;
if (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER_2 : Joycon.Button.SHOULDER2_2)) outputData[outIdx] |= 0x01;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.HOME)) ? (byte)1 : (byte)0;
outputData[++outIdx] = 0; // no touch pad
@ -349,21 +352,21 @@ namespace BetterJoyForCemu {
outputData[++outIdx] = (byte)(Math.Max(0, Math.Min(255, 127 + rightStick[1] * 127)));
//we don't have analog buttons so just use the Button enums (which give either 0 or 0xFF)
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.DPAD_LEFT)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.DPAD_DOWN)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.DPAD_RIGHT)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.DPAD_UP)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_LEFT : Joycon.Button.A)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_DOWN : Joycon.Button.B)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_RIGHT : Joycon.Button.Y)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_UP : Joycon.Button.X)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.Y)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.B)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.A)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.X)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.SHOULDER2_1)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.SHOULDER_1)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER2_1 : Joycon.Button.SHOULDER_1)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER_1 : Joycon.Button.SHOULDER2_1)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.SHOULDER2_2)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.SHOULDER_2)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER2_2 : Joycon.Button.SHOULDER_2)) ? (byte)0xFF : (byte)0;
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.SHOULDER_2 : Joycon.Button.SHOULDER2_2)) ? (byte)0xFF : (byte)0;
outIdx++;
@ -384,7 +387,7 @@ namespace BetterJoyForCemu {
//Array.Copy(BitConverter.GetBytes((float)0), 0, outputData, outIdx, 4);
outIdx += 4;
Array.Copy(BitConverter.GetBytes(-accel.Z), 0, outputData, outIdx, 4);
//Array.Copy(BitConverter.GetBytes((float)-1), 0, outputData, outIdx, 4);
//Array.Copy(BitConverter.GetBytes((float)0), 0, outputData, outIdx, 4);
outIdx += 4;
Array.Copy(BitConverter.GetBytes(accel.X), 0, outputData, outIdx, 4);
//Array.Copy(BitConverter.GetBytes((float)0), 0, outputData, outIdx, 4);

Binary file not shown.