From e85005195702f0d6bf90362ac745d1f782662046 Mon Sep 17 00:00:00 2001 From: David Khachaturov Date: Mon, 5 Mar 2018 17:55:04 +0000 Subject: [PATCH] - Added Joycon Support - Further gyro changes - Updated hidapi --- BetterJoyForCemu/Joycon.cs | 90 ++++++++++++++++++++++++---------- BetterJoyForCemu/Program.cs | 44 +++++++++++++++-- BetterJoyForCemu/UpdServer.cs | 63 ++++++++++++------------ BetterJoyForCemu/hidapi.dll | Bin 15872 -> 19456 bytes 4 files changed, 136 insertions(+), 61 deletions(-) diff --git a/BetterJoyForCemu/Joycon.cs b/BetterJoyForCemu/Joycon.cs index 8c241b0..f838bcf 100644 --- a/BetterJoyForCemu/Joycon.cs +++ b/BetterJoyForCemu/Joycon.cs @@ -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; @@ -261,9 +264,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 }; @@ -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]; diff --git a/BetterJoyForCemu/Program.cs b/BetterJoyForCemu/Program.cs index 38daf15..ff38eb5 100644 --- a/BetterJoyForCemu/Program.cs +++ b/BetterJoyForCemu/Program.cs @@ -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); } diff --git a/BetterJoyForCemu/UpdServer.cs b/BetterJoyForCemu/UpdServer.cs index 0b362ac..e2db123 100644 --- a/BetterJoyForCemu/UpdServer.cs +++ b/BetterJoyForCemu/UpdServer.cs @@ -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); diff --git a/BetterJoyForCemu/hidapi.dll b/BetterJoyForCemu/hidapi.dll index bfb6c27f42e7b7eef540b20348a0e46018b495f0..28c267ae0aacea3420bfc3570ae991f89729be0a 100644 GIT binary patch literal 19456 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 C!;|7K>9fN_uu|H1@h?0yGFD2!dIv4 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