Version 4 - Added HidGuardian support and implemented a GUI

This commit is contained in:
David Khachaturov 2018-05-02 18:57:47 +01:00
parent 32aca0aed9
commit db90d8357b
9 changed files with 1705 additions and 25 deletions

View file

@ -30,5 +30,10 @@
<!--Also swaps buttons when using "Also use for buttons/axes"-->
<!--On is "true"; off is "false". Default: false -->
<add key="SwapButtons" value="false" />
<!-- Determines whether or not HidGuardian's process whitelist is purged on start-up -->
<!-- Can interfere with other programs using HidGuardian, but prevents whitelist from being clogged from crashed instances -->
<!-- Default: true -->
<add key="PurgeWhitelist" value="true"/>
</appSettings>
</configuration>

View file

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1BF709E9-C133-41DF-933A-C9FF3F664C7B}</ProjectGuid>
<OutputType>Exe</OutputType>
<OutputType>WinExe</OutputType>
<RootNamespace>BetterJoyForCemu</RootNamespace>
<AssemblyName>BetterJoyForCemu</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
@ -71,13 +71,23 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>betterjoyforcemu_icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Crc32.NET, Version=1.0.0.0, Culture=neutral, PublicKeyToken=dc0b95cf99bf4e99, processorArchitecture=MSIL">
<HintPath>..\packages\Crc32.NET.1.2.0\lib\net20\Crc32.NET.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Numerics" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -88,6 +98,12 @@
<ItemGroup>
<Compile Include="HIDapi.cs" />
<Compile Include="Joycon.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UpdServer.cs" />
@ -97,6 +113,7 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="betterjoyforcemu_icon.ico" />
<Content Include="hidapi.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@ -107,5 +124,10 @@
<Name>ViGEmClient</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -211,6 +211,8 @@ namespace BetterJoyForCemu {
bool toRumble = Boolean.Parse(ConfigurationSettings.AppSettings["EnableRumble"]);
public MainForm form;
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;
@ -243,7 +245,7 @@ namespace BetterJoyForCemu {
public void DebugPrint(String s, DebugType d) {
if (debug_type == DebugType.NONE) return;
if (d == DebugType.ALL || d == debug_type || debug_type == DebugType.ALL) {
Console.WriteLine(s);
form.console.Text += s + "\r\n";
}
}
public bool GetButtonDown(Button b) {
@ -285,7 +287,7 @@ namespace BetterJoyForCemu {
Subcommand(0x03, new byte[] { 0x3f }, 1, false);
a = Enumerable.Repeat((byte)0, 64).ToArray();
Console.WriteLine("Using USB.");
form.console.Text += "Using USB.\r\n";
a[0] = 0x80;
a[1] = 0x01;
@ -378,7 +380,7 @@ namespace BetterJoyForCemu {
}
if (ts_en == raw_buf[1]) {
Console.WriteLine("Duplicate timestamp enqueued.");
form.console.Text += "Duplicate timestamp enqueued.\r\n";
DebugPrint(string.Format("Duplicate timestamp enqueued. TS: {0:X2}", ts_en), DebugType.THREADING);
}
ts_en = raw_buf[1];
@ -399,7 +401,7 @@ namespace BetterJoyForCemu {
attempts = 0;
} else if (attempts > 1000) {
state = state_.DROPPED;
Console.WriteLine("Dropped");
//form.console.Text += "Dropped\r\n";
DebugPrint("Connection lost. Is the Joy-Con connected?", DebugType.ALL);
break;
} else {
@ -609,7 +611,7 @@ namespace BetterJoyForCemu {
PollThreadObj = new Thread(new ThreadStart(Poll));
PollThreadObj.Start();
Console.WriteLine("Starting poll thread.");
form.console.Text += "Starting poll thread.\r\n";
}
}
@ -675,13 +677,13 @@ namespace BetterJoyForCemu {
bool found = false;
for (int i = 0; i < 9; ++i) {
if (buf_[i] != 0xff) {
Console.WriteLine("Using user stick calibration data.");
form.console.Text += "Using user stick calibration data.\r\n";
found = true;
break;
}
}
if (!found) {
Console.WriteLine("Using factory stick calibration data.");
form.console.Text += "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
@ -698,13 +700,13 @@ namespace BetterJoyForCemu {
found = false;
for (int i = 0; i < 9; ++i) {
if (buf_[i] != 0xff) {
Console.WriteLine("Using user stick calibration data.");
form.console.Text += "Using user stick calibration data.\r\n";
found = true;
break;
}
}
if (!found) {
Console.WriteLine("Using factory stick calibration data.");
form.console.Text += "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

118
BetterJoyForCemu/MainForm.Designer.cs generated Normal file
View file

@ -0,0 +1,118 @@
namespace BetterJoyForCemu {
partial class MainForm {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// 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.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();
}
#endregion
public System.Windows.Forms.TextBox console;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.NotifyIcon notifyIcon;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ContextMenuStrip contextMenu;
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
}
}

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BetterJoyForCemu {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
}
private void MainForm_Resize(object sender, EventArgs e) {
if (this.WindowState == FormWindowState.Minimized) {
notifyIcon.Visible = true;
notifyIcon.ShowBalloonTip(1);
this.ShowInTaskbar = false;
}
}
private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) {
this.WindowState = FormWindowState.Normal;
this.ShowInTaskbar = true;
notifyIcon.Visible = false;
}
private void MainForm_Load(object sender, EventArgs e) {
this.ShowInTaskbar = true;
notifyIcon.Visible = false;
Program.Start();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
Program.Stop();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
Program.Stop();
Application.Exit();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,11 @@ using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Targets;
using System.Net;
using System.Configuration;
using System.Net.Http;
using System.IO;
using System.Windows.Forms;
using System.ServiceProcess;
namespace BetterJoyForCemu {
public class JoyconManager {
@ -32,6 +37,8 @@ namespace BetterJoyForCemu {
public List<Joycon> j; // Array of all connected Joy-Cons
static JoyconManager instance;
public MainForm form;
public static JoyconManager Instance {
get { return instance; }
}
@ -51,7 +58,7 @@ namespace BetterJoyForCemu {
ptr = HIDapi.hid_enumerate(vendor_id_, 0x0);
if (ptr == IntPtr.Zero) {
HIDapi.hid_free_enumeration(ptr);
Console.WriteLine("No Joy-Cons found!");
form.console.Text += "No Joy-Cons found!\r\n";
}
}
@ -62,27 +69,49 @@ namespace BetterJoyForCemu {
if (enumerate.product_id == product_l || enumerate.product_id == product_r || enumerate.product_id == product_pro) {
if (enumerate.product_id == product_l) {
isLeft = true;
Console.WriteLine("Left Joy-Con connected.");
form.console.Text += "Left Joy-Con connected.\r\n";
} else if (enumerate.product_id == product_r) {
isLeft = false;
Console.WriteLine("Right Joy-Con connected.");
form.console.Text += "Right Joy-Con connected.\r\n";
} else if (enumerate.product_id == product_pro) {
isLeft = true;
Console.WriteLine("Pro controller connected.");
form.console.Text += "Pro controller connected.\r\n";
} else {
Console.WriteLine("Non Joy-Con input device skipped.");
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);
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);
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";
}
// -------------------- //
IntPtr handle = HIDapi.hid_open_path(enumerate.path);
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?");
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.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, j.Count, enumerate.product_id == product_pro, enumerate.serial_number == "000000000001"));
j.Last().form = form;
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);
@ -102,7 +131,7 @@ namespace BetterJoyForCemu {
}
if (found == 2) {
Console.WriteLine("Both joycons successfully found.");
form.console.Text += "Both joycons successfully found.\r\n";
Joycon temp = null;
foreach (Joycon v in j) {
if (v.isLeft && !v.isPro) {
@ -124,7 +153,7 @@ namespace BetterJoyForCemu {
}
} // Join up the two joycons
} else if (found != 0)
Console.WriteLine("Only one joycon found. Please connect both and then restart the program.");
form.console.Text += "Only one joycon found. Please connect both and then restart the program.\r\n";
HIDapi.hid_free_enumeration(top_ptr);
}
@ -205,7 +234,43 @@ namespace BetterJoyForCemu {
public static ViGEmClient emClient;
static void Main(string[] args) {
private static readonly HttpClient client = new HttpClient();
static JoyconManager mgr;
static HighResTimer timer;
static string pid;
static MainForm form;
public static void Start() {
pid = Process.GetCurrentProcess().Id.ToString(); // get current process id for HidCerberus.Srv
var HidCerberusService = new ServiceController("HidCerberus Service");
if (HidCerberusService.Status == ServiceControllerStatus.Stopped) {
form.console.Text += "HidGuardian was stopped. Starting...\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";
}
}
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 {
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";
}
emClient = new ViGEmClient(); // Manages emulated XInput
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) {
@ -217,22 +282,38 @@ namespace BetterJoyForCemu {
}
}
JoyconManager mgr = new JoyconManager();
mgr = new JoyconManager();
mgr.form = form;
mgr.Awake();
mgr.Start();
server = new UdpServer(mgr.j);
server.form = form;
server.Start(IPAddress.Parse(ConfigurationSettings.AppSettings["IP"]), Int32.Parse(ConfigurationSettings.AppSettings["Port"]));
HighResTimer timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update));
timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update));
timer.Start();
Console.Write("Press enter to quit.");
Console.ReadLine();
form.console.Text += "All systems go\r\n";
}
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";
}
server.Stop();
timer.Stop();
mgr.OnApplicationQuit();
}
static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new MainForm();
Application.Run(form);
}
}
}

View file

@ -19,6 +19,8 @@ namespace BetterJoyForCemu {
List<Joycon> controllers;
public MainForm form;
public UdpServer(List<Joycon> p) {
controllers = p;
}
@ -293,7 +295,7 @@ namespace BetterJoyForCemu {
udpSock.Close();
udpSock = null;
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.");
form.console.Text += "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.\r\n";
return;
}
@ -302,7 +304,7 @@ namespace BetterJoyForCemu {
serverId = BitConverter.ToUInt32(randomBuf, 0);
running = true;
Console.WriteLine("Starting server on {0}:{1}", ip.ToString(), port);
form.console.Text += String.Format("Starting server on {0}:{1}\r\n", ip.ToString(), port);
StartReceive();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB