Added single joycon mode. (v5 progress)

This commit is contained in:
David Khachaturov 2018-07-16 22:03:51 +03:00
parent e8ba346245
commit 00e51bc4d1
5 changed files with 447 additions and 362 deletions

View file

@ -14,8 +14,8 @@
<add key="Port" value="26760" />
<!--Rumble motor period in millisec. Lower means more granular vibration, higher is more stable.-->
<!--The response of rumble does not only depend on this setting and it's always high. Default: 100 -->
<add key="RumblePeriod" value="100" />
<!--The response of rumble does not only depend on this setting and it's always high. Default: 200 -->
<add key="RumblePeriod" value="200" />
<!--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 -->

View file

@ -14,7 +14,7 @@ using Nefarius.ViGEm.Client.Targets.Xbox360;
namespace BetterJoyForCemu {
public class Joycon {
float timing = 120.0f;
float timing = 60.0f;
public bool isPro = false;
bool isUSB = false;
@ -111,13 +111,14 @@ namespace BetterJoyForCemu {
private const uint report_len = 49;
private struct Rumble {
private float h_f, amp, l_f;
public float t;
private float h_f, l_f;
public float t, amp, fullamp;
public bool timed_rumble;
public void set_vals(float low_freq, float high_freq, float amplitude, int time = 0) {
h_f = high_freq;
amp = amplitude;
fullamp = amplitude;
l_f = low_freq;
timed_rumble = false;
t = 0;
@ -129,6 +130,7 @@ namespace BetterJoyForCemu {
public Rumble(float low_freq, float high_freq, float amplitude, int time = 0) {
h_f = high_freq;
amp = amplitude;
fullamp = amplitude;
l_f = low_freq;
timed_rumble = false;
t = 0;
@ -201,8 +203,8 @@ namespace BetterJoyForCemu {
public PhysicalAddress PadMacAddress = new PhysicalAddress(new byte[] { 01, 02, 03, 04, 05, 06 });
public ulong Timestamp = 0;
public int packetCounter = 0;
// For XInput
public Xbox360Controller xin;
// For XInput
public Xbox360Controller xin = new Xbox360Controller(Program.emClient);
Xbox360Report report;
int rumblePeriod = Int32.Parse(ConfigurationSettings.AppSettings["RumblePeriod"]);
@ -213,6 +215,8 @@ namespace BetterJoyForCemu {
public MainForm form;
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) {
handle = handle_;
imu_enabled = imu;
@ -227,12 +231,13 @@ namespace BetterJoyForCemu {
connection = isUSB ? 0x01 : 0x02;
if (isLeft || isPro) {
xin = new Xbox360Controller(Program.emClient);
//if (isLeft || isPro) {
//xin = new Xbox360Controller(Program.emClient);
//xin.Connect();
if (toRumble)
xin.FeedbackReceived += ReceiveRumble;
report = new Xbox360Report();
}
//}
}
public void ReceiveRumble(object sender, Nefarius.ViGEm.Client.Targets.Xbox360.Xbox360FeedbackReceivedEventArgs e) {
@ -281,9 +286,15 @@ namespace BetterJoyForCemu {
if (!isUSB) {
// Input report mode
Subcommand(0x03, new byte[] { 0x30 }, 1, false);
a[0] = 0x1;
dump_calibration_data();
} else {
a = Enumerable.Repeat((byte)0xFF, 25).ToArray();
a[0] = 0x18;
a[1] = 0x01;
Subcommand(0x38, a, 25, false);
} else {
Subcommand(0x03, new byte[] { 0x3f }, 1, false);
a = Enumerable.Repeat((byte)0, 64).ToArray();
@ -330,6 +341,10 @@ namespace BetterJoyForCemu {
return 0;
}
public void SetLED(byte leds_ = 0x0) {
Subcommand(0x30, new byte[] { leds_ }, 1);
}
public void SetFilterCoeff(float a) {
filterweight = a;
}
@ -339,7 +354,7 @@ namespace BetterJoyForCemu {
if (state > state_.NO_JOYCONS) {
Subcommand(0x40, new byte[] { 0x0 }, 1);
Subcommand(0x48, new byte[] { 0x0 }, 1);
//Subcommand(0x48, new byte[] { 0x0 }, 1); // Would turn off rumble?
if (isUSB) {
byte[] a = Enumerable.Repeat((byte)0, 64).ToArray();
@ -360,8 +375,9 @@ namespace BetterJoyForCemu {
byte[] raw_buf = new byte[report_len];
int ret = HIDapi.hid_read(handle, raw_buf, new UIntPtr(report_len));
if (ret > 0) {
// Process packets as soon as they come
for (int n = 0; n < 3; n++) {
SendRumble(rumble_obj.GetData()); // Needed for USB to not time out
// Process packets as soon as they come
for (int n = 0; n < 3; n++) {
ExtractIMUValues(raw_buf, n);
byte lag = (byte) Math.Max(0, raw_buf[1] - ts_en - 3);
@ -393,9 +409,8 @@ namespace BetterJoyForCemu {
private void Poll() {
int attempts = 0;
while (!stop_polling & state > state_.NO_JOYCONS) {
SendRumble(rumble_obj.GetData()); // Needed for USB to not time out
int a = ReceiveRaw();
//a = ReceiveRaw();
int a = ReceiveRaw();
if (a > 0) {
state = state_.IMU_DATA_OK;
attempts = 0;
@ -414,12 +429,13 @@ namespace BetterJoyForCemu {
}
public void Update() {
if (state > state_.NO_JOYCONS) {
if (state > state_.NO_JOYCONS) {
if (rumble_obj.timed_rumble) {
if (rumble_obj.t < 0) {
rumble_obj.set_vals(160, 320, 0, 0);
rumble_obj.set_vals(lowFreq, highFreq, 0, 0);
} else {
rumble_obj.t -= (1 / timing);
//rumble_obj.amp = (float) Math.Sin(((timing - rumble_obj.t * 1000f) / timing) * Math.PI) * rumble_obj.fullamp;
}
}
}
@ -443,6 +459,7 @@ 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_cal, deadzone);
if (isPro) {
@ -475,6 +492,7 @@ namespace BetterJoyForCemu {
buttons[(int)Button.DPAD_UP] = (report_buf[3 + (isLeft ? 2 : 0)] & (isLeft ? 0x02 : 0x02)) != 0;
buttons[(int)Button.DPAD_LEFT] = (report_buf[3 + (isLeft ? 2 : 0)] & (isLeft ? 0x08 : 0x01)) != 0;
buttons[(int)Button.HOME] = ((report_buf[4] & 0x10) != 0);
buttons[(int)Button.CAPTURE] = ((report_buf[4] & 0x20) != 0);
buttons[(int)Button.MINUS] = ((report_buf[4] & 0x01) != 0);
buttons[(int)Button.PLUS] = ((report_buf[4] & 0x02) != 0);
buttons[(int)Button.STICK] = ((report_buf[4] & (isLeft ? 0x08 : 0x04)) != 0);
@ -530,22 +548,36 @@ namespace BetterJoyForCemu {
buttons[(int)Button.MINUS] = other.buttons[(int)Button.MINUS];
}
if (!isPro && other != null && xin != null) {
report.SetButtonState(!swapButtons ? Xbox360Buttons.A : Xbox360Buttons.B, buttons[(int)(isLeft ? Button.B : Button.DPAD_DOWN)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.B : Xbox360Buttons.A, buttons[(int)(isLeft ? Button.A : Button.DPAD_RIGHT)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.Y : Xbox360Buttons.X, buttons[(int)(isLeft ? Button.X : Button.DPAD_UP)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.X : Xbox360Buttons.Y, buttons[(int)(isLeft ? Button.Y : Button.DPAD_LEFT)]);
report.SetButtonState(Xbox360Buttons.Up, buttons[(int)(isLeft ? Button.DPAD_UP : Button.X)]);
report.SetButtonState(Xbox360Buttons.Down, buttons[(int)(isLeft ? Button.DPAD_DOWN : Button.B)]);
report.SetButtonState(Xbox360Buttons.Left, buttons[(int)(isLeft ? Button.DPAD_LEFT : Button.Y)]);
report.SetButtonState(Xbox360Buttons.Right, buttons[(int)(isLeft ? Button.DPAD_RIGHT : Button.A)]);
report.SetButtonState(Xbox360Buttons.Back, buttons[(int)Button.MINUS]);
report.SetButtonState(Xbox360Buttons.Start, buttons[(int)Button.PLUS]);
report.SetButtonState(Xbox360Buttons.Guide, buttons[(int)Button.HOME]);
report.SetButtonState(Xbox360Buttons.LeftShoulder, buttons[(int)(isLeft ? Button.SHOULDER_1 : Button.SHOULDER2_1)]);
report.SetButtonState(Xbox360Buttons.RightShoulder, buttons[(int)(isLeft ? Button.SHOULDER2_1 : Button.SHOULDER_1)]);
report.SetButtonState(Xbox360Buttons.LeftThumb, buttons[(int)(isLeft ? Button.STICK : Button.STICK2)]);
report.SetButtonState(Xbox360Buttons.RightThumb, buttons[(int)(isLeft ? Button.STICK2 : Button.STICK)]);
if (!isPro && xin != null) {
if (other != null) {
report.SetButtonState(!swapButtons ? Xbox360Buttons.A : Xbox360Buttons.B, buttons[(int)(isLeft ? Button.B : Button.DPAD_DOWN)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.B : Xbox360Buttons.A, buttons[(int)(isLeft ? Button.A : Button.DPAD_RIGHT)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.Y : Xbox360Buttons.X, buttons[(int)(isLeft ? Button.X : Button.DPAD_UP)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.X : Xbox360Buttons.Y, buttons[(int)(isLeft ? Button.Y : Button.DPAD_LEFT)]);
report.SetButtonState(Xbox360Buttons.Up, buttons[(int)(isLeft ? Button.DPAD_UP : Button.X)]);
report.SetButtonState(Xbox360Buttons.Down, buttons[(int)(isLeft ? Button.DPAD_DOWN : Button.B)]);
report.SetButtonState(Xbox360Buttons.Left, buttons[(int)(isLeft ? Button.DPAD_LEFT : Button.Y)]);
report.SetButtonState(Xbox360Buttons.Right, buttons[(int)(isLeft ? Button.DPAD_RIGHT : Button.A)]);
report.SetButtonState(Xbox360Buttons.Back, buttons[(int)Button.MINUS]);
report.SetButtonState(Xbox360Buttons.Start, buttons[(int)Button.PLUS]);
report.SetButtonState(Xbox360Buttons.Guide, buttons[(int)Button.HOME]);
report.SetButtonState(Xbox360Buttons.LeftShoulder, buttons[(int)(isLeft ? Button.SHOULDER_1 : Button.SHOULDER2_1)]);
report.SetButtonState(Xbox360Buttons.RightShoulder, buttons[(int)(isLeft ? Button.SHOULDER2_1 : Button.SHOULDER_1)]);
report.SetButtonState(Xbox360Buttons.LeftThumb, buttons[(int)(isLeft ? Button.STICK : Button.STICK2)]);
report.SetButtonState(Xbox360Buttons.RightThumb, buttons[(int)(isLeft ? Button.STICK2 : Button.STICK)]);
} else { // single joycon mode
report.SetButtonState(!swapButtons ? Xbox360Buttons.A : Xbox360Buttons.B, buttons[(int)(isLeft ? Button.DPAD_LEFT : Button.DPAD_RIGHT)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.B : Xbox360Buttons.A, buttons[(int)(isLeft ? Button.DPAD_DOWN : Button.DPAD_UP)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.Y : Xbox360Buttons.X, buttons[(int)(isLeft ? Button.DPAD_RIGHT : Button.DPAD_LEFT)]);
report.SetButtonState(!swapButtons ? Xbox360Buttons.X : Xbox360Buttons.Y, buttons[(int)(isLeft ? Button.DPAD_UP : Button.DPAD_DOWN)]);
report.SetButtonState(Xbox360Buttons.Back, buttons[(int)Button.MINUS] | buttons[(int)Button.HOME]);
report.SetButtonState(Xbox360Buttons.Start, buttons[(int)Button.PLUS] | buttons[(int)Button.CAPTURE]);
report.SetButtonState(Xbox360Buttons.LeftShoulder, buttons[(int)Button.SL]);
report.SetButtonState(Xbox360Buttons.RightShoulder, buttons[(int)Button.SR]);
report.SetButtonState(Xbox360Buttons.LeftThumb, buttons[(int)Button.STICK]);
}
}
lock (buttons_up) {
@ -559,11 +591,16 @@ namespace BetterJoyForCemu {
}
if (xin != null) {
report.SetAxis(Xbox360Axes.LeftThumbX, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[0] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.LeftThumbY, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[1] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.RightThumbX, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick2[0] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.RightThumbY, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick2[1] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.LeftTrigger, (short)(buttons[(int)(isLeft ? Button.SHOULDER_2 : Button.SHOULDER2_2)] ? Int16.MaxValue : 0));
if (other != null) {
report.SetAxis(Xbox360Axes.LeftThumbX, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[0] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.LeftThumbY, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[1] * (stick[1] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.RightThumbX, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick2[0] * (stick2[0] > 0 ? Int16.MaxValue : -Int16.MinValue))));
report.SetAxis(Xbox360Axes.RightThumbY, (short)Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick2[1] * (stick2[1] > 0 ? Int16.MaxValue : -Int16.MinValue))));
} else { // single joycon mode
report.SetAxis(Xbox360Axes.LeftThumbY, (short)((isLeft ? 1 : -1) * Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[0] * (stick[0] > 0 ? Int16.MaxValue : -Int16.MinValue)))));
report.SetAxis(Xbox360Axes.LeftThumbX, (short)((isLeft ? -1 : 1) * Math.Max(Int16.MinValue, Math.Min(Int16.MaxValue, stick[1] * (stick[1] > 0 ? Int16.MaxValue : -Int16.MinValue)))));
}
report.SetAxis(Xbox360Axes.LeftTrigger, (short)(buttons[(int)(isLeft ? Button.SHOULDER_2 : Button.SHOULDER2_2)] ? Int16.MaxValue : 0));
report.SetAxis(Xbox360Axes.RightTrigger, (short)(buttons[(int)(isLeft ? Button.SHOULDER2_2 : Button.SHOULDER_2)] ? Int16.MaxValue : 0));
}
@ -638,9 +675,9 @@ namespace BetterJoyForCemu {
public void SetRumble(float low_freq, float high_freq, float amp, int time = 0) {
if (state <= Joycon.state_.ATTACHED) return;
if (rumble_obj.timed_rumble == false || rumble_obj.t < 0) {
//if (rumble_obj.timed_rumble == false || rumble_obj.t < 0) {
rumble_obj = new Rumble(low_freq, high_freq, amp, time);
}
//}
}
private void SendRumble(byte[] buf) {

View file

@ -23,86 +23,125 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.console = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.label2 = new System.Windows.Forms.Label();
this.contextMenu.SuspendLayout();
this.SuspendLayout();
//
// console
//
this.console.Location = new System.Drawing.Point(12, 25);
this.console.Multiline = true;
this.console.Name = "console";
this.console.ReadOnly = true;
this.console.Size = new System.Drawing.Size(260, 224);
this.console.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(83, 13);
this.label1.TabIndex = 1;
this.label1.Text = "Console Output:";
//
// notifyIcon
//
this.notifyIcon.BalloonTipText = "Double click the tray icon to maximise";
this.notifyIcon.BalloonTipTitle = "BetterJoyForCemu";
this.notifyIcon.ContextMenuStrip = this.contextMenu;
this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
this.notifyIcon.Text = "BetterJoyForCemu";
this.notifyIcon.Visible = true;
this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
//
// contextMenu
//
this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.console = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.label2 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.passiveScanBox = new System.Windows.Forms.CheckBox();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.contextMenu.SuspendLayout();
this.SuspendLayout();
//
// console
//
this.console.Location = new System.Drawing.Point(12, 25);
this.console.Multiline = true;
this.console.Name = "console";
this.console.ReadOnly = true;
this.console.Size = new System.Drawing.Size(260, 169);
this.console.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(83, 13);
this.label1.TabIndex = 1;
this.label1.Text = "Console Output:";
//
// notifyIcon
//
this.notifyIcon.BalloonTipText = "Double click the tray icon to maximise";
this.notifyIcon.BalloonTipTitle = "BetterJoyForCemu";
this.notifyIcon.ContextMenuStrip = this.contextMenu;
this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
this.notifyIcon.Text = "BetterJoyForCemu";
this.notifyIcon.Visible = true;
this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
//
// contextMenu
//
this.contextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.exitToolStripMenuItem});
this.contextMenu.Name = "contextMenu";
this.contextMenu.Size = new System.Drawing.Size(153, 48);
//
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.exitToolStripMenuItem.Text = "Exit";
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(244, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(28, 13);
this.label2.TabIndex = 2;
this.label2.Text = "v4.0";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.console);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "MainForm";
this.Text = "BetterJoyForCemu";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
this.Load += new System.EventHandler(this.MainForm_Load);
this.Resize += new System.EventHandler(this.MainForm_Resize);
this.contextMenu.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
this.contextMenu.Name = "contextMenu";
this.contextMenu.Size = new System.Drawing.Size(93, 26);
//
// exitToolStripMenuItem
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(92, 22);
this.exitToolStripMenuItem.Text = "Exit";
this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(244, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(28, 13);
this.label2.TabIndex = 2;
this.label2.Text = "v5.0";
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 200);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(260, 26);
this.button1.TabIndex = 3;
this.button1.Text = "Open Controller Configuration";
this.button1.UseVisualStyleBackColor = true;
//
// passiveScanBox
//
this.passiveScanBox.AutoSize = true;
this.passiveScanBox.Checked = true;
this.passiveScanBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.passiveScanBox.Location = new System.Drawing.Point(12, 232);
this.passiveScanBox.Name = "passiveScanBox";
this.passiveScanBox.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
this.passiveScanBox.Size = new System.Drawing.Size(91, 17);
this.passiveScanBox.TabIndex = 4;
this.passiveScanBox.Text = "Passive Scan";
this.passiveScanBox.UseVisualStyleBackColor = true;
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(230, 233);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(42, 13);
this.linkLabel1.TabIndex = 5;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "Donate";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.passiveScanBox);
this.Controls.Add(this.button1);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.console);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "MainForm";
this.Text = "BetterJoyForCemu";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
this.Load += new System.EventHandler(this.MainForm_Load);
this.Resize += new System.EventHandler(this.MainForm_Resize);
this.contextMenu.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
@ -114,5 +153,8 @@
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ContextMenuStrip contextMenu;
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
}
private System.Windows.Forms.Button button1;
private System.Windows.Forms.CheckBox passiveScanBox;
private System.Windows.Forms.LinkLabel linkLabel1;
}
}

View file

@ -36,12 +36,17 @@ namespace BetterJoyForCemu {
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
Program.Stop();
}
Program.Stop();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
Program.Stop();
Application.Exit();
}
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
linkLabel1.LinkVisited = true;
System.Diagnostics.Process.Start("http://paypal.me/DavidKhachaturov/5");
}
}
}

View file

@ -24,296 +24,297 @@ using System.Windows.Forms;
using System.ServiceProcess;
namespace BetterJoyForCemu {
public class JoyconManager {
public bool EnableIMU = true;
public bool EnableLocalize = false;
public class JoyconManager {
public bool EnableIMU = true;
public bool EnableLocalize = false;
private const ushort vendor_id = 0x57e;
private const ushort vendor_id_ = 0x057e;
private const ushort product_l = 0x2006;
private const ushort product_r = 0x2007;
private const ushort product_pro = 0x2009;
private const ushort vendor_id = 0x57e;
private const ushort vendor_id_ = 0x057e;
private const ushort product_l = 0x2006;
private const ushort product_r = 0x2007;
private const ushort product_pro = 0x2009;
public List<Joycon> j; // Array of all connected Joy-Cons
static JoyconManager instance;
public List<Joycon> j; // Array of all connected Joy-Cons
static JoyconManager instance;
public MainForm form;
public MainForm form;
public static JoyconManager Instance {
get { return instance; }
}
public static JoyconManager Instance {
get { return instance; }
}
public void Awake() {
instance = this;
int i = 0;
public void Awake() {
instance = this;
int i = 0;
j = new List<Joycon>();
bool isLeft = false;
HIDapi.hid_init();
j = new List<Joycon>();
bool isLeft = false;
HIDapi.hid_init();
IntPtr ptr = HIDapi.hid_enumerate(vendor_id, 0x0);
IntPtr top_ptr = ptr;
IntPtr ptr = HIDapi.hid_enumerate(vendor_id, 0x0);
IntPtr top_ptr = ptr;
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";
}
}
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";
}
}
hid_device_info enumerate;
while (ptr != IntPtr.Zero) {
enumerate = (hid_device_info)Marshal.PtrToStructure(ptr, typeof(hid_device_info));
hid_device_info enumerate;
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) {
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";
}
// Add controller to block-list for HidGuardian
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/affected/add/");
string postData = @"hwids=HID\" + enumerate.path.Split('#')[1].ToUpper();
var data = Encoding.UTF8.GetBytes(postData);
// Add controller to block-list for HidGuardian
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/affected/add/");
string postData = @"hwids=HID\" + enumerate.path.Split('#')[1].ToUpper();
var data = Encoding.UTF8.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
stream.Write(data, 0, data.Length);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.ContentLength = data.Length;
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";
}
// -------------------- //
using (var stream = request.GetRequestStream())
stream.Write(data, 0, data.Length);
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";
break;
}
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";
}
// -------------------- //
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
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";
break;
}
j.Last().form = form;
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
byte[] mac = new byte[6];
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);
j.Last().form = form;
++i;
}
ptr = enumerate.next;
}
byte[] mac = new byte[6];
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);
int found = 0;
foreach (Joycon v in j) {
if (v.isLeft && !v.isPro)
found++;
if (!v.isLeft && !v.isPro)
found++;
}
++i;
}
ptr = enumerate.next;
}
if (found == 2) {
form.console.Text += "Both joycons successfully found.\r\n";
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;
}
}
int found = 0;
int minPadID = 10;
foreach (Joycon v in j) {
if (!v.isPro) {
found++;
minPadID = Math.Min(v.PadId, minPadID);
}
}
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)
form.console.Text += "Only one joycon found. Please connect both and then restart the program.\r\n";
if (found == 2) {
form.console.Text += "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 {
temp.other = v;
v.other = temp;
HIDapi.hid_free_enumeration(top_ptr);
}
temp.xin.Dispose();
temp.xin = null;
}
}
} // Join up the two joycons
} else if (found != 0)
form.console.Text += "Only one joycon found. Using in single joycone mode.\r\n";
public void Start() {
for (int i = 0; i < j.Count; ++i) {
Joycon jc = j[i];
HIDapi.hid_free_enumeration(top_ptr);
}
if (jc.xin != null)
jc.xin.Connect();
public void Start() {
for (int i = 0; i < j.Count; ++i) {
Joycon jc = j[i];
byte LEDs = 0x0;
LEDs |= (byte)(0x1 << i);
jc.Attach(leds_: LEDs);
jc.Begin();
}
}
if (jc.xin != null)
jc.xin.Connect();
public void Update() {
for (int i = 0; i < j.Count; ++i)
j[i].Update();
}
//byte LEDs = 0x0;
// LEDs |= (byte)(0x1 << jc.PadId);
jc.Attach(leds_: jc.LED);
jc.Begin();
}
}
public void OnApplicationQuit() {
for (int i = 0; i < j.Count; ++i) {
j[i].Detach();
public void Update() {
for (int i = 0; i < j.Count; ++i)
j[i].Update();
}
if (j[i].xin != null) {
j[i].xin.Disconnect();
j[i].xin.Dispose();
}
}
}
}
public void OnApplicationQuit() {
for (int i = 0; i < j.Count; ++i) {
j[i].Detach();
// Custom timer class because system timers have a limit of 15.6ms
class HighResTimer {
double interval = 0;
double frequency = 0;
if (j[i].xin != null) {
j[i].xin.Disconnect();
j[i].xin.Dispose();
}
}
}
}
Thread thread;
// Custom timer class because system timers have a limit of 15.6ms
class HighResTimer {
double interval = 0;
double frequency = 0;
public delegate void ActionDelegate();
ActionDelegate func;
Thread thread;
bool run = false;
public delegate void ActionDelegate();
ActionDelegate func;
public HighResTimer(double f, ActionDelegate a) {
frequency = f;
interval = 1.0 / f;
bool run = false;
func = a;
}
public HighResTimer(double f, ActionDelegate a) {
frequency = f;
interval = 1.0 / f;
public void Start() {
run = true;
thread = new Thread(new ThreadStart(Run));
thread.Start();
}
func = a;
}
void Run() {
while (run) {
func();
int timeToSleep = (int)(interval * 1000);
Thread.Sleep(timeToSleep);
}
}
public void Start() {
run = true;
thread = new Thread(new ThreadStart(Run));
thread.Start();
}
public void Stop() {
run = false;
}
}
void Run() {
while (run) {
func();
int timeToSleep = (int)(interval * 1000);
Thread.Sleep(timeToSleep);
}
}
class Program {
public static PhysicalAddress btMAC = new PhysicalAddress(new byte[] { 0, 0, 0, 0, 0, 0 });
public static UdpServer server;
static double pollsPerSecond = 120.0;
public void Stop() {
run = false;
}
}
public static ViGEmClient emClient;
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;
private static readonly HttpClient client = new HttpClient();
public static ViGEmClient emClient;
static JoyconManager mgr;
static HighResTimer timer;
static string pid;
private static readonly HttpClient client = new HttpClient();
static MainForm form;
static JoyconManager mgr;
static HighResTimer timer;
static string pid;
public static void Start() {
pid = Process.GetCurrentProcess().Id.ToString(); // get current process id for HidCerberus.Srv
static MainForm form;
var HidCerberusService = new ServiceController("HidCerberus Service");
if (HidCerberusService.Status == ServiceControllerStatus.Stopped) {
form.console.Text += "HidGuardian was stopped. Starting...\r\n";
public static void Start() {
pid = Process.GetCurrentProcess().Id.ToString(); // get current process id for HidCerberus.Srv
try {
HidCerberusService.Start();
} catch (Exception e) {
form.console.Text += "Unable to start HidGuardian - everything should work fine without it, but if you need it, run the app again as an admin.\r\n";
}
}
try {
var HidCerberusService = new ServiceController("HidCerberus Service");
if (HidCerberusService.Status == ServiceControllerStatus.Stopped) {
form.console.Text += "HidGuardian was stopped. Starting...\r\n";
HttpWebResponse response;
if (Boolean.Parse(ConfigurationSettings.AppSettings["PurgeWhitelist"])) {
try {
response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/purge/").GetResponse(); // remove all programs allowed to see controller
} catch (Exception e) {
form.console.Text += "Unable to purge whitelist.\r\n";
}
}
try {
HidCerberusService.Start();
} catch (Exception e) {
form.console.Text += "Unable to start HidGuardian - everything should work fine without it, but if you need it, run the app again as an admin.\r\n";
}
}
} catch (Exception e) {
form.console.Text += "Unable to start HidGuardian - everything should work fine without it, but if you need it, install it properly as admin.\r\n";
}
try {
response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/add/" + pid).GetResponse(); // add BetterJoyForCemu to allowed processes
} catch (Exception e) {
form.console.Text += "Unable to add program to whitelist.\r\n";
}
HttpWebResponse response;
if (Boolean.Parse(ConfigurationSettings.AppSettings["PurgeWhitelist"])) {
try {
response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/purge/").GetResponse(); // remove all programs allowed to see controller
} catch (Exception e) {
form.console.Text += "Unable to purge whitelist.\r\n";
}
}
emClient = new ViGEmClient(); // Manages emulated XInput
try {
response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/add/" + pid).GetResponse(); // add BetterJoyForCemu to allowed processes
} catch (Exception e) {
form.console.Text += "Unable to add program to whitelist.\r\n";
}
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
// Get local BT host MAC
if (nic.NetworkInterfaceType != NetworkInterfaceType.FastEthernetFx && nic.NetworkInterfaceType != NetworkInterfaceType.Wireless80211) {
if (nic.Name.Split()[0] == "Bluetooth") {
btMAC = nic.GetPhysicalAddress();
}
}
}
emClient = new ViGEmClient(); // Manages emulated XInput
mgr = new JoyconManager();
mgr.form = form;
mgr.Awake();
mgr.Start();
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
// Get local BT host MAC
if (nic.NetworkInterfaceType != NetworkInterfaceType.FastEthernetFx && nic.NetworkInterfaceType != NetworkInterfaceType.Wireless80211) {
if (nic.Name.Split()[0] == "Bluetooth") {
btMAC = nic.GetPhysicalAddress();
}
}
}
server = new UdpServer(mgr.j);
server.form = form;
mgr = new JoyconManager();
mgr.form = form;
mgr.Awake();
mgr.Start();
server.Start(IPAddress.Parse(ConfigurationSettings.AppSettings["IP"]), Int32.Parse(ConfigurationSettings.AppSettings["Port"]));
timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update));
timer.Start();
server = new UdpServer(mgr.j);
server.form = form;
form.console.Text += "All systems go\r\n";
}
server.Start(IPAddress.Parse(ConfigurationSettings.AppSettings["IP"]), Int32.Parse(ConfigurationSettings.AppSettings["Port"]));
timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update));
timer.Start();
public static void Stop() {
try {
HttpWebResponse response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/remove/" + pid).GetResponse(); // add BetterJoyForCemu to allowed processes
} catch (Exception e) {
form.console.Text += "Unable to remove program from whitelist.\r\n";
}
form.console.Text += "All systems go\r\n";
}
server.Stop();
timer.Stop();
mgr.OnApplicationQuit();
}
public static void Stop() {
try {
HttpWebResponse response = (HttpWebResponse)WebRequest.Create(@"http://localhost:26762/api/v1/hidguardian/whitelist/remove/" + pid).GetResponse(); // add BetterJoyForCemu to allowed processes
} catch (Exception e) {
form.console.Text += "Unable to remove program from whitelist.\r\n";
}
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new MainForm();
Application.Run(form);
}
}
}
server.Stop();
timer.Stop();
mgr.OnApplicationQuit();
}
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new MainForm();
Application.Run(form);
}
}
}