Implemented Progressive Scan. (can leave program running and (dis)connect controllers whenever)
Fixed controllers timing out randomly.
This commit is contained in:
parent
82fbf36796
commit
64946ed444
5 changed files with 123 additions and 75 deletions
|
@ -19,7 +19,7 @@
|
|||
|
||||
<!--The controller's HD rumble settings for the low/high frequency rumble. Change to change the pitch of the rumble.-->
|
||||
<!--Don't set above ~1200. Default: 160 and 320 -->
|
||||
<add key="LowFreqRumble" value="80" />
|
||||
<add key="LowFreqRumble" value="160" />
|
||||
<add key="HighFreqRumble" value="160" />
|
||||
|
||||
<!--Rumble Setting. Turns rumble on or off.-->
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
public static bool Value(string key) {
|
||||
if (!variables.TryGetValue(key, out bool temp)) {
|
||||
if (!variables.ContainsKey("ProgressiveScan")) {
|
||||
return false;
|
||||
}
|
||||
return variables[key];
|
||||
|
|
|
@ -14,8 +14,9 @@ using Nefarius.ViGEm.Client.Targets.Xbox360;
|
|||
|
||||
namespace BetterJoyForCemu {
|
||||
public class Joycon {
|
||||
float timing = 60.0f;
|
||||
float timing = 120.0f;
|
||||
|
||||
public string path = String.Empty;
|
||||
public bool isPro = false;
|
||||
bool isUSB = false;
|
||||
public Joycon other;
|
||||
|
@ -73,8 +74,7 @@ namespace BetterJoyForCemu {
|
|||
private float[] stick = { 0, 0 };
|
||||
private float[] stick2 = { 0, 0 };
|
||||
|
||||
private
|
||||
IntPtr handle;
|
||||
private IntPtr handle;
|
||||
|
||||
byte[] default_buf = { 0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40 };
|
||||
|
||||
|
@ -219,7 +219,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public byte LED = 0x0;
|
||||
|
||||
public Joycon(IntPtr handle_, bool imu, bool localize, float alpha, bool left, int id = 0, bool isPro=false, bool usb = false) {
|
||||
public Joycon(IntPtr handle_, bool imu, bool localize, float alpha, bool left, string path, int id = 0, bool isPro=false, bool usb = false) {
|
||||
handle = handle_;
|
||||
imu_enabled = imu;
|
||||
do_localize = localize;
|
||||
|
@ -231,6 +231,8 @@ namespace BetterJoyForCemu {
|
|||
this.isPro = isPro;
|
||||
isUSB = usb;
|
||||
|
||||
this.path = path;
|
||||
|
||||
connection = isUSB ? 0x01 : 0x02;
|
||||
|
||||
if (showAsXInput) {
|
||||
|
@ -295,7 +297,7 @@ namespace BetterJoyForCemu {
|
|||
Subcommand(0x03, new byte[] { 0x3f }, 1, false);
|
||||
|
||||
a = Enumerable.Repeat((byte)0, 64).ToArray();
|
||||
form.console.Text += "Using USB.\r\n";
|
||||
form.AppendTextBox("Using USB.\r\n");
|
||||
|
||||
a[0] = 0x80;
|
||||
a[1] = 0x01;
|
||||
|
@ -354,6 +356,10 @@ namespace BetterJoyForCemu {
|
|||
public void Detach() {
|
||||
stop_polling = true;
|
||||
|
||||
if (xin != null) {
|
||||
xin.Disconnect(); xin.Dispose();
|
||||
}
|
||||
|
||||
if (state > state_.NO_JOYCONS) {
|
||||
Subcommand(0x40, new byte[] { 0x0 }, 1);
|
||||
//Subcommand(0x48, new byte[] { 0x0 }, 1); // Would turn off rumble?
|
||||
|
@ -375,11 +381,8 @@ namespace BetterJoyForCemu {
|
|||
if (handle == IntPtr.Zero) return -2;
|
||||
HIDapi.hid_set_nonblocking(handle, 0);
|
||||
byte[] raw_buf = new byte[report_len];
|
||||
int ret = HIDapi.hid_read(handle, raw_buf, new UIntPtr(report_len));
|
||||
if (ret > 0) {
|
||||
if (!isPro)
|
||||
SendRumble(rumble_obj.GetData()); // make rumble better when on bluetooth
|
||||
|
||||
int ret = 0;
|
||||
while ((ret = HIDapi.hid_read(handle, raw_buf, new UIntPtr(report_len))) > 0) {
|
||||
// Process packets as soon as they come
|
||||
for (int n = 0; n < 3; n++) {
|
||||
ExtractIMUValues(raw_buf, n);
|
||||
|
@ -400,7 +403,7 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
if (ts_en == raw_buf[1]) {
|
||||
form.console.Text += "Duplicate timestamp enqueued.\r\n";
|
||||
form.AppendTextBox("Duplicate timestamp enqueued.\r\n");
|
||||
DebugPrint(string.Format("Duplicate timestamp enqueued. TS: {0:X2}", ts_en), DebugType.THREADING);
|
||||
}
|
||||
ts_en = raw_buf[1];
|
||||
|
@ -413,17 +416,17 @@ namespace BetterJoyForCemu {
|
|||
private void Poll() {
|
||||
int attempts = 0;
|
||||
while (!stop_polling & state > state_.NO_JOYCONS) {
|
||||
if (isPro)
|
||||
SendRumble(rumble_obj.GetData()); // Needed for USB to not time out
|
||||
SendRumble(rumble_obj.GetData()); // Needed for EVERYTHING to not time out. Never remove pls
|
||||
int a = ReceiveRaw();
|
||||
|
||||
if (a > 0) {
|
||||
state = state_.IMU_DATA_OK;
|
||||
state = state_.IMU_DATA_OK;
|
||||
attempts = 0;
|
||||
} else if (attempts > 1000) {
|
||||
} else if (attempts > 240) {
|
||||
state = state_.DROPPED;
|
||||
//form.console.Text += "Dropped\r\n";
|
||||
DebugPrint("Connection lost. Is the Joy-Con connected?", DebugType.ALL);
|
||||
form.AppendTextBox("Dropped.\r\n");
|
||||
|
||||
DebugPrint("Connection lost. Is the Joy-Con connected?", DebugType.ALL);
|
||||
break;
|
||||
} else {
|
||||
DebugPrint("Pause 5ms", DebugType.THREADING);
|
||||
|
@ -431,7 +434,6 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
++attempts;
|
||||
}
|
||||
DebugPrint("End poll loop.", DebugType.THREADING);
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
|
@ -449,7 +451,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public float[] otherStick = { 0, 0 };
|
||||
|
||||
bool swapButtons = Boolean.Parse(ConfigurationSettings.AppSettings["SwapButtons"]);
|
||||
bool swapButtons = Boolean.Parse(ConfigurationManager.AppSettings["SwapButtons"]);
|
||||
private int ProcessButtonsAndStick(byte[] report_buf) {
|
||||
if (report_buf[0] == 0x00) return -1;
|
||||
|
||||
|
@ -655,8 +657,10 @@ namespace BetterJoyForCemu {
|
|||
PollThreadObj.IsBackground = true;
|
||||
PollThreadObj.Start();
|
||||
|
||||
form.console.Text += "Starting poll thread.\r\n";
|
||||
}
|
||||
form.AppendTextBox("Starting poll thread.\r\n");
|
||||
} else {
|
||||
form.AppendTextBox("Poll cannot start.\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void Recenter() {
|
||||
|
@ -721,13 +725,13 @@ namespace BetterJoyForCemu {
|
|||
bool found = false;
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (buf_[i] != 0xff) {
|
||||
form.console.Text += "Using user stick calibration data.\r\n";
|
||||
form.AppendTextBox("Using user stick calibration data.\r\n");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
form.console.Text += "Using factory stick calibration data.\r\n";
|
||||
form.AppendTextBox("Using factory stick calibration data.\r\n");
|
||||
buf_ = ReadSPI(0x60, (isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
}
|
||||
stick_cal[isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
|
@ -744,13 +748,13 @@ namespace BetterJoyForCemu {
|
|||
found = false;
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (buf_[i] != 0xff) {
|
||||
form.console.Text += "Using user stick calibration data.\r\n";
|
||||
form.AppendTextBox("Using user stick calibration data.\r\n");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
form.console.Text += "Using factory stick calibration data.\r\n";
|
||||
form.AppendTextBox("Using factory stick calibration data.\r\n");
|
||||
buf_ = ReadSPI(0x60, (!isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
}
|
||||
stick2_cal[!isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
|
|
|
@ -63,5 +63,13 @@ namespace BetterJoyForCemu {
|
|||
private void passiveScanBox_CheckedChanged(object sender, EventArgs e) {
|
||||
Config.Save("ProgressiveScan", passiveScanBox.Checked);
|
||||
}
|
||||
|
||||
public void AppendTextBox(string value) { // https://stackoverflow.com/questions/519233/writing-to-a-textbox-from-another-thread
|
||||
if (InvokeRequired) {
|
||||
this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
|
||||
return;
|
||||
}
|
||||
console.AppendText(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public MainForm form;
|
||||
|
||||
bool useHIDG = Boolean.Parse(ConfigurationSettings.AppSettings["UseHIDG"]);
|
||||
System.Timers.Timer controllerCheck;
|
||||
|
||||
bool useHIDG = Boolean.Parse(ConfigurationManager.AppSettings["UseHIDG"]);
|
||||
|
||||
public static JoyconManager Instance {
|
||||
get { return instance; }
|
||||
|
@ -47,39 +49,70 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public void Awake() {
|
||||
instance = this;
|
||||
int i = 0;
|
||||
|
||||
j = new List<Joycon>();
|
||||
bool isLeft = false;
|
||||
HIDapi.hid_init();
|
||||
}
|
||||
|
||||
IntPtr ptr = HIDapi.hid_enumerate(vendor_id, 0x0);
|
||||
IntPtr top_ptr = ptr;
|
||||
public void Start() {
|
||||
controllerCheck = new System.Timers.Timer(2000); // check every 2 seconds
|
||||
controllerCheck.Elapsed += CheckForNewControllersTime;
|
||||
controllerCheck.Start();
|
||||
}
|
||||
|
||||
if (ptr == IntPtr.Zero) {
|
||||
ptr = HIDapi.hid_enumerate(vendor_id_, 0x0);
|
||||
if (ptr == IntPtr.Zero) {
|
||||
HIDapi.hid_free_enumeration(ptr);
|
||||
form.console.Text += "No Joy-Cons found!\r\n";
|
||||
bool ControllerAlreadyAdded(string path) {
|
||||
foreach (Joycon v in j)
|
||||
if (v.path == path)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void CleanUp() { // removes dropped controllers from list
|
||||
List<Joycon> rem = new List<Joycon>();
|
||||
for (int i = 0; i < j.Count; i++) {
|
||||
Joycon v = j[i];
|
||||
if (v.state == Joycon.state_.DROPPED) {
|
||||
v.Detach(); rem.Add(v);
|
||||
form.AppendTextBox("Removed dropped controller to list. Can be reconnected.\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
hid_device_info enumerate;
|
||||
foreach (Joycon v in rem)
|
||||
j.Remove(v);
|
||||
}
|
||||
|
||||
void CheckForNewControllersTime(Object source, ElapsedEventArgs e) {
|
||||
if (Config.Value("ProgressiveScan")) {
|
||||
CheckForNewControllers();
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckForNewControllers() {
|
||||
CleanUp();
|
||||
|
||||
// move all code for initializing devices here and well as the initial code from Start()
|
||||
bool isLeft = false;
|
||||
IntPtr ptr = HIDapi.hid_enumerate(vendor_id, 0x0);
|
||||
IntPtr top_ptr = ptr;
|
||||
|
||||
bool foundNew = false;
|
||||
|
||||
hid_device_info enumerate; // Add device to list
|
||||
while (ptr != IntPtr.Zero) {
|
||||
enumerate = (hid_device_info)Marshal.PtrToStructure(ptr, typeof(hid_device_info));
|
||||
|
||||
if (enumerate.product_id == product_l || enumerate.product_id == product_r || enumerate.product_id == product_pro) {
|
||||
if (enumerate.product_id == product_l) {
|
||||
isLeft = true;
|
||||
form.console.Text += "Left Joy-Con connected.\r\n";
|
||||
} else if (enumerate.product_id == product_r) {
|
||||
isLeft = false;
|
||||
form.console.Text += "Right Joy-Con connected.\r\n";
|
||||
} else if (enumerate.product_id == product_pro) {
|
||||
isLeft = true;
|
||||
form.console.Text += "Pro controller connected.\r\n";
|
||||
} else {
|
||||
form.console.Text += "Non Joy-Con input device skipped.\r\n";
|
||||
if ((enumerate.product_id == product_l || enumerate.product_id == product_r || enumerate.product_id == product_pro) && !ControllerAlreadyAdded(enumerate.path)) {
|
||||
switch (enumerate.product_id) {
|
||||
case product_l:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("Left Joy-Con connected.\r\n"); break;
|
||||
case product_r:
|
||||
isLeft = false;
|
||||
form.AppendTextBox("Right Joy-Con connected.\r\n"); break;
|
||||
case product_pro:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("Pro controller connected.\r\n"); break;
|
||||
default:
|
||||
form.AppendTextBox("Non Joy-Con Nintendo input device skipped.\r\n"); break;
|
||||
}
|
||||
|
||||
// Add controller to block-list for HidGuardian
|
||||
|
@ -98,21 +131,26 @@ namespace BetterJoyForCemu {
|
|||
try {
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
|
||||
} catch (Exception e) {
|
||||
form.console.Text += "Unable to add controller to block-list.\r\n";
|
||||
} catch {
|
||||
form.AppendTextBox("Unable to add controller to block-list.\r\n");
|
||||
}
|
||||
} else { // Remove affected devices from list
|
||||
try {
|
||||
HttpWebResponse r1 = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/affected/purge/").GetResponse();
|
||||
} catch { }
|
||||
}
|
||||
// -------------------- //
|
||||
|
||||
IntPtr handle = HIDapi.hid_open_path(enumerate.path);
|
||||
try {
|
||||
HIDapi.hid_set_nonblocking(handle, 1);
|
||||
} catch (Exception e) {
|
||||
form.console.Text += "Unable to open path to device - are you using the correct (64 vs 32-bit) version for your PC?\r\n";
|
||||
} catch {
|
||||
form.AppendTextBox("Unable to open path to device - are you using the correct (64 vs 32-bit) version for your PC?\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, enumerate.path, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
|
||||
foundNew = true;
|
||||
|
||||
j.Last().form = form;
|
||||
|
||||
|
@ -120,15 +158,14 @@ namespace BetterJoyForCemu {
|
|||
for (int n = 0; n < 6; n++)
|
||||
mac[n] = byte.Parse(enumerate.serial_number.Substring(n * 2, 2), System.Globalization.NumberStyles.HexNumber);
|
||||
j[j.Count - 1].PadMacAddress = new PhysicalAddress(mac);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
ptr = enumerate.next;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
int minPadID = 10;
|
||||
foreach (Joycon v in j) {
|
||||
foreach (Joycon v in j) { // current system is designed for a maximum of two joycons connected to the PC
|
||||
if (!v.isPro) {
|
||||
found++;
|
||||
minPadID = Math.Min(v.PadId, minPadID);
|
||||
|
@ -138,12 +175,12 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
if (found == 2) {
|
||||
form.console.Text += "Both joycons successfully found.\r\n";
|
||||
form.AppendTextBox("Both joycons successfully found.\r\n");
|
||||
Joycon temp = null;
|
||||
foreach (Joycon v in j) {
|
||||
if (!v.isPro) {
|
||||
v.LED = (byte)(0x1 << minPadID);
|
||||
|
||||
|
||||
if (temp == null)
|
||||
temp = v;
|
||||
else {
|
||||
|
@ -155,23 +192,18 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
} // Join up the two joycons
|
||||
} else if (found != 0)
|
||||
form.console.Text += "Only one joycon found. Using in single joycone mode.\r\n";
|
||||
}
|
||||
|
||||
HIDapi.hid_free_enumeration(top_ptr);
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
for (int i = 0; i < j.Count; ++i) {
|
||||
Joycon jc = j[i];
|
||||
foreach (Joycon jc in j) { // Connect device straight away
|
||||
if (jc.state == Joycon.state_.NOT_ATTACHED) {
|
||||
if (jc.xin != null)
|
||||
jc.xin.Connect();
|
||||
|
||||
if (jc.xin != null)
|
||||
jc.xin.Connect();
|
||||
|
||||
//byte LEDs = 0x0;
|
||||
// LEDs |= (byte)(0x1 << jc.PadId);
|
||||
jc.Attach(leds_: jc.LED);
|
||||
jc.Begin();
|
||||
jc.Attach(leds_: jc.LED);
|
||||
jc.Begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,6 +221,9 @@ namespace BetterJoyForCemu {
|
|||
v.xin.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
controllerCheck.Stop();
|
||||
HIDapi.hid_exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +269,7 @@ namespace BetterJoyForCemu {
|
|||
class Program {
|
||||
public static PhysicalAddress btMAC = new PhysicalAddress(new byte[] { 0, 0, 0, 0, 0, 0 });
|
||||
public static UdpServer server;
|
||||
static double pollsPerSecond = 60.0;
|
||||
static double pollsPerSecond = 120.0;
|
||||
|
||||
public static ViGEmClient emClient;
|
||||
|
||||
|
@ -299,6 +334,7 @@ namespace BetterJoyForCemu {
|
|||
mgr = new JoyconManager();
|
||||
mgr.form = form;
|
||||
mgr.Awake();
|
||||
mgr.CheckForNewControllers();
|
||||
mgr.Start();
|
||||
|
||||
server = new UdpServer(mgr.j);
|
||||
|
|
Loading…
Add table
Reference in a new issue