mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2024-11-29 20:44:20 +01:00
Reduced input lag by implementing overlapped IO and changing threading
This commit is contained in:
parent
0dd442f813
commit
5dbc193351
@ -121,6 +121,7 @@ namespace DS4Windows
|
|||||||
private byte[] accel = new byte[6];
|
private byte[] accel = new byte[6];
|
||||||
private byte[] gyro = new byte[6];
|
private byte[] gyro = new byte[6];
|
||||||
private byte[] inputReport;
|
private byte[] inputReport;
|
||||||
|
private byte[] inputReport2;
|
||||||
private byte[] btInputReport = null;
|
private byte[] btInputReport = null;
|
||||||
private byte[] outputReportBuffer, outputReport;
|
private byte[] outputReportBuffer, outputReport;
|
||||||
private readonly DS4Touchpad touchpad = null;
|
private readonly DS4Touchpad touchpad = null;
|
||||||
@ -134,6 +135,8 @@ namespace DS4Windows
|
|||||||
public DateTime lastActive = DateTime.UtcNow;
|
public DateTime lastActive = DateTime.UtcNow;
|
||||||
public DateTime firstActive = DateTime.UtcNow;
|
public DateTime firstActive = DateTime.UtcNow;
|
||||||
private bool charging;
|
private bool charging;
|
||||||
|
// Use large value for worst case scenario
|
||||||
|
private static int readStreamTimeout = 100;
|
||||||
public event EventHandler<EventArgs> Report = null;
|
public event EventHandler<EventArgs> Report = null;
|
||||||
public event EventHandler<EventArgs> Removal = null;
|
public event EventHandler<EventArgs> Removal = null;
|
||||||
|
|
||||||
@ -221,6 +224,7 @@ namespace DS4Windows
|
|||||||
if (conType == ConnectionType.USB)
|
if (conType == ConnectionType.USB)
|
||||||
{
|
{
|
||||||
inputReport = new byte[64];
|
inputReport = new byte[64];
|
||||||
|
inputReport2 = new byte[64];
|
||||||
outputReport = new byte[hDevice.Capabilities.OutputReportByteLength];
|
outputReport = new byte[hDevice.Capabilities.OutputReportByteLength];
|
||||||
outputReportBuffer = new byte[hDevice.Capabilities.OutputReportByteLength];
|
outputReportBuffer = new byte[hDevice.Capabilities.OutputReportByteLength];
|
||||||
}
|
}
|
||||||
@ -244,7 +248,13 @@ namespace DS4Windows
|
|||||||
ds4Output = new Thread(performDs4Output);
|
ds4Output = new Thread(performDs4Output);
|
||||||
ds4Output.Priority = ThreadPriority.Highest;
|
ds4Output.Priority = ThreadPriority.Highest;
|
||||||
ds4Output.Name = "DS4 Output thread: " + Mac;
|
ds4Output.Name = "DS4 Output thread: " + Mac;
|
||||||
|
if (conType == ConnectionType.BT)
|
||||||
|
{
|
||||||
|
// Only use the output thread for Bluetooth connections.
|
||||||
|
// USB will utilize overlapped IO instead.
|
||||||
ds4Output.Start();
|
ds4Output.Start();
|
||||||
|
}
|
||||||
|
|
||||||
ds4Input = new Thread(performDs4Input);
|
ds4Input = new Thread(performDs4Input);
|
||||||
ds4Input.Priority = ThreadPriority.Highest;
|
ds4Input.Priority = ThreadPriority.Highest;
|
||||||
ds4Input.Name = "DS4 Input thread: " + Mac;
|
ds4Input.Name = "DS4 Input thread: " + Mac;
|
||||||
@ -273,7 +283,7 @@ namespace DS4Windows
|
|||||||
|
|
||||||
private void StopOutputUpdate()
|
private void StopOutputUpdate()
|
||||||
{
|
{
|
||||||
if (ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
|
if (ds4Output.ThreadState != System.Threading.ThreadState.Unstarted || ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -295,7 +305,7 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return hDevice.WriteOutputReportViaInterrupt(outputReport, 8);
|
return hDevice.WriteAsyncOutputReportViaInterrupt(outputReport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,10 +313,12 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
lock (outputReport)
|
lock (outputReport)
|
||||||
{
|
{
|
||||||
int lastError = 0;
|
//int lastError = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (writeOutput())
|
Monitor.Wait(outputReport);
|
||||||
|
writeOutput();
|
||||||
|
/*if (writeOutput())
|
||||||
{
|
{
|
||||||
lastError = 0;
|
lastError = 0;
|
||||||
if (testRumble.IsRumbleSet()) // repeat test rumbles periodically; rumble has auto-shut-off in the DS4 firmware
|
if (testRumble.IsRumbleSet()) // repeat test rumbles periodically; rumble has auto-shut-off in the DS4 firmware
|
||||||
@ -323,6 +335,7 @@ namespace DS4Windows
|
|||||||
lastError = thisError;
|
lastError = thisError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +387,8 @@ namespace DS4Windows
|
|||||||
readTimeout.Enabled = true;
|
readTimeout.Enabled = true;
|
||||||
if (conType != ConnectionType.USB)
|
if (conType != ConnectionType.USB)
|
||||||
{
|
{
|
||||||
HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
//HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
||||||
|
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(btInputReport, readStreamTimeout);
|
||||||
readTimeout.Enabled = false;
|
readTimeout.Enabled = false;
|
||||||
if (res == HidDevice.ReadStatus.Success)
|
if (res == HidDevice.ReadStatus.Success)
|
||||||
{
|
{
|
||||||
@ -394,7 +408,8 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
//HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
||||||
|
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(inputReport2, readStreamTimeout);
|
||||||
readTimeout.Enabled = false;
|
readTimeout.Enabled = false;
|
||||||
if (res != HidDevice.ReadStatus.Success)
|
if (res != HidDevice.ReadStatus.Success)
|
||||||
{
|
{
|
||||||
@ -405,6 +420,10 @@ namespace DS4Windows
|
|||||||
Removal(this, EventArgs.Empty);
|
Removal(this, EventArgs.Empty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Array.Copy(inputReport2, 0, inputReport, 0, inputReport.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
|
if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
|
||||||
{
|
{
|
||||||
@ -517,7 +536,12 @@ namespace DS4Windows
|
|||||||
// XXX fix initialization ordering so the null checks all go away
|
// XXX fix initialization ordering so the null checks all go away
|
||||||
if (Report != null)
|
if (Report != null)
|
||||||
Report(this, EventArgs.Empty);
|
Report(this, EventArgs.Empty);
|
||||||
sendOutputReport(false);
|
bool syncWriteReport = true;
|
||||||
|
if (conType == ConnectionType.BT)
|
||||||
|
{
|
||||||
|
syncWriteReport = false;
|
||||||
|
}
|
||||||
|
sendOutputReport(syncWriteReport);
|
||||||
if (!string.IsNullOrEmpty(error))
|
if (!string.IsNullOrEmpty(error))
|
||||||
error = string.Empty;
|
error = string.Empty;
|
||||||
if (!string.IsNullOrEmpty(currerror))
|
if (!string.IsNullOrEmpty(currerror))
|
||||||
|
@ -202,10 +202,9 @@ namespace DS4Windows
|
|||||||
if (safeReadHandle == null)
|
if (safeReadHandle == null)
|
||||||
safeReadHandle = OpenHandle(_devicePath, true);
|
safeReadHandle = OpenHandle(_devicePath, true);
|
||||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, false);
|
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, true);
|
||||||
if (!safeReadHandle.IsInvalid && fileStream.CanRead)
|
if (!safeReadHandle.IsInvalid && fileStream.CanRead)
|
||||||
{
|
{
|
||||||
|
|
||||||
Task<ReadStatus> readFileTask = new Task<ReadStatus>(() => ReadWithFileStreamTask(inputBuffer));
|
Task<ReadStatus> readFileTask = new Task<ReadStatus>(() => ReadWithFileStreamTask(inputBuffer));
|
||||||
readFileTask.Start();
|
readFileTask.Start();
|
||||||
bool success = readFileTask.Wait(timeout);
|
bool success = readFileTask.Wait(timeout);
|
||||||
@ -245,6 +244,46 @@ namespace DS4Windows
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ReadStatus.ReadError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadStatus ReadAsyncWithFileStream(byte[] inputBuffer, int timeout)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (safeReadHandle == null)
|
||||||
|
safeReadHandle = OpenHandle(_devicePath, true);
|
||||||
|
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||||
|
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, true);
|
||||||
|
if (!safeReadHandle.IsInvalid && fileStream.CanRead)
|
||||||
|
{
|
||||||
|
|
||||||
|
Task<int> readTask = fileStream.ReadAsync(inputBuffer, 0, inputBuffer.Length);
|
||||||
|
readTask.Wait(timeout);
|
||||||
|
if (readTask.Result > 0)
|
||||||
|
{
|
||||||
|
return ReadStatus.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadStatus.NoDataRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (e is AggregateException)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.Message);
|
||||||
|
return ReadStatus.WaitFail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadStatus.ReadError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ReadStatus.ReadError;
|
return ReadStatus.ReadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +324,7 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||||
{
|
{
|
||||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, false);
|
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, true);
|
||||||
}
|
}
|
||||||
if (fileStream != null && fileStream.CanWrite && !safeReadHandle.IsInvalid)
|
if (fileStream != null && fileStream.CanWrite && !safeReadHandle.IsInvalid)
|
||||||
{
|
{
|
||||||
@ -304,6 +343,36 @@ namespace DS4Windows
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool WriteAsyncOutputReportViaInterrupt(byte[] outputBuffer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (safeReadHandle == null)
|
||||||
|
{
|
||||||
|
safeReadHandle = OpenHandle(_devicePath, true);
|
||||||
|
}
|
||||||
|
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||||
|
{
|
||||||
|
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, true);
|
||||||
|
}
|
||||||
|
if (fileStream != null && fileStream.CanWrite && !safeReadHandle.IsInvalid)
|
||||||
|
{
|
||||||
|
Task writeTask = fileStream.WriteAsync(outputBuffer, 0, outputBuffer.Length);
|
||||||
|
//fileStream.Write(outputBuffer, 0, outputBuffer.Length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private SafeFileHandle OpenHandle(String devicePathName, Boolean isExclusive)
|
private SafeFileHandle OpenHandle(String devicePathName, Boolean isExclusive)
|
||||||
{
|
{
|
||||||
SafeFileHandle hidHandle;
|
SafeFileHandle hidHandle;
|
||||||
@ -312,11 +381,11 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
if (isExclusive)
|
if (isExclusive)
|
||||||
{
|
{
|
||||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000, 0);
|
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000 | NativeMethods.FILE_FLAG_OVERLAPPED, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000, 0);
|
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000 | NativeMethods.FILE_FLAG_OVERLAPPED, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
Loading…
Reference in New Issue
Block a user