Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
488d152508 |
32 changed files with 3685 additions and 5206 deletions
18
.github/ISSUE_TEMPLATE/bug-report---problems.md
vendored
18
.github/ISSUE_TEMPLATE/bug-report---problems.md
vendored
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
name: Bug Report / Problems
|
||||
about: PLEASE USE THE ISSUE SEARCH FUNCTION FIRST BEFORE MAKING A NEW ISSUE
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Controller (please complete the following information):**
|
||||
- Type: [e.g. Pro/Split Joycons]
|
||||
- Connection: [e.g. USB/BT]
|
14
.github/ISSUE_TEMPLATE/feature-request.md
vendored
14
.github/ISSUE_TEMPLATE/feature-request.md
vendored
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: "[ENHANCEMENT]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
|
@ -1,120 +0,0 @@
|
|||
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
|
||||
###############################
|
||||
# Core EditorConfig Options #
|
||||
###############################
|
||||
root = true
|
||||
# All files
|
||||
[*]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
charset = utf-8-bom
|
||||
###############################
|
||||
# .NET Coding Conventions #
|
||||
###############################
|
||||
[*.{cs,vb}]
|
||||
# Organize usings
|
||||
dotnet_sort_system_directives_first = true
|
||||
# this. preferences
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
# Expression-level preferences
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
###############################
|
||||
# Naming Conventions #
|
||||
###############################
|
||||
# Style Definitions
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
# Use PascalCase for constant fields
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
|
||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
||||
###############################
|
||||
# C# Coding Conventions #
|
||||
###############################
|
||||
[*.cs]
|
||||
# var preferences
|
||||
csharp_style_var_for_built_in_types = true:silent
|
||||
csharp_style_var_when_type_is_apparent = true:silent
|
||||
csharp_style_var_elsewhere = true:silent
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
# Null-checking preferences
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
# Modifier preferences
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
|
||||
# Expression-level preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
###############################
|
||||
# C# Formatting Rules #
|
||||
###############################
|
||||
# New line preferences
|
||||
csharp_new_line_before_open_brace = false
|
||||
csharp_new_line_before_else = false
|
||||
csharp_new_line_before_catch = false
|
||||
csharp_new_line_before_finally = false
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
# Indentation preferences
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = flush_left
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_preserve_single_line_blocks = true
|
46
BetterJoyForCemu/3rdPartyControllers.Designer.cs
generated
46
BetterJoyForCemu/3rdPartyControllers.Designer.cs
generated
|
@ -30,8 +30,8 @@
|
|||
this.btn_add = new System.Windows.Forms.Button();
|
||||
this.btn_remove = new System.Windows.Forms.Button();
|
||||
this.group_props = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.chooseType = new System.Windows.Forms.ComboBox();
|
||||
this.chk_isLeft = new System.Windows.Forms.CheckBox();
|
||||
this.chk_isPro = new System.Windows.Forms.CheckBox();
|
||||
this.btn_applyAndClose = new System.Windows.Forms.Button();
|
||||
this.btn_apply = new System.Windows.Forms.Button();
|
||||
this.lbl_all = new System.Windows.Forms.Label();
|
||||
|
@ -83,8 +83,8 @@
|
|||
//
|
||||
// group_props
|
||||
//
|
||||
this.group_props.Controls.Add(this.label2);
|
||||
this.group_props.Controls.Add(this.chooseType);
|
||||
this.group_props.Controls.Add(this.chk_isLeft);
|
||||
this.group_props.Controls.Add(this.chk_isPro);
|
||||
this.group_props.Location = new System.Drawing.Point(122, 142);
|
||||
this.group_props.Name = "group_props";
|
||||
this.group_props.Size = new System.Drawing.Size(150, 81);
|
||||
|
@ -92,23 +92,29 @@
|
|||
this.group_props.TabStop = false;
|
||||
this.group_props.Text = "Settings";
|
||||
//
|
||||
// label2
|
||||
// chk_isLeft
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(10, 22);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(31, 13);
|
||||
this.label2.TabIndex = 1;
|
||||
this.label2.Text = "Type";
|
||||
this.chk_isLeft.AutoSize = true;
|
||||
this.chk_isLeft.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.chk_isLeft.Location = new System.Drawing.Point(6, 42);
|
||||
this.chk_isLeft.Name = "chk_isLeft";
|
||||
this.chk_isLeft.Size = new System.Drawing.Size(96, 17);
|
||||
this.chk_isLeft.TabIndex = 1;
|
||||
this.chk_isLeft.Text = "Left Joycon? ";
|
||||
this.chk_isLeft.UseVisualStyleBackColor = true;
|
||||
this.chk_isLeft.CheckedChanged += new System.EventHandler(this.chk_isLeft_CheckedChanged);
|
||||
//
|
||||
// chooseType
|
||||
// chk_isPro
|
||||
//
|
||||
this.chooseType.FormattingEnabled = true;
|
||||
this.chooseType.Location = new System.Drawing.Point(47, 19);
|
||||
this.chooseType.Name = "chooseType";
|
||||
this.chooseType.Size = new System.Drawing.Size(97, 21);
|
||||
this.chooseType.TabIndex = 0;
|
||||
this.chooseType.SelectedValueChanged += new System.EventHandler(this.chooseType_SelectedValueChanged);
|
||||
this.chk_isPro.AutoSize = true;
|
||||
this.chk_isPro.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.chk_isPro.Location = new System.Drawing.Point(6, 19);
|
||||
this.chk_isPro.Name = "chk_isPro";
|
||||
this.chk_isPro.Size = new System.Drawing.Size(95, 17);
|
||||
this.chk_isPro.TabIndex = 0;
|
||||
this.chk_isPro.Text = "Pro Controller?";
|
||||
this.chk_isPro.UseVisualStyleBackColor = true;
|
||||
this.chk_isPro.CheckedChanged += new System.EventHandler(this.chk_isPro_CheckedChanged);
|
||||
//
|
||||
// btn_applyAndClose
|
||||
//
|
||||
|
@ -197,10 +203,10 @@
|
|||
private System.Windows.Forms.Button btn_applyAndClose;
|
||||
private System.Windows.Forms.Button btn_apply;
|
||||
private System.Windows.Forms.Label lbl_all;
|
||||
private System.Windows.Forms.CheckBox chk_isPro;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox chk_isLeft;
|
||||
private System.Windows.Forms.ToolTip tip_device;
|
||||
private System.Windows.Forms.Button btn_refresh;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox chooseType;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -14,92 +13,27 @@ using static BetterJoyForCemu.HIDapi;
|
|||
|
||||
namespace BetterJoyForCemu {
|
||||
public partial class _3rdPartyControllers : Form {
|
||||
public class SController {
|
||||
public String name;
|
||||
public ushort product_id;
|
||||
public ushort vendor_id;
|
||||
public string serial_number;
|
||||
public byte type; // 1 is pro, 2 is left joy, 3 is right joy
|
||||
|
||||
public SController(String name, ushort vendor_id, ushort product_id, byte type, string serial_number) {
|
||||
this.product_id = product_id; this.vendor_id = vendor_id; this.type = type;
|
||||
this.serial_number = serial_number;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
//Check for null and compare run-time types.
|
||||
if ((obj == null) || !this.GetType().Equals(obj.GetType())) {
|
||||
return false;
|
||||
} else {
|
||||
SController s = (SController)obj;
|
||||
return (s.product_id == product_id) && (s.vendor_id == vendor_id) && (s.serial_number == serial_number);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return Tuple.Create(product_id, vendor_id, serial_number).GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return name ?? $"Unidentified Device ({this.product_id})";
|
||||
}
|
||||
|
||||
public string Serialise() {
|
||||
return String.Format("{0}|{1}|{2}|{3}|{4}", name, vendor_id, product_id, type, serial_number);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly string path;
|
||||
|
||||
static _3rdPartyControllers() {
|
||||
path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
|
||||
+ "\\3rdPartyControllers";
|
||||
}
|
||||
|
||||
public _3rdPartyControllers() {
|
||||
InitializeComponent();
|
||||
list_allControllers.HorizontalScrollbar = true; list_customControllers.HorizontalScrollbar = true;
|
||||
list_allControllers.DisplayMember = "Text";
|
||||
list_allControllers.ValueMember = "Value";
|
||||
list_customControllers.DisplayMember = "Text";
|
||||
list_customControllers.ValueMember = "Value";
|
||||
|
||||
chooseType.Items.AddRange(new String[] { "Pro Controller", "Left Joycon", "Right Joycon" });
|
||||
|
||||
chooseType.FormattingEnabled = true;
|
||||
group_props.Controls.Add(chooseType);
|
||||
group_props.Enabled = false;
|
||||
|
||||
if (File.Exists(path)) {
|
||||
using (StreamReader file = new StreamReader(path)) {
|
||||
string line = String.Empty;
|
||||
while ((line = file.ReadLine()) != null && (line != String.Empty)) {
|
||||
String[] split = line.Split('|');
|
||||
//won't break existing config file
|
||||
String serial_number = "";
|
||||
if (split.Length > 4) {
|
||||
serial_number = split[4];
|
||||
}
|
||||
list_customControllers.Items.Add(new SController(split[0], ushort.Parse(split[1]), ushort.Parse(split[2]), byte.Parse(split[3]), serial_number));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CopyCustomControllers();
|
||||
RefreshControllerList();
|
||||
}
|
||||
|
||||
public void CopyCustomControllers() {
|
||||
Program.thirdPartyCons.Clear();
|
||||
foreach (SController v in list_customControllers.Items) {
|
||||
Program.thirdPartyCons.Add(v);
|
||||
}
|
||||
group_props.Controls.Add(chk_isLeft);
|
||||
group_props.Controls.Add(chk_isPro);
|
||||
group_props.Enabled = false;
|
||||
}
|
||||
|
||||
private bool ContainsText(ListBox a, String manu) {
|
||||
foreach (SController v in a.Items) {
|
||||
if (v == null)
|
||||
foreach (var v in a.Items)
|
||||
{
|
||||
dynamic d = v as dynamic;
|
||||
if (d.Text == null)
|
||||
continue;
|
||||
if (v.name == null)
|
||||
continue;
|
||||
if (v.name.Equals(manu))
|
||||
if (d.Text.Equals(manu))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -114,29 +48,17 @@ namespace BetterJoyForCemu {
|
|||
while (ptr != IntPtr.Zero) {
|
||||
enumerate = (hid_device_info)Marshal.PtrToStructure(ptr, typeof(hid_device_info));
|
||||
|
||||
if (enumerate.serial_number == null) {
|
||||
ptr = enumerate.next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: try checking against interface number instead
|
||||
String name = enumerate.product_string + '(' + enumerate.vendor_id + '-' + enumerate.product_id + '-'+enumerate.serial_number+')';
|
||||
if (!ContainsText(list_customControllers, name) && !ContainsText(list_allControllers, name)) {
|
||||
list_allControllers.Items.Add(new SController(name, enumerate.vendor_id, enumerate.product_id, 0, enumerate.serial_number));
|
||||
// 0 type is undefined
|
||||
Console.WriteLine("Found controller "+ name);
|
||||
}
|
||||
if (!ContainsText(list_customControllers, enumerate.product_string) && !ContainsText(list_allControllers, enumerate.product_string))
|
||||
list_allControllers.Items.Add(new { Text = enumerate.product_string, Value = enumerate });
|
||||
|
||||
ptr = enumerate.next;
|
||||
}
|
||||
HIDapi.hid_free_enumeration(top_ptr);
|
||||
}
|
||||
|
||||
private void btn_add_Click(object sender, EventArgs e) {
|
||||
if (list_allControllers.SelectedItem != null) {
|
||||
list_customControllers.Items.Add(list_allControllers.SelectedItem);
|
||||
list_allControllers.Items.Remove(list_allControllers.SelectedItem);
|
||||
|
||||
list_allControllers.ClearSelected();
|
||||
}
|
||||
}
|
||||
|
@ -145,18 +67,20 @@ namespace BetterJoyForCemu {
|
|||
if (list_customControllers.SelectedItem != null) {
|
||||
list_allControllers.Items.Add(list_customControllers.SelectedItem);
|
||||
list_customControllers.Items.Remove(list_customControllers.SelectedItem);
|
||||
|
||||
list_customControllers.ClearSelected();
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_apply_Click(object sender, EventArgs e) {
|
||||
String sc = "";
|
||||
foreach (SController v in list_customControllers.Items) {
|
||||
sc += v.Serialise() + "\r\n";
|
||||
private void chk_isPro_CheckedChanged(object sender, EventArgs e) {
|
||||
|
||||
}
|
||||
File.WriteAllText(path, sc);
|
||||
CopyCustomControllers();
|
||||
|
||||
private void chk_isLeft_CheckedChanged(object sender, EventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
private void btn_apply_Click(object sender, EventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
private void btn_applyAndClose_Click(object sender, EventArgs e) {
|
||||
|
@ -174,22 +98,16 @@ namespace BetterJoyForCemu {
|
|||
|
||||
private void list_allControllers_SelectedValueChanged(object sender, EventArgs e) {
|
||||
if (list_allControllers.SelectedItem != null)
|
||||
tip_device.Show((list_allControllers.SelectedItem as SController).name, list_allControllers);
|
||||
tip_device.Show((list_allControllers.SelectedItem as dynamic).Text, list_allControllers);
|
||||
}
|
||||
|
||||
private void list_customControllers_SelectedValueChanged(object sender, EventArgs e) {
|
||||
if (list_customControllers.SelectedItem != null) {
|
||||
SController v = (list_customControllers.SelectedItem as SController);
|
||||
tip_device.Show(v.name, list_customControllers);
|
||||
|
||||
chooseType.SelectedIndex = v.type - 1;
|
||||
|
||||
tip_device.Show((list_customControllers.SelectedItem as dynamic).Text, list_customControllers);
|
||||
group_props.Enabled = true;
|
||||
} else {
|
||||
chooseType.SelectedIndex = -1;
|
||||
} else
|
||||
group_props.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void list_customControllers_MouseDown(object sender, MouseEventArgs e) {
|
||||
if (e.Y > list_customControllers.ItemHeight * list_customControllers.Items.Count)
|
||||
|
@ -200,12 +118,5 @@ namespace BetterJoyForCemu {
|
|||
if (e.Y > list_allControllers.ItemHeight * list_allControllers.Items.Count)
|
||||
list_allControllers.SelectedItems.Clear();
|
||||
}
|
||||
|
||||
private void chooseType_SelectedValueChanged(object sender, EventArgs e) {
|
||||
if (list_customControllers.SelectedItem != null) {
|
||||
SController v = (list_customControllers.SelectedItem as SController);
|
||||
v.type = (byte)(chooseType.SelectedIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
|
@ -13,25 +13,17 @@
|
|||
<!--Whether the Motion Server is enabled or not. Default: true -->
|
||||
<add key="MotionServer" value="true" />
|
||||
|
||||
<!--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: 300 -->
|
||||
<add key="RumblePeriod" value="300" />
|
||||
<!--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: 40 and 120 -->
|
||||
<!--To have "stronger" rumble, try setting the low/high to 160/320-->
|
||||
<add key="LowFreqRumble" value="40" />
|
||||
<add key="HighFreqRumble" value="120" />
|
||||
<!--Don't set above ~1200. Default: 20 and 20 -->
|
||||
<add key="LowFreqRumble" value="20" />
|
||||
<add key="HighFreqRumble" value="20" />
|
||||
<!--Rumble Setting. Turns rumble on or off.-->
|
||||
<!--On is "true"; off is "false". Default: true -->
|
||||
<add key="EnableRumble" value="true" />
|
||||
|
||||
<!--Enables a input when shaking a controller, only works with DS4 for now, replaces the touchpad input (Button 13 on DirectInput)-->
|
||||
<!--On is "true"; off is "false". Default: false -->
|
||||
<add key="EnableShakeInput" value="false" />
|
||||
<!--How sensitve the shake detection should be. Default: 10-->
|
||||
<add key="ShakeInputSensitivity" value="10" />
|
||||
<!--How often should the shake input run in milliseconds. -->
|
||||
<!--Don't set this lower than 15 -->
|
||||
<!-- Default: 200 -->
|
||||
<add key="ShakeInputDelay" value="200" />
|
||||
|
||||
<!--Swap A-B buttons; if on, this mimicks the (half of) Xbox layout by the button name, rather than by the physical layout.-->
|
||||
<!--Also swaps buttons when using "Also use for buttons/axes"-->
|
||||
<!--On is "true"; off is "false". Default: false -->
|
||||
|
@ -41,33 +33,6 @@
|
|||
<!--On is "true"; off is "false". Default: false -->
|
||||
<add key="SwapXY" value="false" />
|
||||
|
||||
<!-- Allows for calibration of the controller's gyro. Adds a "Calibrate" button.-->
|
||||
<!-- When "true", click the "Calibrate" button once to get gyro calibrate data.-->
|
||||
<!-- When enabled, can only calibrate one controller at a time.-->
|
||||
<!-- Default: false -->
|
||||
<add key="AllowCalibration" value="false" />
|
||||
<!-- Allows to emulate the n64 range of joystick (.8, .8) instead of real xbox360 (1, 1). -->
|
||||
<add key="N64Range" value="true" />
|
||||
<!-- Default calibration; used for third party controller -->
|
||||
<add key="acc_sensiti" value="16384,16384,16384"/>
|
||||
<add key="gyr_sensiti" value="18642,18642,18642"/>
|
||||
<add key="stick_cal" value="0x780,0x780,0x780,0x830,0x780,0x780"/>
|
||||
<add key="deadzone" value="200"/>
|
||||
<add key="stick2_cal" value="0x780,0x780,0x780,0x830,0x780,0x780"/>
|
||||
<add key="deadzone2" value="200"/>
|
||||
|
||||
<!-- Scales the xy coordinates each of the joysticks report. Increase this if you can't push the stick to its maximum. -->
|
||||
<add key="StickScalingFactor" value="1.00" />
|
||||
<add key="StickScalingFactor2" value="1.00" />
|
||||
|
||||
<!-- Allows use of gyroscope tilting to get full control of the slider values (big triggers)-->
|
||||
<!-- Works on pro controller and joined joycons (pro controller case - triggers combined, joycons case - separate tilt)-->
|
||||
<!-- Default: false -->
|
||||
<add key="GyroAnalogSliders" value="false" />
|
||||
<!-- Change to -400 to change direction of tilt needed. Positive is ramp up if pointing up-->
|
||||
<!-- Default: 400 -->
|
||||
<add key="GyroAnalogSensitivity" value="400" />
|
||||
|
||||
<!-- Determines whether or not the program should purge the affected devices list upon exit -->
|
||||
<!-- Should prevent any more issues of the controller being unusable after the program (even though this can be fixed if you read the README) -->
|
||||
<!-- Default: true -->
|
||||
|
@ -77,41 +42,28 @@
|
|||
<!-- Default: true -->
|
||||
<add key="PurgeWhitelist" value="false" />
|
||||
<!-- Determines whether or not to use HidGuardian (improves compatibility with other programs, like Steam, when set to "false") -->
|
||||
<!-- When "true", BetterJoy will hide the Pro/Joycons from other programs to prevent glitching out on exit and to prevent DI/XI clashes in certain programs -->
|
||||
<!-- When "true", BetterJoyForCemu will hide the Pro/Joycons from other programs to prevent glitching out on exit and to prevent DI/XI clashes in certain programs -->
|
||||
<!-- Default: false -->
|
||||
<add key="UseHIDG" value="false" />
|
||||
<add key="UseHIDG" value="true" />
|
||||
|
||||
|
||||
<!-- Determines whether or not to enable (experimental - currently default controller to pro) support for 3rd-party controllers. Adds a "Calibrate" button. -->
|
||||
<!-- When "true", click "Calibrate" button once to get gyro calibrate data. -->
|
||||
<!-- When enabled, can only calibrate one controller at a time. -->
|
||||
<!-- Default: false -->
|
||||
<add key="NonOriginalController" value="false" />
|
||||
<!-- The program will keep the HOME button LED ring light on at all times. -->
|
||||
<!-- Default: true -->
|
||||
<add key="HomeLEDOn" value="true"/>
|
||||
<!-- Will use multiple lights to display the current player rather than a single LED-->
|
||||
<add key="UseIncrementalLights" value="true" />
|
||||
|
||||
<!-- Determines whether or not to translate gyro movements into joystick ("joy") or mouse movement ("mouse"), or have no effect ("none") -->
|
||||
<!-- When "joy_left" or "joy_right", turn gyro movements into respective left/right joystick (mouse-like) movements -->
|
||||
<!-- When "joy", turn gyro movements into joystick movement (left/right depends on setting) [not yet implemented]-->
|
||||
<!-- When "mouse", turn gyro movements into mouse movement. Press either stick-button to reset to middle of primary display -->
|
||||
<!-- Default: none -->
|
||||
<add key="GyroToJoyOrMouse" value="false"/>
|
||||
<!-- Whether to use filtered IMU or raw gyro values (the latter is more responsive) -->
|
||||
<!-- Default: true -->
|
||||
<add key="UseFilteredIMU" value="true"/>
|
||||
<!-- Beta value of AHRS. Affects divergence of filter -->
|
||||
<!-- Default: 0.05 -->
|
||||
<add key="AHRS_beta" value="0.05"/>
|
||||
<add key="GyroToJoyOrMouse" value="none"/>
|
||||
<!-- Sensitivity of gyro-to-mouse movements -->
|
||||
<!-- Default: 1200; 800 (if using raw values, decrease by a factor of ~15) -->
|
||||
<add key="GyroMouseSensitivityX" value="1200"/>
|
||||
<add key="GyroMouseSensitivityY" value="800"/>
|
||||
<!-- Sensitivity of gyro-to-joystick movements -->
|
||||
<!-- Default: 40.0; 10.0 (if using raw values, decrease by a factor of ~15: eg 2.6, 0.6) -->
|
||||
<add key="GyroStickSensitivityX" value="40.0"/>
|
||||
<add key="GyroStickSensitivityY" value="10.0"/>
|
||||
<!-- Stick range reduction when gyro-to-joystick is enabled and active; divides range by factor (so 1 is no change; 1.5 is halved range (with deadzone in mind)) -->
|
||||
<!-- Default: 1.5 -->
|
||||
<add key="GyroStickReduction" value="1.5"/>
|
||||
<!-- Gyro Hold/Toggle activation; true will require the mapped button to be continuously held down to keep gyro active -->
|
||||
<!-- Default: true [hold], false [toggle] -->
|
||||
<add key="GyroHoldToggle" value="true"/>
|
||||
<!-- Default: 50 -->
|
||||
<add key="GyroMouseSensitivity" value="50"/>
|
||||
<!-- When two joycons are connected, it would take the gyro movement of the right joycon for mouse movement. This swaps that -->
|
||||
<!-- Default: false -->
|
||||
<add key="GyroMouseLeftHanded" value="false"/>
|
||||
|
@ -121,40 +73,11 @@
|
|||
<add key="DragToggle" value="false"/>
|
||||
|
||||
<!-- Determines whether or not the program will expose detected controllers as Xbox 360 controllers -->
|
||||
<!-- When "false", BetterJoy is only usable with programs that support UDPServer. -->
|
||||
<!-- When "false", BetterJoyForCemu is only usable with CEMU. -->
|
||||
<!-- Default: true -->
|
||||
<add key="ShowAsXInput" value="true" />
|
||||
<!-- Have ShowAsXInput as false if using this -->
|
||||
<!-- Default: false -->
|
||||
<add key="ShowAsDS4" value="false"/>
|
||||
|
||||
<!-- Automatically power off controllers at program exit -->
|
||||
<!-- Default: false -->
|
||||
<add key="AutoPowerOff" value="false" />
|
||||
<!-- Automatically power off controllers after a period of inactivity (in minutes) -->
|
||||
<!-- Default: 30 (-1 indicates infinite time) -->
|
||||
<add key="PowerOffInactivity" value="-1" />
|
||||
<!-- Power off controllers when Capture (left only) or Home (right only or combined) buttons are pressed for a long interval (2s) -->
|
||||
<!-- Default: true -->
|
||||
<add key="HomeLongPowerOff" value="true" />
|
||||
|
||||
<!-- Double click sticks on joycons (L3, R3) to change joycon orientation -->
|
||||
<!-- Default: true -->
|
||||
<add key="ChangeOrientationDoubleClick" value="true" />
|
||||
<!-- Do not rejoin joycons once split via clicking on their icon -->
|
||||
<!-- When 'true' allows you to double-click the joycons to split them and then change their orientation to vertical -->
|
||||
<!-- Default: false -->
|
||||
<add key="DoNotRejoinJoycons" value="false" />
|
||||
|
||||
<!-- Determines what type of debugging information to be printed -->
|
||||
<!-- None = 0 -->
|
||||
<!-- All = 1 -->
|
||||
<!-- Comms = 2 -->
|
||||
<!-- Threading = 3 -->
|
||||
<!-- IMU = 4 -->
|
||||
<!-- Rumble = 5 -->
|
||||
<!-- Shake Input = 6 -->
|
||||
<!-- Default: 0 -->
|
||||
<add key="DebugType" value="0" />
|
||||
</appSettings>
|
||||
</configuration>
|
|
@ -102,8 +102,8 @@
|
|||
<Reference Include="JetBrains.Annotations, Version=2020.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\JetBrains.Annotations.2020.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Nefarius.ViGEm.Client, Version=1.17.178.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Nefarius.ViGEm.Client.1.17.178\lib\net452\Nefarius.ViGEm.Client.dll</HintPath>
|
||||
<Reference Include="Nefarius.ViGEm.Client, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Nefarius.ViGEm.Client.1.0.0\lib\net452\Nefarius.ViGEm.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
|
@ -119,8 +119,8 @@
|
|||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WindowsInput, Version=6.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsInput.6.3.0\lib\net461\WindowsInput.dll</HintPath>
|
||||
<Reference Include="WindowsInput, Version=6.1.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsInput.6.1.1\lib\net461\WindowsInput.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -130,13 +130,9 @@
|
|||
<Compile Include="3rdPartyControllers.Designer.cs">
|
||||
<DependentUpon>3rdPartyControllers.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Collections\ConcurrentList.cs" />
|
||||
<Compile Include="Config.cs" />
|
||||
<Compile Include="Controller\OutputControllerDualShock4.cs" />
|
||||
<Compile Include="Controller\OutputControllerXbox360.cs" />
|
||||
<Compile Include="HIDapi.cs" />
|
||||
<Compile Include="Joycon.cs" />
|
||||
<Compile Include="MadgwickAHRS.cs" />
|
||||
<Compile Include="MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -180,12 +176,6 @@
|
|||
<None Include="Drivers\HIDGuardian\_drivers\HidGuardian\HidGuardian.sys">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="Drivers\ViGEmBusSetup_x64.msi">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Drivers\ViGEmBusSetup_x86.msi">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -238,14 +228,13 @@
|
|||
<Content Include="Drivers\README.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Icons\snes.png" />
|
||||
<Content Include="Icons\ultra.png" />
|
||||
<None Include="Properties\app.manifest" />
|
||||
<Content Include="Icons\betterjoyforcemu_icon.ico" />
|
||||
<Content Include="x86\hidapi.dll">
|
||||
<Content Include="Drivers\ViGEmBus_Setup_1.16.116.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x64\hidapi.dll">
|
||||
<Content Include="Icons\snes.png" />
|
||||
<None Include="Properties\app.manifest" />
|
||||
<Content Include="Icons\betterjoyforcemu_icon.ico" />
|
||||
<Content Include="hidapi.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Icons\cross.png" />
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BetterJoyForCemu.Collections {
|
||||
|
||||
// https://codereview.stackexchange.com/a/125341
|
||||
public class ConcurrentList<T> : IList<T> {
|
||||
#region Fields
|
||||
|
||||
private IList<T> _internalList;
|
||||
|
||||
private readonly object lockObject = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
#region ctor
|
||||
|
||||
public ConcurrentList() {
|
||||
_internalList = new List<T>();
|
||||
}
|
||||
|
||||
public ConcurrentList(int capacity) {
|
||||
_internalList = new List<T>(capacity);
|
||||
}
|
||||
|
||||
public ConcurrentList(IEnumerable<T> list) {
|
||||
_internalList = new List<T>();
|
||||
foreach (T item in list) {
|
||||
_internalList.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public T this[int index] {
|
||||
get {
|
||||
return LockInternalListAndGet(l => l[index]);
|
||||
}
|
||||
|
||||
set {
|
||||
LockInternalListAndCommand(l => l[index] = value);
|
||||
}
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return LockInternalListAndQuery(l => l.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public void Add(T item) {
|
||||
LockInternalListAndCommand(l => l.Add(item));
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
LockInternalListAndCommand(l => l.Clear());
|
||||
}
|
||||
|
||||
public bool Contains(T item) {
|
||||
return LockInternalListAndQuery(l => l.Contains(item));
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex) {
|
||||
LockInternalListAndCommand(l => l.CopyTo(array, arrayIndex));
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator() {
|
||||
return LockInternalListAndQuery(l => l.GetEnumerator());
|
||||
}
|
||||
|
||||
public int IndexOf(T item) {
|
||||
return LockInternalListAndQuery(l => l.IndexOf(item));
|
||||
}
|
||||
|
||||
public void Insert(int index, T item) {
|
||||
LockInternalListAndCommand(l => l.Insert(index, item));
|
||||
}
|
||||
|
||||
public bool Remove(T item) {
|
||||
return LockInternalListAndQuery(l => l.Remove(item));
|
||||
}
|
||||
|
||||
public void RemoveAt(int index) {
|
||||
LockInternalListAndCommand(l => l.RemoveAt(index));
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return LockInternalListAndQuery(l => l.GetEnumerator());
|
||||
}
|
||||
|
||||
#region Utilities
|
||||
|
||||
protected virtual void LockInternalListAndCommand(Action<IList<T>> action) {
|
||||
lock (lockObject) {
|
||||
action(_internalList);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual T LockInternalListAndGet(Func<IList<T>, T> func) {
|
||||
lock (lockObject) {
|
||||
return func(_internalList);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual TObject LockInternalListAndQuery<TObject>(Func<IList<T>, TObject> query) {
|
||||
lock (lockObject) {
|
||||
return query(_internalList);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterJoyForCemu {
|
||||
public static class Config { // stores dynamic configuration, including
|
||||
static readonly string path;
|
||||
const string PATH = "settings";
|
||||
static Dictionary<string, string> variables = new Dictionary<string, string>();
|
||||
|
||||
const int settingsNum = 11; // currently - ProgressiveScan, StartInTray + special buttons
|
||||
|
||||
static Config() {
|
||||
path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\settings";
|
||||
}
|
||||
const int settingsNum = 10; // currently - ProgressiveScan, StartInTray + special buttons
|
||||
|
||||
public static string GetDefaultValue(string s) {
|
||||
switch(s) {
|
||||
|
@ -25,36 +24,15 @@ namespace BetterJoyForCemu {
|
|||
return "0";
|
||||
}
|
||||
|
||||
// Helper function to count how many lines are in a file
|
||||
// https://www.dotnetperls.com/line-count
|
||||
static long CountLinesInFile(string f) {
|
||||
// Zero based count
|
||||
long count = -1;
|
||||
using (StreamReader r = new StreamReader(f)) {
|
||||
string line;
|
||||
while ((line = r.ReadLine()) != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void Init(List<KeyValuePair<string, float[]>> caliData) {
|
||||
foreach (string s in new string[] { "ProgressiveScan", "StartInTray", "capture", "home", "sl_l", "sl_r", "sr_l", "sr_r", "shake", "reset_mouse", "active_gyro" })
|
||||
foreach (string s in new string[] { "ProgressiveScan", "StartInTray", "capture", "home", "sl_l", "sl_r", "sr_l", "sr_r", "reset_mouse", "active_gyro" })
|
||||
variables[s] = GetDefaultValue(s);
|
||||
|
||||
if (File.Exists(path)) {
|
||||
|
||||
// Reset settings file if old settings
|
||||
if (CountLinesInFile(path) < settingsNum) {
|
||||
File.Delete(path);
|
||||
Init(caliData);
|
||||
return;
|
||||
}
|
||||
|
||||
using (StreamReader file = new StreamReader(path)) {
|
||||
string line = String.Empty;
|
||||
if (File.Exists(PATH)) {
|
||||
int lineNO = 0;
|
||||
using (StreamReader file = new StreamReader(PATH)) {
|
||||
string line = String.Empty;
|
||||
|
||||
while ((line = file.ReadLine()) != null) {
|
||||
string[] vs = line.Split();
|
||||
try {
|
||||
|
@ -77,9 +55,17 @@ namespace BetterJoyForCemu {
|
|||
} catch { }
|
||||
lineNO++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// if old settings
|
||||
if (lineNO < settingsNum) {
|
||||
File.Delete(PATH);
|
||||
Init(caliData);
|
||||
}
|
||||
} else {
|
||||
using (StreamWriter file = new StreamWriter(path)) {
|
||||
using (StreamWriter file = new StreamWriter(PATH)) {
|
||||
foreach (string k in variables.Keys)
|
||||
file.WriteLine(String.Format("{0} {1}", k, variables[k]));
|
||||
string caliStr = "";
|
||||
|
@ -115,7 +101,7 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
public static void SaveCaliData(List<KeyValuePair<string, float[]>> caliData) {
|
||||
string[] txt = File.ReadAllLines(path);
|
||||
string[] txt = File.ReadAllLines(PATH);
|
||||
if (txt.Length < settingsNum + 1) // no custom calibrations yet
|
||||
Array.Resize(ref txt, txt.Length + 1);
|
||||
|
||||
|
@ -125,18 +111,18 @@ namespace BetterJoyForCemu {
|
|||
if (i == 0) space = "";
|
||||
caliStr += space + caliData[i].Key + "," + String.Join(",", caliData[i].Value);
|
||||
}
|
||||
txt[settingsNum] = caliStr;
|
||||
File.WriteAllLines(path, txt);
|
||||
txt[2] = caliStr;
|
||||
File.WriteAllLines(PATH, txt);
|
||||
}
|
||||
|
||||
public static void Save() {
|
||||
string[] txt = File.ReadAllLines(path);
|
||||
string[] txt = File.ReadAllLines(PATH);
|
||||
int NO = 0;
|
||||
foreach (string k in variables.Keys) {
|
||||
txt[NO] = String.Format("{0} {1}", k, variables[k]);
|
||||
NO++;
|
||||
}
|
||||
File.WriteAllLines(path, txt);
|
||||
File.WriteAllLines(PATH, txt);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
using System;
|
||||
using Nefarius.ViGEm.Client.Targets;
|
||||
using Nefarius.ViGEm.Client.Targets.DualShock4;
|
||||
|
||||
namespace BetterJoyForCemu.Controller {
|
||||
public enum DpadDirection {
|
||||
None,
|
||||
Northwest,
|
||||
West,
|
||||
Southwest,
|
||||
South,
|
||||
Southeast,
|
||||
East,
|
||||
Northeast,
|
||||
North,
|
||||
}
|
||||
|
||||
public struct OutputControllerDualShock4InputState {
|
||||
public bool triangle;
|
||||
public bool circle;
|
||||
public bool cross;
|
||||
public bool square;
|
||||
|
||||
public bool trigger_left;
|
||||
public bool trigger_right;
|
||||
|
||||
public bool shoulder_left;
|
||||
public bool shoulder_right;
|
||||
|
||||
public bool options;
|
||||
public bool share;
|
||||
public bool ps;
|
||||
public bool touchpad;
|
||||
|
||||
public bool thumb_left;
|
||||
public bool thumb_right;
|
||||
|
||||
public DpadDirection dPad;
|
||||
|
||||
public byte thumb_left_x;
|
||||
public byte thumb_left_y;
|
||||
public byte thumb_right_x;
|
||||
public byte thumb_right_y;
|
||||
|
||||
public byte trigger_left_value;
|
||||
public byte trigger_right_value;
|
||||
|
||||
public bool IsEqual(OutputControllerDualShock4InputState other) {
|
||||
bool buttons = triangle == other.triangle
|
||||
&& circle == other.circle
|
||||
&& cross == other.cross
|
||||
&& square == other.square
|
||||
&& trigger_left == other.trigger_left
|
||||
&& trigger_right == other.trigger_right
|
||||
&& shoulder_left == other.shoulder_left
|
||||
&& shoulder_right == other.shoulder_right
|
||||
&& options == other.options
|
||||
&& share == other.share
|
||||
&& ps == other.ps
|
||||
&& touchpad == other.touchpad
|
||||
&& thumb_left == other.thumb_left
|
||||
&& thumb_right == other.thumb_right
|
||||
&& dPad == other.dPad;
|
||||
|
||||
bool axis = thumb_left_x == other.thumb_left_x
|
||||
&& thumb_left_y == other.thumb_left_y
|
||||
&& thumb_right_x == other.thumb_right_x
|
||||
&& thumb_right_y == other.thumb_right_y;
|
||||
|
||||
bool triggers = trigger_left_value == other.trigger_left_value
|
||||
&& trigger_right_value == other.trigger_right_value;
|
||||
|
||||
return buttons && axis && triggers;
|
||||
}
|
||||
}
|
||||
|
||||
public class OutputControllerDualShock4 {
|
||||
private IDualShock4Controller controller;
|
||||
|
||||
private OutputControllerDualShock4InputState current_state;
|
||||
|
||||
|
||||
public delegate void DualShock4FeedbackReceivedEventHandler(DualShock4FeedbackReceivedEventArgs e);
|
||||
public event DualShock4FeedbackReceivedEventHandler FeedbackReceived;
|
||||
|
||||
public OutputControllerDualShock4() {
|
||||
controller = Program.emClient.CreateDualShock4Controller();
|
||||
Init();
|
||||
}
|
||||
|
||||
public OutputControllerDualShock4(ushort vendor_id, ushort product_id) {
|
||||
controller = Program.emClient.CreateDualShock4Controller(vendor_id, product_id);
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init() {
|
||||
controller.AutoSubmitReport = false;
|
||||
controller.FeedbackReceived += FeedbackReceivedRcv;
|
||||
}
|
||||
|
||||
private void FeedbackReceivedRcv(object _sender, DualShock4FeedbackReceivedEventArgs e) {
|
||||
FeedbackReceived(e);
|
||||
}
|
||||
|
||||
public void Connect() {
|
||||
controller.Connect();
|
||||
}
|
||||
|
||||
public void Disconnect() {
|
||||
controller.Disconnect();
|
||||
}
|
||||
|
||||
public bool UpdateInput(OutputControllerDualShock4InputState new_state) {
|
||||
if (current_state.IsEqual(new_state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DoUpdateInput(new_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DoUpdateInput(OutputControllerDualShock4InputState new_state) {
|
||||
controller.SetButtonState(DualShock4Button.Triangle, new_state.triangle);
|
||||
controller.SetButtonState(DualShock4Button.Circle, new_state.circle);
|
||||
controller.SetButtonState(DualShock4Button.Cross, new_state.cross);
|
||||
controller.SetButtonState(DualShock4Button.Square, new_state.square);
|
||||
|
||||
controller.SetButtonState(DualShock4Button.ShoulderLeft, new_state.shoulder_left);
|
||||
controller.SetButtonState(DualShock4Button.ShoulderRight, new_state.shoulder_right);
|
||||
|
||||
controller.SetButtonState(DualShock4Button.TriggerLeft, new_state.trigger_left);
|
||||
controller.SetButtonState(DualShock4Button.TriggerRight, new_state.trigger_right);
|
||||
|
||||
controller.SetButtonState(DualShock4Button.ThumbLeft, new_state.thumb_left);
|
||||
controller.SetButtonState(DualShock4Button.ThumbRight, new_state.thumb_right);
|
||||
|
||||
controller.SetButtonState(DualShock4Button.Share, new_state.share);
|
||||
controller.SetButtonState(DualShock4Button.Options, new_state.options);
|
||||
controller.SetButtonState(DualShock4SpecialButton.Ps, new_state.ps);
|
||||
controller.SetButtonState(DualShock4SpecialButton.Touchpad, new_state.touchpad);
|
||||
|
||||
controller.SetDPadDirection(MapDPadDirection(new_state.dPad));
|
||||
|
||||
controller.SetAxisValue(DualShock4Axis.LeftThumbX, new_state.thumb_left_x);
|
||||
controller.SetAxisValue(DualShock4Axis.LeftThumbY, new_state.thumb_left_y);
|
||||
controller.SetAxisValue(DualShock4Axis.RightThumbX, new_state.thumb_right_x);
|
||||
controller.SetAxisValue(DualShock4Axis.RightThumbY, new_state.thumb_right_y);
|
||||
|
||||
controller.SetSliderValue(DualShock4Slider.LeftTrigger, new_state.trigger_left_value);
|
||||
controller.SetSliderValue(DualShock4Slider.RightTrigger, new_state.trigger_right_value);
|
||||
|
||||
controller.SubmitReport();
|
||||
|
||||
current_state = new_state;
|
||||
}
|
||||
|
||||
private DualShock4DPadDirection MapDPadDirection(DpadDirection dPad) {
|
||||
switch (dPad) {
|
||||
case DpadDirection.None: return DualShock4DPadDirection.None;
|
||||
case DpadDirection.North: return DualShock4DPadDirection.North;
|
||||
case DpadDirection.Northeast: return DualShock4DPadDirection.Northeast;
|
||||
case DpadDirection.East: return DualShock4DPadDirection.East;
|
||||
case DpadDirection.Southeast: return DualShock4DPadDirection.Southeast;
|
||||
case DpadDirection.South: return DualShock4DPadDirection.South;
|
||||
case DpadDirection.Southwest: return DualShock4DPadDirection.Southwest;
|
||||
case DpadDirection.West: return DualShock4DPadDirection.West;
|
||||
case DpadDirection.Northwest: return DualShock4DPadDirection.Northwest;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
using Nefarius.ViGEm.Client.Targets;
|
||||
using Nefarius.ViGEm.Client.Targets.Xbox360;
|
||||
|
||||
namespace BetterJoyForCemu.Controller {
|
||||
public struct OutputControllerXbox360InputState {
|
||||
// buttons
|
||||
public bool thumb_stick_left;
|
||||
public bool thumb_stick_right;
|
||||
|
||||
public bool y;
|
||||
public bool x;
|
||||
public bool b;
|
||||
public bool a;
|
||||
|
||||
public bool start;
|
||||
public bool back;
|
||||
|
||||
public bool guide;
|
||||
|
||||
public bool shoulder_left;
|
||||
public bool shoulder_right;
|
||||
|
||||
// dpad
|
||||
public bool dpad_up;
|
||||
public bool dpad_right;
|
||||
public bool dpad_down;
|
||||
public bool dpad_left;
|
||||
|
||||
// axis
|
||||
public short axis_left_x;
|
||||
public short axis_left_y;
|
||||
|
||||
public short axis_right_x;
|
||||
public short axis_right_y;
|
||||
|
||||
// triggers
|
||||
public byte trigger_left;
|
||||
public byte trigger_right;
|
||||
|
||||
public bool IsEqual(OutputControllerXbox360InputState other) {
|
||||
bool buttons = thumb_stick_left == other.thumb_stick_left
|
||||
&& thumb_stick_right == other.thumb_stick_right
|
||||
&& y == other.y
|
||||
&& x == other.x
|
||||
&& b == other.b
|
||||
&& a == other.a
|
||||
&& start == other.start
|
||||
&& back == other.back
|
||||
&& guide == other.guide
|
||||
&& shoulder_left == other.shoulder_left
|
||||
&& shoulder_right == other.shoulder_right;
|
||||
|
||||
bool dpad = dpad_up == other.dpad_up
|
||||
&& dpad_right == other.dpad_right
|
||||
&& dpad_down == other.dpad_down
|
||||
&& dpad_left == other.dpad_left;
|
||||
|
||||
bool axis = axis_left_x == other.axis_left_x
|
||||
&& axis_left_y == other.axis_left_y
|
||||
&& axis_right_x == other.axis_right_x
|
||||
&& axis_right_y == other.axis_right_y;
|
||||
|
||||
bool triggers = trigger_left == other.trigger_left
|
||||
&& trigger_right == other.trigger_right;
|
||||
|
||||
return buttons && dpad && axis && triggers;
|
||||
}
|
||||
}
|
||||
|
||||
public class OutputControllerXbox360 {
|
||||
private IXbox360Controller xbox_controller;
|
||||
private OutputControllerXbox360InputState current_state;
|
||||
|
||||
public delegate void Xbox360FeedbackReceivedEventHandler(Xbox360FeedbackReceivedEventArgs e);
|
||||
|
||||
public event Xbox360FeedbackReceivedEventHandler FeedbackReceived;
|
||||
|
||||
public OutputControllerXbox360() {
|
||||
xbox_controller = Program.emClient.CreateXbox360Controller();
|
||||
Init();
|
||||
}
|
||||
|
||||
public OutputControllerXbox360(ushort vendor_id, ushort product_id) {
|
||||
xbox_controller = Program.emClient.CreateXbox360Controller(vendor_id, product_id);
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init() {
|
||||
xbox_controller.FeedbackReceived += FeedbackReceivedRcv;
|
||||
xbox_controller.AutoSubmitReport = false;
|
||||
}
|
||||
|
||||
private void FeedbackReceivedRcv(object _sender, Xbox360FeedbackReceivedEventArgs e) {
|
||||
if(FeedbackReceived!=null)
|
||||
FeedbackReceived(e);
|
||||
}
|
||||
|
||||
public bool UpdateInput(OutputControllerXbox360InputState new_state) {
|
||||
if (current_state.IsEqual(new_state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DoUpdateInput(new_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Connect() {
|
||||
xbox_controller.Connect();
|
||||
DoUpdateInput(new OutputControllerXbox360InputState());
|
||||
}
|
||||
|
||||
public void Disconnect() {
|
||||
xbox_controller.Disconnect();
|
||||
}
|
||||
|
||||
private void DoUpdateInput(OutputControllerXbox360InputState new_state) {
|
||||
xbox_controller.SetButtonState(Xbox360Button.LeftThumb, new_state.thumb_stick_left);
|
||||
xbox_controller.SetButtonState(Xbox360Button.RightThumb, new_state.thumb_stick_right);
|
||||
|
||||
xbox_controller.SetButtonState(Xbox360Button.Y, new_state.y);
|
||||
xbox_controller.SetButtonState(Xbox360Button.X, new_state.x);
|
||||
xbox_controller.SetButtonState(Xbox360Button.B, new_state.b);
|
||||
xbox_controller.SetButtonState(Xbox360Button.A, new_state.a);
|
||||
|
||||
xbox_controller.SetButtonState(Xbox360Button.Start, new_state.start);
|
||||
xbox_controller.SetButtonState(Xbox360Button.Back, new_state.back);
|
||||
xbox_controller.SetButtonState(Xbox360Button.Guide, new_state.guide);
|
||||
|
||||
xbox_controller.SetButtonState(Xbox360Button.Up, new_state.dpad_up);
|
||||
xbox_controller.SetButtonState(Xbox360Button.Right, new_state.dpad_right);
|
||||
xbox_controller.SetButtonState(Xbox360Button.Down, new_state.dpad_down);
|
||||
xbox_controller.SetButtonState(Xbox360Button.Left, new_state.dpad_left);
|
||||
|
||||
xbox_controller.SetButtonState(Xbox360Button.LeftShoulder, new_state.shoulder_left);
|
||||
xbox_controller.SetButtonState(Xbox360Button.RightShoulder, new_state.shoulder_right);
|
||||
|
||||
xbox_controller.SetAxisValue(Xbox360Axis.LeftThumbX, new_state.axis_left_x);
|
||||
xbox_controller.SetAxisValue(Xbox360Axis.LeftThumbY, new_state.axis_left_y);
|
||||
xbox_controller.SetAxisValue(Xbox360Axis.RightThumbX, new_state.axis_right_x);
|
||||
xbox_controller.SetAxisValue(Xbox360Axis.RightThumbY, new_state.axis_right_y);
|
||||
|
||||
xbox_controller.SetSliderValue(Xbox360Slider.LeftTrigger, new_state.trigger_left);
|
||||
xbox_controller.SetSliderValue(Xbox360Slider.RightTrigger, new_state.trigger_right);
|
||||
|
||||
xbox_controller.SubmitReport();
|
||||
|
||||
current_state = new_state;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
BetterJoyForCemu/Drivers/ViGEmBus_Setup_1.16.116.exe
Normal file
BIN
BetterJoyForCemu/Drivers/ViGEmBus_Setup_1.16.116.exe
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 31 KiB |
File diff suppressed because it is too large
Load diff
|
@ -1,162 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// source: https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MadgwickAHRS.cs
|
||||
|
||||
namespace BetterJoyForCemu {
|
||||
/// <summary>
|
||||
/// MadgwickAHRS class. Implementation of Madgwick's IMU and AHRS algorithms.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
|
||||
/// </remarks>
|
||||
public class MadgwickAHRS {
|
||||
/// <summary>
|
||||
/// Gets or sets the sample period.
|
||||
/// </summary>
|
||||
public float SamplePeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the algorithm gain beta.
|
||||
/// </summary>
|
||||
public float Beta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Quaternion output.
|
||||
/// </summary>
|
||||
public float[] Quaternion { get; set; }
|
||||
|
||||
public float[] old_pitchYawRoll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MadgwickAHRS"/> class.
|
||||
/// </summary>
|
||||
/// <param name="samplePeriod">
|
||||
/// Sample period.
|
||||
/// </param>
|
||||
public MadgwickAHRS(float samplePeriod)
|
||||
: this(samplePeriod, 1f) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MadgwickAHRS"/> class.
|
||||
/// </summary>
|
||||
/// <param name="samplePeriod">
|
||||
/// Sample period.
|
||||
/// </param>
|
||||
/// <param name="beta">
|
||||
/// Algorithm gain beta.
|
||||
/// </param>
|
||||
public MadgwickAHRS(float samplePeriod, float beta) {
|
||||
SamplePeriod = samplePeriod;
|
||||
Beta = beta;
|
||||
Quaternion = new float[] { 1f, 0f, 0f, 0f };
|
||||
old_pitchYawRoll = new float[] { 0f, 0f, 0f };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Algorithm IMU update method. Requires only gyroscope and accelerometer data.
|
||||
/// </summary>
|
||||
/// <param name="gx">
|
||||
/// Gyroscope x axis measurement in radians/s.
|
||||
/// </param>
|
||||
/// <param name="gy">
|
||||
/// Gyroscope y axis measurement in radians/s.
|
||||
/// </param>
|
||||
/// <param name="gz">
|
||||
/// Gyroscope z axis measurement in radians/s.
|
||||
/// </param>
|
||||
/// <param name="ax">
|
||||
/// Accelerometer x axis measurement in any calibrated units.
|
||||
/// </param>
|
||||
/// <param name="ay">
|
||||
/// Accelerometer y axis measurement in any calibrated units.
|
||||
/// </param>
|
||||
/// <param name="az">
|
||||
/// Accelerometer z axis measurement in any calibrated units.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Optimised for minimal arithmetic.
|
||||
/// Total ±: 45
|
||||
/// Total *: 85
|
||||
/// Total /: 3
|
||||
/// Total sqrt: 3
|
||||
/// </remarks>
|
||||
public void Update(float gx, float gy, float gz, float ax, float ay, float az) {
|
||||
float q1 = Quaternion[0], q2 = Quaternion[1], q3 = Quaternion[2], q4 = Quaternion[3]; // short name local variable for readability
|
||||
float norm;
|
||||
float s1, s2, s3, s4;
|
||||
float qDot1, qDot2, qDot3, qDot4;
|
||||
|
||||
// Auxiliary variables to avoid repeated arithmetic
|
||||
float _2q1 = 2f * q1;
|
||||
float _2q2 = 2f * q2;
|
||||
float _2q3 = 2f * q3;
|
||||
float _2q4 = 2f * q4;
|
||||
float _4q1 = 4f * q1;
|
||||
float _4q2 = 4f * q2;
|
||||
float _4q3 = 4f * q3;
|
||||
float _8q2 = 8f * q2;
|
||||
float _8q3 = 8f * q3;
|
||||
float q1q1 = q1 * q1;
|
||||
float q2q2 = q2 * q2;
|
||||
float q3q3 = q3 * q3;
|
||||
float q4q4 = q4 * q4;
|
||||
|
||||
// Normalise accelerometer measurement
|
||||
norm = (float)Math.Sqrt(ax * ax + ay * ay + az * az);
|
||||
if (norm == 0f) return; // handle NaN
|
||||
norm = 1 / norm; // use reciprocal for division
|
||||
ax *= norm;
|
||||
ay *= norm;
|
||||
az *= norm;
|
||||
|
||||
// Gradient decent algorithm corrective step
|
||||
s1 = _4q1 * q3q3 + _2q3 * ax + _4q1 * q2q2 - _2q2 * ay;
|
||||
s2 = _4q2 * q4q4 - _2q4 * ax + 4f * q1q1 * q2 - _2q1 * ay - _4q2 + _8q2 * q2q2 + _8q2 * q3q3 + _4q2 * az;
|
||||
s3 = 4f * q1q1 * q3 + _2q1 * ax + _4q3 * q4q4 - _2q4 * ay - _4q3 + _8q3 * q2q2 + _8q3 * q3q3 + _4q3 * az;
|
||||
s4 = 4f * q2q2 * q4 - _2q2 * ax + 4f * q3q3 * q4 - _2q3 * ay;
|
||||
norm = 1f / (float)Math.Sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise step magnitude
|
||||
s1 *= norm;
|
||||
s2 *= norm;
|
||||
s3 *= norm;
|
||||
s4 *= norm;
|
||||
|
||||
// Compute rate of change of quaternion
|
||||
qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - Beta * s1;
|
||||
qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - Beta * s2;
|
||||
qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - Beta * s3;
|
||||
qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - Beta * s4;
|
||||
|
||||
// Integrate to yield quaternion
|
||||
q1 += qDot1 * SamplePeriod;
|
||||
q2 += qDot2 * SamplePeriod;
|
||||
q3 += qDot3 * SamplePeriod;
|
||||
q4 += qDot4 * SamplePeriod;
|
||||
norm = 1f / (float)Math.Sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise quaternion
|
||||
Quaternion[0] = q1 * norm;
|
||||
Quaternion[1] = q2 * norm;
|
||||
Quaternion[2] = q3 * norm;
|
||||
Quaternion[3] = q4 * norm;
|
||||
}
|
||||
|
||||
public float[] GetEulerAngles() {
|
||||
float[] pitchYawRoll = new float[3];
|
||||
float q0 = Quaternion[0], q1 = Quaternion[1], q2 = Quaternion[2], q3 = Quaternion[3];
|
||||
float sq1 = q1 * q1, sq2 = q2 * q2, sq3 = q3 * q3;
|
||||
pitchYawRoll[0] = (float)Math.Asin(2f * (q0 * q2 - q3 * q1)); // Pitch
|
||||
pitchYawRoll[1] = (float)Math.Atan2(2f * (q0 * q3 + q1 * q2), 1 - 2f * (sq2 + sq3)); // Yaw
|
||||
pitchYawRoll[2] = (float)Math.Atan2(2f * (q0 * q1 + q2 * q3), 1 - 2f * (sq1 + sq2)); // Roll
|
||||
|
||||
float[] returnAngles = new float[6];
|
||||
Array.Copy(pitchYawRoll, returnAngles, 3);
|
||||
Array.Copy(old_pitchYawRoll, 0, returnAngles, 3, 3);
|
||||
old_pitchYawRoll = pitchYawRoll;
|
||||
|
||||
return returnAngles;
|
||||
}
|
||||
}
|
||||
}
|
38
BetterJoyForCemu/MainForm.Designer.cs
generated
38
BetterJoyForCemu/MainForm.Designer.cs
generated
|
@ -26,6 +26,7 @@
|
|||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.console = new System.Windows.Forms.TextBox();
|
||||
this.console_lbl = 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();
|
||||
|
@ -63,17 +64,26 @@
|
|||
this.console.Multiline = true;
|
||||
this.console.Name = "console";
|
||||
this.console.ReadOnly = true;
|
||||
this.console.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.console.Size = new System.Drawing.Size(262, 100);
|
||||
this.console.TabIndex = 2;
|
||||
//
|
||||
// console_lbl
|
||||
//
|
||||
this.console_lbl.AutoSize = true;
|
||||
this.console_lbl.Location = new System.Drawing.Point(9, 116);
|
||||
this.console_lbl.Name = "console_lbl";
|
||||
this.console_lbl.Size = new System.Drawing.Size(80, 13);
|
||||
this.console_lbl.TabIndex = 1;
|
||||
this.console_lbl.Text = "Console Output";
|
||||
this.console_lbl.TextAlign = System.Drawing.ContentAlignment.TopCenter;
|
||||
//
|
||||
// notifyIcon
|
||||
//
|
||||
this.notifyIcon.BalloonTipText = "Double click the tray icon to maximise!";
|
||||
this.notifyIcon.BalloonTipTitle = "BetterJoy";
|
||||
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 = "BetterJoy";
|
||||
this.notifyIcon.Text = "BetterJoyForCemu";
|
||||
this.notifyIcon.Visible = true;
|
||||
this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
|
||||
//
|
||||
|
@ -99,7 +109,7 @@
|
|||
this.version_lbl.Name = "version_lbl";
|
||||
this.version_lbl.Size = new System.Drawing.Size(28, 13);
|
||||
this.version_lbl.TabIndex = 2;
|
||||
this.version_lbl.Text = "v7.1";
|
||||
this.version_lbl.Text = "v6.0";
|
||||
//
|
||||
// passiveScanBox
|
||||
//
|
||||
|
@ -254,7 +264,7 @@
|
|||
//
|
||||
// btn_open3rdP
|
||||
//
|
||||
this.btn_open3rdP.Location = new System.Drawing.Point(93, 112);
|
||||
this.btn_open3rdP.Location = new System.Drawing.Point(188, 112);
|
||||
this.btn_open3rdP.Name = "btn_open3rdP";
|
||||
this.btn_open3rdP.Size = new System.Drawing.Size(86, 20);
|
||||
this.btn_open3rdP.TabIndex = 7;
|
||||
|
@ -269,7 +279,7 @@
|
|||
this.groupBox1.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(2);
|
||||
this.groupBox1.Size = new System.Drawing.Size(304, 242);
|
||||
this.groupBox1.Size = new System.Drawing.Size(227, 242);
|
||||
this.groupBox1.TabIndex = 9;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Config";
|
||||
|
@ -287,7 +297,7 @@
|
|||
this.settingsTable.Name = "settingsTable";
|
||||
this.settingsTable.RowCount = 1;
|
||||
this.settingsTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.settingsTable.Size = new System.Drawing.Size(300, 219);
|
||||
this.settingsTable.Size = new System.Drawing.Size(219, 219);
|
||||
this.settingsTable.TabIndex = 1;
|
||||
//
|
||||
// rightPanel
|
||||
|
@ -297,7 +307,7 @@
|
|||
this.rightPanel.Location = new System.Drawing.Point(289, 1);
|
||||
this.rightPanel.Margin = new System.Windows.Forms.Padding(2, 2, 12, 2);
|
||||
this.rightPanel.Name = "rightPanel";
|
||||
this.rightPanel.Size = new System.Drawing.Size(312, 273);
|
||||
this.rightPanel.Size = new System.Drawing.Size(231, 273);
|
||||
this.rightPanel.TabIndex = 11;
|
||||
this.rightPanel.Visible = false;
|
||||
//
|
||||
|
@ -305,7 +315,7 @@
|
|||
//
|
||||
this.settingsApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.settingsApply.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.settingsApply.Location = new System.Drawing.Point(246, 252);
|
||||
this.settingsApply.Location = new System.Drawing.Point(165, 252);
|
||||
this.settingsApply.Margin = new System.Windows.Forms.Padding(2);
|
||||
this.settingsApply.Name = "settingsApply";
|
||||
this.settingsApply.Size = new System.Drawing.Size(61, 21);
|
||||
|
@ -326,7 +336,7 @@
|
|||
//
|
||||
// btn_reassign_open
|
||||
//
|
||||
this.btn_reassign_open.Location = new System.Drawing.Point(12, 112);
|
||||
this.btn_reassign_open.Location = new System.Drawing.Point(107, 112);
|
||||
this.btn_reassign_open.Name = "btn_reassign_open";
|
||||
this.btn_reassign_open.Size = new System.Drawing.Size(75, 20);
|
||||
this.btn_reassign_open.TabIndex = 13;
|
||||
|
@ -340,7 +350,7 @@
|
|||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.ClientSize = new System.Drawing.Size(615, 308);
|
||||
this.ClientSize = new System.Drawing.Size(284, 261);
|
||||
this.Controls.Add(this.btn_reassign_open);
|
||||
this.Controls.Add(this.foldLbl);
|
||||
this.Controls.Add(this.rightPanel);
|
||||
|
@ -351,6 +361,7 @@
|
|||
this.Controls.Add(this.donationLink);
|
||||
this.Controls.Add(this.passiveScanBox);
|
||||
this.Controls.Add(this.version_lbl);
|
||||
this.Controls.Add(this.console_lbl);
|
||||
this.Controls.Add(this.console);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
|
@ -372,7 +383,8 @@
|
|||
#endregion
|
||||
|
||||
public System.Windows.Forms.TextBox console;
|
||||
public System.Windows.Forms.NotifyIcon notifyIcon;
|
||||
private System.Windows.Forms.Label console_lbl;
|
||||
private System.Windows.Forms.NotifyIcon notifyIcon;
|
||||
private System.Windows.Forms.Label version_lbl;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
|
|
|
@ -15,22 +15,13 @@ using System.Xml.Linq;
|
|||
|
||||
namespace BetterJoyForCemu {
|
||||
public partial class MainForm : Form {
|
||||
public bool allowCalibration = Boolean.Parse(ConfigurationManager.AppSettings["AllowCalibration"]);
|
||||
public bool nonOriginal = Boolean.Parse(ConfigurationManager.AppSettings["NonOriginalController"]);
|
||||
public List<Button> con, loc;
|
||||
public bool calibrate;
|
||||
public List<KeyValuePair<string, float[]>> caliData;
|
||||
private Timer countDown;
|
||||
private int count;
|
||||
public List<int> xG, yG, zG, xA, yA, zA;
|
||||
public bool shakeInputEnabled = Boolean.Parse(ConfigurationManager.AppSettings["EnableShakeInput"]);
|
||||
public float shakeSesitivity = float.Parse(ConfigurationManager.AppSettings["ShakeInputSensitivity"]);
|
||||
public float shakeDelay = float.Parse(ConfigurationManager.AppSettings["ShakeInputDelay"]);
|
||||
|
||||
public enum NonOriginalController : int {
|
||||
Disabled = 0,
|
||||
DefaultCalibration = 1,
|
||||
ControllerCalibration = 2,
|
||||
}
|
||||
|
||||
public MainForm() {
|
||||
xG = new List<int>(); yG = new List<int>(); zG = new List<int>();
|
||||
|
@ -41,15 +32,18 @@ namespace BetterJoyForCemu {
|
|||
|
||||
InitializeComponent();
|
||||
|
||||
if (!allowCalibration)
|
||||
if (!nonOriginal)
|
||||
AutoCalibrate.Hide();
|
||||
|
||||
// Feature not yet implemented - hide
|
||||
btn_open3rdP.Hide();
|
||||
|
||||
con = new List<Button> { con1, con2, con3, con4 };
|
||||
loc = new List<Button> { loc1, loc2, loc3, loc4 };
|
||||
|
||||
//list all options
|
||||
string[] myConfigs = ConfigurationManager.AppSettings.AllKeys;
|
||||
Size childSize = new Size(150, 20);
|
||||
Size childSize = new Size(87, 20);
|
||||
for (int i = 0; i != myConfigs.Length; i++) {
|
||||
settingsTable.RowCount++;
|
||||
settingsTable.Controls.Add(new Label() { Text = myConfigs[i], TextAlign = ContentAlignment.BottomLeft, AutoEllipsis = true, Size = childSize }, 0, i);
|
||||
|
@ -70,8 +64,7 @@ namespace BetterJoyForCemu {
|
|||
private void HideToTray() {
|
||||
this.WindowState = FormWindowState.Minimized;
|
||||
notifyIcon.Visible = true;
|
||||
notifyIcon.BalloonTipText = "Double click the tray icon to maximise!";
|
||||
notifyIcon.ShowBalloonTip(0);
|
||||
notifyIcon.ShowBalloonTip(1);
|
||||
this.ShowInTaskbar = false;
|
||||
this.Hide();
|
||||
}
|
||||
|
@ -145,9 +138,8 @@ namespace BetterJoyForCemu {
|
|||
|
||||
bool toRumble = Boolean.Parse(ConfigurationManager.AppSettings["EnableRumble"]);
|
||||
bool showAsXInput = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsXInput"]);
|
||||
bool showAsDS4 = Boolean.Parse(ConfigurationManager.AppSettings["ShowAsDS4"]);
|
||||
|
||||
public async void locBtnClickAsync(object sender, EventArgs e) {
|
||||
public void locBtnClick(object sender, EventArgs e) {
|
||||
Button bb = sender as Button;
|
||||
|
||||
if (bb.Tag.GetType() == typeof(Button)) {
|
||||
|
@ -155,15 +147,11 @@ namespace BetterJoyForCemu {
|
|||
|
||||
if (button.Tag.GetType() == typeof(Joycon)) {
|
||||
Joycon v = (Joycon)button.Tag;
|
||||
v.SetRumble(160.0f, 320.0f, 1.0f);
|
||||
await Task.Delay(300);
|
||||
v.SetRumble(160.0f, 320.0f, 0);
|
||||
v.SetRumble(20.0f, 400.0f, 1.0f, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool doNotRejoin = Boolean.Parse(ConfigurationManager.AppSettings["DoNotRejoinJoycons"]);
|
||||
|
||||
public void conBtnClick(object sender, EventArgs e) {
|
||||
Button button = sender as Button;
|
||||
|
||||
|
@ -173,7 +161,7 @@ namespace BetterJoyForCemu {
|
|||
if (v.other == null && !v.isPro) { // needs connecting to other joycon (so messy omg)
|
||||
bool succ = false;
|
||||
|
||||
if (Program.mgr.j.Count == 1 || doNotRejoin) { // when want to have a single joycon in vertical mode
|
||||
if (Program.mgr.j.Count == 1) { // when want to have a single joycon in vertical mode
|
||||
v.other = v; // hacky; implement check in Joycon.cs to account for this
|
||||
succ = true;
|
||||
} else {
|
||||
|
@ -182,15 +170,15 @@ namespace BetterJoyForCemu {
|
|||
v.other = jc;
|
||||
jc.other = v;
|
||||
|
||||
if (v.out_xbox != null) {
|
||||
v.out_xbox.Disconnect();
|
||||
v.out_xbox = null;
|
||||
}
|
||||
//Set both Joycon LEDs to the one with the lowest ID
|
||||
byte led = jc.LED <= v.LED ? jc.LED : v.LED;
|
||||
jc.LED = led;
|
||||
v.LED = led;
|
||||
jc.SetPlayerLED(led);
|
||||
v.SetPlayerLED(led);
|
||||
|
||||
if (v.out_ds4 != null) {
|
||||
v.out_ds4.Disconnect();
|
||||
v.out_ds4 = null;
|
||||
}
|
||||
v.xin.Disconnect();
|
||||
v.xin = null;
|
||||
|
||||
// setting the other joycon's button image
|
||||
foreach (Button b in con)
|
||||
|
@ -208,8 +196,15 @@ namespace BetterJoyForCemu {
|
|||
if (b.Tag == v)
|
||||
b.BackgroundImage = v.isLeft ? Properties.Resources.jc_left : Properties.Resources.jc_right;
|
||||
} else if (v.other != null && !v.isPro) { // needs disconnecting from other joycon
|
||||
ReenableViGEm(v);
|
||||
ReenableViGEm(v.other);
|
||||
if (v.xin == null) {
|
||||
ReenableXinput(v);
|
||||
v.xin.Connect();
|
||||
}
|
||||
|
||||
if (v.other.xin == null) {
|
||||
ReenableXinput(v.other);
|
||||
v.other.xin.Connect();
|
||||
}
|
||||
|
||||
button.BackgroundImage = v.isLeft ? Properties.Resources.jc_left_s : Properties.Resources.jc_right_s;
|
||||
|
||||
|
@ -217,6 +212,12 @@ namespace BetterJoyForCemu {
|
|||
if (b.Tag == v.other)
|
||||
b.BackgroundImage = v.other.isLeft ? Properties.Resources.jc_left_s : Properties.Resources.jc_right_s;
|
||||
|
||||
//Set original Joycon LEDs
|
||||
v.other.LED = (byte)(0x1 << v.other.PadId);
|
||||
v.LED = (byte)(0x1 << v.PadId);
|
||||
v.other.SetPlayerLED(v.other.LED);
|
||||
v.SetPlayerLED(v.LED);
|
||||
|
||||
v.other.other = null;
|
||||
v.other = null;
|
||||
}
|
||||
|
@ -254,26 +255,16 @@ namespace BetterJoyForCemu {
|
|||
AppendTextBox("Error writing app settings.\r\n");
|
||||
}
|
||||
|
||||
ConfigurationManager.AppSettings["AutoPowerOff"] = "false"; // Prevent joycons poweroff when applying settings
|
||||
Application.Restart();
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
void ReenableViGEm(Joycon v) {
|
||||
if (showAsXInput && v.out_xbox == null) {
|
||||
v.out_xbox = new Controller.OutputControllerXbox360();
|
||||
void ReenableXinput(Joycon v) {
|
||||
if (showAsXInput) {
|
||||
v.xin = Program.emClient.CreateXbox360Controller();
|
||||
|
||||
if (toRumble)
|
||||
v.out_xbox.FeedbackReceived += v.ReceiveRumble;
|
||||
v.out_xbox.Connect();
|
||||
}
|
||||
|
||||
if (showAsDS4 && v.out_ds4 == null) {
|
||||
v.out_ds4 = new Controller.OutputControllerDualShock4();
|
||||
|
||||
if (toRumble)
|
||||
v.out_ds4.FeedbackReceived += v.Ds4_FeedbackReceived;
|
||||
v.out_ds4.Connect();
|
||||
v.xin.FeedbackReceived += v.ReceiveRumble;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Timers;
|
||||
using System.Windows.Forms;
|
||||
using BetterJoyForCemu.Collections;
|
||||
using Nefarius.ViGEm.Client;
|
||||
using static BetterJoyForCemu._3rdPartyControllers;
|
||||
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Diagnostics;
|
||||
|
||||
using static BetterJoyForCemu.HIDapi;
|
||||
using Nefarius.ViGEm.Client;
|
||||
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 {
|
||||
|
@ -26,13 +26,13 @@ namespace BetterJoyForCemu {
|
|||
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 product_snes = 0x2017;
|
||||
private const ushort product_n64 = 0x2019;
|
||||
|
||||
public ConcurrentList<Joycon> j { get; private set; } // Array of all connected Joy-Cons
|
||||
public List<Joycon> j; // Array of all connected Joy-Cons
|
||||
static JoyconManager instance;
|
||||
|
||||
public MainForm form;
|
||||
|
@ -45,7 +45,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public void Awake() {
|
||||
instance = this;
|
||||
j = new ConcurrentList<Joycon>();
|
||||
j = new List<Joycon>();
|
||||
HIDapi.hid_init();
|
||||
}
|
||||
|
||||
|
@ -64,16 +64,16 @@ namespace BetterJoyForCemu {
|
|||
|
||||
void CleanUp() { // removes dropped controllers from list
|
||||
List<Joycon> rem = new List<Joycon>();
|
||||
foreach (Joycon joycon in j) {
|
||||
if (joycon.state == Joycon.state_.DROPPED) {
|
||||
if (joycon.other != null)
|
||||
joycon.other.other = null; // The other of the other is the joycon itself
|
||||
for (int i = 0; i < j.Count; i++) {
|
||||
Joycon v = j[i];
|
||||
if (v.state == Joycon.state_.DROPPED) {
|
||||
if (v.other != null)
|
||||
v.other.other = null; // The other of the other is the joycon itself
|
||||
|
||||
joycon.Detach(true);
|
||||
rem.Add(joycon);
|
||||
v.Detach(); rem.Add(v);
|
||||
|
||||
foreach (Button b in form.con) {
|
||||
if (b.Enabled & b.Tag == joycon) {
|
||||
if (b.Enabled & b.Tag == v) {
|
||||
b.Invoke(new MethodInvoker(delegate {
|
||||
b.BackColor = System.Drawing.Color.FromArgb(0x00, System.Drawing.SystemColors.Control);
|
||||
b.Enabled = false;
|
||||
|
@ -83,7 +83,7 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
|
||||
form.AppendTextBox("Removed dropped controller. Can be reconnected.\r\n");
|
||||
form.AppendTextBox("Removed dropped controller to list. Can be reconnected.\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,34 +92,22 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
void CheckForNewControllersTime(Object source, ElapsedEventArgs e) {
|
||||
CleanUp();
|
||||
if (Config.IntValue("ProgressiveScan") == 1) {
|
||||
CheckForNewControllers();
|
||||
}
|
||||
}
|
||||
|
||||
private ushort TypeToProdId(byte type) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return product_pro;
|
||||
case 2:
|
||||
return product_l;
|
||||
case 3:
|
||||
return product_r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(0x0, 0x0);
|
||||
IntPtr ptr = HIDapi.hid_enumerate(vendor_id, 0x0);
|
||||
IntPtr top_ptr = ptr;
|
||||
|
||||
hid_device_info enumerate; // Add device to list
|
||||
bool foundNew = false;
|
||||
while (ptr != IntPtr.Zero) {
|
||||
SController thirdParty = null;
|
||||
enumerate = (hid_device_info)Marshal.PtrToStructure(ptr, typeof(hid_device_info));
|
||||
|
||||
if (enumerate.serial_number == null) {
|
||||
|
@ -128,25 +116,14 @@ namespace BetterJoyForCemu {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (form.nonOriginal) {
|
||||
enumerate.product_id = product_pro;
|
||||
}
|
||||
|
||||
bool validController = (enumerate.product_id == product_l || enumerate.product_id == product_r ||
|
||||
enumerate.product_id == product_pro || enumerate.product_id == product_snes || enumerate.product_id == product_n64) && enumerate.vendor_id == vendor_id;
|
||||
// check list of custom controllers specified
|
||||
foreach (SController v in Program.thirdPartyCons) {
|
||||
if (enumerate.vendor_id == v.vendor_id && enumerate.product_id == v.product_id && enumerate.serial_number == v.serial_number) {
|
||||
validController = true;
|
||||
thirdParty = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ushort prod_id = thirdParty == null ? enumerate.product_id : TypeToProdId(thirdParty.type);
|
||||
if (prod_id == 0) {
|
||||
ptr = enumerate.next; // controller was not assigned a type, but advance ptr anyway
|
||||
continue;
|
||||
}
|
||||
|
||||
enumerate.product_id == product_pro || enumerate.product_id == product_snes);
|
||||
if (validController && !ControllerAlreadyAdded(enumerate.path)) {
|
||||
switch (prod_id) {
|
||||
switch (enumerate.product_id) {
|
||||
case product_l:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("Left Joy-Con connected.\r\n"); break;
|
||||
|
@ -159,9 +136,6 @@ namespace BetterJoyForCemu {
|
|||
case product_snes:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("SNES controller connected.\r\n"); break;
|
||||
case product_n64:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("N64 controller connected.\r\n"); break;
|
||||
default:
|
||||
form.AppendTextBox("Non Joy-Con Nintendo input device skipped.\r\n"); break;
|
||||
}
|
||||
|
@ -196,10 +170,9 @@ namespace BetterJoyForCemu {
|
|||
break;
|
||||
}
|
||||
|
||||
bool isPro = prod_id == product_pro;
|
||||
bool isSnes = prod_id == product_snes;
|
||||
bool is64 = prod_id == product_n64;
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, enumerate.path, enumerate.serial_number, j.Count, isPro, isSnes, is64,thirdParty != null));
|
||||
bool isPro = enumerate.product_id == product_pro;
|
||||
bool isSnes = enumerate.product_id == product_snes;
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, enumerate.path, enumerate.serial_number, j.Count, isPro, isSnes));
|
||||
|
||||
foundNew = true;
|
||||
j.Last().form = form;
|
||||
|
@ -210,7 +183,7 @@ namespace BetterJoyForCemu {
|
|||
ii++;
|
||||
if (!v.Enabled) {
|
||||
System.Drawing.Bitmap temp;
|
||||
switch (prod_id) {
|
||||
switch (enumerate.product_id) {
|
||||
case (product_l):
|
||||
temp = Properties.Resources.jc_left_s; break;
|
||||
case (product_r):
|
||||
|
@ -219,8 +192,6 @@ namespace BetterJoyForCemu {
|
|||
temp = Properties.Resources.pro; break;
|
||||
case (product_snes):
|
||||
temp = Properties.Resources.snes; break;
|
||||
case (product_n64):
|
||||
temp = Properties.Resources.ultra; break;
|
||||
default:
|
||||
temp = Properties.Resources.cross; break;
|
||||
}
|
||||
|
@ -234,7 +205,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
form.loc[ii].Invoke(new MethodInvoker(delegate {
|
||||
form.loc[ii].Tag = v;
|
||||
form.loc[ii].Click += new EventHandler(form.locBtnClickAsync);
|
||||
form.loc[ii].Click += new EventHandler(form.locBtnClick);
|
||||
}));
|
||||
|
||||
break;
|
||||
|
@ -243,12 +214,8 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
byte[] mac = new byte[6];
|
||||
try {
|
||||
for (int n = 0; n < 6; n++)
|
||||
mac[n] = byte.Parse(enumerate.serial_number.Substring(n * 2, 2), System.Globalization.NumberStyles.HexNumber);
|
||||
} catch (Exception e) {
|
||||
// could not parse mac address
|
||||
}
|
||||
j[j.Count - 1].PadMacAddress = new PhysicalAddress(mac);
|
||||
}
|
||||
|
||||
|
@ -258,37 +225,36 @@ namespace BetterJoyForCemu {
|
|||
if (foundNew) { // attempt to auto join-up joycons on connection
|
||||
Joycon temp = null;
|
||||
foreach (Joycon v in j) {
|
||||
// Do not attach two controllers if they are either:
|
||||
// - Not a Joycon
|
||||
// - Already attached to another Joycon (that isn't itself)
|
||||
if (v.isPro || (v.other != null && v.other != v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, iterate through and find the Joycon with the lowest
|
||||
// id that has not been attached already (Does not include self)
|
||||
if (!v.isPro) {
|
||||
if (temp == null)
|
||||
temp = v;
|
||||
else if (temp.isLeft != v.isLeft && v.other == null) {
|
||||
temp.other = v;
|
||||
v.other = temp;
|
||||
|
||||
if (temp.out_xbox != null) {
|
||||
//Set both Joycon LEDs to the one with the lowest ID
|
||||
byte led = temp.LED <= v.LED ? temp.LED : v.LED;
|
||||
temp.LED = led;
|
||||
v.LED = led;
|
||||
temp.SetPlayerLED(led);
|
||||
v.SetPlayerLED(led);
|
||||
|
||||
if (temp.xin != null) {
|
||||
try {
|
||||
temp.out_xbox.Disconnect();
|
||||
temp.xin.Disconnect();
|
||||
} catch (Exception e) {
|
||||
// it wasn't connected in the first place, go figure
|
||||
}
|
||||
}
|
||||
if (temp.out_ds4 != null) {
|
||||
if (temp.ds4 != null) {
|
||||
try {
|
||||
temp.out_ds4.Disconnect();
|
||||
temp.ds4.Disconnect();
|
||||
} catch (Exception e) {
|
||||
// it wasn't connected in the first place, go figure
|
||||
}
|
||||
}
|
||||
temp.out_xbox = null;
|
||||
temp.out_ds4 = null;
|
||||
temp.xin = null;
|
||||
temp.ds4 = null;
|
||||
|
||||
foreach (Button b in form.con)
|
||||
if (b.Tag == v || b.Tag == temp) {
|
||||
|
@ -300,47 +266,48 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HIDapi.hid_free_enumeration(top_ptr);
|
||||
|
||||
bool on = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings["HomeLEDOn"].Value.ToLower() == "true";
|
||||
foreach (Joycon jc in j) { // Connect device straight away
|
||||
if (jc.state == Joycon.state_.NOT_ATTACHED) {
|
||||
if (jc.out_xbox != null)
|
||||
jc.out_xbox.Connect();
|
||||
if (jc.out_ds4 != null)
|
||||
jc.out_ds4.Connect();
|
||||
if (jc.xin != null)
|
||||
jc.xin.Connect();
|
||||
if (jc.ds4 != null)
|
||||
jc.ds4.Connect();
|
||||
|
||||
try {
|
||||
jc.Attach();
|
||||
} catch (Exception e) {
|
||||
jc.state = Joycon.state_.DROPPED;
|
||||
continue;
|
||||
jc.Attach(leds_: jc.LED);
|
||||
|
||||
bool on = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings["HomeLEDOn"].Value.ToLower() == "true";
|
||||
foreach (Joycon j in Program.mgr.j) {
|
||||
j.SetHomeLight(on);
|
||||
}
|
||||
|
||||
jc.SetHomeLight(on);
|
||||
|
||||
jc.Begin();
|
||||
if (form.allowCalibration) {
|
||||
if (form.nonOriginal) {
|
||||
jc.getActiveData();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
for (int i = 0; i < j.Count; ++i)
|
||||
j[i].Update();
|
||||
}
|
||||
|
||||
public void OnApplicationQuit() {
|
||||
foreach (Joycon v in j) {
|
||||
if (Boolean.Parse(ConfigurationManager.AppSettings["AutoPowerOff"]))
|
||||
v.PowerOff();
|
||||
|
||||
v.Detach();
|
||||
|
||||
if (v.out_xbox != null) {
|
||||
v.out_xbox.Disconnect();
|
||||
if (v.xin != null) {
|
||||
v.xin.Disconnect();
|
||||
}
|
||||
|
||||
if (v.out_ds4 != null) {
|
||||
v.out_ds4.Disconnect();
|
||||
if (v.ds4 != null) {
|
||||
v.ds4.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,23 +316,62 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
|
||||
// Custom timer class because system timers have a limit of 15.6ms
|
||||
class HighResTimer {
|
||||
double interval = 0;
|
||||
double frequency = 0;
|
||||
|
||||
Thread thread;
|
||||
|
||||
public delegate void ActionDelegate();
|
||||
ActionDelegate func;
|
||||
|
||||
bool run = false;
|
||||
|
||||
public HighResTimer(double f, ActionDelegate a) {
|
||||
frequency = f;
|
||||
interval = 1.0 / f;
|
||||
|
||||
func = a;
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
run = true;
|
||||
thread = new Thread(new ThreadStart(Run));
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
void Run() {
|
||||
while (run) {
|
||||
func();
|
||||
int timeToSleep = (int)(interval * 1000);
|
||||
Thread.Sleep(timeToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop() {
|
||||
run = false;
|
||||
}
|
||||
}
|
||||
|
||||
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 static ViGEmClient emClient;
|
||||
|
||||
private static readonly HttpClient client = new HttpClient();
|
||||
|
||||
public static JoyconManager mgr;
|
||||
static HighResTimer timer;
|
||||
static string pid;
|
||||
|
||||
static MainForm form;
|
||||
|
||||
static public bool useHIDG = Boolean.Parse(ConfigurationManager.AppSettings["UseHIDG"]);
|
||||
|
||||
public static List<SController> thirdPartyCons = new List<SController>();
|
||||
|
||||
private static WindowsInput.Events.Sources.IKeyboardEventSource keyboard;
|
||||
private static WindowsInput.Events.Sources.IMouseEventSource mouse;
|
||||
|
||||
|
@ -426,10 +432,6 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
|
||||
// a bit hacky
|
||||
_3rdPartyControllers partyForm = new _3rdPartyControllers();
|
||||
partyForm.CopyCustomControllers();
|
||||
|
||||
mgr = new JoyconManager();
|
||||
mgr.form = form;
|
||||
mgr.Awake();
|
||||
|
@ -440,6 +442,8 @@ namespace BetterJoyForCemu {
|
|||
server.form = form;
|
||||
|
||||
server.Start(IPAddress.Parse(ConfigurationManager.AppSettings["IP"]), Int32.Parse(ConfigurationManager.AppSettings["Port"]));
|
||||
timer = new HighResTimer(pollsPerSecond, new HighResTimer.ActionDelegate(mgr.Update));
|
||||
timer.Start();
|
||||
|
||||
// Capture keyboard + mouse events for binding's sake
|
||||
keyboard = WindowsInput.Capture.Global.KeyboardAsync();
|
||||
|
@ -513,43 +517,15 @@ namespace BetterJoyForCemu {
|
|||
|
||||
keyboard.Dispose(); mouse.Dispose();
|
||||
server.Stop();
|
||||
timer.Stop();
|
||||
mgr.OnApplicationQuit();
|
||||
}
|
||||
|
||||
private static string appGuid = "1bf709e9-c133-41df-933a-c9ff3f664c7b"; // randomly-generated
|
||||
static void Main(string[] args) {
|
||||
|
||||
// Setting the culturesettings so float gets parsed correctly
|
||||
CultureInfo.CurrentCulture = new CultureInfo("en-US", false);
|
||||
|
||||
// Set the correct DLL for the current OS
|
||||
SetupDlls();
|
||||
|
||||
using (Mutex mutex = new Mutex(false, "Global\\" + appGuid)) {
|
||||
if (!mutex.WaitOne(0, false)) {
|
||||
MessageBox.Show("Instance already running.", "BetterJoy");
|
||||
return;
|
||||
}
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
form = new MainForm();
|
||||
Application.Run(form);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupDlls() {
|
||||
string archPath = $"{AppDomain.CurrentDomain.BaseDirectory}{(Environment.Is64BitProcess ? "x64" : "x86")}\\";
|
||||
string pathVariable = Environment.GetEnvironmentVariable("PATH");
|
||||
pathVariable = $"{archPath};{pathVariable}";
|
||||
Environment.SetEnvironmentVariable("PATH", pathVariable);
|
||||
}
|
||||
|
||||
// Helper funtions to set the hidapi dll location acording to the system instruction set.
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
static extern bool SetDefaultDllDirectories(int directoryFlags);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
static extern void AddDllDirectory(string lpPathName);
|
||||
}
|
||||
}
|
|
@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
|
|||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("BetterJoy")]
|
||||
[assembly: AssemblyTitle("BetterJoyForCemu")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("BetterJoy")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyProduct("BetterJoyForCemu")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
|
10
BetterJoyForCemu/Properties/Resources.Designer.cs
generated
10
BetterJoyForCemu/Properties/Resources.Designer.cs
generated
|
@ -139,15 +139,5 @@ namespace BetterJoyForCemu.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap ultra {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ultra", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,9 +121,6 @@
|
|||
<data name="snes" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Icons\snes.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="ultra" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Icons\ultra.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="pro" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Icons\pro.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
|
44
BetterJoyForCemu/Reassign.Designer.cs
generated
44
BetterJoyForCemu/Reassign.Designer.cs
generated
|
@ -93,15 +93,13 @@ namespace BetterJoyForCemu {
|
|||
this.btn_sl_r = new BetterJoyForCemu.SplitButton();
|
||||
this.lbl_sr_r = new System.Windows.Forms.Label();
|
||||
this.btn_sr_r = new BetterJoyForCemu.SplitButton();
|
||||
this.btn_close = new System.Windows.Forms.Button();
|
||||
this.btn_apply = new System.Windows.Forms.Button();
|
||||
this.btn_close = new Button();
|
||||
this.btn_apply = new Button();
|
||||
this.tip_reassign = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.lbl_reset_mouse = new System.Windows.Forms.Label();
|
||||
this.btn_reset_mouse = new BetterJoyForCemu.SplitButton();
|
||||
this.lbl_activate_gyro = new System.Windows.Forms.Label();
|
||||
this.btn_active_gyro = new BetterJoyForCemu.SplitButton();
|
||||
this.lbl_shake = new System.Windows.Forms.Label();
|
||||
this.btn_shake = new BetterJoyForCemu.SplitButton();
|
||||
this.btn_active_gyro = new SplitButton();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btn_capture
|
||||
|
@ -214,7 +212,7 @@ namespace BetterJoyForCemu {
|
|||
//
|
||||
// btn_close
|
||||
//
|
||||
this.btn_close.Location = new System.Drawing.Point(15, 289);
|
||||
this.btn_close.Location = new System.Drawing.Point(15, 257);
|
||||
this.btn_close.Name = "btn_close";
|
||||
this.btn_close.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_close.TabIndex = 13;
|
||||
|
@ -224,7 +222,7 @@ namespace BetterJoyForCemu {
|
|||
//
|
||||
// btn_apply
|
||||
//
|
||||
this.btn_apply.Location = new System.Drawing.Point(105, 289);
|
||||
this.btn_apply.Location = new System.Drawing.Point(105, 257);
|
||||
this.btn_apply.Name = "btn_apply";
|
||||
this.btn_apply.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_apply.TabIndex = 14;
|
||||
|
@ -235,7 +233,7 @@ namespace BetterJoyForCemu {
|
|||
// lbl_reset_mouse
|
||||
//
|
||||
this.lbl_reset_mouse.AutoSize = true;
|
||||
this.lbl_reset_mouse.Location = new System.Drawing.Point(15, 223);
|
||||
this.lbl_reset_mouse.Location = new System.Drawing.Point(15, 191);
|
||||
this.lbl_reset_mouse.Name = "lbl_reset_mouse";
|
||||
this.lbl_reset_mouse.Size = new System.Drawing.Size(80, 13);
|
||||
this.lbl_reset_mouse.TabIndex = 16;
|
||||
|
@ -244,7 +242,7 @@ namespace BetterJoyForCemu {
|
|||
//
|
||||
// btn_reset_mouse
|
||||
//
|
||||
this.btn_reset_mouse.Location = new System.Drawing.Point(105, 218);
|
||||
this.btn_reset_mouse.Location = new System.Drawing.Point(105, 186);
|
||||
this.btn_reset_mouse.Name = "btn_reset_mouse";
|
||||
this.btn_reset_mouse.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_reset_mouse.TabIndex = 15;
|
||||
|
@ -253,7 +251,7 @@ namespace BetterJoyForCemu {
|
|||
// lbl_activate_gyro
|
||||
//
|
||||
this.lbl_activate_gyro.AutoSize = true;
|
||||
this.lbl_activate_gyro.Location = new System.Drawing.Point(14, 252);
|
||||
this.lbl_activate_gyro.Location = new System.Drawing.Point(14, 220);
|
||||
this.lbl_activate_gyro.Name = "lbl_activate_gyro";
|
||||
this.lbl_activate_gyro.Size = new System.Drawing.Size(71, 13);
|
||||
this.lbl_activate_gyro.TabIndex = 17;
|
||||
|
@ -262,37 +260,17 @@ namespace BetterJoyForCemu {
|
|||
//
|
||||
// btn_active_gyro
|
||||
//
|
||||
this.btn_active_gyro.Location = new System.Drawing.Point(105, 247);
|
||||
this.btn_active_gyro.Location = new System.Drawing.Point(105, 215);
|
||||
this.btn_active_gyro.Name = "btn_active_gyro";
|
||||
this.btn_active_gyro.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_active_gyro.TabIndex = 18;
|
||||
this.btn_active_gyro.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.lbl_shake.AutoSize = true;
|
||||
this.lbl_shake.Location = new System.Drawing.Point(15, 191);
|
||||
this.lbl_shake.Name = "lbl_shake";
|
||||
this.lbl_shake.Size = new System.Drawing.Size(87, 13);
|
||||
this.lbl_shake.TabIndex = 20;
|
||||
this.lbl_shake.Text = "Shake Input";
|
||||
this.lbl_shake.TextAlign = System.Drawing.ContentAlignment.TopCenter;
|
||||
//
|
||||
// splitButton1
|
||||
//
|
||||
this.btn_shake.Location = new System.Drawing.Point(105, 186);
|
||||
this.btn_shake.Name = "btn_shake";
|
||||
this.btn_shake.Size = new System.Drawing.Size(75, 23);
|
||||
this.btn_shake.TabIndex = 19;
|
||||
this.btn_shake.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Reassign
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(192, 338);
|
||||
this.Controls.Add(this.lbl_shake);
|
||||
this.Controls.Add(this.btn_shake);
|
||||
this.ClientSize = new System.Drawing.Size(192, 292);
|
||||
this.Controls.Add(this.btn_active_gyro);
|
||||
this.Controls.Add(this.lbl_activate_gyro);
|
||||
this.Controls.Add(this.lbl_reset_mouse);
|
||||
|
@ -345,7 +323,5 @@ namespace BetterJoyForCemu {
|
|||
private SplitButton btn_reset_mouse;
|
||||
private Label lbl_activate_gyro;
|
||||
private SplitButton btn_active_gyro;
|
||||
private Label lbl_shake;
|
||||
private SplitButton btn_shake;
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
menu_joy_buttons.ItemClicked += Menu_joy_buttons_ItemClicked;
|
||||
|
||||
foreach (SplitButton c in new SplitButton[] { btn_capture, btn_home, btn_sl_l, btn_sl_r, btn_sr_l, btn_sr_r, btn_shake, btn_reset_mouse, btn_active_gyro }) {
|
||||
foreach (SplitButton c in new SplitButton[] { btn_capture, btn_home, btn_sl_l, btn_sl_r, btn_sr_l, btn_sr_r, btn_reset_mouse , btn_active_gyro}) {
|
||||
c.Tag = c.Name.Substring(4);
|
||||
GetPrettyName(c);
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Force.Crc32;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using Force.Crc32;
|
||||
using System.Configuration;
|
||||
|
||||
namespace BetterJoyForCemu {
|
||||
class UdpServer {
|
||||
|
@ -13,11 +17,11 @@ namespace BetterJoyForCemu {
|
|||
private bool running;
|
||||
private byte[] recvBuffer = new byte[1024];
|
||||
|
||||
IList<Joycon> controllers;
|
||||
List<Joycon> controllers;
|
||||
|
||||
public MainForm form;
|
||||
|
||||
public UdpServer(IList<Joycon> p) {
|
||||
public UdpServer(List<Joycon> p) {
|
||||
controllers = p;
|
||||
}
|
||||
|
||||
|
@ -317,57 +321,62 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
}
|
||||
|
||||
bool swapAB = Boolean.Parse(ConfigurationManager.AppSettings["SwapAB"]);
|
||||
bool swapXY = Boolean.Parse(ConfigurationManager.AppSettings["SwapXY"]);
|
||||
private bool ReportToBuffer(Joycon hidReport, byte[] outputData, ref int outIdx) {
|
||||
var ds4 = Joycon.MapToDualShock4Input(hidReport);
|
||||
|
||||
outputData[outIdx] = 0;
|
||||
|
||||
if (ds4.dPad == Controller.DpadDirection.West || ds4.dPad == Controller.DpadDirection.Northwest || ds4.dPad == Controller.DpadDirection.Southwest) outputData[outIdx] |= 0x80;
|
||||
if (ds4.dPad == Controller.DpadDirection.South || ds4.dPad == Controller.DpadDirection.Southwest || ds4.dPad == Controller.DpadDirection.Southeast) outputData[outIdx] |= 0x40;
|
||||
if (ds4.dPad == Controller.DpadDirection.East || ds4.dPad == Controller.DpadDirection.Northeast || ds4.dPad == Controller.DpadDirection.Southeast) outputData[outIdx] |= 0x20;
|
||||
if (ds4.dPad == Controller.DpadDirection.North || ds4.dPad == Controller.DpadDirection.Northwest || ds4.dPad == Controller.DpadDirection.Northeast) outputData[outIdx] |= 0x10;
|
||||
bool isLeft = hidReport.isLeft;
|
||||
|
||||
if (ds4.options) outputData[outIdx] |= 0x08;
|
||||
if (ds4.thumb_right) outputData[outIdx] |= 0x04;
|
||||
if (ds4.thumb_left) outputData[outIdx] |= 0x02;
|
||||
if (ds4.share) outputData[outIdx] |= 0x01;
|
||||
if (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_LEFT : Joycon.Button.Y)) 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.A)) 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 (ds4.square) outputData[outIdx] |= 0x80;
|
||||
if (ds4.cross) outputData[outIdx] |= 0x40;
|
||||
if (ds4.circle) outputData[outIdx] |= 0x20;
|
||||
if (ds4.triangle) outputData[outIdx] |= 0x10;
|
||||
if (hidReport.GetButton(!swapXY ? (isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT) : (isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP))) outputData[outIdx] |= 0x80;
|
||||
if (hidReport.GetButton(!swapAB ? (isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN) : (isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT))) outputData[outIdx] |= 0x40;
|
||||
if (hidReport.GetButton(!swapAB ? (isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT) : (isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN))) outputData[outIdx] |= 0x20;
|
||||
if (hidReport.GetButton(!swapXY ? (isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP) : (isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT))) outputData[outIdx] |= 0x10;
|
||||
|
||||
if (ds4.shoulder_right) outputData[outIdx] |= 0x08;
|
||||
if (ds4.shoulder_left) outputData[outIdx] |= 0x04;
|
||||
if (ds4.trigger_right_value == Byte.MaxValue) outputData[outIdx] |= 0x02;
|
||||
if (ds4.trigger_left_value == Byte.MaxValue) 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] = ds4.ps ? (byte)1 : (byte)0;
|
||||
outputData[++outIdx] = ds4.touchpad ? (byte)1 : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(Joycon.Button.HOME)) ? (byte)1 : (byte)0;
|
||||
outputData[++outIdx] = 0; // no touch pad
|
||||
|
||||
outputData[++outIdx] = ds4.thumb_left_x;
|
||||
outputData[++outIdx] = ds4.thumb_left_y;
|
||||
outputData[++outIdx] = ds4.thumb_right_x;
|
||||
outputData[++outIdx] = ds4.thumb_right_y;
|
||||
float[] leftStick = hidReport.GetStick(); // 127 is 0
|
||||
outputData[++outIdx] = (byte)(Math.Max(0, Math.Min(255, 127 + leftStick[0] * 127)));
|
||||
outputData[++outIdx] = (byte)(Math.Max(0, Math.Min(255, 127 + leftStick[1] * 127)));
|
||||
|
||||
float[] rightStick = hidReport.GetStick2(); // 127 is 0
|
||||
outputData[++outIdx] = (byte)(Math.Max(0, Math.Min(255, 127 + rightStick[0] * 127)));
|
||||
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] = (ds4.dPad == Controller.DpadDirection.West || ds4.dPad == Controller.DpadDirection.Northwest || ds4.dPad == Controller.DpadDirection.Southwest) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (ds4.dPad == Controller.DpadDirection.South || ds4.dPad == Controller.DpadDirection.Southwest || ds4.dPad == Controller.DpadDirection.Southeast) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (ds4.dPad == Controller.DpadDirection.East || ds4.dPad == Controller.DpadDirection.Northeast || ds4.dPad == Controller.DpadDirection.Southeast) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (ds4.dPad == Controller.DpadDirection.North || ds4.dPad == Controller.DpadDirection.Northwest || ds4.dPad == Controller.DpadDirection.Northeast) ? (byte)0xFF : (byte)0; ;
|
||||
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_LEFT : Joycon.Button.Y)) ? (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.A)) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(isLeft ? Joycon.Button.DPAD_UP : Joycon.Button.X)) ? (byte)0xFF : (byte)0;
|
||||
|
||||
outputData[++outIdx] = ds4.square ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = ds4.cross ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = ds4.circle ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = ds4.triangle ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(!swapXY ? (isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT) : (isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP))) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(!swapAB ? (isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN) : (isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT))) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(!swapAB ? (isLeft ? Joycon.Button.A : Joycon.Button.DPAD_RIGHT) : (isLeft ? Joycon.Button.B : Joycon.Button.DPAD_DOWN))) ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = (hidReport.GetButton(!swapXY ? (isLeft ? Joycon.Button.X : Joycon.Button.DPAD_UP) : (isLeft ? Joycon.Button.Y : Joycon.Button.DPAD_LEFT))) ? (byte)0xFF : (byte)0;
|
||||
|
||||
outputData[++outIdx] = ds4.shoulder_right ? (byte)0xFF : (byte)0;
|
||||
outputData[++outIdx] = ds4.shoulder_left ? (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] = ds4.trigger_right_value;
|
||||
outputData[++outIdx] = ds4.trigger_left_value;
|
||||
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++;
|
||||
|
||||
|
|
BIN
BetterJoyForCemu/hidapi.dll
Normal file
BIN
BetterJoyForCemu/hidapi.dll
Normal file
Binary file not shown.
|
@ -2,6 +2,6 @@
|
|||
<packages>
|
||||
<package id="Crc32.NET" version="1.2.0" targetFramework="net461" />
|
||||
<package id="JetBrains.Annotations" version="2020.1.0" targetFramework="net461" />
|
||||
<package id="Nefarius.ViGEm.Client" version="1.17.178" targetFramework="net461" />
|
||||
<package id="WindowsInput" version="6.3.0" targetFramework="net461" />
|
||||
<package id="Nefarius.ViGEm.Client" version="1.0.0" targetFramework="net461" />
|
||||
<package id="WindowsInput" version="6.1.1" targetFramework="net461" />
|
||||
</packages>
|
Binary file not shown.
Binary file not shown.
109
README.md
109
README.md
|
@ -1,107 +1,4 @@
|
|||
<p align="center">
|
||||
<img src="title.png">
|
||||
</p>
|
||||
# BetterJoy v6.1 - DS4 Gyro
|
||||
This is an experimental branch of BetterJoy that uses a custom build of ViGEm to allow the use of DS4 gyro/accel controls. For more info, please see [the following wiki page](https://github.com/Davidobot/BetterJoy/wiki/DS4-Gyro).
|
||||
|
||||
# BetterJoy v7.0
|
||||
Allows the Nintendo Switch Pro Controller, Joycons, and Switch SNES controller to be used with [Cemu](http://cemu.info/) using [Cemuhook](https://sshnuke.net/cemuhook/), [Citra](https://citra-emu.org/), [Dolphin](https://dolphin-emu.org/), [Yuzu](https://yuzu-emu.org/), and system-wide with generic XInput support.
|
||||
|
||||
It also allows using the gyro to control your mouse and remap the special buttons (SL, SR, Capture) to key bindings of your choice.
|
||||
|
||||
If anyone would like to donate (for whatever reason), [you can do so here](https://www.paypal.me/DavidKhachaturov/5).
|
||||
|
||||
#### Personal note
|
||||
Thank you for using my software and all the constructive feedback I've been getting about it. I started writing this project a while back and have since then learnt a lot more about programming and software development in general. I don't have too much time to work on this project, but I will try to fix bugs when and if they arise. Thank you for your patience in that regard too!
|
||||
|
||||
It's been quite a wild ride, with nearly **590k** (!!) official download on GitHub and probably many more through the nightlies. I think this project was responsible for both software jobs I landed so far, so I am quite proud of it.
|
||||
|
||||
### Screenshot
|
||||
![Example](https://user-images.githubusercontent.com/16619943/67919451-bf8e5680-fb76-11e9-995e-7193b87548e1.png)
|
||||
|
||||
# Downloads
|
||||
Go to the [Releases tab](https://github.com/Davidobot/BetterJoy/releases/)!
|
||||
|
||||
# How to use
|
||||
1. Install drivers
|
||||
1. Read the READMEs (they're there for a reason!)
|
||||
1. Run *Drivers/ViGEmBus_Setup_1.16.116.exe*
|
||||
1. Restart your computer
|
||||
2. Run *BetterJoyForCemu.exe*
|
||||
1. Run as Administrator if your keyboard/mouse button mappings don't work
|
||||
3. Connect your controllers.
|
||||
4. Start Cemu and ensure CemuHook has the controller selected.
|
||||
1. If using Joycons, CemuHook will detect two controllers - each will give all buttons, but choosing one over the other just chooses preference for which hand to use for gyro controls.
|
||||
5. Go into *Input Settings*, choose XInput as a source and assign buttons normally.
|
||||
1. If you don't want to do this for some reason, just have one input profile set up with *Wii U Gamepad* as the controller and enable "Also use for buttons/axes" under *GamePad motion source*. **This is no longer required as of version 3**
|
||||
2. Turn rumble up to 70-80% if you want rumble.
|
||||
|
||||
* As of version 3, you can use the pro controller and Joycons as normal xbox controllers on your PC - try it with Steam!
|
||||
|
||||
# More Info
|
||||
Check out the [wiki](https://github.com/Davidobot/BetterJoy/wiki)! There, you'll find all sorts of goodness such as the changelog, description of app settings, the FAQ and Problems page, and info on how to make BetterJoy work with Steam *better*.
|
||||
|
||||
# Connecting and Disconnecting the Controller
|
||||
## Bluetooth Mode
|
||||
* Hold down the small button (sync) on the top of the controller for 5 seconds - this puts the controller into broadcasting mode.
|
||||
* Search for it in your bluetooth settings and pair normally.
|
||||
* To disconnect the controller - hold the home button (or capture button) down for 2 seconds (or press the sync button). To reconnect - press any button on your controller.
|
||||
|
||||
## USB Mode
|
||||
* Plug the controller into your computer.
|
||||
|
||||
## Disconnecting \[Windows 10]
|
||||
1. Go into "Bluetooth and other devices settings"
|
||||
1. Under the first category "Mouse, keyboard, & pen", there should be the pro controller.
|
||||
1. Click on it and a "Remove" button will be revealed.
|
||||
1. Press the "Remove" button
|
||||
|
||||
# Building
|
||||
|
||||
## Visual Studio (IDE)
|
||||
|
||||
1. If you didn't already, install **Visual Studio Community 2019** via
|
||||
[the official guide](https://docs.microsoft.com/en-us/visualstudio/install/install-visual-studio?view=vs-2019).
|
||||
When asked about the workloads, select **.NET Desktop Development**.
|
||||
2. Get the code project via Git or by using the *Download ZIP* button.
|
||||
3. Open Visual Studio Community and open the solution file (*BetterJoy.sln*).
|
||||
4. Open the NuGet manager via *Tools > NuGet Package Manager > Package Manager Settings*.
|
||||
5. You should have a warning mentioning *restoring your packages*. Click on the **Restore** button.
|
||||
6. You can now run and build BetterJoy.
|
||||
|
||||
## Visual Studio Build Tools (CLI)
|
||||
1. Download **Visual Studio Build Tools** via
|
||||
[the official link](https://visualstudio.microsoft.com/it/downloads/#build-tools-for-visual-studio-2019).
|
||||
2. Install **NuGet** by following
|
||||
[the official guide](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools#nugetexe-cli).
|
||||
You should follow the section for ***nuget.exe***.
|
||||
Verify that you can run `nuget` from your favourite terminal.
|
||||
3. Get the code project via Git or by using the *Download ZIP* button.
|
||||
4. Open a terminal (*cmd*, *PowerShell*, ...) and enter the folder with the source code.
|
||||
5. Restore the NuGet dependencies by running: `nuget restore`
|
||||
6. Now build the app with MSBuild:
|
||||
```
|
||||
msbuild .\BetterJoy.sln -p:Configuration=CONFIGURATION -p:Platform=PLATFORM -t:Rebuild
|
||||
```
|
||||
The available values for **CONFIGURATION** are *Release* and *Debug*.
|
||||
The available values for **PLATFORM** are *x86* and *x64* (you want the latter 99.99% of the time).
|
||||
7. You have now built the app. See the next section for locating the binaries.
|
||||
|
||||
## Binaries location
|
||||
The built binaries are located under
|
||||
|
||||
*BetterJoyForCemu\bin\PLATFORM\CONFIGURATION*
|
||||
|
||||
where `PLATFORM` and `CONFIGURATION` are the one provided at build time.
|
||||
|
||||
# Acknowledgements
|
||||
A massive thanks goes out to [rajkosto](https://github.com/rajkosto/) for putting up with 17 emails and replying very quickly to my silly queries. The UDP server is also mostly taken from his [ScpToolkit](https://github.com/rajkosto/ScpToolkit) repo.
|
||||
|
||||
Also I am very grateful to [mfosse](https://github.com/mfosse/JoyCon-Driver) for pointing me in the right direction and to [Looking-Glass](https://github.com/Looking-Glass/JoyconLib) without whom I would not be able to figure anything out. (being honest here - the joycon code is his)
|
||||
|
||||
Many thanks to [nefarius](https://github.com/ViGEm/ViGEmBus) for his ViGEm project! Apologies and appreciation go out to [epigramx](https://github.com/epigramx), creator of *WiimoteHook*, for giving me the driver idea and for letting me keep using his installation batch script even though I took it without permission. Thanks go out to [MTCKC](https://github.com/MTCKC/ProconXInput) for inspiration and batch files.
|
||||
|
||||
A last thanks goes out to [dekuNukem](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering) for his documentation, especially on the SPI calibration data and the IMU sensor notes!
|
||||
|
||||
Massive *thank you* to **all** code contributors!
|
||||
|
||||
Icons (modified): "[Switch Pro Controller](https://thenounproject.com/term/nintendo-switch/930119/)", "[
|
||||
Switch Detachable Controller Left](https://thenounproject.com/remsing/uploads/?i=930115)", "[Switch Detachable Controller Right](https://thenounproject.com/remsing/uploads/?i=930121)" icons by Chad Remsing from [the Noun Project](http://thenounproject.com/). [Super Nintendo Controller](https://thenounproject.com/themizarkshow/collection/vectogram/?i=193592) icon by Mark Davis from the [the Noun Project](http://thenounproject.com/); icon modified by [Amy Alexander](https://www.linkedin.com/in/-amy-alexander/). [Nintendo 64 Controller](https://thenounproject.com/icon/game-controller-193588/) icon by Mark Davis from the [the Noun Project](http://thenounproject.com/); icon modified by [Gino Moena](https://www.github.com/GinoMoena).
|
||||
I will merge this branch into master once ViGEm updates to include the gyro API (we're working on it)
|
||||
|
|
Loading…
Add table
Reference in a new issue