Do not connect Joycons that are already paired. Fix concurrent modifications on Joycon list with concurrent list implementation. (#612)
This commit is contained in:
parent
c0b9240887
commit
40dce4149c
5 changed files with 173 additions and 51 deletions
|
@ -130,6 +130,7 @@
|
||||||
<Compile Include="3rdPartyControllers.Designer.cs">
|
<Compile Include="3rdPartyControllers.Designer.cs">
|
||||||
<DependentUpon>3rdPartyControllers.cs</DependentUpon>
|
<DependentUpon>3rdPartyControllers.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Collections\ConcurrentList.cs" />
|
||||||
<Compile Include="Config.cs" />
|
<Compile Include="Config.cs" />
|
||||||
<Compile Include="Controller\OutputControllerDualShock4.cs" />
|
<Compile Include="Controller\OutputControllerDualShock4.cs" />
|
||||||
<Compile Include="Controller\OutputControllerXbox360.cs" />
|
<Compile Include="Controller\OutputControllerXbox360.cs" />
|
||||||
|
|
116
BetterJoyForCemu/Collections/ConcurrentList.cs
Normal file
116
BetterJoyForCemu/Collections/ConcurrentList.cs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ namespace BetterJoyForCemu {
|
||||||
public bool isPro = false;
|
public bool isPro = false;
|
||||||
public bool isSnes = false;
|
public bool isSnes = false;
|
||||||
bool isUSB = false;
|
bool isUSB = false;
|
||||||
public Joycon other;
|
public Joycon other = null;
|
||||||
public bool active_gyro = false;
|
public bool active_gyro = false;
|
||||||
|
|
||||||
private long inactivity = Stopwatch.GetTimestamp();
|
private long inactivity = Stopwatch.GetTimestamp();
|
||||||
|
|
|
@ -12,8 +12,8 @@ using System.ServiceProcess;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Web.Configuration;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using BetterJoyForCemu.Collections;
|
||||||
using Nefarius.ViGEm.Client;
|
using Nefarius.ViGEm.Client;
|
||||||
using static BetterJoyForCemu._3rdPartyControllers;
|
using static BetterJoyForCemu._3rdPartyControllers;
|
||||||
using static BetterJoyForCemu.HIDapi;
|
using static BetterJoyForCemu.HIDapi;
|
||||||
|
@ -29,7 +29,7 @@ namespace BetterJoyForCemu {
|
||||||
private const ushort product_pro = 0x2009;
|
private const ushort product_pro = 0x2009;
|
||||||
private const ushort product_snes = 0x2017;
|
private const ushort product_snes = 0x2017;
|
||||||
|
|
||||||
public List<Joycon> j; // Array of all connected Joy-Cons
|
public ConcurrentList<Joycon> j { get; private set; } // Array of all connected Joy-Cons
|
||||||
static JoyconManager instance;
|
static JoyconManager instance;
|
||||||
|
|
||||||
public MainForm form;
|
public MainForm form;
|
||||||
|
@ -42,7 +42,7 @@ namespace BetterJoyForCemu {
|
||||||
|
|
||||||
public void Awake() {
|
public void Awake() {
|
||||||
instance = this;
|
instance = this;
|
||||||
j = new List<Joycon>();
|
j = new ConcurrentList<Joycon>();
|
||||||
HIDapi.hid_init();
|
HIDapi.hid_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,16 +61,16 @@ namespace BetterJoyForCemu {
|
||||||
|
|
||||||
void CleanUp() { // removes dropped controllers from list
|
void CleanUp() { // removes dropped controllers from list
|
||||||
List<Joycon> rem = new List<Joycon>();
|
List<Joycon> rem = new List<Joycon>();
|
||||||
for (int i = 0; i < j.Count; i++) {
|
foreach (Joycon joycon in j) {
|
||||||
Joycon v = j[i];
|
if (joycon.state == Joycon.state_.DROPPED) {
|
||||||
if (v.state == Joycon.state_.DROPPED) {
|
if (joycon.other != null)
|
||||||
if (v.other != null)
|
joycon.other.other = null; // The other of the other is the joycon itself
|
||||||
v.other.other = null; // The other of the other is the joycon itself
|
|
||||||
|
|
||||||
v.Detach(true); rem.Add(v);
|
joycon.Detach(true);
|
||||||
|
rem.Add(joycon);
|
||||||
|
|
||||||
foreach (Button b in form.con) {
|
foreach (Button b in form.con) {
|
||||||
if (b.Enabled & b.Tag == v) {
|
if (b.Enabled & b.Tag == joycon) {
|
||||||
b.Invoke(new MethodInvoker(delegate {
|
b.Invoke(new MethodInvoker(delegate {
|
||||||
b.BackColor = System.Drawing.Color.FromArgb(0x00, System.Drawing.SystemColors.Control);
|
b.BackColor = System.Drawing.Color.FromArgb(0x00, System.Drawing.SystemColors.Control);
|
||||||
b.Enabled = false;
|
b.Enabled = false;
|
||||||
|
@ -253,7 +253,15 @@ namespace BetterJoyForCemu {
|
||||||
if (foundNew) { // attempt to auto join-up joycons on connection
|
if (foundNew) { // attempt to auto join-up joycons on connection
|
||||||
Joycon temp = null;
|
Joycon temp = null;
|
||||||
foreach (Joycon v in j) {
|
foreach (Joycon v in j) {
|
||||||
if (!v.isPro) {
|
// 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 (temp == null)
|
if (temp == null)
|
||||||
temp = v;
|
temp = v;
|
||||||
else if (temp.isLeft != v.isLeft && v.other == null) {
|
else if (temp.isLeft != v.isLeft && v.other == null) {
|
||||||
|
@ -294,10 +302,10 @@ namespace BetterJoyForCemu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
HIDapi.hid_free_enumeration(top_ptr);
|
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
|
foreach (Joycon jc in j) { // Connect device straight away
|
||||||
if (jc.state == Joycon.state_.NOT_ATTACHED) {
|
if (jc.state == Joycon.state_.NOT_ATTACHED) {
|
||||||
if (jc.out_xbox != null)
|
if (jc.out_xbox != null)
|
||||||
|
@ -312,10 +320,7 @@ namespace BetterJoyForCemu {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool on = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings["HomeLEDOn"].Value.ToLower() == "true";
|
jc.SetHomeLight(on);
|
||||||
foreach (Joycon j in Program.mgr.j) {
|
|
||||||
j.SetHomeLight(on);
|
|
||||||
}
|
|
||||||
|
|
||||||
jc.Begin();
|
jc.Begin();
|
||||||
if (form.allowCalibration) {
|
if (form.allowCalibration) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace BetterJoyForCemu {
|
||||||
|
|
||||||
public MainForm form;
|
public MainForm form;
|
||||||
|
|
||||||
public UdpServer(List<Joycon> p) {
|
public UdpServer(IList<Joycon> p) {
|
||||||
controllers = p;
|
controllers = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue