diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs index 3c4ff38..c9d6ecc 100644 --- a/DS4Windows/DS4Control/ControlService.cs +++ b/DS4Windows/DS4Control/ControlService.cs @@ -39,6 +39,7 @@ namespace DS4Windows }; public bool suspending; //SoundPlayer sp = new SoundPlayer(); + private UdpServer _udpServer; private class X360Data { @@ -48,6 +49,75 @@ namespace DS4Windows private X360Data[] processingData = new X360Data[4]; + void GetPadDetailForIdx(int padIdx, ref DualShockPadMeta meta) + { + //meta = new DualShockPadMeta(); + meta.PadId = (byte) padIdx; + meta.Model = DsModel.DS4; + + var d = DS4Controllers[padIdx]; + if (d == null) + { + meta.PadMacAddress = null; + meta.PadState = DsState.Disconnected; + meta.ConnectionType = DsConnection.None; + meta.Model = DsModel.None; + meta.BatteryStatus = 0; + meta.IsActive = false; + + //return meta; + } + + bool isValidSerial = false; + //if (d.isValidSerial()) + //{ + string stringMac = d.getMacAddress(); + if (!string.IsNullOrEmpty(stringMac)) + { + stringMac = string.Join("", stringMac.Split(':')); + //stringMac = stringMac.Replace(":", "").Trim(); + meta.PadMacAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(stringMac); + isValidSerial = d.isValidSerial(); + } + //} + + if (!isValidSerial) + { + //meta.PadMacAddress = null; + meta.PadState = DsState.Disconnected; + } + else + { + if (d.isSynced() || d.IsAlive()) + meta.PadState = DsState.Connected; + else + meta.PadState = DsState.Reserved; + } + + meta.ConnectionType = (d.getConnectionType() == ConnectionType.USB) ? DsConnection.Usb : DsConnection.Bluetooth; + meta.IsActive = !d.isDS4Idle(); + + if (d.isCharging() && d.getBattery() >= 100) + meta.BatteryStatus = DsBattery.Charged; + else + { + if (d.getBattery() >= 95) + meta.BatteryStatus = DsBattery.Full; + else if (d.getBattery() >= 70) + meta.BatteryStatus = DsBattery.High; + else if (d.getBattery() >= 50) + meta.BatteryStatus = DsBattery.Medium; + else if (d.getBattery() >= 20) + meta.BatteryStatus = DsBattery.Low; + else if (d.getBattery() >= 5) + meta.BatteryStatus = DsBattery.Dying; + else + meta.BatteryStatus = DsBattery.None; + } + + //return meta; + } + public ControlService() { //sp.Stream = Properties.Resources.EE; @@ -70,6 +140,8 @@ namespace DS4Windows PreviousState[i] = new DS4State(); ExposedState[i] = new DS4StateExposed(CurrentState[i]); } + + _udpServer = new UdpServer(GetPadDetailForIdx); } private void WarnExclusiveModeFailure(DS4Device device) @@ -211,6 +283,20 @@ namespace DS4Windows { this.On_Report(sender, e, tempIdx); }; + + if (_udpServer != null) + { + EventHandler tempEvnt = (sender, args) => + { + DualShockPadMeta padDetail = new DualShockPadMeta(); + GetPadDetailForIdx(tempIdx, ref padDetail); + _udpServer.NewReportIncoming(ref padDetail, CurrentState[tempIdx]); + }; + + device.Report += tempEvnt; + device.MotionEvent = tempEvnt; + } + TouchPadOn(i, device); CheckProfileOptions(i, device, true); device.StartUpdate(); @@ -243,6 +329,24 @@ namespace DS4Windows } running = true; + + if (_udpServer != null) + { + var UDP_SERVER_PORT = 26760; + + try + { + _udpServer.Start(UDP_SERVER_PORT); + LogDebug("UDP server listening on port " + UDP_SERVER_PORT); + } + catch (System.Net.Sockets.SocketException ex) + { + var errMsg = String.Format("Couldn't start UDP server on port {0}, outside applications won't be able to access pad data ({1})", UDP_SERVER_PORT, ex.SocketErrorCode); + + LogDebug(errMsg, true); + Log.LogToTray(errMsg, true, true); + } + } } else { @@ -319,6 +423,10 @@ namespace DS4Windows LogDebug(Properties.Resources.StoppingDS4); DS4Devices.stopControllers(); + + if (_udpServer != null) + _udpServer.Stop(); + if (showlog) LogDebug(Properties.Resources.StoppedDS4Windows); } @@ -388,6 +496,20 @@ namespace DS4Windows { this.On_Report(sender, e, tempIdx); }; + + if (_udpServer != null) + { + EventHandler tempEvnt = (sender, args) => + { + DualShockPadMeta padDetail = new DualShockPadMeta(); + GetPadDetailForIdx(tempIdx, ref padDetail); + _udpServer.NewReportIncoming(ref padDetail, CurrentState[tempIdx]); + }; + + device.Report += tempEvnt; + device.MotionEvent = tempEvnt; + } + if (!getDInputOnly(Index) && device.isSynced()) { int xinputIndex = x360Bus.FirstController + Index; @@ -855,6 +977,14 @@ namespace DS4Windows } } + /*if (_udpServer != null) + { + DualShockPadMeta padDetail = new DualShockPadMeta(); + GetPadDetailForIdx(ind, ref padDetail); + _udpServer.NewReportIncoming(ref padDetail, CurrentState[ind]); + } + */ + // Output any synthetic events. Mapping.Commit(ind); diff --git a/DS4Windows/DS4Library/DS4Device.cs b/DS4Windows/DS4Library/DS4Device.cs index 9ebf68d..30d2923 100644 --- a/DS4Windows/DS4Library/DS4Device.cs +++ b/DS4Windows/DS4Library/DS4Device.cs @@ -164,6 +164,7 @@ namespace DS4Windows public event EventHandler Removal = null; public event EventHandler SyncChange = null; public event EventHandler SerialChange = null; + public EventHandler MotionEvent = null; public HidDevice HidDevice => hDevice; public bool IsExclusive => HidDevice.IsExclusive; @@ -774,7 +775,7 @@ namespace DS4Windows //Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "" + // "> invalid CRC32 in BT input report: 0x" + recvCrc32.ToString("X8") + " expected: 0x" + calcCrc32.ToString("X8")); - //cState.PacketCounter = pState.PacketCounter + 1; //still increase so we know there were lost packets + cState.PacketCounter = pState.PacketCounter + 1; //still increase so we know there were lost packets continue; } } @@ -857,6 +858,7 @@ namespace DS4Windows utcNow = DateTime.UtcNow; // timestamp with UTC in case system time zone changes resetHapticState(); + cState.PacketCounter = pState.PacketCounter + 1; cState.ReportTimeStamp = utcNow; cState.LX = inputReport[1]; cState.LY = inputReport[2]; @@ -894,6 +896,8 @@ namespace DS4Windows cState.L3 = (tempByte & (1 << 6)) != 0; cState.Options = (tempByte & (1 << 5)) != 0; cState.Share = (tempByte & (1 << 4)) != 0; + cState.R2Btn = (inputReport[6] & (1 << 3)) != 0; + cState.L2Btn = (inputReport[6] & (1 << 2)) != 0; cState.R1 = (tempByte & (1 << 1)) != 0; cState.L1 = (tempByte & (1 << 0)) != 0; @@ -935,6 +939,18 @@ namespace DS4Windows timeStampPrevious = tempStamp; elapsedDeltaTime = 0.000001 * deltaTimeCurrent; // Convert from microseconds to seconds cState.elapsedTime = elapsedDeltaTime; + cState.totalMicroSec = pState.totalMicroSec + deltaTimeCurrent; + + //Simpler touch storing + cState.TrackPadTouch0.Id = (byte)(inputReport[35] & 0x7f); + cState.TrackPadTouch0.IsActive = (inputReport[35] & 0x80) == 0; + cState.TrackPadTouch0.X = (short)(((ushort)(inputReport[37] & 0x0f) << 8) | (ushort)(inputReport[36])); + cState.TrackPadTouch0.Y = (short)(((ushort)(inputReport[38]) << 4) | ((ushort)(inputReport[37] & 0xf0) >> 4)); + + cState.TrackPadTouch1.Id = (byte)(inputReport[39] & 0x7f); + cState.TrackPadTouch1.IsActive = (inputReport[39] & 0x80) == 0; + cState.TrackPadTouch1.X = (short)(((ushort)(inputReport[41] & 0x0f) << 8) | (ushort)(inputReport[40])); + cState.TrackPadTouch1.Y = (short)(((ushort)(inputReport[42]) << 4) | ((ushort)(inputReport[41] & 0xf0) >> 4)); // XXX DS4State mapping needs fixup, turn touches into an array[4] of structs. And include the touchpad details there instead. try @@ -1367,7 +1383,7 @@ namespace DS4Windows return pState; } - private bool isDS4Idle() + public bool isDS4Idle() { if (cState.Square || cState.Cross || cState.Circle || cState.Triangle) return false; diff --git a/DS4Windows/DS4Library/DS4State.cs b/DS4Windows/DS4Library/DS4State.cs index 66982eb..2978c2c 100644 --- a/DS4Windows/DS4Library/DS4State.cs +++ b/DS4Windows/DS4Library/DS4State.cs @@ -4,10 +4,11 @@ namespace DS4Windows { public class DS4State { + public uint PacketCounter; public DateTime ReportTimeStamp; public bool Square, Triangle, Circle, Cross; public bool DpadUp, DpadDown, DpadLeft, DpadRight; - public bool L1, L3, R1, R3; + public bool L1, L2Btn, L3, R1, R2Btn, R3; public bool Share, Options, PS, Touch1, Touch2, TouchButton, TouchRight, TouchLeft, Touch1Finger, Touch2Fingers; public byte Touch1Identifier, Touch2Identifier; @@ -24,14 +25,27 @@ namespace DS4Windows public double RXUnit; public double RYUnit; public double elapsedTime = 0.0; + public ulong totalMicroSec = 0; public SixAxis Motion = null; public static readonly int DEFAULT_AXISDIR_VALUE = 127; + public struct TrackPadTouch + { + public bool IsActive; + public byte Id; + public short X; + public short Y; + } + + public TrackPadTouch TrackPadTouch0; + public TrackPadTouch TrackPadTouch1; + public DS4State() { + PacketCounter = 0; Square = Triangle = Circle = Cross = false; DpadUp = DpadDown = DpadLeft = DpadRight = false; - L1 = L3 = R1 = R3 = false; + L1 = L2Btn = L3 = R1 = R2Btn = R3 = false; Share = Options = PS = Touch1 = Touch2 = TouchButton = TouchRight = TouchLeft = false; Touch1Finger = Touch2Fingers = false; LX = RX = LY = RY = 127; @@ -48,11 +62,15 @@ namespace DS4Windows RXUnit = 0.0; RYUnit = 0.0; elapsedTime = 0.0; + totalMicroSec = 0; Motion = new SixAxis(0, 0, 0, 0, 0, 0, 0.0); + TrackPadTouch0.IsActive = false; + TrackPadTouch1.IsActive = false; } public DS4State(DS4State state) { + PacketCounter = state.PacketCounter; ReportTimeStamp = state.ReportTimeStamp; Square = state.Square; Triangle = state.Triangle; @@ -64,9 +82,11 @@ namespace DS4Windows DpadRight = state.DpadRight; L1 = state.L1; L2 = state.L2; + L2Btn = state.L2Btn; L3 = state.L3; R1 = state.R1; R2 = state.R2; + R2Btn = state.R2Btn; R3 = state.R3; Share = state.Share; Options = state.Options; @@ -96,7 +116,10 @@ namespace DS4Windows RXUnit = state.RXUnit; RYUnit = state.RYUnit; elapsedTime = state.elapsedTime; + totalMicroSec = state.totalMicroSec; Motion = state.Motion; + TrackPadTouch0 = state.TrackPadTouch0; + TrackPadTouch1 = state.TrackPadTouch1; } public DS4State Clone() @@ -106,6 +129,7 @@ namespace DS4Windows public void CopyTo(DS4State state) { + state.PacketCounter = PacketCounter; state.ReportTimeStamp = ReportTimeStamp; state.Square = Square; state.Triangle = Triangle; @@ -117,9 +141,11 @@ namespace DS4Windows state.DpadRight = DpadRight; state.L1 = L1; state.L2 = L2; + state.L2Btn = L2Btn; state.L3 = L3; state.R1 = R1; state.R2 = R2; + state.R2Btn = R2Btn; state.R3 = R3; state.Share = Share; state.Options = Options; @@ -149,7 +175,10 @@ namespace DS4Windows state.RXUnit = RXUnit; state.RYUnit = RYUnit; state.elapsedTime = elapsedTime; + state.totalMicroSec = totalMicroSec; state.Motion = Motion; + state.TrackPadTouch0 = TrackPadTouch0; + state.TrackPadTouch1 = TrackPadTouch1; } public void calculateStickAngles() diff --git a/DS4Windows/DS4Windows.csproj b/DS4Windows/DS4Windows.csproj index ba5bb6b..d31b757 100644 --- a/DS4Windows/DS4Windows.csproj +++ b/DS4Windows/DS4Windows.csproj @@ -158,6 +158,7 @@ ScpHub.cs + Component