2014-03-28 02:50:40 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using DS4Library;
|
2014-05-07 06:35:08 +02:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Reflection;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
namespace DS4Control
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
public class Control
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
|
|
|
|
X360Device x360Bus;
|
2014-05-19 07:55:12 +02:00
|
|
|
|
public DS4Device[] DS4Controllers = new DS4Device[4];
|
2014-04-27 21:32:09 +02:00
|
|
|
|
//TPadModeSwitcher[] modeSwitcher = new TPadModeSwitcher[4];
|
|
|
|
|
Mouse[] touchPad = new Mouse[4];
|
2014-03-28 02:50:40 +01:00
|
|
|
|
private bool running = false;
|
|
|
|
|
private DS4State[] MappedState = new DS4State[4];
|
|
|
|
|
private DS4State[] CurrentState = new DS4State[4];
|
|
|
|
|
private DS4State[] PreviousState = new DS4State[4];
|
|
|
|
|
public DS4StateExposed[] ExposedState = new DS4StateExposed[4];
|
|
|
|
|
|
|
|
|
|
public event EventHandler<DebugEventArgs> Debug = null;
|
|
|
|
|
|
|
|
|
|
private class X360Data
|
|
|
|
|
{
|
|
|
|
|
public byte[] Report = new byte[28];
|
|
|
|
|
public byte[] Rumble = new byte[8];
|
|
|
|
|
}
|
|
|
|
|
private X360Data[] processingData = new X360Data[4];
|
|
|
|
|
|
|
|
|
|
public Control()
|
|
|
|
|
{
|
|
|
|
|
x360Bus = new X360Device();
|
|
|
|
|
for (int i = 0; i < DS4Controllers.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
processingData[i] = new X360Data();
|
|
|
|
|
MappedState[i] = new DS4State();
|
|
|
|
|
CurrentState[i] = new DS4State();
|
|
|
|
|
PreviousState[i] = new DS4State();
|
|
|
|
|
ExposedState[i] = new DS4StateExposed(CurrentState[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-29 06:29:08 +01:00
|
|
|
|
private void WarnExclusiveModeFailure(DS4Device device)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Devices.isExclusiveMode && !device.IsExclusive)
|
|
|
|
|
{
|
|
|
|
|
String message = "Warning: Could not open DS4 " + device.MacAddress + " exclusively. " +
|
|
|
|
|
"You must quit other applications like Steam, Uplay before activating the 'Hide DS4 Controller' option.";
|
|
|
|
|
LogDebug(message);
|
|
|
|
|
Log.LogToTray(message);
|
|
|
|
|
}
|
2014-05-07 06:35:08 +02:00
|
|
|
|
}
|
2014-05-25 01:08:40 +02:00
|
|
|
|
public bool Start(bool showlog = true)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
|
|
|
|
if (x360Bus.Open() && x360Bus.Start())
|
|
|
|
|
{
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
LogDebug("Starting...");
|
|
|
|
|
DS4Devices.isExclusiveMode = Global.getUseExclusiveMode();
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
|
|
|
|
{
|
|
|
|
|
LogDebug("Searching for controllers....");
|
|
|
|
|
LogDebug("Using " + (DS4Devices.isExclusiveMode ? "Exclusive Mode" : "Shared Mode"));
|
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
DS4Devices.findControllers();
|
|
|
|
|
IEnumerable<DS4Device> devices = DS4Devices.getDS4Controllers();
|
|
|
|
|
int ind = 0;
|
2014-06-02 05:19:04 +02:00
|
|
|
|
DS4LightBar.defualtLight = false;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
foreach (DS4Device device in devices)
|
|
|
|
|
{
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
|
|
|
|
LogDebug("Found Controller: " + device.MacAddress + " (" + device.ConnectionType + ")");
|
2014-03-29 06:29:08 +01:00
|
|
|
|
WarnExclusiveModeFailure(device);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Controllers[ind] = device;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
device.Removal -= DS4Devices.On_Removal;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
device.Removal += this.On_DS4Removal;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
device.Removal += DS4Devices.On_Removal;
|
|
|
|
|
//TPadModeSwitcher m_switcher = new TPadModeSwitcher(device, ind);
|
|
|
|
|
//m_switcher.Debug += OnDebug;
|
|
|
|
|
//modeSwitcher[ind] = m_switcher;
|
|
|
|
|
touchPad[ind] = new Mouse(ind, device);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Color color = Global.loadColor(ind);
|
|
|
|
|
device.LightBarColor = color;
|
2014-04-30 05:54:41 +02:00
|
|
|
|
x360Bus.Plugin(ind);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
device.Report += this.On_Report;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
//m_switcher.setMode(Global.getInitialMode(ind));
|
|
|
|
|
TouchPadOn(ind, device);
|
2014-05-21 07:36:05 +02:00
|
|
|
|
string filename = Path.GetFileName(Global.getAProfile(ind));
|
2014-03-28 02:50:40 +01:00
|
|
|
|
ind++;
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
|
|
|
|
if (System.IO.File.Exists(Global.appdatapath + "\\Profiles\\" + filename))
|
|
|
|
|
{
|
|
|
|
|
LogDebug("Controller " + ind + " is using Profile \"" + filename.Substring(0, filename.Length - 4) + "\"");
|
|
|
|
|
Log.LogToTray("Controller " + ind + " is using Profile \"" + filename.Substring(0, filename.Length - 4) + "\"");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LogDebug("Controller " + ind + " is not using a profile");
|
|
|
|
|
Log.LogToTray("Controller " + ind + " is not using a profile");
|
|
|
|
|
}
|
2014-03-29 06:29:08 +01:00
|
|
|
|
if (ind >= 4) // out of Xinput devices!
|
2014-03-28 02:50:40 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
LogDebug(e.Message);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
Log.LogToTray(e.Message);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
running = true;
|
2014-05-05 09:31:24 +02:00
|
|
|
|
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-25 01:08:40 +02:00
|
|
|
|
public bool Stop(bool showlog = true)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
|
|
|
|
if (running)
|
|
|
|
|
{
|
|
|
|
|
running = false;
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
2014-05-28 04:49:58 +02:00
|
|
|
|
LogDebug("Stopping X360 Controllers");
|
|
|
|
|
bool anyUnplugged = false;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
for (int i = 0; i < DS4Controllers.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[i] != null)
|
2014-06-21 20:00:28 +02:00
|
|
|
|
{
|
|
|
|
|
if (Global.getDCBTatStop() && !DS4Controllers[i].Charging && showlog)
|
|
|
|
|
DS4Controllers[i].DisconnectBT();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DS4LightBar.defualtLight = true;
|
|
|
|
|
DS4LightBar.updateLightBar(DS4Controllers[i], i);
|
|
|
|
|
System.Threading.Thread.Sleep(50);
|
|
|
|
|
}
|
2014-04-27 21:32:09 +02:00
|
|
|
|
CurrentState[i].Battery = PreviousState[i].Battery = 0; // Reset for the next connection's initial status change.
|
2014-04-30 05:54:41 +02:00
|
|
|
|
x360Bus.Unplug(i);
|
2014-04-27 21:32:09 +02:00
|
|
|
|
anyUnplugged = true;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Controllers[i] = null;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
touchPad[i] = null;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-27 21:32:09 +02:00
|
|
|
|
if (anyUnplugged)
|
|
|
|
|
System.Threading.Thread.Sleep(XINPUT_UNPLUG_SETTLE_TIME);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
x360Bus.Stop();
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
2014-05-28 04:49:58 +02:00
|
|
|
|
LogDebug("Stopping DS4 Controllers");
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Devices.stopControllers();
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (showlog)
|
2014-05-28 04:49:58 +02:00
|
|
|
|
LogDebug("Stopped DS4 Tool");
|
|
|
|
|
Global.ControllerStatusChanged(this);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool HotPlug()
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
if (running)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
|
|
|
|
DS4Devices.findControllers();
|
|
|
|
|
IEnumerable<DS4Device> devices = DS4Devices.getDS4Controllers();
|
|
|
|
|
foreach (DS4Device device in devices)
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
if (device.IsDisconnecting)
|
|
|
|
|
continue;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (((Func<bool>)delegate
|
|
|
|
|
{
|
|
|
|
|
for (Int32 Index = 0; Index < DS4Controllers.Length; Index++)
|
2014-05-25 01:08:40 +02:00
|
|
|
|
if (DS4Controllers[Index] != null && DS4Controllers[Index].MacAddress == device.MacAddress)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
})())
|
|
|
|
|
continue;
|
|
|
|
|
for (Int32 Index = 0; Index < DS4Controllers.Length; Index++)
|
|
|
|
|
if (DS4Controllers[Index] == null)
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
LogDebug("Found Controller: " + device.MacAddress + " (" + device.ConnectionType + ")");
|
|
|
|
|
WarnExclusiveModeFailure(device);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Controllers[Index] = device;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
device.Removal -= DS4Devices.On_Removal;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
device.Removal += this.On_DS4Removal;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
device.Removal += DS4Devices.On_Removal;
|
2014-05-05 09:31:24 +02:00
|
|
|
|
touchPad[Index] = new Mouse(Index, device);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
device.LightBarColor = Global.loadColor(Index);
|
|
|
|
|
device.Report += this.On_Report;
|
2014-04-30 05:54:41 +02:00
|
|
|
|
x360Bus.Plugin(Index);
|
2014-04-27 21:32:09 +02:00
|
|
|
|
TouchPadOn(Index, device);
|
2014-05-21 07:36:05 +02:00
|
|
|
|
string filename = Path.GetFileName(Global.getAProfile(Index));
|
2014-05-19 07:55:12 +02:00
|
|
|
|
if (System.IO.File.Exists(Global.appdatapath + "\\Profiles\\" + filename))
|
2014-05-07 06:35:08 +02:00
|
|
|
|
{
|
2014-05-21 07:36:05 +02:00
|
|
|
|
LogDebug("Controller " + (Index + 1) + " is using Profile \"" + filename.Substring(0, filename.Length - 4) + "\"");
|
2014-05-07 06:46:36 +02:00
|
|
|
|
Log.LogToTray("Controller " + (Index + 1) + " is using Profile \"" + filename.Substring(0, filename.Length - 4) + "\"");
|
2014-05-07 06:35:08 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-05-21 07:36:05 +02:00
|
|
|
|
LogDebug("Controller " + (Index + 1) + " is not using a profile");
|
|
|
|
|
Log.LogToTray("Controller " + (Index + 1) + " is not using a profile");
|
2014-05-07 06:35:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 02:50:40 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-27 21:32:09 +02:00
|
|
|
|
public void TouchPadOn(int ind, DS4Device device)
|
|
|
|
|
{
|
|
|
|
|
ITouchpadBehaviour tPad = touchPad[ind];
|
|
|
|
|
device.Touchpad.TouchButtonDown += tPad.touchButtonDown;
|
|
|
|
|
device.Touchpad.TouchButtonUp += tPad.touchButtonUp;
|
|
|
|
|
device.Touchpad.TouchesBegan += tPad.touchesBegan;
|
|
|
|
|
device.Touchpad.TouchesMoved += tPad.touchesMoved;
|
|
|
|
|
device.Touchpad.TouchesEnded += tPad.touchesEnded;
|
|
|
|
|
device.Touchpad.TouchUnchanged += tPad.touchUnchanged;
|
|
|
|
|
//LogDebug("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString());
|
|
|
|
|
//Log.LogToTray("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString());
|
|
|
|
|
Global.ControllerStatusChanged(this);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-25 01:08:40 +02:00
|
|
|
|
public void TimeoutConnection(DS4Device d)
|
2014-05-24 01:44:30 +02:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
|
|
|
|
sw.Start();
|
|
|
|
|
while (!d.IsAlive())
|
|
|
|
|
{
|
|
|
|
|
if (sw.ElapsedMilliseconds < 1000)
|
|
|
|
|
System.Threading.Thread.SpinWait(500);
|
|
|
|
|
//If weve been waiting less than 1 second let the thread keep its processing chunk
|
|
|
|
|
else
|
|
|
|
|
System.Threading.Thread.Sleep(500);
|
|
|
|
|
//If weve been waiting more than 1 second give up some resources
|
|
|
|
|
|
|
|
|
|
if (sw.ElapsedMilliseconds > 5000) throw new TimeoutException(); //Weve waited long enough
|
|
|
|
|
}
|
|
|
|
|
sw.Reset();
|
|
|
|
|
}
|
2014-05-25 01:08:40 +02:00
|
|
|
|
catch (TimeoutException)
|
2014-05-24 01:44:30 +02:00
|
|
|
|
{
|
2014-05-25 01:08:40 +02:00
|
|
|
|
Stop(false);
|
|
|
|
|
Start(false);
|
2014-05-24 01:44:30 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 02:50:40 +01:00
|
|
|
|
public string getDS4ControllerInfo(int index)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[index] != null)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[index];
|
2014-03-29 06:29:08 +01:00
|
|
|
|
if (!d.IsAlive())
|
2014-05-24 01:44:30 +02:00
|
|
|
|
//return "Connecting..."; // awaiting the first battery charge indication
|
|
|
|
|
{
|
|
|
|
|
var TimeoutThread = new System.Threading.Thread(() => TimeoutConnection(d));
|
|
|
|
|
TimeoutThread.IsBackground = true;
|
|
|
|
|
TimeoutThread.Name = "TimeoutFor" + d.MacAddress.ToString();
|
|
|
|
|
TimeoutThread.Start();
|
|
|
|
|
return "Connecting...";
|
|
|
|
|
}
|
2014-03-29 06:29:08 +01:00
|
|
|
|
String battery;
|
|
|
|
|
if (d.Charging)
|
|
|
|
|
{
|
|
|
|
|
if (d.Battery >= 100)
|
2014-04-27 21:32:09 +02:00
|
|
|
|
battery = "Charged";
|
2014-03-29 06:29:08 +01:00
|
|
|
|
else
|
2014-04-27 21:32:09 +02:00
|
|
|
|
battery = "Charging:" + d.Battery + "%";
|
2014-03-29 06:29:08 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-04-27 21:32:09 +02:00
|
|
|
|
battery = "Battery: " + d.Battery + "%";
|
2014-03-29 06:29:08 +01:00
|
|
|
|
}
|
2014-04-27 21:32:09 +02:00
|
|
|
|
return d.MacAddress + " (" + d.ConnectionType + "), " + battery;
|
|
|
|
|
//return d.MacAddress + " (" + d.ConnectionType + "), Battery is " + battery + ", Touchpad in " + modeSwitcher[index].ToString();
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
2014-04-27 21:32:09 +02:00
|
|
|
|
return String.Empty;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-30 22:39:39 +02:00
|
|
|
|
public string getDS4MacAddress(int index)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[index] != null)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[index];
|
|
|
|
|
if (!d.IsAlive())
|
|
|
|
|
//return "Connecting..."; // awaiting the first battery charge indication
|
|
|
|
|
{
|
|
|
|
|
var TimeoutThread = new System.Threading.Thread(() => TimeoutConnection(d));
|
|
|
|
|
TimeoutThread.IsBackground = true;
|
|
|
|
|
TimeoutThread.Name = "TimeoutFor" + d.MacAddress.ToString();
|
|
|
|
|
TimeoutThread.Start();
|
|
|
|
|
return "Connecting...";
|
|
|
|
|
}
|
|
|
|
|
return d.MacAddress;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return String.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-27 21:32:09 +02:00
|
|
|
|
public string getShortDS4ControllerInfo(int index)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[index] != null)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[index];
|
|
|
|
|
String battery;
|
|
|
|
|
if (!d.IsAlive())
|
|
|
|
|
battery = "...";
|
|
|
|
|
if (d.Charging)
|
|
|
|
|
{
|
|
|
|
|
if (d.Battery >= 100)
|
|
|
|
|
battery = "Full";
|
|
|
|
|
else
|
2014-04-30 21:32:44 +02:00
|
|
|
|
battery = d.Battery + "%+";
|
2014-04-27 21:32:09 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
battery = d.Battery + "%";
|
|
|
|
|
}
|
2014-05-30 22:39:39 +02:00
|
|
|
|
return d.ConnectionType + " " + battery + " (" + System.IO.Path.GetFileNameWithoutExtension(Global.getAProfile(index)) + ")";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "None";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string getDS4Battery(int index)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[index] != null)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[index];
|
|
|
|
|
String battery;
|
|
|
|
|
if (!d.IsAlive())
|
|
|
|
|
battery = "...";
|
|
|
|
|
if (d.Charging)
|
|
|
|
|
{
|
|
|
|
|
if (d.Battery >= 100)
|
|
|
|
|
battery = "Full";
|
|
|
|
|
else
|
|
|
|
|
battery = d.Battery + "%+";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
battery = d.Battery + "%";
|
|
|
|
|
}
|
|
|
|
|
return battery;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "N/A";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string getDS4Status(int index)
|
|
|
|
|
{
|
|
|
|
|
if (DS4Controllers[index] != null)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[index];
|
|
|
|
|
return d.ConnectionType+"";
|
2014-04-27 21:32:09 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "None";
|
|
|
|
|
}
|
|
|
|
|
|
Rest of DS4Windows has been upped to .NET 4.5 (If you have .net 4/already can run DS4Windows, this won't affect you), thanks to this update, you can now...
Add delay to macros from one millisecond to 60 seconds, macros with delays only run once until pressed again. Without delays, the macro can be repeated while held down.
Profiles and settings are now back inside the application folder to help portability. It will remain in appdata as previous versions if DS4Windows is in a admin folder, I may try to add a setting for location saving.
Import profile option will automatically go to the appdata profile folder, auto profiles and settings will automatically copy over.
Option to delete the appdata folder if not in use in the settings tab, this way it helps with cleanup.
Another fix for auto profiles startup bug
Better reading of autoprofile program path names
Now only one instance of DS4Windows is possible, if another DS4Tool or DS4Windows that is not this version is started, this DS4Windows comes back into focus.
UI fixes
2014-06-10 21:45:09 +02:00
|
|
|
|
|
2014-04-27 21:32:09 +02:00
|
|
|
|
private int XINPUT_UNPLUG_SETTLE_TIME = 250; // Inhibit races that occur with the asynchronous teardown of ScpVBus -> X360 driver instance.
|
2014-03-28 02:50:40 +01:00
|
|
|
|
//Called when DS4 is disconnected or timed out
|
|
|
|
|
protected virtual void On_DS4Removal(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
DS4Device device = (DS4Device)sender;
|
|
|
|
|
int ind = -1;
|
|
|
|
|
for (int i = 0; i < DS4Controllers.Length; i++)
|
|
|
|
|
if (DS4Controllers[i] != null && device.MacAddress == DS4Controllers[i].MacAddress)
|
|
|
|
|
ind = i;
|
|
|
|
|
if (ind != -1)
|
|
|
|
|
{
|
2014-04-27 21:32:09 +02:00
|
|
|
|
CurrentState[ind].Battery = PreviousState[ind].Battery = 0; // Reset for the next connection's initial status change.
|
2014-04-30 05:54:41 +02:00
|
|
|
|
x360Bus.Unplug(ind);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
LogDebug("Controller " + device.MacAddress + " was removed or lost connection");
|
|
|
|
|
Log.LogToTray("Controller " + device.MacAddress + " was removed or lost connection");
|
2014-04-27 21:32:09 +02:00
|
|
|
|
System.Threading.Thread.Sleep(XINPUT_UNPLUG_SETTLE_TIME);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
DS4Controllers[ind] = null;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
//modeSwitcher[ind] = null;
|
|
|
|
|
touchPad[ind] = null;
|
2014-03-29 06:29:08 +01:00
|
|
|
|
Global.ControllerStatusChanged(this);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Called every time the new input report has arrived
|
|
|
|
|
protected virtual void On_Report(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
DS4Device device = (DS4Device)sender;
|
|
|
|
|
|
2014-05-05 09:31:24 +02:00
|
|
|
|
int ind = -1;
|
|
|
|
|
for (int i = 0; i < DS4Controllers.Length; i++)
|
|
|
|
|
if (device == DS4Controllers[i])
|
2014-03-28 02:50:40 +01:00
|
|
|
|
ind = i;
|
|
|
|
|
|
2014-05-05 09:31:24 +02:00
|
|
|
|
if (ind != -1)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
device.getExposedState(ExposedState[ind], CurrentState[ind]);
|
|
|
|
|
DS4State cState = CurrentState[ind];
|
|
|
|
|
device.getPreviousState(PreviousState[ind]);
|
|
|
|
|
DS4State pState = PreviousState[ind];
|
2014-04-27 21:32:09 +02:00
|
|
|
|
if (pState.Battery != cState.Battery)
|
|
|
|
|
Global.ControllerStatusChanged(this);
|
|
|
|
|
CheckForHotkeys(ind, cState, pState);
|
2014-05-19 07:55:12 +02:00
|
|
|
|
GetInputkeys(ind);
|
2014-05-05 09:31:24 +02:00
|
|
|
|
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (Global.getHasCustomKeysorButtons(ind))
|
|
|
|
|
{
|
2014-06-24 00:27:14 +02:00
|
|
|
|
Mapping.MapCustom(ind, cState, MappedState[ind], ExposedState[ind]);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
cState = MappedState[ind];
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-29 06:29:08 +01:00
|
|
|
|
// Update the GUI/whatever.
|
|
|
|
|
DS4LightBar.updateLightBar(device, ind);
|
2014-06-02 05:19:04 +02:00
|
|
|
|
//DS4LightBar.defualtLight(device, ind);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
|
2014-06-12 20:46:00 +02:00
|
|
|
|
x360Bus.Parse(cState, processingData[ind].Report, ind);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
// We push the translated Xinput state, and simultaneously we
|
|
|
|
|
// pull back any possible rumble data coming from Xinput consumers.
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (x360Bus.Report(processingData[ind].Report, processingData[ind].Rumble))
|
|
|
|
|
{
|
|
|
|
|
Byte Big = (Byte)(processingData[ind].Rumble[3]);
|
|
|
|
|
Byte Small = (Byte)(processingData[ind].Rumble[4]);
|
|
|
|
|
|
|
|
|
|
if (processingData[ind].Rumble[1] == 0x08)
|
|
|
|
|
{
|
|
|
|
|
setRumble(Small, Big, ind);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-27 21:32:09 +02:00
|
|
|
|
|
|
|
|
|
// Output any synthetic events.
|
|
|
|
|
Mapping.Commit(ind);
|
|
|
|
|
// Pull settings updates.
|
|
|
|
|
device.IdleTimeout = Global.getIdleDisconnectTimeout(ind);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-19 07:55:12 +02:00
|
|
|
|
public string GetInputkeys(int ind)
|
|
|
|
|
{
|
|
|
|
|
DS4State cState = CurrentState[ind];
|
2014-06-24 00:27:14 +02:00
|
|
|
|
DS4StateExposed eState = ExposedState[ind];
|
2014-05-30 22:39:39 +02:00
|
|
|
|
if (DS4Controllers[ind] != null)
|
2014-06-24 00:27:14 +02:00
|
|
|
|
if (Mapping.getBoolMapping(DS4Controls.Cross, cState, eState)) return "Cross";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.Circle, cState, eState)) return "Circle";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.Triangle, cState, eState)) return "Triangle";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.Square, cState, eState)) return "Square";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.L1, cState, eState)) return "L1";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.R1, cState, eState)) return "R1";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.L2, cState, eState)) return "L2";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.R2, cState, eState)) return "R2";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.L3, cState, eState)) return "L3";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.R3, cState, eState)) return "R3";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.DpadUp, cState, eState)) return "Up";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.DpadDown, cState, eState)) return "Down";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.DpadLeft, cState, eState)) return "Left";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.DpadRight, cState, eState)) return "Right";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.Share, cState, eState)) return "Share";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.Options, cState, eState)) return "Options";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.PS, cState, eState)) return "PS";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.LXPos, cState, eState)) return "LS Right";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.LXNeg, cState, eState)) return "LS Left";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.LYPos, cState, eState)) return "LS Down";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.LYNeg, cState, eState)) return "LS Up";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.RXPos, cState, eState)) return "RS Right";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.RXNeg, cState, eState)) return "RS Left";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.RYPos, cState, eState)) return "RS Down";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.RYNeg, cState, eState)) return "RS Up";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.TouchLeft, cState, eState)) return "Touch Left";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.TouchRight, cState, eState)) return "Touch Right";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.TouchMulti, cState, eState)) return "Touch Multi";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.TouchUpper, cState, eState)) return "Touch Upper";
|
|
|
|
|
/*else if (Mapping.getBoolMapping(DS4Controls.GyroXPos, cState, eState)) return "GyroXP";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.GyroXNeg, cState, eState)) return "GyroXN";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.GyroZPos, cState, eState)) return "GyroZP";
|
|
|
|
|
else if (Mapping.getBoolMapping(DS4Controls.GyroZNeg, cState, eState)) return "GyroZN";*/
|
|
|
|
|
return "nothing";
|
2014-05-19 07:55:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-02 19:29:38 +02:00
|
|
|
|
bool[] touchreleased = { true, true, true, true }, touchslid = { false, false, false, false };
|
2014-05-28 04:49:58 +02:00
|
|
|
|
byte[] oldtouchvalue = { 0, 0, 0, 0 };
|
2014-03-28 02:50:40 +01:00
|
|
|
|
protected virtual void CheckForHotkeys(int deviceID, DS4State cState, DS4State pState)
|
|
|
|
|
{
|
|
|
|
|
DS4Device d = DS4Controllers[deviceID];
|
2014-05-28 04:49:58 +02:00
|
|
|
|
if ((!pState.PS || !pState.Options) && cState.PS && cState.Options)
|
|
|
|
|
{
|
2014-05-28 21:47:25 +02:00
|
|
|
|
if (!d.Charging)
|
2014-05-28 04:49:58 +02:00
|
|
|
|
{
|
2014-05-28 21:47:25 +02:00
|
|
|
|
d.DisconnectBT();
|
|
|
|
|
InputMethods.performKeyRelease(Global.getCustomKey(0, DS4Controls.PS));
|
|
|
|
|
string[] skeys = Global.getCustomMacro(0, DS4Controls.PS).Split('/');
|
|
|
|
|
ushort[] keys = new ushort[skeys.Length];
|
|
|
|
|
for (int i = 0; i < keys.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
keys[i] = ushort.Parse(skeys[i]);
|
|
|
|
|
InputMethods.performKeyRelease(keys[i]);
|
|
|
|
|
}
|
2014-05-28 04:49:58 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-12 20:46:00 +02:00
|
|
|
|
if (cState.Touch1 && pState.PS)
|
2014-04-27 21:32:09 +02:00
|
|
|
|
{
|
2014-06-02 19:29:38 +02:00
|
|
|
|
if (Global.getTouchSensitivity(deviceID) > 0 && touchreleased[deviceID])
|
2014-04-27 21:32:09 +02:00
|
|
|
|
{
|
2014-05-28 04:49:58 +02:00
|
|
|
|
oldtouchvalue[deviceID] = Global.getTouchSensitivity(deviceID);
|
2014-04-27 21:32:09 +02:00
|
|
|
|
Global.setTouchSensitivity(deviceID, 0);
|
2014-04-29 04:50:56 +02:00
|
|
|
|
LogDebug("Touchpad Movement is now " + (Global.getTouchSensitivity(deviceID) > 0 ? "On" : "Off"));
|
|
|
|
|
Log.LogToTray("Touchpad Movement is now " + (Global.getTouchSensitivity(deviceID) > 0 ? "On" : "Off"));
|
2014-06-02 19:29:38 +02:00
|
|
|
|
touchreleased[deviceID] = false;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
}
|
2014-06-02 19:29:38 +02:00
|
|
|
|
else if (touchreleased[deviceID])
|
2014-04-27 21:32:09 +02:00
|
|
|
|
{
|
2014-05-28 04:49:58 +02:00
|
|
|
|
Global.setTouchSensitivity(deviceID, oldtouchvalue[deviceID]);
|
2014-04-29 04:50:56 +02:00
|
|
|
|
LogDebug("Touchpad Movement is now " + (Global.getTouchSensitivity(deviceID) > 0 ? "On" : "Off"));
|
|
|
|
|
Log.LogToTray("Touchpad Movement is now " + (Global.getTouchSensitivity(deviceID) > 0 ? "On" : "Off"));
|
2014-06-02 19:29:38 +02:00
|
|
|
|
touchreleased[deviceID] = false;
|
2014-04-27 21:32:09 +02:00
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
2014-04-27 21:32:09 +02:00
|
|
|
|
else
|
2014-06-02 19:29:38 +02:00
|
|
|
|
touchreleased[deviceID] = true;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-30 22:39:39 +02:00
|
|
|
|
public virtual string TouchpadSlide(int ind)
|
|
|
|
|
{
|
|
|
|
|
DS4State cState = CurrentState[ind];
|
|
|
|
|
string slidedir = "none";
|
2014-06-06 22:38:52 +02:00
|
|
|
|
if (DS4Controllers[ind] != null)
|
|
|
|
|
if (cState.Touch2)
|
|
|
|
|
if (DS4Controllers[ind] != null)
|
|
|
|
|
if (touchPad[ind].slideright && !touchslid[ind])
|
|
|
|
|
{
|
|
|
|
|
slidedir = "right";
|
|
|
|
|
touchslid[ind] = true;
|
|
|
|
|
}
|
|
|
|
|
else if (touchPad[ind].slideleft && !touchslid[ind])
|
|
|
|
|
{
|
|
|
|
|
slidedir = "left";
|
|
|
|
|
touchslid[ind] = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!touchPad[ind].slideleft && !touchPad[ind].slideright)
|
|
|
|
|
{
|
|
|
|
|
slidedir = "";
|
|
|
|
|
touchslid[ind] = false;
|
|
|
|
|
}
|
2014-05-30 22:39:39 +02:00
|
|
|
|
return slidedir;
|
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
public virtual void LogDebug(String Data)
|
|
|
|
|
{
|
2014-05-21 07:36:05 +02:00
|
|
|
|
Console.WriteLine(System.DateTime.Now.ToString("G") + "> " + Data);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (Debug != null)
|
|
|
|
|
{
|
|
|
|
|
DebugEventArgs args = new DebugEventArgs(Data);
|
|
|
|
|
OnDebug(this, args);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void OnDebug(object sender, DebugEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (Debug != null)
|
|
|
|
|
Debug(this, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//sets the rumble adjusted with rumble boost
|
|
|
|
|
public virtual void setRumble(byte heavyMotor, byte lightMotor, int deviceNum)
|
|
|
|
|
{
|
|
|
|
|
byte boost = Global.loadRumbleBoost(deviceNum);
|
|
|
|
|
uint lightBoosted = ((uint)lightMotor * (uint)boost) / 100;
|
|
|
|
|
if (lightBoosted > 255)
|
|
|
|
|
lightBoosted = 255;
|
|
|
|
|
uint heavyBoosted = ((uint)heavyMotor * (uint)boost) / 100;
|
|
|
|
|
if (heavyBoosted > 255)
|
|
|
|
|
heavyBoosted = 255;
|
2014-05-30 22:39:39 +02:00
|
|
|
|
if (deviceNum < 4)
|
|
|
|
|
if (DS4Controllers[deviceNum] != null)
|
|
|
|
|
DS4Controllers[deviceNum].setRumble((byte)lightBoosted, (byte)heavyBoosted);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
2014-05-28 04:49:58 +02:00
|
|
|
|
|
|
|
|
|
public DS4State getDS4State(int ind)
|
|
|
|
|
{
|
|
|
|
|
return CurrentState[ind];
|
|
|
|
|
}
|
Rest of DS4Windows has been upped to .NET 4.5 (If you have .net 4/already can run DS4Windows, this won't affect you), thanks to this update, you can now...
Add delay to macros from one millisecond to 60 seconds, macros with delays only run once until pressed again. Without delays, the macro can be repeated while held down.
Profiles and settings are now back inside the application folder to help portability. It will remain in appdata as previous versions if DS4Windows is in a admin folder, I may try to add a setting for location saving.
Import profile option will automatically go to the appdata profile folder, auto profiles and settings will automatically copy over.
Option to delete the appdata folder if not in use in the settings tab, this way it helps with cleanup.
Another fix for auto profiles startup bug
Better reading of autoprofile program path names
Now only one instance of DS4Windows is possible, if another DS4Tool or DS4Windows that is not this version is started, this DS4Windows comes back into focus.
UI fixes
2014-06-10 21:45:09 +02:00
|
|
|
|
public DS4State getDS4StateMapped(int ind)
|
|
|
|
|
{
|
|
|
|
|
return MappedState[ind];
|
2014-06-21 20:00:28 +02:00
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|