Merge pull request #2 from Ryochan7/jay
Another attempt at keeping an experimental branch up to date with Ryochan7's fork
2
.gitignore
vendored
@ -97,7 +97,7 @@ publish/
|
|||||||
|
|
||||||
# NuGet Packages Directory
|
# NuGet Packages Directory
|
||||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||||
#packages/
|
packages/
|
||||||
|
|
||||||
# Windows Azure Build Output
|
# Windows Azure Build Output
|
||||||
csx
|
csx
|
||||||
|
@ -15,12 +15,12 @@ Global
|
|||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|x64.Build.0 = Debug|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Debug|x64.Build.0 = Debug|x64
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|Any CPU.Build.0 = Release|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|x64.ActiveCfg = Release|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|x64.ActiveCfg = Release|x64
|
||||||
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|x64.Build.0 = Release|Any CPU
|
{7B9354BF-AF82-4CCB-A83D-4BEB1E9D8C96}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -5,6 +5,8 @@ using System.Text;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using static System.Math;
|
using static System.Math;
|
||||||
using static DS4Windows.Global;
|
using static DS4Windows.Global;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
public class DS4LightBar
|
public class DS4LightBar
|
||||||
@ -23,124 +25,210 @@ namespace DS4Windows
|
|||||||
{ 252, 28 } // on 90% of the time at 90
|
{ 252, 28 } // on 90% of the time at 90
|
||||||
};
|
};
|
||||||
static double[] counters = new double[4] { 0, 0, 0, 0 };
|
static double[] counters = new double[4] { 0, 0, 0, 0 };
|
||||||
public static double[] fadetimer = new double[4] { 0, 0, 0, 0 };
|
public static Stopwatch[] fadewatches = { new Stopwatch(), new Stopwatch(), new Stopwatch(), new Stopwatch() };
|
||||||
static bool[] fadedirection = new bool[4] { false, false, false, false };
|
static bool[] fadedirection = new bool[4] { false, false, false, false };
|
||||||
static DateTime oldnow = DateTime.UtcNow;
|
static DateTime[] oldnow = { DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow };
|
||||||
public static bool[] forcelight = new bool[4] { false, false, false, false };
|
public static bool[] forcelight = new bool[4] { false, false, false, false };
|
||||||
public static DS4Color[] forcedColor = new DS4Color[4];
|
public static DS4Color[] forcedColor = new DS4Color[4];
|
||||||
public static byte[] forcedFlash = new byte[4];
|
public static byte[] forcedFlash = new byte[4];
|
||||||
public static void updateLightBar(DS4Device device, int deviceNum, DS4State cState, DS4StateExposed eState, Mouse tp)
|
internal const int PULSE_FLASH_DURATION = 2000;
|
||||||
{
|
internal const int PULSE_CHARGING_DURATION = 4000;
|
||||||
DS4Color color;
|
|
||||||
if (!defualtLight && !forcelight[deviceNum])
|
|
||||||
{
|
|
||||||
if (UseCustomLed[deviceNum])
|
|
||||||
{
|
|
||||||
if (LedAsBatteryIndicator[deviceNum])
|
|
||||||
{
|
|
||||||
DS4Color fullColor = CustomColor[deviceNum];
|
|
||||||
DS4Color lowColor = LowColor[deviceNum];
|
|
||||||
|
|
||||||
|
public static void updateLightBar(DS4Device device, int deviceNum, DS4State cState,
|
||||||
|
DS4StateExposed eState, Mouse tp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* TODO: Remove more property usage and use explicit getter methods instead.
|
||||||
|
* Testing in proper optimized release builds shows that it is
|
||||||
|
* still necessary to reduce lag.
|
||||||
|
*/
|
||||||
|
DS4Color color;
|
||||||
|
if (!defaultLight && !forcelight[deviceNum])
|
||||||
|
{
|
||||||
|
if (getUseCustomLed(deviceNum))
|
||||||
|
{
|
||||||
|
if (getLedAsBatteryIndicator(deviceNum))
|
||||||
|
{
|
||||||
|
DS4Color fullColor = getCustomColor(deviceNum);
|
||||||
|
DS4Color lowColor = getLowColor(deviceNum);
|
||||||
color = getTransitionedColor(lowColor, fullColor, device.Battery);
|
color = getTransitionedColor(lowColor, fullColor, device.Battery);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
color = CustomColor[deviceNum];
|
color = getCustomColor(deviceNum);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Rainbow[deviceNum] > 0)
|
double rainbow = getRainbow(deviceNum);
|
||||||
{// Display rainbow
|
if (rainbow > 0)
|
||||||
|
{
|
||||||
|
// Display rainbow
|
||||||
DateTime now = DateTime.UtcNow;
|
DateTime now = DateTime.UtcNow;
|
||||||
if (now >= oldnow + TimeSpan.FromMilliseconds(10)) //update by the millisecond that way it's a smooth transtion
|
if (now >= oldnow[deviceNum] + TimeSpan.FromMilliseconds(10)) //update by the millisecond that way it's a smooth transtion
|
||||||
{
|
{
|
||||||
oldnow = now;
|
oldnow[deviceNum] = now;
|
||||||
if (device.Charging)
|
if (device.isCharging())
|
||||||
counters[deviceNum] -= 1.5 * 3 / Rainbow[deviceNum];
|
counters[deviceNum] -= 1.5 * 3 / rainbow;
|
||||||
else
|
else
|
||||||
counters[deviceNum] += 1.5 * 3 / Rainbow[deviceNum];
|
counters[deviceNum] += 1.5 * 3 / rainbow;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counters[deviceNum] < 0)
|
if (counters[deviceNum] < 0)
|
||||||
counters[deviceNum] = 180000;
|
counters[deviceNum] = 180000;
|
||||||
if (counters[deviceNum] > 180000)
|
else if (counters[deviceNum] > 180000)
|
||||||
counters[deviceNum] = 0;
|
counters[deviceNum] = 0;
|
||||||
if (LedAsBatteryIndicator[deviceNum])
|
|
||||||
color = HuetoRGB((float)counters[deviceNum] % 360, (byte)(2.55 * device.Battery));
|
if (getLedAsBatteryIndicator(deviceNum))
|
||||||
|
color = HuetoRGB((float)counters[deviceNum] % 360, (byte)(2.55 * device.getBattery()));
|
||||||
else
|
else
|
||||||
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (LedAsBatteryIndicator[deviceNum])
|
else if (getLedAsBatteryIndicator(deviceNum))
|
||||||
{
|
{
|
||||||
//if (device.Charging == false || device.Battery >= 100) // when charged, don't show the charging animation
|
//if (device.Charging == false || device.Battery >= 100) // when charged, don't show the charging animation
|
||||||
{
|
{
|
||||||
DS4Color fullColor = MainColor[deviceNum];
|
DS4Color fullColor = getMainColor(deviceNum);
|
||||||
DS4Color lowColor = LowColor[deviceNum];
|
DS4Color lowColor = getLowColor(deviceNum);
|
||||||
|
|
||||||
color = getTransitionedColor(lowColor, fullColor, (uint)device.Battery);
|
color = getTransitionedColor(lowColor, fullColor, (uint)device.getBattery());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color = MainColor[deviceNum];
|
color = getMainColor(deviceNum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (device.getBattery() <= getFlashAt(deviceNum) && !defaultLight && !device.isCharging())
|
||||||
|
{
|
||||||
|
DS4Color flashColor = getFlashColor(deviceNum);
|
||||||
|
if (!(flashColor.red == 0 &&
|
||||||
|
flashColor.green == 0 &&
|
||||||
|
flashColor.blue == 0))
|
||||||
|
color = flashColor;
|
||||||
|
|
||||||
if (device.Battery <= FlashAt[deviceNum] && !defualtLight && !device.Charging)
|
if (getFlashType(deviceNum) == 1)
|
||||||
{
|
{
|
||||||
if (!(FlashColor[deviceNum].red == 0 &&
|
double ratio = 0.0;
|
||||||
FlashColor[deviceNum].green == 0 &&
|
|
||||||
FlashColor[deviceNum].blue == 0))
|
if (!fadewatches[deviceNum].IsRunning)
|
||||||
color = FlashColor[deviceNum];
|
|
||||||
if (FlashType[deviceNum] == 1)
|
|
||||||
{
|
{
|
||||||
if (fadetimer[deviceNum] <= 0)
|
bool temp = fadedirection[deviceNum];
|
||||||
fadedirection[deviceNum] = true;
|
fadedirection[deviceNum] = !temp;
|
||||||
else if (fadetimer[deviceNum] >= 100)
|
fadewatches[deviceNum].Restart();
|
||||||
fadedirection[deviceNum] = false;
|
ratio = temp ? 100.0 : 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long elapsed = fadewatches[deviceNum].ElapsedMilliseconds;
|
||||||
|
|
||||||
if (fadedirection[deviceNum])
|
if (fadedirection[deviceNum])
|
||||||
fadetimer[deviceNum] += 1;
|
{
|
||||||
|
if (elapsed < PULSE_FLASH_DURATION)
|
||||||
|
{
|
||||||
|
ratio = 100.0 * (elapsed / (double)PULSE_FLASH_DURATION);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fadetimer[deviceNum] -= 1;
|
{
|
||||||
color = getTransitionedColor(color, new DS4Color(0, 0, 0), fadetimer[deviceNum]);
|
ratio = 100.0;
|
||||||
|
fadewatches[deviceNum].Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (elapsed < PULSE_FLASH_DURATION)
|
||||||
|
{
|
||||||
|
ratio = (0 - 100.0) * (elapsed / (double)PULSE_FLASH_DURATION) + 100.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ratio = 0.0;
|
||||||
|
fadewatches[deviceNum].Stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IdleDisconnectTimeout[deviceNum] > 0 && LedAsBatteryIndicator[deviceNum] && (!device.Charging || device.Battery >= 100))
|
color = getTransitionedColor(color, new DS4Color(0, 0, 0), ratio);
|
||||||
{//Fade lightbar by idle time
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int idleDisconnectTimeout = getIdleDisconnectTimeout(deviceNum);
|
||||||
|
if (idleDisconnectTimeout > 0 && getLedAsBatteryIndicator(deviceNum) &&
|
||||||
|
(!device.isCharging() || device.getBattery() >= 100))
|
||||||
|
{
|
||||||
|
//Fade lightbar by idle time
|
||||||
TimeSpan timeratio = new TimeSpan(DateTime.UtcNow.Ticks - device.lastActive.Ticks);
|
TimeSpan timeratio = new TimeSpan(DateTime.UtcNow.Ticks - device.lastActive.Ticks);
|
||||||
double botratio = timeratio.TotalMilliseconds;
|
double botratio = timeratio.TotalMilliseconds;
|
||||||
double topratio = TimeSpan.FromSeconds(IdleDisconnectTimeout[deviceNum]).TotalMilliseconds;
|
double topratio = TimeSpan.FromSeconds(idleDisconnectTimeout).TotalMilliseconds;
|
||||||
double ratio = ((botratio / topratio) * 100);
|
double ratio = 100.0 * (botratio / topratio);
|
||||||
if (ratio >= 50 && ratio <= 100)
|
if (ratio >= 50.0 && ratio <= 100.0)
|
||||||
color = getTransitionedColor(color, new DS4Color(0, 0, 0), (uint)((ratio - 50) * 2));
|
color = getTransitionedColor(color, new DS4Color(0, 0, 0), (uint)((ratio - 50) * 2));
|
||||||
else if (ratio >= 100)
|
else if (ratio >= 100.0)
|
||||||
color = getTransitionedColor(color, new DS4Color(0, 0, 0), 100);
|
color = getTransitionedColor(color, new DS4Color(0, 0, 0), 100.0);
|
||||||
}
|
}
|
||||||
if (device.Charging && device.Battery < 100)
|
|
||||||
switch (ChargingType[deviceNum])
|
if (device.isCharging() && device.getBattery() < 100)
|
||||||
|
{
|
||||||
|
switch (getChargingType(deviceNum))
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
if (fadetimer[deviceNum] <= 0)
|
{
|
||||||
fadedirection[deviceNum] = true;
|
double ratio = 0.0;
|
||||||
else if (fadetimer[deviceNum] >= 105)
|
|
||||||
fadedirection[deviceNum] = false;
|
if (!fadewatches[deviceNum].IsRunning)
|
||||||
if (fadedirection[deviceNum])
|
{
|
||||||
fadetimer[deviceNum] += .1;
|
bool temp = fadedirection[deviceNum];
|
||||||
|
fadedirection[deviceNum] = !temp;
|
||||||
|
fadewatches[deviceNum].Restart();
|
||||||
|
ratio = temp ? 100.0 : 0.0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fadetimer[deviceNum] -= .1;
|
{
|
||||||
color = getTransitionedColor(color, new DS4Color(0, 0, 0), fadetimer[deviceNum]);
|
long elapsed = fadewatches[deviceNum].ElapsedMilliseconds;
|
||||||
|
|
||||||
|
if (fadedirection[deviceNum])
|
||||||
|
{
|
||||||
|
if (elapsed < PULSE_CHARGING_DURATION)
|
||||||
|
{
|
||||||
|
ratio = 100.0 * (elapsed / (double)PULSE_CHARGING_DURATION);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ratio = 100.0;
|
||||||
|
fadewatches[deviceNum].Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (elapsed < PULSE_CHARGING_DURATION)
|
||||||
|
{
|
||||||
|
ratio = (0 - 100.0) * (elapsed / (double)PULSE_CHARGING_DURATION) + 100.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ratio = 0.0;
|
||||||
|
fadewatches[deviceNum].Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color = getTransitionedColor(color, new DS4Color(0, 0, 0), ratio);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
counters[deviceNum] += .167;
|
{
|
||||||
|
counters[deviceNum] += 0.167;
|
||||||
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
color = HuetoRGB((float)counters[deviceNum] % 360, 255);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 3:
|
case 3:
|
||||||
color = ChargingColor[deviceNum];
|
{
|
||||||
break;
|
color = getChargingColor(deviceNum);
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (forcelight[deviceNum])
|
else if (forcelight[deviceNum])
|
||||||
{
|
{
|
||||||
@ -150,25 +238,30 @@ namespace DS4Windows
|
|||||||
color = new DS4Color(0, 0, 0);
|
color = new DS4Color(0, 0, 0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (device.ConnectionType == ConnectionType.BT)
|
if (device.getConnectionType() == ConnectionType.BT)
|
||||||
color = new DS4Color(32, 64, 64);
|
color = new DS4Color(32, 64, 64);
|
||||||
else
|
else
|
||||||
color = new DS4Color(0, 0, 0);
|
color = new DS4Color(0, 0, 0);
|
||||||
}
|
}
|
||||||
bool distanceprofile = (ProfilePath[deviceNum].ToLower().Contains("distance") || tempprofilename[deviceNum].ToLower().Contains("distance"));
|
|
||||||
if (distanceprofile && !defualtLight)
|
bool distanceprofile = DistanceProfiles[deviceNum] || tempprofileDistance[deviceNum];
|
||||||
{ //Thing I did for Distance
|
//distanceprofile = (ProfilePath[deviceNum].ToLower().Contains("distance") || tempprofilename[deviceNum].ToLower().Contains("distance"));
|
||||||
float rumble = device.LeftHeavySlowRumble / 2.55f;
|
if (distanceprofile && !defaultLight)
|
||||||
|
{
|
||||||
|
// Thing I did for Distance
|
||||||
|
float rumble = device.getLeftHeavySlowRumble() / 2.55f;
|
||||||
byte max = Max(color.red, Max(color.green, color.blue));
|
byte max = Max(color.red, Max(color.green, color.blue));
|
||||||
if (device.LeftHeavySlowRumble > 100)
|
if (device.getLeftHeavySlowRumble() > 100)
|
||||||
color = getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), rumble);
|
color = getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), rumble);
|
||||||
else
|
else
|
||||||
color = getTransitionedColor(color, getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), 39.6078f), device.LeftHeavySlowRumble);
|
color = getTransitionedColor(color, getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), 39.6078f), device.getLeftHeavySlowRumble());
|
||||||
}
|
}
|
||||||
|
|
||||||
DS4HapticState haptics = new DS4HapticState
|
DS4HapticState haptics = new DS4HapticState
|
||||||
{
|
{
|
||||||
LightBarColor = color
|
LightBarColor = color
|
||||||
};
|
};
|
||||||
|
|
||||||
if (haptics.IsLightBarSet())
|
if (haptics.IsLightBarSet())
|
||||||
{
|
{
|
||||||
if (forcelight[deviceNum] && forcedFlash[deviceNum] > 0)
|
if (forcelight[deviceNum] && forcedFlash[deviceNum] > 0)
|
||||||
@ -176,17 +269,18 @@ namespace DS4Windows
|
|||||||
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = (byte)(25 - forcedFlash[deviceNum]);
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = (byte)(25 - forcedFlash[deviceNum]);
|
||||||
haptics.LightBarExplicitlyOff = true;
|
haptics.LightBarExplicitlyOff = true;
|
||||||
}
|
}
|
||||||
else if (device.Battery <= FlashAt[deviceNum] && FlashType[deviceNum] == 0 && !defualtLight && !device.Charging)
|
else if (device.getBattery() <= getFlashAt(deviceNum) && getFlashType(deviceNum) == 0 && !defaultLight && !device.isCharging())
|
||||||
{
|
{
|
||||||
int level = device.Battery / 10;
|
int level = device.getBattery() / 10;
|
||||||
//if (level >= 10)
|
if (level >= 10)
|
||||||
//level = 0; // all values of ~0% or >~100% are rendered the same
|
level = 0; // all values of ~0% or >~100% are rendered the same
|
||||||
|
|
||||||
haptics.LightBarFlashDurationOn = BatteryIndicatorDurations[level, 0];
|
haptics.LightBarFlashDurationOn = BatteryIndicatorDurations[level, 0];
|
||||||
haptics.LightBarFlashDurationOff = BatteryIndicatorDurations[level, 1];
|
haptics.LightBarFlashDurationOff = BatteryIndicatorDurations[level, 1];
|
||||||
}
|
}
|
||||||
else if (distanceprofile && device.LeftHeavySlowRumble > 155) //also part of Distance
|
else if (distanceprofile && device.getLeftHeavySlowRumble() > 155) //also part of Distance
|
||||||
{
|
{
|
||||||
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = (byte)((-device.LeftHeavySlowRumble + 265));
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = (byte)((-device.getLeftHeavySlowRumble() + 265));
|
||||||
haptics.LightBarExplicitlyOff = true;
|
haptics.LightBarExplicitlyOff = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -200,14 +294,19 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
haptics.LightBarExplicitlyOff = true;
|
haptics.LightBarExplicitlyOff = true;
|
||||||
}
|
}
|
||||||
if (device.LightBarOnDuration != haptics.LightBarFlashDurationOn && device.LightBarOnDuration != 1 && haptics.LightBarFlashDurationOn == 0)
|
|
||||||
|
byte tempLightBarOnDuration = device.getLightBarOnDuration();
|
||||||
|
if (tempLightBarOnDuration != haptics.LightBarFlashDurationOn && tempLightBarOnDuration != 1 && haptics.LightBarFlashDurationOn == 0)
|
||||||
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 1;
|
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 1;
|
||||||
if (device.LightBarOnDuration == 1) //helps better reset the color
|
|
||||||
System.Threading.Thread.Sleep(5);
|
// Comment out code for now. This condition gets hit too often and bogs down the GUI
|
||||||
|
//if (device.LightBarOnDuration == 1) //helps better reset the color
|
||||||
|
// System.Threading.Thread.Sleep(5);
|
||||||
|
|
||||||
device.pushHapticState(haptics);
|
device.pushHapticState(haptics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool defualtLight = false, shuttingdown = false;
|
public static bool defaultLight = false, shuttingdown = false;
|
||||||
|
|
||||||
public static DS4Color HuetoRGB(float hue, byte sat)
|
public static DS4Color HuetoRGB(float hue, byte sat)
|
||||||
{
|
{
|
||||||
|
146
DS4Windows/DS4Control/DS4StateFieldMapping.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
namespace DS4Windows
|
||||||
|
{
|
||||||
|
public class DS4StateFieldMapping
|
||||||
|
{
|
||||||
|
public enum ControlType { Unknown = 0, Button, AxisDir, Trigger, Touch, GyroDir, SwipeDir }
|
||||||
|
|
||||||
|
public bool[] buttons = new bool[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
public byte[] axisdirs = new byte[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
public byte[] triggers = new byte[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
public int[] gryodirs = new int[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
public byte[] swipedirs = new byte[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
public bool[] swipedirbools = new bool[(int)DS4Controls.SwipeDown + 1];
|
||||||
|
|
||||||
|
public static ControlType[] mappedType = { ControlType.Unknown, // DS4Controls.None
|
||||||
|
ControlType.AxisDir, // DS4Controls.LXNeg
|
||||||
|
ControlType.AxisDir, // DS4Controls.LXPos
|
||||||
|
ControlType.AxisDir, // DS4Controls.LYNeg
|
||||||
|
ControlType.AxisDir, // DS4Controls.LYPos
|
||||||
|
ControlType.AxisDir, // DS4Controls.RXNeg
|
||||||
|
ControlType.AxisDir, // DS4Controls.RXPos
|
||||||
|
ControlType.AxisDir, // DS4Controls.RYNeg
|
||||||
|
ControlType.AxisDir, // DS4Controls.RYPos
|
||||||
|
ControlType.Button, // DS4Controls.L1
|
||||||
|
ControlType.Trigger, // DS4Controls.L2
|
||||||
|
ControlType.Button, // DS4Controls.L3
|
||||||
|
ControlType.Button, // DS4Controls.R1
|
||||||
|
ControlType.Trigger, // DS4Controls.R2
|
||||||
|
ControlType.Button, // DS4Controls.R3
|
||||||
|
ControlType.Button, // DS4Controls.Square
|
||||||
|
ControlType.Button, // DS4Controls.Triangle
|
||||||
|
ControlType.Button, // DS4Controls.Circle
|
||||||
|
ControlType.Button, // DS4Controls.Cross
|
||||||
|
ControlType.Button, // DS4Controls.DpadUp
|
||||||
|
ControlType.Button, // DS4Controls.DpadRight
|
||||||
|
ControlType.Button, // DS4Controls.DpadDown
|
||||||
|
ControlType.Button, // DS4Controls.DpadLeft
|
||||||
|
ControlType.Button, // DS4Controls.PS
|
||||||
|
ControlType.Touch, // DS4Controls.TouchLeft
|
||||||
|
ControlType.Touch, // DS4Controls.TouchUpper
|
||||||
|
ControlType.Touch, // DS4Controls.TouchMulti
|
||||||
|
ControlType.Touch, // DS4Controls.TouchRight
|
||||||
|
ControlType.Button, // DS4Controls.Share
|
||||||
|
ControlType.Button, // DS4Controls.Options
|
||||||
|
ControlType.GyroDir, // DS4Controls.GyroXPos
|
||||||
|
ControlType.GyroDir, // DS4Controls.GyroXNeg
|
||||||
|
ControlType.GyroDir, // DS4Controls.GyroZPos
|
||||||
|
ControlType.GyroDir, // DS4Controls.GyroZNeg
|
||||||
|
ControlType.SwipeDir, // DS4Controls.SwipeLeft
|
||||||
|
ControlType.SwipeDir, // DS4Controls.SwipeRight
|
||||||
|
ControlType.SwipeDir, // DS4Controls.SwipeUp
|
||||||
|
ControlType.SwipeDir, // DS4Controls.SwipeDown
|
||||||
|
};
|
||||||
|
|
||||||
|
public DS4StateFieldMapping(DS4State cState, DS4StateExposed exposeState, Mouse tp)
|
||||||
|
{
|
||||||
|
axisdirs[(int)DS4Controls.LXNeg] = cState.LX;
|
||||||
|
axisdirs[(int)DS4Controls.LXPos] = cState.LX;
|
||||||
|
axisdirs[(int)DS4Controls.LYNeg] = cState.LY;
|
||||||
|
axisdirs[(int)DS4Controls.LYPos] = cState.LY;
|
||||||
|
|
||||||
|
axisdirs[(int)DS4Controls.RXNeg] = cState.RX;
|
||||||
|
axisdirs[(int)DS4Controls.RXPos] = cState.RX;
|
||||||
|
axisdirs[(int)DS4Controls.RYNeg] = cState.RY;
|
||||||
|
axisdirs[(int)DS4Controls.RYPos] = cState.RY;
|
||||||
|
|
||||||
|
triggers[(int)DS4Controls.L2] = cState.L2;
|
||||||
|
triggers[(int)DS4Controls.R2] = cState.R2;
|
||||||
|
|
||||||
|
buttons[(int)DS4Controls.L1] = cState.L1;
|
||||||
|
buttons[(int)DS4Controls.L3] = cState.L3;
|
||||||
|
buttons[(int)DS4Controls.R1] = cState.R1;
|
||||||
|
buttons[(int)DS4Controls.R3] = cState.R3;
|
||||||
|
|
||||||
|
buttons[(int)DS4Controls.Cross] = cState.Cross;
|
||||||
|
buttons[(int)DS4Controls.Triangle] = cState.Triangle;
|
||||||
|
buttons[(int)DS4Controls.Circle] = cState.Circle;
|
||||||
|
buttons[(int)DS4Controls.Square] = cState.Square;
|
||||||
|
buttons[(int)DS4Controls.PS] = cState.PS;
|
||||||
|
buttons[(int)DS4Controls.Options] = cState.Options;
|
||||||
|
buttons[(int)DS4Controls.Share] = cState.Share;
|
||||||
|
|
||||||
|
buttons[(int)DS4Controls.DpadUp] = cState.DpadUp;
|
||||||
|
buttons[(int)DS4Controls.DpadRight] = cState.DpadRight;
|
||||||
|
buttons[(int)DS4Controls.DpadDown] = cState.DpadDown;
|
||||||
|
buttons[(int)DS4Controls.DpadLeft] = cState.DpadLeft;
|
||||||
|
|
||||||
|
buttons[(int)DS4Controls.TouchLeft] = tp != null ? tp.leftDown : false;
|
||||||
|
buttons[(int)DS4Controls.TouchRight] = tp != null ? tp.rightDown : false;
|
||||||
|
buttons[(int)DS4Controls.TouchUpper] = tp != null ? tp.upperDown : false;
|
||||||
|
buttons[(int)DS4Controls.TouchMulti] = tp != null ? tp.multiDown : false;
|
||||||
|
|
||||||
|
int gyroX = exposeState.getGyroX();
|
||||||
|
gryodirs[(int)DS4Controls.GyroXPos] = gyroX > 0 ? gyroX : 0;
|
||||||
|
gryodirs[(int)DS4Controls.GyroXNeg] = gyroX < 0 ? gyroX : 0;
|
||||||
|
|
||||||
|
int gyroZ = exposeState.getGyroZ();
|
||||||
|
gryodirs[(int)DS4Controls.GyroZPos] = gyroZ > 0 ? gyroZ : 0;
|
||||||
|
gryodirs[(int)DS4Controls.GyroZNeg] = gyroZ < 0 ? gyroZ : 0;
|
||||||
|
|
||||||
|
swipedirs[(int)DS4Controls.SwipeLeft] = tp != null ? tp.swipeLeftB : (byte)0;
|
||||||
|
swipedirs[(int)DS4Controls.SwipeRight] = tp != null ? tp.swipeRightB : (byte)0;
|
||||||
|
swipedirs[(int)DS4Controls.SwipeUp] = tp != null ? tp.swipeUpB : (byte)0;
|
||||||
|
swipedirs[(int)DS4Controls.SwipeDown] = tp != null ? tp.swipeDownB : (byte)0;
|
||||||
|
|
||||||
|
swipedirbools[(int)DS4Controls.SwipeLeft] = tp != null ? tp.swipeLeft : false;
|
||||||
|
swipedirbools[(int)DS4Controls.SwipeRight] = tp != null ? tp.swipeRight : false;
|
||||||
|
swipedirbools[(int)DS4Controls.SwipeUp] = tp != null ? tp.swipeUp : false;
|
||||||
|
swipedirbools[(int)DS4Controls.SwipeDown] = tp != null ? tp.swipeDown : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populateState(DS4State state)
|
||||||
|
{
|
||||||
|
state.LX = axisdirs[(int)DS4Controls.LXNeg];
|
||||||
|
state.LX = axisdirs[(int)DS4Controls.LXPos];
|
||||||
|
state.LY = axisdirs[(int)DS4Controls.LYNeg];
|
||||||
|
state.LY = axisdirs[(int)DS4Controls.LYPos];
|
||||||
|
|
||||||
|
state.RX = axisdirs[(int)DS4Controls.RXNeg];
|
||||||
|
state.RX = axisdirs[(int)DS4Controls.RXPos];
|
||||||
|
state.RY = axisdirs[(int)DS4Controls.RYNeg];
|
||||||
|
state.RY = axisdirs[(int)DS4Controls.RYPos];
|
||||||
|
|
||||||
|
state.L2 = triggers[(int)DS4Controls.L2];
|
||||||
|
state.R2 = triggers[(int)DS4Controls.R2];
|
||||||
|
|
||||||
|
state.L1 = buttons[(int)DS4Controls.L1];
|
||||||
|
state.L3 = buttons[(int)DS4Controls.L3];
|
||||||
|
state.R1 = buttons[(int)DS4Controls.R1];
|
||||||
|
state.R3 = buttons[(int)DS4Controls.R3];
|
||||||
|
|
||||||
|
state.Cross = buttons[(int)DS4Controls.Cross];
|
||||||
|
state.Triangle = buttons[(int)DS4Controls.Triangle];
|
||||||
|
state.Circle = buttons[(int)DS4Controls.Circle];
|
||||||
|
state.Square = buttons[(int)DS4Controls.Square];
|
||||||
|
state.PS = buttons[(int)DS4Controls.PS];
|
||||||
|
state.Options = buttons[(int)DS4Controls.Options];
|
||||||
|
state.Share = buttons[(int)DS4Controls.Share];
|
||||||
|
|
||||||
|
state.DpadUp = buttons[(int)DS4Controls.DpadUp];
|
||||||
|
state.DpadRight = buttons[(int)DS4Controls.DpadRight];
|
||||||
|
state.DpadDown = buttons[(int)DS4Controls.DpadDown];
|
||||||
|
state.DpadLeft = buttons[(int)DS4Controls.DpadLeft];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
class InputMethods
|
class InputMethods
|
||||||
{
|
{
|
||||||
private static INPUT[] sendInputs = new INPUT[2]; // will allow for keyboard + mouse/tablet input within one SendInput call, or two mouse events
|
private static INPUT[] sendInputs = new INPUT[2]; // will allow for keyboard + mouse/tablet input within one SendInput call, or two mouse events
|
||||||
private static object lockob = new object();
|
private static object lockob = new object();
|
||||||
|
|
||||||
public static void MoveCursorBy(int x, int y)
|
public static void MoveCursorBy(int x, int y)
|
||||||
{
|
{
|
||||||
lock (lockob)
|
lock (lockob)
|
||||||
@ -43,6 +42,7 @@ namespace DS4Windows
|
|||||||
sendInputs[inputs].Data.Mouse.Y = 0;
|
sendInputs[inputs].Data.Mouse.Y = 0;
|
||||||
inputs++;
|
inputs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (horizontal != 0)
|
if (horizontal != 0)
|
||||||
{
|
{
|
||||||
sendInputs[inputs].Type = INPUT_MOUSE;
|
sendInputs[inputs].Type = INPUT_MOUSE;
|
||||||
@ -54,6 +54,7 @@ namespace DS4Windows
|
|||||||
sendInputs[inputs].Data.Mouse.Y = 0;
|
sendInputs[inputs].Data.Mouse.Y = 0;
|
||||||
inputs++;
|
inputs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendInput(inputs, sendInputs, (int)inputs * Marshal.SizeOf(sendInputs[0]));
|
SendInput(inputs, sendInputs, (int)inputs * Marshal.SizeOf(sendInputs[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,69 +89,6 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void performLeftClick()
|
|
||||||
{
|
|
||||||
lock (lockob)
|
|
||||||
{
|
|
||||||
sendInputs[0].Type = INPUT_MOUSE;
|
|
||||||
sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero;
|
|
||||||
sendInputs[0].Data.Mouse.Flags = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;
|
|
||||||
sendInputs[0].Data.Mouse.MouseData = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Time = 0;
|
|
||||||
sendInputs[0].Data.Mouse.X = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Y = 0;
|
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void performRightClick()
|
|
||||||
{
|
|
||||||
lock (lockob)
|
|
||||||
{
|
|
||||||
sendInputs[0].Type = INPUT_MOUSE;
|
|
||||||
sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero;
|
|
||||||
sendInputs[0].Data.Mouse.Flags = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP;
|
|
||||||
sendInputs[0].Data.Mouse.MouseData = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Time = 0;
|
|
||||||
sendInputs[0].Data.Mouse.X = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Y = 0;
|
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void performMiddleClick()
|
|
||||||
{
|
|
||||||
lock (lockob)
|
|
||||||
{
|
|
||||||
sendInputs[0].Type = INPUT_MOUSE;
|
|
||||||
sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero;
|
|
||||||
sendInputs[0].Data.Mouse.Flags = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP;
|
|
||||||
sendInputs[0].Data.Mouse.MouseData = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Time = 0;
|
|
||||||
sendInputs[0].Data.Mouse.X = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Y = 0;
|
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void performFourthClick()
|
|
||||||
{
|
|
||||||
lock (lockob)
|
|
||||||
{
|
|
||||||
sendInputs[0].Type = INPUT_MOUSE;
|
|
||||||
sendInputs[0].Data.Mouse.ExtraInfo = IntPtr.Zero;
|
|
||||||
sendInputs[0].Data.Mouse.Flags = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Flags |= MOUSEEVENTF_XBUTTONDOWN | MOUSEEVENTF_XBUTTONUP;
|
|
||||||
sendInputs[0].Data.Mouse.MouseData = 1;
|
|
||||||
sendInputs[0].Data.Mouse.Time = 0;
|
|
||||||
sendInputs[0].Data.Mouse.X = 0;
|
|
||||||
sendInputs[0].Data.Mouse.Y = 0;
|
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void performSCKeyPress(ushort key)
|
public static void performSCKeyPress(ushort key)
|
||||||
{
|
{
|
||||||
lock (lockob)
|
lock (lockob)
|
||||||
@ -169,10 +107,16 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
lock (lockob)
|
lock (lockob)
|
||||||
{
|
{
|
||||||
|
ushort scancode = scancodeFromVK(key);
|
||||||
|
bool extended = (scancode & 0x100) != 0;
|
||||||
|
uint curflags = extended ? KEYEVENTF_EXTENDEDKEY : 0;
|
||||||
|
|
||||||
sendInputs[0].Type = INPUT_KEYBOARD;
|
sendInputs[0].Type = INPUT_KEYBOARD;
|
||||||
sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero;
|
sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero;
|
||||||
sendInputs[0].Data.Keyboard.Flags = 1;
|
sendInputs[0].Data.Keyboard.Flags = curflags;
|
||||||
sendInputs[0].Data.Keyboard.Scan = 0;
|
sendInputs[0].Data.Keyboard.Scan = scancode;
|
||||||
|
//sendInputs[0].Data.Keyboard.Flags = 1;
|
||||||
|
//sendInputs[0].Data.Keyboard.Scan = 0;
|
||||||
sendInputs[0].Data.Keyboard.Time = 0;
|
sendInputs[0].Data.Keyboard.Time = 0;
|
||||||
sendInputs[0].Data.Keyboard.Vk = key;
|
sendInputs[0].Data.Keyboard.Vk = key;
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
||||||
@ -197,16 +141,60 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
lock (lockob)
|
lock (lockob)
|
||||||
{
|
{
|
||||||
|
ushort scancode = scancodeFromVK(key);
|
||||||
|
bool extended = (scancode & 0x100) != 0;
|
||||||
|
uint curflags = extended ? KEYEVENTF_EXTENDEDKEY : 0;
|
||||||
|
|
||||||
sendInputs[0].Type = INPUT_KEYBOARD;
|
sendInputs[0].Type = INPUT_KEYBOARD;
|
||||||
sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero;
|
sendInputs[0].Data.Keyboard.ExtraInfo = IntPtr.Zero;
|
||||||
sendInputs[0].Data.Keyboard.Flags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
|
sendInputs[0].Data.Keyboard.Flags = curflags | KEYEVENTF_KEYUP;
|
||||||
sendInputs[0].Data.Keyboard.Scan = 0;
|
sendInputs[0].Data.Keyboard.Scan = scancode;
|
||||||
|
//sendInputs[0].Data.Keyboard.Flags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
|
||||||
|
//sendInputs[0].Data.Keyboard.Scan = 0;
|
||||||
sendInputs[0].Data.Keyboard.Time = 0;
|
sendInputs[0].Data.Keyboard.Time = 0;
|
||||||
sendInputs[0].Data.Keyboard.Vk = key;
|
sendInputs[0].Data.Keyboard.Vk = key;
|
||||||
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ushort scancodeFromVK(uint vkey)
|
||||||
|
{
|
||||||
|
ushort scancode = 0;
|
||||||
|
if (vkey == VK_PAUSE)
|
||||||
|
{
|
||||||
|
// MapVirtualKey does not work with VK_PAUSE
|
||||||
|
scancode = 0x45;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scancode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (vkey)
|
||||||
|
{
|
||||||
|
case VK_LEFT:
|
||||||
|
case VK_UP:
|
||||||
|
case VK_RIGHT:
|
||||||
|
case VK_DOWN:
|
||||||
|
case VK_PRIOR:
|
||||||
|
case VK_NEXT:
|
||||||
|
case VK_END:
|
||||||
|
case VK_HOME:
|
||||||
|
case VK_INSERT:
|
||||||
|
case VK_DELETE:
|
||||||
|
case VK_DIVIDE:
|
||||||
|
case VK_NUMLOCK:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
case VK_RMENU:
|
||||||
|
{
|
||||||
|
scancode |= (ushort)EXTENDED_FLAG; // set extended bit
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scancode;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
|
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -277,7 +265,11 @@ namespace DS4Windows
|
|||||||
MOUSEEVENTF_XBUTTONDOWN = 128, MOUSEEVENTF_XBUTTONUP = 256,
|
MOUSEEVENTF_XBUTTONDOWN = 128, MOUSEEVENTF_XBUTTONUP = 256,
|
||||||
KEYEVENTF_EXTENDEDKEY = 1, KEYEVENTF_KEYUP = 2, MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_HWHEEL = 0x1000,
|
KEYEVENTF_EXTENDEDKEY = 1, KEYEVENTF_KEYUP = 2, MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_HWHEEL = 0x1000,
|
||||||
MOUSEEVENTF_MIDDLEWDOWN = 0x0020, MOUSEEVENTF_MIDDLEWUP = 0x0040,
|
MOUSEEVENTF_MIDDLEWDOWN = 0x0020, MOUSEEVENTF_MIDDLEWUP = 0x0040,
|
||||||
KEYEVENTF_SCANCODE = 0x0008, MAPVK_VK_TO_VSC = 0, KEYEVENTF_UNICODE = 0x0004;
|
KEYEVENTF_SCANCODE = 0x0008, MAPVK_VK_TO_VSC = 0, KEYEVENTF_UNICODE = 0x0004, EXTENDED_FLAG = 0x100;
|
||||||
|
|
||||||
|
internal const uint VK_PAUSE = 0x13, VK_LEFT = 0x25, VK_UP = 0x26, VK_RIGHT = 0x27, VK_DOWN = 0x28,
|
||||||
|
VK_PRIOR = 0x21, VK_NEXT = 0x22, VK_END = 0x23, VK_HOME = 0x24, VK_INSERT = 0x2D, VK_DELETE = 0x2E,
|
||||||
|
VK_DIVIDE = 0x6F, VK_NUMLOCK = 0x90, VK_RCONTROL = 0xAE, VK_RMENU = 0xA5;
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputs);
|
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputs);
|
||||||
@ -285,6 +277,7 @@ namespace DS4Windows
|
|||||||
private static extern ushort MapVirtualKey(uint uCode, uint uMapType);
|
private static extern ushort MapVirtualKey(uint uCode, uint uMapType);
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
|
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
|
||||||
|
|
||||||
//Not used, just here
|
//Not used, just here
|
||||||
public static void DownKeys(ushort key)
|
public static void DownKeys(ushort key)
|
||||||
{
|
{
|
||||||
@ -301,5 +294,5 @@ namespace DS4Windows
|
|||||||
keybd_event((byte)key, 0, (int)KEYEVENTF_KEYUP, 0);
|
keybd_event((byte)key, 0, (int)KEYEVENTF_KEYUP, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
|
@ -73,7 +73,9 @@ namespace DS4Windows
|
|||||||
case 16: return s.Options;
|
case 16: return s.Options;
|
||||||
case 17: return s.Share;
|
case 17: return s.Share;
|
||||||
case 18: return s.PS;
|
case 18: return s.PS;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +100,13 @@ namespace DS4Windows
|
|||||||
swipeLeftB = (byte)Math.Min(255, Math.Max(0, firstTouch.hwX - arg.touches[0].hwX));
|
swipeLeftB = (byte)Math.Min(255, Math.Max(0, firstTouch.hwX - arg.touches[0].hwX));
|
||||||
swipeRightB = (byte)Math.Min(255, Math.Max(0, arg.touches[0].hwX - firstTouch.hwX));
|
swipeRightB = (byte)Math.Min(255, Math.Max(0, arg.touches[0].hwX - firstTouch.hwX));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 50 && arg.touches.Length == 2)
|
if (Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 50 && arg.touches.Length == 2)
|
||||||
if (arg.touches[0].hwX - firstTouch.hwX > 200 && !slideleft)
|
if (arg.touches[0].hwX - firstTouch.hwX > 200 && !slideleft)
|
||||||
slideright = true;
|
slideright = true;
|
||||||
else if (firstTouch.hwX - arg.touches[0].hwX > 200 && !slideright)
|
else if (firstTouch.hwX - arg.touches[0].hwX > 200 && !slideright)
|
||||||
slideleft = true;
|
slideleft = true;
|
||||||
|
|
||||||
dev.getCurrentState(s);
|
dev.getCurrentState(s);
|
||||||
synthesizeMouseButtons();
|
synthesizeMouseButtons();
|
||||||
}
|
}
|
||||||
@ -113,14 +117,17 @@ namespace DS4Windows
|
|||||||
cursor.touchesBegan(arg);
|
cursor.touchesBegan(arg);
|
||||||
wheel.touchesBegan(arg);
|
wheel.touchesBegan(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
pastTime = arg.timeStamp;
|
pastTime = arg.timeStamp;
|
||||||
firstTouch = arg.touches[0];
|
firstTouch = arg.touches[0];
|
||||||
|
|
||||||
if (Global.DoubleTap[deviceNum])
|
if (Global.DoubleTap[deviceNum])
|
||||||
{
|
{
|
||||||
DateTime test = arg.timeStamp;
|
DateTime test = arg.timeStamp;
|
||||||
if (test <= (firstTap + TimeSpan.FromMilliseconds((double)Global.TapSensitivity[deviceNum] * 1.5)) && !arg.touchButtonPressed)
|
if (test <= (firstTap + TimeSpan.FromMilliseconds((double)Global.TapSensitivity[deviceNum] * 1.5)) && !arg.touchButtonPressed)
|
||||||
secondtouchbegin = true;
|
secondtouchbegin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev.getCurrentState(s);
|
dev.getCurrentState(s);
|
||||||
synthesizeMouseButtons();
|
synthesizeMouseButtons();
|
||||||
}
|
}
|
||||||
@ -129,16 +136,17 @@ namespace DS4Windows
|
|||||||
slideright = slideleft = false;
|
slideright = slideleft = false;
|
||||||
swipeUp = swipeDown = swipeLeft = swipeRight = false;
|
swipeUp = swipeDown = swipeLeft = swipeRight = false;
|
||||||
swipeUpB = swipeDownB = swipeLeftB = swipeRightB = 0;
|
swipeUpB = swipeDownB = swipeLeftB = swipeRightB = 0;
|
||||||
if (Global.TapSensitivity[deviceNum] != 0 && !Global.UseTPforControls[deviceNum])
|
byte tapSensitivity = Global.TapSensitivity[deviceNum];
|
||||||
|
if (tapSensitivity != 0 && !Global.UseTPforControls[deviceNum])
|
||||||
{
|
{
|
||||||
|
|
||||||
if (secondtouchbegin)
|
if (secondtouchbegin)
|
||||||
{
|
{
|
||||||
tappedOnce = false;
|
tappedOnce = false;
|
||||||
secondtouchbegin = false;
|
secondtouchbegin = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime test = arg.timeStamp;
|
DateTime test = arg.timeStamp;
|
||||||
if (test <= (pastTime + TimeSpan.FromMilliseconds((double)Global.TapSensitivity[deviceNum] * 2)) && !arg.touchButtonPressed && !tappedOnce)
|
if (test <= (pastTime + TimeSpan.FromMilliseconds((double)tapSensitivity * 2)) && !arg.touchButtonPressed && !tappedOnce)
|
||||||
if (Math.Abs(firstTouch.hwX - arg.touches[0].hwX) < 10 && Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 10)
|
if (Math.Abs(firstTouch.hwX - arg.touches[0].hwX) < 10 && Math.Abs(firstTouch.hwY - arg.touches[0].hwY) < 10)
|
||||||
if (Global.DoubleTap[deviceNum])
|
if (Global.DoubleTap[deviceNum])
|
||||||
{
|
{
|
||||||
@ -149,6 +157,7 @@ namespace DS4Windows
|
|||||||
else
|
else
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Left); //this way no delay if disabled
|
Mapping.MapClick(deviceNum, Mapping.Click.Left); //this way no delay if disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
dev.getCurrentState(s);
|
dev.getCurrentState(s);
|
||||||
synthesizeMouseButtons();
|
synthesizeMouseButtons();
|
||||||
}
|
}
|
||||||
@ -174,19 +183,23 @@ namespace DS4Windows
|
|||||||
public bool dragging, dragging2;
|
public bool dragging, dragging2;
|
||||||
private void synthesizeMouseButtons()
|
private void synthesizeMouseButtons()
|
||||||
{
|
{
|
||||||
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchLeft.ToString(), false) == null && leftDown)
|
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchLeft, false) == null && leftDown)
|
||||||
{
|
{
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Left);
|
Mapping.MapClick(deviceNum, Mapping.Click.Left);
|
||||||
dragging2 = true;
|
dragging2 = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
dragging2 = false;
|
dragging2 = false;
|
||||||
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchUpper.ToString(), false) == null && upperDown)
|
}
|
||||||
|
|
||||||
|
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchUpper, false) == null && upperDown)
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Middle);
|
Mapping.MapClick(deviceNum, Mapping.Click.Middle);
|
||||||
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchRight.ToString(), false) == null && rightDown)
|
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchRight, false) == null && rightDown)
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Left);
|
Mapping.MapClick(deviceNum, Mapping.Click.Left);
|
||||||
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchMulti.ToString(), false) == null && multiDown)
|
if (Global.GetDS4Action(deviceNum, DS4Controls.TouchMulti, false) == null && multiDown)
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Right);
|
Mapping.MapClick(deviceNum, Mapping.Click.Right);
|
||||||
|
|
||||||
if (!Global.UseTPforControls[deviceNum])
|
if (!Global.UseTPforControls[deviceNum])
|
||||||
{
|
{
|
||||||
if (tappedOnce)
|
if (tappedOnce)
|
||||||
@ -205,8 +218,11 @@ namespace DS4Windows
|
|||||||
dragging = true;
|
dragging = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
dragging = false;
|
dragging = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s = remapped;
|
s = remapped;
|
||||||
//remapped.CopyTo(s);
|
//remapped.CopyTo(s);
|
||||||
}
|
}
|
||||||
@ -231,11 +247,13 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
if ((Global.LowerRCOn[deviceNum] && arg.touches[0].hwX > (1920 * 3) / 4 && arg.touches[0].hwY > (960 * 3) / 4))
|
if ((Global.LowerRCOn[deviceNum] && arg.touches[0].hwX > (1920 * 3) / 4 && arg.touches[0].hwY > (960 * 3) / 4))
|
||||||
Mapping.MapClick(deviceNum, Mapping.Click.Right);
|
Mapping.MapClick(deviceNum, Mapping.Click.Right);
|
||||||
|
|
||||||
if (isLeft(arg.touches[0]))
|
if (isLeft(arg.touches[0]))
|
||||||
leftDown = true;
|
leftDown = true;
|
||||||
else if (isRight(arg.touches[0]))
|
else if (isRight(arg.touches[0]))
|
||||||
rightDown = true;
|
rightDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev.getCurrentState(s);
|
dev.getCurrentState(s);
|
||||||
synthesizeMouseButtons();
|
synthesizeMouseButtons();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
class MouseCursor
|
class MouseCursor
|
||||||
@ -42,10 +37,14 @@ namespace DS4Windows
|
|||||||
int yAction = (int)yMotion;
|
int yAction = (int)yMotion;
|
||||||
vRemainder += yMotion - yAction;
|
vRemainder += yMotion - yAction;
|
||||||
vRemainder -= (int)vRemainder;
|
vRemainder -= (int)vRemainder;
|
||||||
if (Global.GyroInvert[deviceNumber] == 2 || Global.GyroInvert[deviceNumber] == 3)
|
|
||||||
|
int gyroInvert = Global.GyroInvert[deviceNumber];
|
||||||
|
if (gyroInvert == 2 || gyroInvert == 3)
|
||||||
xAction *= -1;
|
xAction *= -1;
|
||||||
if (Global.GyroInvert[deviceNumber] == 1 || Global.GyroInvert[deviceNumber] == 3)
|
|
||||||
|
if (gyroInvert == 1 || gyroInvert == 3)
|
||||||
yAction *= -1;
|
yAction *= -1;
|
||||||
|
|
||||||
if (yAction != 0 || xAction != 0)
|
if (yAction != 0 || xAction != 0)
|
||||||
InputMethods.MoveCursorBy(xAction, yAction);
|
InputMethods.MoveCursorBy(xAction, yAction);
|
||||||
|
|
||||||
@ -65,8 +64,10 @@ namespace DS4Windows
|
|||||||
private byte lastTouchID;
|
private byte lastTouchID;
|
||||||
public void touchesMoved(TouchpadEventArgs arg, bool dragging)
|
public void touchesMoved(TouchpadEventArgs arg, bool dragging)
|
||||||
{
|
{
|
||||||
if ((!dragging && arg.touches.Length != 1) || (dragging && arg.touches.Length < 1))
|
int touchesLen = arg.touches.Length;
|
||||||
|
if ((!dragging && touchesLen != 1) || (dragging && touchesLen < 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int deltaX, deltaY;
|
int deltaX, deltaY;
|
||||||
if (arg.touches[0].touchID != lastTouchID)
|
if (arg.touches[0].touchID != lastTouchID)
|
||||||
{
|
{
|
||||||
@ -78,8 +79,7 @@ namespace DS4Windows
|
|||||||
else if (Global.TouchpadJitterCompensation[deviceNumber])
|
else if (Global.TouchpadJitterCompensation[deviceNumber])
|
||||||
{
|
{
|
||||||
// Often the DS4's internal jitter compensation kicks in and starts hiding changes, ironically creating jitter...
|
// Often the DS4's internal jitter compensation kicks in and starts hiding changes, ironically creating jitter...
|
||||||
|
if (dragging && touchesLen > 1)
|
||||||
if (dragging && arg.touches.Length > 1)
|
|
||||||
{
|
{
|
||||||
deltaX = arg.touches[1].deltaX;
|
deltaX = arg.touches[1].deltaX;
|
||||||
deltaY = arg.touches[1].deltaY;
|
deltaY = arg.touches[1].deltaY;
|
||||||
@ -89,6 +89,7 @@ namespace DS4Windows
|
|||||||
deltaX = arg.touches[0].deltaX;
|
deltaX = arg.touches[0].deltaX;
|
||||||
deltaY = arg.touches[0].deltaY;
|
deltaY = arg.touches[0].deltaY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow only very fine, slow motions, when changing direction, even from neutral
|
// allow only very fine, slow motions, when changing direction, even from neutral
|
||||||
// TODO maybe just consume it completely?
|
// TODO maybe just consume it completely?
|
||||||
if (deltaX <= -1)
|
if (deltaX <= -1)
|
||||||
@ -127,7 +128,7 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (dragging && arg.touches.Length > 1)
|
if (dragging && touchesLen > 1)
|
||||||
{
|
{
|
||||||
deltaX = arg.touches[1].deltaX;
|
deltaX = arg.touches[1].deltaX;
|
||||||
deltaY = arg.touches[1].deltaY;
|
deltaY = arg.touches[1].deltaY;
|
||||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
class MouseWheel
|
class MouseWheel
|
||||||
@ -27,6 +26,7 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
if (arg.touches.Length != 2 || dragging)
|
if (arg.touches.Length != 2 || dragging)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Touch lastT0 = arg.touches[0].previousTouch;
|
Touch lastT0 = arg.touches[0].previousTouch;
|
||||||
Touch lastT1 = arg.touches[1].previousTouch;
|
Touch lastT1 = arg.touches[1].previousTouch;
|
||||||
Touch T0 = arg.touches[0];
|
Touch T0 = arg.touches[0];
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.Win32.SafeHandles;
|
using Microsoft.Win32.SafeHandles;
|
||||||
@ -522,7 +521,7 @@ namespace DS4Windows
|
|||||||
|
|
||||||
protected virtual Boolean GetDeviceHandle(String Path)
|
protected virtual Boolean GetDeviceHandle(String Path)
|
||||||
{
|
{
|
||||||
m_FileHandle = CreateFile(Path, (GENERIC_WRITE | GENERIC_READ), FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
|
m_FileHandle = CreateFile(Path, (GENERIC_WRITE | GENERIC_READ), FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | 0x20000000 | 0x80000000, 0);
|
||||||
|
|
||||||
return !m_FileHandle.IsInvalid;
|
return !m_FileHandle.IsInvalid;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.Win32.SafeHandles;
|
using Microsoft.Win32.SafeHandles;
|
||||||
@ -12,6 +11,9 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
private const String DS3_BUS_CLASS_GUID = "{F679F562-3164-42CE-A4DB-E7DDBE723909}";
|
private const String DS3_BUS_CLASS_GUID = "{F679F562-3164-42CE-A4DB-E7DDBE723909}";
|
||||||
private const int CONTROLLER_OFFSET = 1; // Device 0 is the virtual USB hub itself, and we leave devices 1-10 available for other software (like the Scarlet.Crush DualShock driver itself)
|
private const int CONTROLLER_OFFSET = 1; // Device 0 is the virtual USB hub itself, and we leave devices 1-10 available for other software (like the Scarlet.Crush DualShock driver itself)
|
||||||
|
private const int inputResolution = 127 - (-128);
|
||||||
|
private const float reciprocalInputResolution = 1 / (float)inputResolution;
|
||||||
|
private const int outputResolution = 32767 - (-32768);
|
||||||
|
|
||||||
private int firstController = 1;
|
private int firstController = 1;
|
||||||
// Device 0 is the virtual USB hub itself, and we can leave more available for other software (like the Scarlet.Crush DualShock driver)
|
// Device 0 is the virtual USB hub itself, and we can leave more available for other software (like the Scarlet.Crush DualShock driver)
|
||||||
@ -25,10 +27,11 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
Value -= 0x80;
|
Value -= 0x80;
|
||||||
|
|
||||||
if (Value == -128) Value = -127;
|
//float temp = (Value - (-128)) / (float)inputResolution;
|
||||||
if (Flip) Value *= -1;
|
float temp = (Value - (-128)) * reciprocalInputResolution;
|
||||||
|
if (Flip) temp = (temp - 0.5f) * -1.0f + 0.5f;
|
||||||
|
|
||||||
return (Int32)((float)Value * 258.00787401574803149606299212599f);
|
return (Int32)(temp * outputResolution + (-32768));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,10 +108,11 @@ namespace DS4Windows
|
|||||||
Output[4] = (Byte)(device + firstController);
|
Output[4] = (Byte)(device + firstController);
|
||||||
Output[9] = 0x14;
|
Output[9] = 0x14;
|
||||||
|
|
||||||
for (int i = 10; i < Output.Length; i++)
|
for (int i = 10, outLen = Output.Length; i < outLen; i++)
|
||||||
{
|
{
|
||||||
Output[i] = 0;
|
Output[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.Share) Output[10] |= (Byte)(1 << 5); // Back
|
if (state.Share) Output[10] |= (Byte)(1 << 5); // Back
|
||||||
if (state.L3) Output[10] |= (Byte)(1 << 6); // Left Thumb
|
if (state.L3) Output[10] |= (Byte)(1 << 6); // Left Thumb
|
||||||
if (state.R3) Output[10] |= (Byte)(1 << 7); // Right Thumb
|
if (state.R3) Output[10] |= (Byte)(1 << 7); // Right Thumb
|
||||||
@ -133,9 +137,9 @@ namespace DS4Windows
|
|||||||
Output[13] = state.R2; // Right Trigger
|
Output[13] = state.R2; // Right Trigger
|
||||||
|
|
||||||
Int32 ThumbLX = Scale(state.LX, false);
|
Int32 ThumbLX = Scale(state.LX, false);
|
||||||
Int32 ThumbLY = -Scale(state.LY, false);
|
Int32 ThumbLY = Scale(state.LY, true);
|
||||||
Int32 ThumbRX = Scale(state.RX, false);
|
Int32 ThumbRX = Scale(state.RX, false);
|
||||||
Int32 ThumbRY = -Scale(state.RY, false);
|
Int32 ThumbRY = Scale(state.RY, true);
|
||||||
Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX
|
Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX
|
||||||
Output[15] = (Byte)((ThumbLX >> 8) & 0xFF);
|
Output[15] = (Byte)((ThumbLX >> 8) & 0xFF);
|
||||||
Output[16] = (Byte)((ThumbLY >> 0) & 0xFF); // LY
|
Output[16] = (Byte)((ThumbLY >> 0) & 0xFF); // LY
|
||||||
|
@ -19,26 +19,26 @@ namespace DS4Windows
|
|||||||
internal class WindowsEnumerator
|
internal class WindowsEnumerator
|
||||||
{
|
{
|
||||||
private delegate int EnumCallBackDelegate(IntPtr hwnd, int lParam);
|
private delegate int EnumCallBackDelegate(IntPtr hwnd, int lParam);
|
||||||
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
private static extern int EnumWindows(EnumCallBackDelegate lpEnumFunc, int lParam);
|
private static extern int EnumWindows(EnumCallBackDelegate lpEnumFunc, int lParam);
|
||||||
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
private static extern int EnumChildWindows(IntPtr hWndParent, EnumCallBackDelegate lpEnumFunc, int lParam);
|
private static extern int EnumChildWindows(IntPtr hWndParent, EnumCallBackDelegate lpEnumFunc, int lParam);
|
||||||
|
|
||||||
[DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
[DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
|
|
||||||
private static extern int GetClassName(IntPtr hwnd, System.Text.StringBuilder lpClassName, int nMaxCount);
|
private static extern int GetClassName(IntPtr hwnd, System.Text.StringBuilder lpClassName, int nMaxCount);
|
||||||
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
private static extern int IsWindowVisible(IntPtr hwnd);
|
private static extern int IsWindowVisible(IntPtr hwnd);
|
||||||
|
|
||||||
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
|
|
||||||
private static extern int GetParent(IntPtr hwnd);
|
private static extern int GetParent(IntPtr hwnd);
|
||||||
[DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
|
||||||
|
|
||||||
|
[DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
|
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
|
||||||
[DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
|
||||||
|
|
||||||
|
[DllImport("user32", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||||
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, System.Text.StringBuilder lParam);
|
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, System.Text.StringBuilder lParam);
|
||||||
|
|
||||||
private List<ApiWindow> _listChildren = new List<ApiWindow>();
|
private List<ApiWindow> _listChildren = new List<ApiWindow>();
|
||||||
|
88
DS4Windows/DS4Forms/DS4Form.Designer.cs
generated
@ -118,6 +118,11 @@
|
|||||||
this.hideDS4CheckBox = new System.Windows.Forms.CheckBox();
|
this.hideDS4CheckBox = new System.Windows.Forms.CheckBox();
|
||||||
this.cBSwipeProfiles = new System.Windows.Forms.CheckBox();
|
this.cBSwipeProfiles = new System.Windows.Forms.CheckBox();
|
||||||
this.StartWindowsCheckBox = new System.Windows.Forms.CheckBox();
|
this.StartWindowsCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
|
this.runStartupPanel = new System.Windows.Forms.Panel();
|
||||||
|
this.uacPictureBox = new System.Windows.Forms.PictureBox();
|
||||||
|
this.runStartTaskRadio = new System.Windows.Forms.RadioButton();
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.runStartProgRadio = new System.Windows.Forms.RadioButton();
|
||||||
this.startMinimizedCheckBox = new System.Windows.Forms.CheckBox();
|
this.startMinimizedCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
this.panel1 = new System.Windows.Forms.Panel();
|
this.panel1 = new System.Windows.Forms.Panel();
|
||||||
this.lbNotifications = new System.Windows.Forms.Label();
|
this.lbNotifications = new System.Windows.Forms.Label();
|
||||||
@ -129,6 +134,7 @@
|
|||||||
this.cBFlashWhenLate = new System.Windows.Forms.CheckBox();
|
this.cBFlashWhenLate = new System.Windows.Forms.CheckBox();
|
||||||
this.cBCloseMini = new System.Windows.Forms.CheckBox();
|
this.cBCloseMini = new System.Windows.Forms.CheckBox();
|
||||||
this.cBQuickCharge = new System.Windows.Forms.CheckBox();
|
this.cBQuickCharge = new System.Windows.Forms.CheckBox();
|
||||||
|
this.cBUseWhiteIcon = new System.Windows.Forms.CheckBox();
|
||||||
this.cBDownloadLangauge = new System.Windows.Forms.CheckBox();
|
this.cBDownloadLangauge = new System.Windows.Forms.CheckBox();
|
||||||
this.cBUpdate = new System.Windows.Forms.CheckBox();
|
this.cBUpdate = new System.Windows.Forms.CheckBox();
|
||||||
this.pNUpdate = new System.Windows.Forms.Panel();
|
this.pNUpdate = new System.Windows.Forms.Panel();
|
||||||
@ -139,7 +145,6 @@
|
|||||||
this.lbUseXIPorts = new System.Windows.Forms.Label();
|
this.lbUseXIPorts = new System.Windows.Forms.Label();
|
||||||
this.nUDXIPorts = new System.Windows.Forms.NumericUpDown();
|
this.nUDXIPorts = new System.Windows.Forms.NumericUpDown();
|
||||||
this.lbLastXIPort = new System.Windows.Forms.Label();
|
this.lbLastXIPort = new System.Windows.Forms.Label();
|
||||||
this.cBUseWhiteIcon = new System.Windows.Forms.CheckBox();
|
|
||||||
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
|
||||||
this.linkProfiles = new System.Windows.Forms.LinkLabel();
|
this.linkProfiles = new System.Windows.Forms.LinkLabel();
|
||||||
this.lnkControllers = new System.Windows.Forms.LinkLabel();
|
this.lnkControllers = new System.Windows.Forms.LinkLabel();
|
||||||
@ -168,6 +173,8 @@
|
|||||||
this.toolStrip1.SuspendLayout();
|
this.toolStrip1.SuspendLayout();
|
||||||
this.tabSettings.SuspendLayout();
|
this.tabSettings.SuspendLayout();
|
||||||
this.fLPSettings.SuspendLayout();
|
this.fLPSettings.SuspendLayout();
|
||||||
|
this.runStartupPanel.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.uacPictureBox)).BeginInit();
|
||||||
this.panel1.SuspendLayout();
|
this.panel1.SuspendLayout();
|
||||||
this.panel2.SuspendLayout();
|
this.panel2.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.nUDLatency)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.nUDLatency)).BeginInit();
|
||||||
@ -632,8 +639,8 @@
|
|||||||
this.lBProfiles.ContextMenuStrip = this.cMProfile;
|
this.lBProfiles.ContextMenuStrip = this.cMProfile;
|
||||||
resources.ApplyResources(this.lBProfiles, "lBProfiles");
|
resources.ApplyResources(this.lBProfiles, "lBProfiles");
|
||||||
this.lBProfiles.FormattingEnabled = true;
|
this.lBProfiles.FormattingEnabled = true;
|
||||||
this.lBProfiles.MultiColumn = true;
|
|
||||||
this.lBProfiles.Name = "lBProfiles";
|
this.lBProfiles.Name = "lBProfiles";
|
||||||
|
this.lBProfiles.SelectedIndexChanged += new System.EventHandler(this.lBProfiles_SelectedIndexChanged);
|
||||||
this.lBProfiles.KeyDown += new System.Windows.Forms.KeyEventHandler(this.lBProfiles_KeyDown);
|
this.lBProfiles.KeyDown += new System.Windows.Forms.KeyEventHandler(this.lBProfiles_KeyDown);
|
||||||
this.lBProfiles.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.lBProfiles_MouseDoubleClick);
|
this.lBProfiles.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.lBProfiles_MouseDoubleClick);
|
||||||
this.lBProfiles.MouseDown += new System.Windows.Forms.MouseEventHandler(this.lBProfiles_MouseDown);
|
this.lBProfiles.MouseDown += new System.Windows.Forms.MouseEventHandler(this.lBProfiles_MouseDown);
|
||||||
@ -795,36 +802,36 @@
|
|||||||
//
|
//
|
||||||
// tsBEditProfile
|
// tsBEditProfile
|
||||||
//
|
//
|
||||||
this.tsBEditProfile.Image = global::DS4Windows.Properties.Resources.edit;
|
|
||||||
resources.ApplyResources(this.tsBEditProfile, "tsBEditProfile");
|
resources.ApplyResources(this.tsBEditProfile, "tsBEditProfile");
|
||||||
|
this.tsBEditProfile.Image = global::DS4Windows.Properties.Resources.edit;
|
||||||
this.tsBEditProfile.Name = "tsBEditProfile";
|
this.tsBEditProfile.Name = "tsBEditProfile";
|
||||||
this.tsBEditProfile.Click += new System.EventHandler(this.tsBNEditProfile_Click);
|
this.tsBEditProfile.Click += new System.EventHandler(this.tsBNEditProfile_Click);
|
||||||
//
|
//
|
||||||
// tsBDeleteProfile
|
// tsBDeleteProfile
|
||||||
//
|
//
|
||||||
this.tsBDeleteProfile.Image = global::DS4Windows.Properties.Resources.delete;
|
|
||||||
resources.ApplyResources(this.tsBDeleteProfile, "tsBDeleteProfile");
|
resources.ApplyResources(this.tsBDeleteProfile, "tsBDeleteProfile");
|
||||||
|
this.tsBDeleteProfile.Image = global::DS4Windows.Properties.Resources.delete;
|
||||||
this.tsBDeleteProfile.Name = "tsBDeleteProfile";
|
this.tsBDeleteProfile.Name = "tsBDeleteProfile";
|
||||||
this.tsBDeleteProfile.Click += new System.EventHandler(this.tsBDeleteProfle_Click);
|
this.tsBDeleteProfile.Click += new System.EventHandler(this.tsBDeleteProfle_Click);
|
||||||
//
|
//
|
||||||
// tSBDupProfile
|
// tSBDupProfile
|
||||||
//
|
//
|
||||||
this.tSBDupProfile.Image = global::DS4Windows.Properties.Resources.copy;
|
|
||||||
resources.ApplyResources(this.tSBDupProfile, "tSBDupProfile");
|
resources.ApplyResources(this.tSBDupProfile, "tSBDupProfile");
|
||||||
|
this.tSBDupProfile.Image = global::DS4Windows.Properties.Resources.copy;
|
||||||
this.tSBDupProfile.Name = "tSBDupProfile";
|
this.tSBDupProfile.Name = "tSBDupProfile";
|
||||||
this.tSBDupProfile.Click += new System.EventHandler(this.tSBDupProfile_Click);
|
this.tSBDupProfile.Click += new System.EventHandler(this.tSBDupProfile_Click);
|
||||||
//
|
//
|
||||||
// tSBImportProfile
|
// tSBImportProfile
|
||||||
//
|
//
|
||||||
this.tSBImportProfile.Image = global::DS4Windows.Properties.Resources.import;
|
|
||||||
resources.ApplyResources(this.tSBImportProfile, "tSBImportProfile");
|
resources.ApplyResources(this.tSBImportProfile, "tSBImportProfile");
|
||||||
|
this.tSBImportProfile.Image = global::DS4Windows.Properties.Resources.import;
|
||||||
this.tSBImportProfile.Name = "tSBImportProfile";
|
this.tSBImportProfile.Name = "tSBImportProfile";
|
||||||
this.tSBImportProfile.Click += new System.EventHandler(this.tSBImportProfile_Click);
|
this.tSBImportProfile.Click += new System.EventHandler(this.tSBImportProfile_Click);
|
||||||
//
|
//
|
||||||
// tSBExportProfile
|
// tSBExportProfile
|
||||||
//
|
//
|
||||||
this.tSBExportProfile.Image = global::DS4Windows.Properties.Resources.export;
|
|
||||||
resources.ApplyResources(this.tSBExportProfile, "tSBExportProfile");
|
resources.ApplyResources(this.tSBExportProfile, "tSBExportProfile");
|
||||||
|
this.tSBExportProfile.Image = global::DS4Windows.Properties.Resources.export;
|
||||||
this.tSBExportProfile.Name = "tSBExportProfile";
|
this.tSBExportProfile.Name = "tSBExportProfile";
|
||||||
this.tSBExportProfile.Click += new System.EventHandler(this.tSBExportProfile_Click);
|
this.tSBExportProfile.Click += new System.EventHandler(this.tSBExportProfile_Click);
|
||||||
//
|
//
|
||||||
@ -847,6 +854,7 @@
|
|||||||
this.fLPSettings.Controls.Add(this.hideDS4CheckBox);
|
this.fLPSettings.Controls.Add(this.hideDS4CheckBox);
|
||||||
this.fLPSettings.Controls.Add(this.cBSwipeProfiles);
|
this.fLPSettings.Controls.Add(this.cBSwipeProfiles);
|
||||||
this.fLPSettings.Controls.Add(this.StartWindowsCheckBox);
|
this.fLPSettings.Controls.Add(this.StartWindowsCheckBox);
|
||||||
|
this.fLPSettings.Controls.Add(this.runStartupPanel);
|
||||||
this.fLPSettings.Controls.Add(this.startMinimizedCheckBox);
|
this.fLPSettings.Controls.Add(this.startMinimizedCheckBox);
|
||||||
this.fLPSettings.Controls.Add(this.panel1);
|
this.fLPSettings.Controls.Add(this.panel1);
|
||||||
this.fLPSettings.Controls.Add(this.cBDisconnectBT);
|
this.fLPSettings.Controls.Add(this.cBDisconnectBT);
|
||||||
@ -884,6 +892,44 @@
|
|||||||
this.StartWindowsCheckBox.UseVisualStyleBackColor = true;
|
this.StartWindowsCheckBox.UseVisualStyleBackColor = true;
|
||||||
this.StartWindowsCheckBox.CheckedChanged += new System.EventHandler(this.StartWindowsCheckBox_CheckedChanged);
|
this.StartWindowsCheckBox.CheckedChanged += new System.EventHandler(this.StartWindowsCheckBox_CheckedChanged);
|
||||||
//
|
//
|
||||||
|
// runStartupPanel
|
||||||
|
//
|
||||||
|
this.runStartupPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
|
this.runStartupPanel.Controls.Add(this.uacPictureBox);
|
||||||
|
this.runStartupPanel.Controls.Add(this.runStartTaskRadio);
|
||||||
|
this.runStartupPanel.Controls.Add(this.label1);
|
||||||
|
this.runStartupPanel.Controls.Add(this.runStartProgRadio);
|
||||||
|
resources.ApplyResources(this.runStartupPanel, "runStartupPanel");
|
||||||
|
this.runStartupPanel.Name = "runStartupPanel";
|
||||||
|
//
|
||||||
|
// uacPictureBox
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.uacPictureBox, "uacPictureBox");
|
||||||
|
this.uacPictureBox.Name = "uacPictureBox";
|
||||||
|
this.uacPictureBox.TabStop = false;
|
||||||
|
//
|
||||||
|
// runStartTaskRadio
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.runStartTaskRadio, "runStartTaskRadio");
|
||||||
|
this.runStartTaskRadio.Name = "runStartTaskRadio";
|
||||||
|
this.runStartTaskRadio.TabStop = true;
|
||||||
|
this.runStartTaskRadio.UseVisualStyleBackColor = true;
|
||||||
|
this.runStartTaskRadio.Click += new System.EventHandler(this.runStartTaskRadio_Click);
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.label1, "label1");
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
//
|
||||||
|
// runStartProgRadio
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.runStartProgRadio, "runStartProgRadio");
|
||||||
|
this.runStartProgRadio.Checked = true;
|
||||||
|
this.runStartProgRadio.Name = "runStartProgRadio";
|
||||||
|
this.runStartProgRadio.TabStop = true;
|
||||||
|
this.runStartProgRadio.UseVisualStyleBackColor = true;
|
||||||
|
this.runStartProgRadio.Click += new System.EventHandler(this.runStartProgRadio_Click);
|
||||||
|
//
|
||||||
// startMinimizedCheckBox
|
// startMinimizedCheckBox
|
||||||
//
|
//
|
||||||
resources.ApplyResources(this.startMinimizedCheckBox, "startMinimizedCheckBox");
|
resources.ApplyResources(this.startMinimizedCheckBox, "startMinimizedCheckBox");
|
||||||
@ -940,7 +986,7 @@
|
|||||||
0});
|
0});
|
||||||
this.nUDLatency.Name = "nUDLatency";
|
this.nUDLatency.Name = "nUDLatency";
|
||||||
this.nUDLatency.Value = new decimal(new int[] {
|
this.nUDLatency.Value = new decimal(new int[] {
|
||||||
10,
|
20,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0});
|
0});
|
||||||
@ -974,6 +1020,13 @@
|
|||||||
this.cBQuickCharge.UseVisualStyleBackColor = true;
|
this.cBQuickCharge.UseVisualStyleBackColor = true;
|
||||||
this.cBQuickCharge.CheckedChanged += new System.EventHandler(this.cBQuickCharge_CheckedChanged);
|
this.cBQuickCharge.CheckedChanged += new System.EventHandler(this.cBQuickCharge_CheckedChanged);
|
||||||
//
|
//
|
||||||
|
// cBUseWhiteIcon
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.cBUseWhiteIcon, "cBUseWhiteIcon");
|
||||||
|
this.cBUseWhiteIcon.Name = "cBUseWhiteIcon";
|
||||||
|
this.cBUseWhiteIcon.UseVisualStyleBackColor = true;
|
||||||
|
this.cBUseWhiteIcon.CheckedChanged += new System.EventHandler(this.cBUseWhiteIcon_CheckedChanged);
|
||||||
|
//
|
||||||
// cBDownloadLangauge
|
// cBDownloadLangauge
|
||||||
//
|
//
|
||||||
resources.ApplyResources(this.cBDownloadLangauge, "cBDownloadLangauge");
|
resources.ApplyResources(this.cBDownloadLangauge, "cBDownloadLangauge");
|
||||||
@ -1068,13 +1121,6 @@
|
|||||||
resources.ApplyResources(this.lbLastXIPort, "lbLastXIPort");
|
resources.ApplyResources(this.lbLastXIPort, "lbLastXIPort");
|
||||||
this.lbLastXIPort.Name = "lbLastXIPort";
|
this.lbLastXIPort.Name = "lbLastXIPort";
|
||||||
//
|
//
|
||||||
// cBUseWhiteIcon
|
|
||||||
//
|
|
||||||
resources.ApplyResources(this.cBUseWhiteIcon, "cBUseWhiteIcon");
|
|
||||||
this.cBUseWhiteIcon.Name = "cBUseWhiteIcon";
|
|
||||||
this.cBUseWhiteIcon.UseVisualStyleBackColor = true;
|
|
||||||
this.cBUseWhiteIcon.CheckedChanged += new System.EventHandler(this.cBUseWhiteIcon_CheckedChanged);
|
|
||||||
//
|
|
||||||
// flowLayoutPanel1
|
// flowLayoutPanel1
|
||||||
//
|
//
|
||||||
resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1");
|
resources.ApplyResources(this.flowLayoutPanel1, "flowLayoutPanel1");
|
||||||
@ -1157,10 +1203,6 @@
|
|||||||
resources.ApplyResources(this.useCustomColorToolStripMenuItem, "useCustomColorToolStripMenuItem");
|
resources.ApplyResources(this.useCustomColorToolStripMenuItem, "useCustomColorToolStripMenuItem");
|
||||||
this.useCustomColorToolStripMenuItem.Click += new System.EventHandler(this.useCustomColorToolStripMenuItem_Click);
|
this.useCustomColorToolStripMenuItem.Click += new System.EventHandler(this.useCustomColorToolStripMenuItem_Click);
|
||||||
//
|
//
|
||||||
// advColorDialog
|
|
||||||
//
|
|
||||||
this.advColorDialog.OnUpdateColor += new DS4Windows.AdvancedColorDialog.ColorUpdateHandler(this.advColorDialog_OnUpdateColor);
|
|
||||||
//
|
|
||||||
// DS4Form
|
// DS4Form
|
||||||
//
|
//
|
||||||
this.AllowDrop = true;
|
this.AllowDrop = true;
|
||||||
@ -1196,6 +1238,9 @@
|
|||||||
this.tabSettings.ResumeLayout(false);
|
this.tabSettings.ResumeLayout(false);
|
||||||
this.fLPSettings.ResumeLayout(false);
|
this.fLPSettings.ResumeLayout(false);
|
||||||
this.fLPSettings.PerformLayout();
|
this.fLPSettings.PerformLayout();
|
||||||
|
this.runStartupPanel.ResumeLayout(false);
|
||||||
|
this.runStartupPanel.PerformLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.uacPictureBox)).EndInit();
|
||||||
this.panel1.ResumeLayout(false);
|
this.panel1.ResumeLayout(false);
|
||||||
this.panel1.PerformLayout();
|
this.panel1.PerformLayout();
|
||||||
this.panel2.ResumeLayout(false);
|
this.panel2.ResumeLayout(false);
|
||||||
@ -1340,6 +1385,11 @@
|
|||||||
private System.Windows.Forms.ToolStripMenuItem useCustomColorToolStripMenuItem;
|
private System.Windows.Forms.ToolStripMenuItem useCustomColorToolStripMenuItem;
|
||||||
private AdvancedColorDialog advColorDialog;
|
private AdvancedColorDialog advColorDialog;
|
||||||
private System.Windows.Forms.CheckBox cBUseWhiteIcon;
|
private System.Windows.Forms.CheckBox cBUseWhiteIcon;
|
||||||
|
private System.Windows.Forms.Panel runStartupPanel;
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.RadioButton runStartProgRadio;
|
||||||
|
private System.Windows.Forms.RadioButton runStartTaskRadio;
|
||||||
|
private System.Windows.Forms.PictureBox uacPictureBox;
|
||||||
//private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2;
|
//private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
DS4Windows/DS4Forms/Hotkeys.Designer.cs
generated
@ -40,6 +40,7 @@
|
|||||||
this.tPHotkeys = new System.Windows.Forms.TabPage();
|
this.tPHotkeys = new System.Windows.Forms.TabPage();
|
||||||
this.lbHotkeys = new System.Windows.Forms.Label();
|
this.lbHotkeys = new System.Windows.Forms.Label();
|
||||||
this.tPCredits = new System.Windows.Forms.TabPage();
|
this.tPCredits = new System.Windows.Forms.TabPage();
|
||||||
|
this.linkTeokp = new System.Windows.Forms.LinkLabel();
|
||||||
this.linkKiliansch = new System.Windows.Forms.LinkLabel();
|
this.linkKiliansch = new System.Windows.Forms.LinkLabel();
|
||||||
this.linkChamilsaan = new System.Windows.Forms.LinkLabel();
|
this.linkChamilsaan = new System.Windows.Forms.LinkLabel();
|
||||||
this.linkBoganhobo = new System.Windows.Forms.LinkLabel();
|
this.linkBoganhobo = new System.Windows.Forms.LinkLabel();
|
||||||
@ -85,7 +86,6 @@
|
|||||||
this.lbTranslators = new System.Windows.Forms.Label();
|
this.lbTranslators = new System.Windows.Forms.Label();
|
||||||
this.linkSourceCode = new System.Windows.Forms.LinkLabel();
|
this.linkSourceCode = new System.Windows.Forms.LinkLabel();
|
||||||
this.lbLinkText = new System.Windows.Forms.Label();
|
this.lbLinkText = new System.Windows.Forms.Label();
|
||||||
this.linkTeokp = new System.Windows.Forms.LinkLabel();
|
|
||||||
this.tCAbout.SuspendLayout();
|
this.tCAbout.SuspendLayout();
|
||||||
this.tPHotkeys.SuspendLayout();
|
this.tPHotkeys.SuspendLayout();
|
||||||
this.tPCredits.SuspendLayout();
|
this.tPCredits.SuspendLayout();
|
||||||
@ -177,6 +177,13 @@
|
|||||||
this.tPCredits.Name = "tPCredits";
|
this.tPCredits.Name = "tPCredits";
|
||||||
this.tPCredits.UseVisualStyleBackColor = true;
|
this.tPCredits.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
|
// linkTeokp
|
||||||
|
//
|
||||||
|
resources.ApplyResources(this.linkTeokp, "linkTeokp");
|
||||||
|
this.linkTeokp.Name = "linkTeokp";
|
||||||
|
this.linkTeokp.TabStop = true;
|
||||||
|
this.linkTeokp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkTeokp_LinkClicked);
|
||||||
|
//
|
||||||
// linkKiliansch
|
// linkKiliansch
|
||||||
//
|
//
|
||||||
resources.ApplyResources(this.linkKiliansch, "linkKiliansch");
|
resources.ApplyResources(this.linkKiliansch, "linkKiliansch");
|
||||||
@ -448,13 +455,6 @@
|
|||||||
resources.ApplyResources(this.lbLinkText, "lbLinkText");
|
resources.ApplyResources(this.lbLinkText, "lbLinkText");
|
||||||
this.lbLinkText.Name = "lbLinkText";
|
this.lbLinkText.Name = "lbLinkText";
|
||||||
//
|
//
|
||||||
// linkTeokp
|
|
||||||
//
|
|
||||||
resources.ApplyResources(this.linkTeokp, "linkTeokp");
|
|
||||||
this.linkTeokp.Name = "linkTeokp";
|
|
||||||
this.linkTeokp.TabStop = true;
|
|
||||||
this.linkTeokp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkTeokp_LinkClicked);
|
|
||||||
//
|
|
||||||
// Hotkeys
|
// Hotkeys
|
||||||
//
|
//
|
||||||
resources.ApplyResources(this, "$this");
|
resources.ApplyResources(this, "$this");
|
||||||
|
@ -77,7 +77,7 @@ namespace DS4Windows
|
|||||||
|
|
||||||
private void lLChangelog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
private void lLChangelog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start("https://docs.google.com/document/d/1l4xcgVQkGUskc5CQ0p069yW22Cd5WAH_yE3Fz2hXo0E/edit?usp=sharing");
|
Process.Start("https://docs.google.com/document/d/1CovpH08fbPSXrC6TmEprzgPwCe0tTjQ_HTFfDotpmxk/edit?usp=sharing");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void linkDonate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
private void linkDonate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
@ -34,8 +34,9 @@ namespace DS4Windows
|
|||||||
device = deviceNum;
|
device = deviceNum;
|
||||||
ops = ooo;
|
ops = ooo;
|
||||||
button = buton;
|
button = buton;
|
||||||
cBToggle.Checked = button.Font.Italic;
|
DS4ControlSettings dcs = Global.getDS4CSetting(device, button.Name);
|
||||||
cBScanCode.Checked = button.Font.Bold;
|
cBToggle.Checked = dcs.keyType.HasFlag(DS4KeyType.Toggle);
|
||||||
|
cBScanCode.Checked = dcs.keyType.HasFlag(DS4KeyType.ScanCode);
|
||||||
oldSC = cBScanCode.Location;
|
oldSC = cBScanCode.Location;
|
||||||
defaultText = btnDefault.Text;
|
defaultText = btnDefault.Text;
|
||||||
if (button.Name.StartsWith("bnShift"))
|
if (button.Name.StartsWith("bnShift"))
|
||||||
@ -140,7 +141,17 @@ namespace DS4Windows
|
|||||||
object keytag;
|
object keytag;
|
||||||
//ushort val;
|
//ushort val;
|
||||||
if (((Button)sender).Tag != null && ((Button)sender).Tag.ToString().Contains("X360"))
|
if (((Button)sender).Tag != null && ((Button)sender).Tag.ToString().Contains("X360"))
|
||||||
keytag = ((Button)sender).Tag.ToString().Substring(4);
|
{
|
||||||
|
//keytag = ((Button)sender).Tag.ToString().Substring(4);
|
||||||
|
keytag = Global.getX360ControlsByName(((Button)sender).Tag.ToString().Substring(4));
|
||||||
|
DS4Controls psButton = Global.getDS4ControlsByName(button.Name);
|
||||||
|
if ((X360Controls)keytag == Global.getDefaultX360ControlBinding(psButton) &&
|
||||||
|
!cBScanCode.Checked && !cBToggle.Checked && !rBShiftModifer.Checked)
|
||||||
|
{
|
||||||
|
// Reset action
|
||||||
|
keytag = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (((Button)sender).Tag != null && ushort.TryParse(((Button)sender).Tag.ToString(), out val))
|
else if (((Button)sender).Tag != null && ushort.TryParse(((Button)sender).Tag.ToString(), out val))
|
||||||
keytag = val;
|
keytag = val;
|
||||||
else
|
else
|
||||||
@ -454,7 +465,7 @@ namespace DS4Windows
|
|||||||
lBMacroOn.Visible = true;
|
lBMacroOn.Visible = true;
|
||||||
foreach (int i in tag)
|
foreach (int i in tag)
|
||||||
macrostag.Add(i);
|
macrostag.Add(i);
|
||||||
if (Global.GetDS4KeyType(device, button.Name, rBShiftModifer.Checked).HasFlag(DS4KeyType.RepeatMacro))
|
if (Global.GetDS4KeyType(device, button.Name, rBShiftModifer.Checked).HasFlag(DS4KeyType.HoldMacro))
|
||||||
macrorepeat = true;
|
macrorepeat = true;
|
||||||
}
|
}
|
||||||
else if (tagO is string || tagO is X360Controls)
|
else if (tagO is string || tagO is X360Controls)
|
||||||
@ -509,7 +520,15 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string[] extras = Global.GetDS4Extra(device, button.Name, rBShiftModifer.Checked).Split(',');
|
string dcExtras = Global.GetDS4Extra(device, button.Name, rBShiftModifer.Checked);
|
||||||
|
string[] extras = null;
|
||||||
|
if (!string.IsNullOrEmpty(dcExtras))
|
||||||
|
{
|
||||||
|
extras = dcExtras.Split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extras != null)
|
||||||
|
{
|
||||||
int b;
|
int b;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -558,6 +577,8 @@ namespace DS4Windows
|
|||||||
nUDMouse.Value = 25;
|
nUDMouse.Value = 25;
|
||||||
cBMouse.Checked = false;
|
cBMouse.Checked = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extraChanged = false;
|
extraChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
646
DS4Windows/DS4Forms/Options.Designer.cs
generated
@ -86,7 +86,6 @@ namespace DS4Windows
|
|||||||
|
|
||||||
void AddtoDS4List()
|
void AddtoDS4List()
|
||||||
{
|
{
|
||||||
dcs.Add(DS4Controls.Cross);
|
|
||||||
dcs.Add(DS4Controls.Cross);
|
dcs.Add(DS4Controls.Cross);
|
||||||
dcs.Add(DS4Controls.Circle);
|
dcs.Add(DS4Controls.Circle);
|
||||||
dcs.Add(DS4Controls.Square);
|
dcs.Add(DS4Controls.Square);
|
||||||
@ -121,7 +120,9 @@ namespace DS4Windows
|
|||||||
else
|
else
|
||||||
macros.Add(value);
|
macros.Add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool[] pTP = new bool[4];
|
bool[] pTP = new bool[4];
|
||||||
|
|
||||||
void ds4_Tick(object sender, EventArgs e)
|
void ds4_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (Program.rootHub.DS4Controllers[0] != null)
|
if (Program.rootHub.DS4Controllers[0] != null)
|
||||||
@ -147,17 +148,25 @@ namespace DS4Windows
|
|||||||
pTP[0] = tP.leftDown;
|
pTP[0] = tP.leftDown;
|
||||||
pTP[1] = tP.rightDown;
|
pTP[1] = tP.rightDown;
|
||||||
}
|
}
|
||||||
foreach (DS4Controls dc in dcs)
|
|
||||||
|
//foreach (DS4Controls dc in dcs)
|
||||||
|
for (int controlIndex = 0, dcsLen = dcs.Count; controlIndex < dcsLen; controlIndex++)
|
||||||
|
{
|
||||||
|
DS4Controls dc = dcs[controlIndex];
|
||||||
if (Mapping.getBoolMapping(0, dc, cState, null, null))
|
if (Mapping.getBoolMapping(0, dc, cState, null, null))
|
||||||
{
|
{
|
||||||
int value = DS4ControltoInt(dc);
|
int value = DS4ControltoInt(dc);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach (int i in macros)
|
int macroLen = macros.Count;
|
||||||
|
//foreach (int i in macros)
|
||||||
|
for (int macroIndex = 0; macroIndex < macroLen; macroIndex++)
|
||||||
{
|
{
|
||||||
|
int i = macros[macroIndex];
|
||||||
if (i == value)
|
if (i == value)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (macros.Count == 0)
|
|
||||||
|
if (macroLen == 0)
|
||||||
{
|
{
|
||||||
AddMacroValue(value);
|
AddMacroValue(value);
|
||||||
lVMacros.Items.Add(DS4ControltoX360(dc), 0);
|
lVMacros.Items.Add(DS4ControltoX360(dc), 0);
|
||||||
@ -179,22 +188,28 @@ namespace DS4Windows
|
|||||||
AddMacroValue(value);
|
AddMacroValue(value);
|
||||||
lVMacros.Items.Add(DS4ControltoX360(dc), 0);
|
lVMacros.Items.Add(DS4ControltoX360(dc), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
lVMacros.Items[lVMacros.Items.Count - 1].EnsureVisible();
|
lVMacros.Items[lVMacros.Items.Count - 1].EnsureVisible();
|
||||||
}
|
}
|
||||||
else if (!Mapping.getBoolMapping(0, dc, cState, null, null))
|
else if (!Mapping.getBoolMapping(0, dc, cState, null, null))
|
||||||
{
|
{
|
||||||
if (macros.Count != 0)
|
int macroLen = macros.Count;
|
||||||
|
if (macroLen != 0)
|
||||||
{
|
{
|
||||||
int value = DS4ControltoInt(dc);
|
int value = DS4ControltoInt(dc);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach (int i in macros)
|
//foreach (int i in macros)
|
||||||
|
for (int macroIndex = 0; macroIndex < macroLen; macroIndex++)
|
||||||
{
|
{
|
||||||
|
int i = macros[macroIndex];
|
||||||
if (i == value)
|
if (i == value)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*for (int i = macros.Count - 1; i >= 0; i--)
|
/*for (int i = macros.Count - 1; i >= 0; i--)
|
||||||
if (macros.Count == 261)
|
if (macros.Count == 261)
|
||||||
count++;*/
|
count++;*/
|
||||||
|
|
||||||
if (count % 2 == 1)
|
if (count % 2 == 1)
|
||||||
{
|
{
|
||||||
if (cBRecordDelays.Checked)
|
if (cBRecordDelays.Checked)
|
||||||
@ -204,6 +219,7 @@ namespace DS4Windows
|
|||||||
sw.Reset();
|
sw.Reset();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMacroValue(value);
|
AddMacroValue(value);
|
||||||
lVMacros.Items.Add(DS4ControltoX360(dc), 1);
|
lVMacros.Items.Add(DS4ControltoX360(dc), 1);
|
||||||
lVMacros.Items[lVMacros.Items.Count - 1].EnsureVisible();
|
lVMacros.Items[lVMacros.Items.Count - 1].EnsureVisible();
|
||||||
@ -213,6 +229,7 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int DS4ControltoInt(DS4Controls ctrl)
|
public static int DS4ControltoInt(DS4Controls ctrl)
|
||||||
{
|
{
|
||||||
@ -279,8 +296,10 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recordAfter = false;
|
bool recordAfter = false;
|
||||||
int recordAfterInt = 0;
|
int recordAfterInt = 0;
|
||||||
|
|
||||||
private void btnRecord_Click(object sender, EventArgs e)
|
private void btnRecord_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (btnRecord.Text != Properties.Resources.StopText)
|
if (btnRecord.Text != Properties.Resources.StopText)
|
||||||
@ -784,8 +803,7 @@ namespace DS4Windows
|
|||||||
kbm.macrostag = macros;
|
kbm.macrostag = macros;
|
||||||
kbm.macros = macronames;
|
kbm.macros = macronames;
|
||||||
kbm.lBMacroOn.Visible = true;
|
kbm.lBMacroOn.Visible = true;
|
||||||
if (cBStyle.SelectedIndex == 1)
|
kbm.macrorepeat = cBStyle.SelectedIndex == 1;
|
||||||
kbm.macrorepeat = true;
|
|
||||||
saved = true;
|
saved = true;
|
||||||
if (sender != kbm)
|
if (sender != kbm)
|
||||||
kbm.Close();
|
kbm.Close();
|
||||||
@ -796,8 +814,7 @@ namespace DS4Windows
|
|||||||
sA.macros = macronames;
|
sA.macros = macronames;
|
||||||
sA.lbMacroRecorded.Text = string.Join(", ", macronames);
|
sA.lbMacroRecorded.Text = string.Join(", ", macronames);
|
||||||
//kbm.lBMacroOn.Visible = true;
|
//kbm.lBMacroOn.Visible = true;
|
||||||
if (cBStyle.SelectedIndex == 1)
|
sA.macrorepeat = cBStyle.SelectedIndex == 1;
|
||||||
sA.macrorepeat = true;
|
|
||||||
saved = true;
|
saved = true;
|
||||||
//if (sender != sA)
|
//if (sender != sA)
|
||||||
// sA.Close();
|
// sA.Close();
|
||||||
|
@ -42,7 +42,7 @@ namespace DS4Windows
|
|||||||
WebClient wb = new WebClient();
|
WebClient wb = new WebClient();
|
||||||
if (!driverinstalling)
|
if (!driverinstalling)
|
||||||
{
|
{
|
||||||
wb.DownloadFileAsync(new Uri("http://ds4windows.com/Files/Virtual Bus Driver.zip"), exepath + "\\VBus.zip");
|
wb.DownloadFileAsync(new Uri("http://23.239.26.40/ds4windows/files/Virtual Bus Driver.zip"), exepath + "\\VBus.zip");
|
||||||
wb.DownloadProgressChanged += wb_DownloadProgressChanged;
|
wb.DownloadProgressChanged += wb_DownloadProgressChanged;
|
||||||
wb.DownloadFileCompleted += wb_DownloadFileCompleted;
|
wb.DownloadFileCompleted += wb_DownloadFileCompleted;
|
||||||
driverinstalling = true;
|
driverinstalling = true;
|
||||||
@ -131,7 +131,7 @@ namespace DS4Windows
|
|||||||
|
|
||||||
private void button2_Click(object sender, EventArgs e)
|
private void button2_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start("http://www.microsoft.com/hardware/en-us/d/xbox-360-controller-for-windows");
|
Process.Start("http://www.microsoft.com/accessories/en-gb/d/xbox-360-controller-for-windows");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
251
DS4Windows/DS4Library/DS4Audio.cs
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using DS4Windows.DS4Library.CoreAudio;
|
||||||
|
|
||||||
|
namespace DS4Windows.DS4Library
|
||||||
|
{
|
||||||
|
public class DS4Audio
|
||||||
|
{
|
||||||
|
private IAudioEndpointVolume endpointVolume;
|
||||||
|
|
||||||
|
private static Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A");
|
||||||
|
private static readonly PropertyKey PKEY_Device_FriendlyName =
|
||||||
|
new PropertyKey(new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), 14);
|
||||||
|
|
||||||
|
public uint Volume
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
float pfLevel = 0;
|
||||||
|
|
||||||
|
if (endpointVolume != null)
|
||||||
|
endpointVolume.GetMasterVolumeLevelScalar(out pfLevel);
|
||||||
|
|
||||||
|
return Convert.ToUInt32(pfLevel * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint getVolume()
|
||||||
|
{
|
||||||
|
float pfLevel = 0;
|
||||||
|
|
||||||
|
if (endpointVolume != null)
|
||||||
|
endpointVolume.GetMasterVolumeLevelScalar(out pfLevel);
|
||||||
|
|
||||||
|
return Convert.ToUInt32(pfLevel * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DS4Audio(DataFlow audioFlags = DataFlow.Render)
|
||||||
|
{
|
||||||
|
var audioEnumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
|
||||||
|
IMMDeviceCollection audioDevices;
|
||||||
|
audioEnumerator.EnumAudioEndpoints(audioFlags, DeviceState.Active, out audioDevices);
|
||||||
|
|
||||||
|
int numAudioDevices;
|
||||||
|
Marshal.ThrowExceptionForHR(audioDevices.GetCount(out numAudioDevices));
|
||||||
|
|
||||||
|
for (int deviceNumber = 0; deviceNumber < numAudioDevices; ++deviceNumber)
|
||||||
|
{
|
||||||
|
IMMDevice audioDevice;
|
||||||
|
Marshal.ThrowExceptionForHR(audioDevices.Item(deviceNumber, out audioDevice));
|
||||||
|
string deviceName = GetAudioDeviceName(ref audioDevice);
|
||||||
|
|
||||||
|
if (deviceName.Contains("DUALSHOCK®4 USB Wireless Adaptor"))
|
||||||
|
{
|
||||||
|
object interfacePointer;
|
||||||
|
Marshal.ThrowExceptionForHR(audioDevice.Activate(ref IID_IAudioEndpointVolume, ClsCtx.ALL, IntPtr.Zero, out interfacePointer));
|
||||||
|
endpointVolume = interfacePointer as IAudioEndpointVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.ReleaseComObject(audioDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.ReleaseComObject(audioDevices);
|
||||||
|
Marshal.ReleaseComObject(audioEnumerator);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DS4Audio()
|
||||||
|
{
|
||||||
|
if (endpointVolume != null)
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(endpointVolume);
|
||||||
|
endpointVolume = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAudioDeviceName(ref IMMDevice audioDevice)
|
||||||
|
{
|
||||||
|
IPropertyStore propertyStore;
|
||||||
|
Marshal.ThrowExceptionForHR(audioDevice.OpenPropertyStore(StorageAccessMode.Read, out propertyStore));
|
||||||
|
|
||||||
|
int numProperties;
|
||||||
|
Marshal.ThrowExceptionForHR(propertyStore.GetCount(out numProperties));
|
||||||
|
|
||||||
|
string deviceName = String.Empty;
|
||||||
|
|
||||||
|
for (int propertyNum = 0; propertyNum < numProperties; ++propertyNum)
|
||||||
|
{
|
||||||
|
PropertyKey propertyKey;
|
||||||
|
Marshal.ThrowExceptionForHR(propertyStore.GetAt(propertyNum, out propertyKey));
|
||||||
|
|
||||||
|
if ((propertyKey.formatId == PKEY_Device_FriendlyName.formatId) && (propertyKey.propertyId == PKEY_Device_FriendlyName.propertyId))
|
||||||
|
{
|
||||||
|
PropVariant propertyValue;
|
||||||
|
Marshal.ThrowExceptionForHR(propertyStore.GetValue(ref propertyKey, out propertyValue));
|
||||||
|
deviceName = Marshal.PtrToStringUni(propertyValue.pointerValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.ReleaseComObject(propertyStore);
|
||||||
|
return deviceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DS4Windows.DS4Library.CoreAudio
|
||||||
|
{
|
||||||
|
public enum DataFlow
|
||||||
|
{
|
||||||
|
Render,
|
||||||
|
Capture,
|
||||||
|
All
|
||||||
|
};
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum DeviceState
|
||||||
|
{
|
||||||
|
Active = 0x00000001,
|
||||||
|
Disabled = 0x00000002,
|
||||||
|
NotPresent = 0x00000004,
|
||||||
|
Unplugged = 0x00000008,
|
||||||
|
All = 0x0000000F
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StorageAccessMode
|
||||||
|
{
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
ReadWrite
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ClsCtx
|
||||||
|
{
|
||||||
|
INPROC_SERVER = 0x1,
|
||||||
|
INPROC_HANDLER = 0x2,
|
||||||
|
LOCAL_SERVER = 0x4,
|
||||||
|
INPROC_SERVER16 = 0x8,
|
||||||
|
REMOTE_SERVER = 0x10,
|
||||||
|
INPROC_HANDLER16 = 0x20,
|
||||||
|
NO_CODE_DOWNLOAD = 0x400,
|
||||||
|
NO_CUSTOM_MARSHAL = 0x1000,
|
||||||
|
ENABLE_CODE_DOWNLOAD = 0x2000,
|
||||||
|
NO_FAILURE_LOG = 0x4000,
|
||||||
|
DISABLE_AAA = 0x8000,
|
||||||
|
ENABLE_AAA = 0x10000,
|
||||||
|
FROM_DEFAULT_CONTEXT = 0x20000,
|
||||||
|
ACTIVATE_32_BIT_SERVER = 0x40000,
|
||||||
|
ACTIVATE_64_BIT_SERVER = 0x80000,
|
||||||
|
ENABLE_CLOAKING = 0x100000,
|
||||||
|
PS_DLL = unchecked((int)0x80000000),
|
||||||
|
INPROC = INPROC_SERVER | INPROC_HANDLER,
|
||||||
|
SERVER = INPROC_SERVER | LOCAL_SERVER | REMOTE_SERVER,
|
||||||
|
ALL = SERVER | INPROC_HANDLER
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct PropertyKey
|
||||||
|
{
|
||||||
|
public Guid formatId;
|
||||||
|
public int propertyId;
|
||||||
|
public PropertyKey(Guid formatId, int propertyId)
|
||||||
|
{
|
||||||
|
this.formatId = formatId;
|
||||||
|
this.propertyId = propertyId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct PropVariant
|
||||||
|
{
|
||||||
|
[FieldOffset(0)] private short vt;
|
||||||
|
[FieldOffset(2)] private short wReserved1;
|
||||||
|
[FieldOffset(4)] private short wReserved2;
|
||||||
|
[FieldOffset(6)] private short wReserved3;
|
||||||
|
[FieldOffset(8)] public IntPtr pointerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
interface IPropertyStore
|
||||||
|
{
|
||||||
|
int GetCount(out int propCount);
|
||||||
|
int GetAt(int property, out PropertyKey key);
|
||||||
|
int GetValue(ref PropertyKey key, out PropVariant value);
|
||||||
|
int SetValue(ref PropertyKey key, ref PropVariant value);
|
||||||
|
int Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("D666063F-1587-4E43-81F1-B948E807363F"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
interface IMMDevice
|
||||||
|
{
|
||||||
|
int Activate(ref Guid id, ClsCtx clsCtx, IntPtr activationParams,
|
||||||
|
[MarshalAs(UnmanagedType.IUnknown)] out object interfacePointer);
|
||||||
|
|
||||||
|
int OpenPropertyStore(StorageAccessMode stgmAccess, out IPropertyStore properties);
|
||||||
|
|
||||||
|
int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
interface IMMDeviceCollection
|
||||||
|
{
|
||||||
|
int GetCount(out int numDevices);
|
||||||
|
int Item(int deviceNumber, out IMMDevice device);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
interface IMMDeviceEnumerator
|
||||||
|
{
|
||||||
|
int EnumAudioEndpoints(DataFlow dataFlow, DeviceState stateMask, out IMMDeviceCollection devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
|
||||||
|
class MMDeviceEnumeratorComObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("657804FA-D6AD-4496-8A60-352752AF4F89"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
internal interface IAudioEndpointVolumeCallback
|
||||||
|
{
|
||||||
|
void OnNotify(IntPtr notifyData);
|
||||||
|
};
|
||||||
|
|
||||||
|
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"),
|
||||||
|
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
internal interface IAudioEndpointVolume
|
||||||
|
{
|
||||||
|
int RegisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);
|
||||||
|
int UnregisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify);
|
||||||
|
int GetChannelCount(out int pnChannelCount);
|
||||||
|
int SetMasterVolumeLevel(float fLevelDB, ref Guid pguidEventContext);
|
||||||
|
int SetMasterVolumeLevelScalar(float fLevel, ref Guid pguidEventContext);
|
||||||
|
int GetMasterVolumeLevel(out float pfLevelDB);
|
||||||
|
int GetMasterVolumeLevelScalar(out float pfLevel);
|
||||||
|
int SetChannelVolumeLevel(uint nChannel, float fLevelDB, ref Guid pguidEventContext);
|
||||||
|
int SetChannelVolumeLevelScalar(uint nChannel, float fLevel, ref Guid pguidEventContext);
|
||||||
|
int GetChannelVolumeLevel(uint nChannel, out float pfLevelDB);
|
||||||
|
int GetChannelVolumeLevelScalar(uint nChannel, out float pfLevel);
|
||||||
|
int SetMute([MarshalAs(UnmanagedType.Bool)] Boolean bMute, ref Guid pguidEventContext);
|
||||||
|
int GetMute(out bool pbMute);
|
||||||
|
int GetVolumeStepInfo(out uint pnStep, out uint pnStepCount);
|
||||||
|
int VolumeStepUp(ref Guid pguidEventContext);
|
||||||
|
int VolumeStepDown(ref Guid pguidEventContext);
|
||||||
|
int QueryHardwareSupport(out uint pdwHardwareSupportMask);
|
||||||
|
int GetVolumeRange(out float pflVolumeMindB, out float pflVolumeMaxdB, out float pflVolumeIncrementdB);
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ using System.Text;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using DS4Windows.DS4Library;
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
@ -28,12 +29,14 @@ namespace DS4Windows
|
|||||||
green = c.G;
|
green = c.G;
|
||||||
blue = c.B;
|
blue = c.B;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DS4Color(byte r, byte g, byte b)
|
public DS4Color(byte r, byte g, byte b)
|
||||||
{
|
{
|
||||||
red = r;
|
red = r;
|
||||||
green = g;
|
green = g;
|
||||||
blue = b;
|
blue = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj is DS4Color)
|
if (obj is DS4Color)
|
||||||
@ -44,6 +47,7 @@ namespace DS4Windows
|
|||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color ToColor => Color.FromArgb(red, green, blue);
|
public Color ToColor => Color.FromArgb(red, green, blue);
|
||||||
public Color ToColorA
|
public Color ToColorA
|
||||||
{
|
{
|
||||||
@ -83,10 +87,11 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
catch { return false; }
|
catch { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => $"Red: {red} Green: {green} Blue: {blue}";
|
public override string ToString() => $"Red: {red} Green: {green} Blue: {blue}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ConnectionType : byte { BT, USB }; // Prioritize Bluetooth when both are connected.
|
public enum ConnectionType : byte { BT, SONYWA, USB }; // Prioritize Bluetooth when both BT and USB are connected.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The haptics engine uses a stack of these states representing the light bar and rumble motor settings.
|
* The haptics engine uses a stack of these states representing the light bar and rumble motor settings.
|
||||||
@ -99,10 +104,12 @@ namespace DS4Windows
|
|||||||
public byte LightBarFlashDurationOn, LightBarFlashDurationOff;
|
public byte LightBarFlashDurationOn, LightBarFlashDurationOff;
|
||||||
public byte RumbleMotorStrengthLeftHeavySlow, RumbleMotorStrengthRightLightFast;
|
public byte RumbleMotorStrengthLeftHeavySlow, RumbleMotorStrengthRightLightFast;
|
||||||
public bool RumbleMotorsExplicitlyOff;
|
public bool RumbleMotorsExplicitlyOff;
|
||||||
|
|
||||||
public bool IsLightBarSet()
|
public bool IsLightBarSet()
|
||||||
{
|
{
|
||||||
return LightBarExplicitlyOff || LightBarColor.red != 0 || LightBarColor.green != 0 || LightBarColor.blue != 0;
|
return LightBarExplicitlyOff || LightBarColor.red != 0 || LightBarColor.green != 0 || LightBarColor.blue != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsRumbleSet()
|
public bool IsRumbleSet()
|
||||||
{
|
{
|
||||||
return RumbleMotorsExplicitlyOff || RumbleMotorStrengthLeftHeavySlow != 0 || RumbleMotorStrengthRightLightFast != 0;
|
return RumbleMotorsExplicitlyOff || RumbleMotorStrengthLeftHeavySlow != 0 || RumbleMotorStrengthRightLightFast != 0;
|
||||||
@ -113,6 +120,16 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
private const int BT_OUTPUT_REPORT_LENGTH = 78;
|
private const int BT_OUTPUT_REPORT_LENGTH = 78;
|
||||||
private const int BT_INPUT_REPORT_LENGTH = 547;
|
private const int BT_INPUT_REPORT_LENGTH = 547;
|
||||||
|
// Use large value for worst case scenario
|
||||||
|
private const int READ_STREAM_TIMEOUT = 100;
|
||||||
|
// Isolated BT report can have latency as high as 15 ms
|
||||||
|
// due to hardware.
|
||||||
|
private const int WARN_INTERVAL_BT = 20;
|
||||||
|
private const int WARN_INTERVAL_USB = 10;
|
||||||
|
// Maximum values for battery level when no USB cable is connected
|
||||||
|
// and when a USB cable is connected
|
||||||
|
private const int BATTERY_MAX = 8;
|
||||||
|
private const int BATTERY_MAX_USB = 11;
|
||||||
private HidDevice hDevice;
|
private HidDevice hDevice;
|
||||||
private string Mac;
|
private string Mac;
|
||||||
private DS4State cState = new DS4State();
|
private DS4State cState = new DS4State();
|
||||||
@ -121,6 +138,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;
|
||||||
@ -131,30 +149,128 @@ namespace DS4Windows
|
|||||||
private byte ledFlashOn, ledFlashOff;
|
private byte ledFlashOn, ledFlashOff;
|
||||||
private Thread ds4Input, ds4Output;
|
private Thread ds4Input, ds4Output;
|
||||||
private int battery;
|
private int battery;
|
||||||
|
private DS4Audio audio = null;
|
||||||
|
private DS4Audio micAudio = null;
|
||||||
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;
|
||||||
|
private bool outputRumble = false;
|
||||||
|
private int warnInterval = WARN_INTERVAL_USB;
|
||||||
|
public int getWarnInterval()
|
||||||
|
{
|
||||||
|
return warnInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool exitOutputThread = false;
|
||||||
|
private bool exitInputThread = false;
|
||||||
|
private object exitLocker = new object();
|
||||||
public event EventHandler<EventArgs> Report = null;
|
public event EventHandler<EventArgs> Report = null;
|
||||||
public event EventHandler<EventArgs> Removal = null;
|
public event EventHandler<EventArgs> Removal = null;
|
||||||
|
|
||||||
public HidDevice HidDevice => hDevice;
|
public HidDevice HidDevice => hDevice;
|
||||||
public bool IsExclusive => HidDevice.IsExclusive;
|
public bool IsExclusive => HidDevice.IsExclusive;
|
||||||
public bool IsDisconnecting { get; private set; }
|
public bool isExclusive()
|
||||||
|
{
|
||||||
|
return HidDevice.IsExclusive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDisconnecting = false;
|
||||||
|
public bool IsDisconnecting
|
||||||
|
{
|
||||||
|
get { return isDisconnecting; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
this.isDisconnecting = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool isDisconnectingStatus()
|
||||||
|
{
|
||||||
|
return this.isDisconnecting;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isRemoving = false;
|
||||||
|
public bool IsRemoving
|
||||||
|
{
|
||||||
|
get { return isRemoving; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.isRemoving = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isRemoved = false;
|
||||||
|
public bool IsRemoved
|
||||||
|
{
|
||||||
|
get { return isRemoved; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.isRemoved = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object removeLocker = new object();
|
||||||
|
|
||||||
public string MacAddress => Mac;
|
public string MacAddress => Mac;
|
||||||
|
public string getMacAddress()
|
||||||
|
{
|
||||||
|
return this.Mac;
|
||||||
|
}
|
||||||
|
|
||||||
public ConnectionType ConnectionType => conType;
|
public ConnectionType ConnectionType => conType;
|
||||||
public int IdleTimeout { get; set; } // behavior only active when > 0
|
public ConnectionType getConnectionType()
|
||||||
|
{
|
||||||
|
return this.conType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// behavior only active when > 0
|
||||||
|
private int idleTimeout = 0;
|
||||||
|
public int IdleTimeout
|
||||||
|
{
|
||||||
|
get { return idleTimeout; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
idleTimeout = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIdleTimeout()
|
||||||
|
{
|
||||||
|
return idleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdleTimeout(int value)
|
||||||
|
{
|
||||||
|
if (idleTimeout != value)
|
||||||
|
{
|
||||||
|
idleTimeout = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int Battery => battery;
|
public int Battery => battery;
|
||||||
|
public int getBattery()
|
||||||
|
{
|
||||||
|
return battery;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Charging => charging;
|
public bool Charging => charging;
|
||||||
|
public bool isCharging()
|
||||||
|
{
|
||||||
|
return charging;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long lastTimeElapsed = 0;
|
||||||
|
public long getLastTimeElapsed()
|
||||||
|
{
|
||||||
|
return lastTimeElapsed;
|
||||||
|
}
|
||||||
|
|
||||||
public byte RightLightFastRumble
|
public byte RightLightFastRumble
|
||||||
{
|
{
|
||||||
get { return rightLightFastRumble; }
|
get { return rightLightFastRumble; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == rightLightFastRumble) return;
|
if (rightLightFastRumble != value)
|
||||||
rightLightFastRumble = value;
|
rightLightFastRumble = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,11 +280,16 @@ namespace DS4Windows
|
|||||||
get { return leftHeavySlowRumble; }
|
get { return leftHeavySlowRumble; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == leftHeavySlowRumble) return;
|
if (leftHeavySlowRumble != value)
|
||||||
leftHeavySlowRumble = value;
|
leftHeavySlowRumble = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getLeftHeavySlowRumble()
|
||||||
|
{
|
||||||
|
return leftHeavySlowRumble;
|
||||||
|
}
|
||||||
|
|
||||||
public DS4Color LightBarColor
|
public DS4Color LightBarColor
|
||||||
{
|
{
|
||||||
get { return ligtBarColor; }
|
get { return ligtBarColor; }
|
||||||
@ -193,6 +314,11 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getLightBarOnDuration()
|
||||||
|
{
|
||||||
|
return ledFlashOn;
|
||||||
|
}
|
||||||
|
|
||||||
public byte LightBarOffDuration
|
public byte LightBarOffDuration
|
||||||
{
|
{
|
||||||
get { return ledFlashOff; }
|
get { return ledFlashOff; }
|
||||||
@ -205,24 +331,55 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getLightBarOffDuration()
|
||||||
|
{
|
||||||
|
return ledFlashOff;
|
||||||
|
}
|
||||||
|
|
||||||
public DS4Touchpad Touchpad { get { return touchpad; } }
|
public DS4Touchpad Touchpad { get { return touchpad; } }
|
||||||
public DS4SixAxis SixAxis { get { return sixAxis; } }
|
public DS4SixAxis SixAxis { get { return sixAxis; } }
|
||||||
|
|
||||||
public static ConnectionType HidConnectionType(HidDevice hidDevice)
|
public static ConnectionType HidConnectionType(HidDevice hidDevice)
|
||||||
{
|
{
|
||||||
return hidDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT;
|
ConnectionType result = ConnectionType.USB;
|
||||||
|
if (hidDevice.Capabilities.InputReportByteLength == 64)
|
||||||
|
{
|
||||||
|
if (hidDevice.Capabilities.NumberFeatureDataIndices == 22)
|
||||||
|
{
|
||||||
|
result = ConnectionType.SONYWA;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = ConnectionType.BT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SynchronizationContext uiContext = null;
|
||||||
|
|
||||||
public DS4Device(HidDevice hidDevice)
|
public DS4Device(HidDevice hidDevice)
|
||||||
{
|
{
|
||||||
hDevice = hidDevice;
|
hDevice = hidDevice;
|
||||||
conType = HidConnectionType(hDevice);
|
conType = HidConnectionType(hDevice);
|
||||||
Mac = hDevice.readSerial();
|
Mac = hDevice.readSerial();
|
||||||
if (conType == ConnectionType.USB)
|
if (conType == ConnectionType.USB || conType == ConnectionType.SONYWA)
|
||||||
{
|
{
|
||||||
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];
|
||||||
|
if (conType == ConnectionType.USB)
|
||||||
|
{
|
||||||
|
warnInterval = WARN_INTERVAL_USB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warnInterval = WARN_INTERVAL_BT;
|
||||||
|
audio = new DS4Audio();
|
||||||
|
micAudio = new DS4Audio(DS4Library.CoreAudio.DataFlow.Render);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -230,22 +387,41 @@ namespace DS4Windows
|
|||||||
inputReport = new byte[btInputReport.Length - 2];
|
inputReport = new byte[btInputReport.Length - 2];
|
||||||
outputReport = new byte[BT_OUTPUT_REPORT_LENGTH];
|
outputReport = new byte[BT_OUTPUT_REPORT_LENGTH];
|
||||||
outputReportBuffer = new byte[BT_OUTPUT_REPORT_LENGTH];
|
outputReportBuffer = new byte[BT_OUTPUT_REPORT_LENGTH];
|
||||||
|
warnInterval = WARN_INTERVAL_BT;
|
||||||
}
|
}
|
||||||
|
|
||||||
touchpad = new DS4Touchpad();
|
touchpad = new DS4Touchpad();
|
||||||
sixAxis = new DS4SixAxis();
|
sixAxis = new DS4SixAxis();
|
||||||
|
uiContext = SynchronizationContext.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartUpdate()
|
public void StartUpdate()
|
||||||
{
|
{
|
||||||
if (ds4Input == null)
|
if (ds4Input == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> start");
|
if (!hDevice.IsFileStreamOpen())
|
||||||
|
{
|
||||||
|
hDevice.OpenFileStream(inputReport.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> start");
|
||||||
sendOutputReport(true); // initialize the output report
|
sendOutputReport(true); // initialize the output report
|
||||||
|
|
||||||
|
if (conType == ConnectionType.BT)
|
||||||
|
{
|
||||||
|
// Only use the output thread for Bluetooth connections.
|
||||||
|
// USB will utilize overlapped IO instead.
|
||||||
ds4Output = new Thread(performDs4Output);
|
ds4Output = new Thread(performDs4Output);
|
||||||
|
ds4Output.Priority = ThreadPriority.AboveNormal;
|
||||||
ds4Output.Name = "DS4 Output thread: " + Mac;
|
ds4Output.Name = "DS4 Output thread: " + Mac;
|
||||||
|
ds4Output.IsBackground = true;
|
||||||
ds4Output.Start();
|
ds4Output.Start();
|
||||||
|
}
|
||||||
|
|
||||||
ds4Input = new Thread(performDs4Input);
|
ds4Input = new Thread(performDs4Input);
|
||||||
|
ds4Input.Priority = ThreadPriority.AboveNormal;
|
||||||
ds4Input.Name = "DS4 Input thread: " + Mac;
|
ds4Input.Name = "DS4 Input thread: " + Mac;
|
||||||
|
ds4Input.IsBackground = true;
|
||||||
ds4Input.Start();
|
ds4Input.Start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -254,11 +430,14 @@ namespace DS4Windows
|
|||||||
|
|
||||||
public void StopUpdate()
|
public void StopUpdate()
|
||||||
{
|
{
|
||||||
if (ds4Input.ThreadState != System.Threading.ThreadState.Stopped || ds4Input.ThreadState != System.Threading.ThreadState.Aborted)
|
if (ds4Input != null &&
|
||||||
|
ds4Input.IsAlive && !ds4Input.ThreadState.HasFlag(System.Threading.ThreadState.Stopped) &&
|
||||||
|
!ds4Input.ThreadState.HasFlag(System.Threading.ThreadState.AbortRequested))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ds4Input.Abort();
|
exitInputThread = true;
|
||||||
|
//ds4Input.Abort();
|
||||||
ds4Input.Join();
|
ds4Input.Join();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -266,16 +445,28 @@ namespace DS4Windows
|
|||||||
Console.WriteLine(e.Message);
|
Console.WriteLine(e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StopOutputUpdate();
|
StopOutputUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopOutputUpdate()
|
private void StopOutputUpdate()
|
||||||
{
|
{
|
||||||
if (ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
|
lock (exitLocker)
|
||||||
|
{
|
||||||
|
if (ds4Output != null &&
|
||||||
|
ds4Output.IsAlive && !ds4Output.ThreadState.HasFlag(System.Threading.ThreadState.Stopped) &&
|
||||||
|
!ds4Output.ThreadState.HasFlag(System.Threading.ThreadState.AbortRequested))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ds4Output.Abort();
|
exitOutputThread = true;
|
||||||
|
/*lock (outputReport)
|
||||||
|
{
|
||||||
|
Monitor.PulseAll(outputReport);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ds4Output.Interrupt();
|
||||||
ds4Output.Join();
|
ds4Output.Join();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -284,6 +475,7 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool writeOutput()
|
private bool writeOutput()
|
||||||
{
|
{
|
||||||
@ -293,26 +485,25 @@ namespace DS4Windows
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return hDevice.WriteOutputReportViaInterrupt(outputReport, 8);
|
return hDevice.WriteAsyncOutputReportViaInterrupt(outputReport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performDs4Output()
|
private void performDs4Output()
|
||||||
{
|
{
|
||||||
lock (outputReport)
|
lock (outputReport)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
int lastError = 0;
|
int lastError = 0;
|
||||||
while (true)
|
while (!exitOutputThread)
|
||||||
{
|
{
|
||||||
if (writeOutput())
|
bool result = false;
|
||||||
|
if (outputRumble)
|
||||||
{
|
{
|
||||||
lastError = 0;
|
result = writeOutput();
|
||||||
if (testRumble.IsRumbleSet()) // repeat test rumbles periodically; rumble has auto-shut-off in the DS4 firmware
|
|
||||||
Monitor.Wait(outputReport, 10000); // DS4 firmware stops it after 5 seconds, so let the motors rest for that long, too.
|
if (!result)
|
||||||
else
|
|
||||||
Monitor.Wait(outputReport);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int thisError = Marshal.GetLastWin32Error();
|
int thisError = Marshal.GetLastWin32Error();
|
||||||
if (lastError != thisError)
|
if (lastError != thisError)
|
||||||
@ -321,6 +512,27 @@ namespace DS4Windows
|
|||||||
lastError = thisError;
|
lastError = thisError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outputRumble = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outputRumble)
|
||||||
|
{
|
||||||
|
lastError = 0;
|
||||||
|
Monitor.Wait(outputReport);
|
||||||
|
/*if (testRumble.IsRumbleSet()) // repeat test rumbles periodically; rumble has auto-shut-off in the DS4 firmware
|
||||||
|
Monitor.Wait(outputReport, 10000); // DS4 firmware stops it after 5 seconds, so let the motors rest for that long, too.
|
||||||
|
else
|
||||||
|
Monitor.Wait(outputReport);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ThreadInterruptedException)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,49 +542,37 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
return priorInputReport30 != 0xff;
|
return priorInputReport30 != 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte priorInputReport30 = 0xff;
|
private byte priorInputReport30 = 0xff;
|
||||||
public double Latency = 0;
|
public double Latency = 0;
|
||||||
bool warn;
|
|
||||||
public string error;
|
public string error;
|
||||||
|
public bool firstReport = false;
|
||||||
|
|
||||||
private void performDs4Input()
|
private void performDs4Input()
|
||||||
{
|
{
|
||||||
firstActive = DateTime.UtcNow;
|
firstActive = DateTime.UtcNow;
|
||||||
System.Timers.Timer readTimeout = new System.Timers.Timer(); // Await 30 seconds for the initial packet, then 3 seconds thereafter.
|
NativeMethods.HidD_SetNumInputBuffers(hDevice.safeReadHandle.DangerousGetHandle(), 2);
|
||||||
readTimeout.Elapsed += delegate { HidDevice.CancelIO(); };
|
List<long> Latency = new List<long>(100);
|
||||||
List<long> Latency = new List<long>();
|
|
||||||
long oldtime = 0;
|
long oldtime = 0;
|
||||||
Stopwatch sw = new Stopwatch();
|
Stopwatch sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
while (true)
|
while (!exitInputThread)
|
||||||
{
|
{
|
||||||
string currerror = string.Empty;
|
string currerror = string.Empty;
|
||||||
Latency.Add(sw.ElapsedMilliseconds - oldtime);
|
long curtime = sw.ElapsedMilliseconds;
|
||||||
oldtime = sw.ElapsedMilliseconds;
|
this.lastTimeElapsed = curtime - oldtime;
|
||||||
|
Latency.Add(this.lastTimeElapsed);
|
||||||
|
oldtime = curtime;
|
||||||
|
|
||||||
if (Latency.Count > 100)
|
if (Latency.Count > 100)
|
||||||
Latency.RemoveAt(0);
|
Latency.RemoveAt(0);
|
||||||
|
|
||||||
this.Latency = Latency.Average();
|
this.Latency = Latency.Average();
|
||||||
|
|
||||||
if (this.Latency > 10 && !warn && sw.ElapsedMilliseconds > 4000)
|
if (conType == ConnectionType.BT)
|
||||||
{
|
{
|
||||||
warn = true;
|
//HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
||||||
//System.Diagnostics.Trace.WriteLine(System.DateTime.UtcNow.ToString("o") + "> " + "Controller " + /*this.DeviceNum*/ + 1 + " (" + this.MacAddress + ") is experiencing latency issues. Currently at " + Math.Round(this.Latency, 2).ToString() + "ms of recomended maximum 10ms");
|
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(btInputReport, READ_STREAM_TIMEOUT);
|
||||||
}
|
|
||||||
else if (this.Latency <= 10 && warn) warn = false;
|
|
||||||
|
|
||||||
if (readTimeout.Interval != 3000.0)
|
|
||||||
{
|
|
||||||
if (readTimeout.Interval != 30000.0)
|
|
||||||
readTimeout.Interval = 30000.0;
|
|
||||||
else
|
|
||||||
readTimeout.Interval = 3000.0;
|
|
||||||
}
|
|
||||||
readTimeout.Enabled = true;
|
|
||||||
if (conType != ConnectionType.USB)
|
|
||||||
{
|
|
||||||
HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
|
||||||
readTimeout.Enabled = false;
|
|
||||||
if (res == HidDevice.ReadStatus.Success)
|
if (res == HidDevice.ReadStatus.Success)
|
||||||
{
|
{
|
||||||
Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
|
Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
|
||||||
@ -382,32 +582,51 @@ namespace DS4Windows
|
|||||||
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
|
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
|
||||||
sendOutputReport(true); // Kick Windows into noticing the disconnection.
|
sendOutputReport(true); // Kick Windows into noticing the disconnection.
|
||||||
StopOutputUpdate();
|
StopOutputUpdate();
|
||||||
IsDisconnecting = true;
|
isDisconnecting = true;
|
||||||
|
uiContext.Send(new SendOrPostCallback(delegate (object state4)
|
||||||
|
{
|
||||||
|
Removal?.Invoke(this, EventArgs.Empty);
|
||||||
|
}), null);
|
||||||
|
|
||||||
|
/*
|
||||||
if (Removal != null)
|
if (Removal != null)
|
||||||
Removal(this, EventArgs.Empty);
|
Removal(this, EventArgs.Empty);
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
//HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
||||||
readTimeout.Enabled = false;
|
//Array.Clear(inputReport, 0, inputReport.Length);
|
||||||
|
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(inputReport, READ_STREAM_TIMEOUT);
|
||||||
if (res != HidDevice.ReadStatus.Success)
|
if (res != HidDevice.ReadStatus.Success)
|
||||||
{
|
{
|
||||||
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
|
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
|
||||||
StopOutputUpdate();
|
StopOutputUpdate();
|
||||||
IsDisconnecting = true;
|
isDisconnecting = true;
|
||||||
if (Removal != null)
|
uiContext.Send(new SendOrPostCallback(delegate (object state4)
|
||||||
Removal(this, EventArgs.Empty);
|
{
|
||||||
|
Removal?.Invoke(this, EventArgs.Empty);
|
||||||
|
}), null);
|
||||||
|
|
||||||
|
//if (Removal != null)
|
||||||
|
// Removal(this, EventArgs.Empty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Array.Copy(inputReport2, 0, inputReport, 0, inputReport.Length);
|
||||||
}
|
}
|
||||||
if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
|
}
|
||||||
|
|
||||||
|
if (conType == ConnectionType.BT && btInputReport[0] != 0x11)
|
||||||
{
|
{
|
||||||
//Received incorrect report, skip it
|
//Received incorrect report, skip it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
|
DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
|
||||||
resetHapticState();
|
resetHapticState();
|
||||||
cState.ReportTimeStamp = utcNow;
|
cState.ReportTimeStamp = utcNow;
|
||||||
@ -418,23 +637,14 @@ namespace DS4Windows
|
|||||||
cState.L2 = inputReport[8];
|
cState.L2 = inputReport[8];
|
||||||
cState.R2 = inputReport[9];
|
cState.R2 = inputReport[9];
|
||||||
|
|
||||||
cState.Triangle = ((byte)inputReport[5] & (1 << 7)) != 0;
|
cState.Triangle = (inputReport[5] & (1 << 7)) != 0;
|
||||||
cState.Circle = ((byte)inputReport[5] & (1 << 6)) != 0;
|
cState.Circle = (inputReport[5] & (1 << 6)) != 0;
|
||||||
cState.Cross = ((byte)inputReport[5] & (1 << 5)) != 0;
|
cState.Cross = (inputReport[5] & (1 << 5)) != 0;
|
||||||
cState.Square = ((byte)inputReport[5] & (1 << 4)) != 0;
|
cState.Square = (inputReport[5] & (1 << 4)) != 0;
|
||||||
cState.DpadUp = ((byte)inputReport[5] & (1 << 3)) != 0;
|
|
||||||
cState.DpadDown = ((byte)inputReport[5] & (1 << 2)) != 0;
|
|
||||||
cState.DpadLeft = ((byte)inputReport[5] & (1 << 1)) != 0;
|
|
||||||
cState.DpadRight = ((byte)inputReport[5] & (1 << 0)) != 0;
|
|
||||||
|
|
||||||
//Convert dpad into individual On/Off bits instead of a clock representation
|
// First 4 bits denote dpad state. Clock representation
|
||||||
byte dpad_state = 0;
|
// with 8 meaning centered and 0 meaning DpadUp.
|
||||||
|
byte dpad_state = (byte)(inputReport[5] & 0x0F);
|
||||||
dpad_state = (byte)(
|
|
||||||
((cState.DpadRight ? 1 : 0) << 0) |
|
|
||||||
((cState.DpadLeft ? 1 : 0) << 1) |
|
|
||||||
((cState.DpadDown ? 1 : 0) << 2) |
|
|
||||||
((cState.DpadUp ? 1 : 0) << 3));
|
|
||||||
|
|
||||||
switch (dpad_state)
|
switch (dpad_state)
|
||||||
{
|
{
|
||||||
@ -446,17 +656,18 @@ namespace DS4Windows
|
|||||||
case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;
|
case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;
|
||||||
case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;
|
case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;
|
||||||
case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;
|
case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;
|
||||||
case 8: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
|
case 8:
|
||||||
|
default: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cState.R3 = ((byte)inputReport[6] & (1 << 7)) != 0;
|
cState.R3 = (inputReport[6] & (1 << 7)) != 0;
|
||||||
cState.L3 = ((byte)inputReport[6] & (1 << 6)) != 0;
|
cState.L3 = (inputReport[6] & (1 << 6)) != 0;
|
||||||
cState.Options = ((byte)inputReport[6] & (1 << 5)) != 0;
|
cState.Options = (inputReport[6] & (1 << 5)) != 0;
|
||||||
cState.Share = ((byte)inputReport[6] & (1 << 4)) != 0;
|
cState.Share = (inputReport[6] & (1 << 4)) != 0;
|
||||||
cState.R1 = ((byte)inputReport[6] & (1 << 1)) != 0;
|
cState.R1 = (inputReport[6] & (1 << 1)) != 0;
|
||||||
cState.L1 = ((byte)inputReport[6] & (1 << 0)) != 0;
|
cState.L1 = (inputReport[6] & (1 << 0)) != 0;
|
||||||
|
|
||||||
cState.PS = ((byte)inputReport[7] & (1 << 0)) != 0;
|
cState.PS = (inputReport[7] & (1 << 0)) != 0;
|
||||||
cState.TouchButton = (inputReport[7] & (1 << 2 - 1)) != 0;
|
cState.TouchButton = (inputReport[7] & (1 << 2 - 1)) != 0;
|
||||||
cState.FrameCounter = (byte)(inputReport[7] >> 2);
|
cState.FrameCounter = (byte)(inputReport[7] >> 2);
|
||||||
|
|
||||||
@ -468,19 +679,25 @@ namespace DS4Windows
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
charging = (inputReport[30] & 0x10) != 0;
|
charging = (inputReport[30] & 0x10) != 0;
|
||||||
battery = (inputReport[30] & 0x0f) * 10;
|
int maxBatteryValue = charging ? BATTERY_MAX_USB : BATTERY_MAX;
|
||||||
|
int tempBattery = (inputReport[30] & 0x0f) * 100 / maxBatteryValue;
|
||||||
|
battery = Math.Min((byte)tempBattery, (byte)100);
|
||||||
cState.Battery = (byte)battery;
|
cState.Battery = (byte)battery;
|
||||||
if (inputReport[30] != priorInputReport30)
|
if (inputReport[30] != priorInputReport30)
|
||||||
{
|
{
|
||||||
priorInputReport30 = inputReport[30];
|
priorInputReport30 = inputReport[30];
|
||||||
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
|
//Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { currerror = "Index out of bounds: battery"; }
|
catch { currerror = "Index out of bounds: battery"; }
|
||||||
|
|
||||||
// XXX DS4State mapping needs fixup, turn touches into an array[4] of structs. And include the touchpad details there instead.
|
// XXX DS4State mapping needs fixup, turn touches into an array[4] of structs. And include the touchpad details there instead.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
|
// Only care if one touch packet is detected. Other touch packets
|
||||||
|
// don't seem to contain relevant data. ds4drv does not use them either.
|
||||||
|
for (int touches = Math.Max((int)(inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1]), 1), touchOffset = 0; touches > 0; touches--, touchOffset += 9)
|
||||||
|
//for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
|
||||||
{
|
{
|
||||||
cState.TouchPacketCounter = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset];
|
cState.TouchPacketCounter = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset];
|
||||||
cState.Touch1 = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected
|
cState.Touch1 = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected
|
||||||
@ -503,31 +720,70 @@ namespace DS4Windows
|
|||||||
Console.Write(" " + inputReport[i].ToString("x2"));
|
Console.Write(" " + inputReport[i].ToString("x2"));
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
} */
|
} */
|
||||||
if (!isDS4Idle())
|
|
||||||
|
bool ds4Idle = cState.FrameCounter == pState.FrameCounter;
|
||||||
|
if (!ds4Idle)
|
||||||
|
{
|
||||||
|
isRemoved = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conType == ConnectionType.USB)
|
||||||
|
{
|
||||||
lastActive = utcNow;
|
lastActive = utcNow;
|
||||||
if (conType == ConnectionType.BT)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bool shouldDisconnect = false;
|
bool shouldDisconnect = false;
|
||||||
if (IdleTimeout > 0)
|
int idleTime = idleTimeout;
|
||||||
|
if (!isRemoved && idleTime > 0)
|
||||||
{
|
{
|
||||||
if (isDS4Idle())
|
bool idleInput = isDS4Idle();
|
||||||
|
if (idleInput)
|
||||||
{
|
{
|
||||||
DateTime timeout = lastActive + TimeSpan.FromSeconds(IdleTimeout);
|
DateTime timeout = lastActive + TimeSpan.FromSeconds(idleTime);
|
||||||
if (!Charging)
|
if (!charging)
|
||||||
shouldDisconnect = utcNow >= timeout;
|
shouldDisconnect = utcNow >= timeout;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastActive = utcNow;
|
||||||
}
|
}
|
||||||
if (shouldDisconnect && DisconnectBT())
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastActive = utcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldDisconnect)
|
||||||
|
{
|
||||||
|
if (conType == ConnectionType.BT)
|
||||||
|
{
|
||||||
|
if (DisconnectBT(true))
|
||||||
return; // all done
|
return; // all done
|
||||||
}
|
}
|
||||||
// XXX fix initialization ordering so the null checks all go away
|
else if (conType == ConnectionType.SONYWA)
|
||||||
|
{
|
||||||
|
DisconnectDongle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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))
|
||||||
error = currerror;
|
error = currerror;
|
||||||
|
|
||||||
cState.CopyTo(pState);
|
cState.CopyTo(pState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,10 +792,12 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
hDevice.flush_Queue();
|
hDevice.flush_Queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendOutputReport(bool synchronous)
|
private void sendOutputReport(bool synchronous)
|
||||||
{
|
{
|
||||||
setTestRumble();
|
setTestRumble();
|
||||||
setHapticState();
|
setHapticState();
|
||||||
|
|
||||||
if (conType == ConnectionType.BT)
|
if (conType == ConnectionType.BT)
|
||||||
{
|
{
|
||||||
outputReportBuffer[0] = 0x11;
|
outputReportBuffer[0] = 0x11;
|
||||||
@ -564,19 +822,29 @@ namespace DS4Windows
|
|||||||
outputReportBuffer[8] = LightBarColor.blue; //blue
|
outputReportBuffer[8] = LightBarColor.blue; //blue
|
||||||
outputReportBuffer[9] = ledFlashOn; //flash on duration
|
outputReportBuffer[9] = ledFlashOn; //flash on duration
|
||||||
outputReportBuffer[10] = ledFlashOff; //flash off duration
|
outputReportBuffer[10] = ledFlashOff; //flash off duration
|
||||||
|
if (conType == ConnectionType.SONYWA)
|
||||||
|
{
|
||||||
|
// Headphone volume levels
|
||||||
|
outputReportBuffer[19] = outputReportBuffer[20] = Convert.ToByte(audio.getVolume());
|
||||||
|
// Microphone volume level
|
||||||
|
outputReportBuffer[21] = Convert.ToByte(micAudio.getVolume());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool quitOutputThread = false;
|
||||||
|
|
||||||
lock (outputReport)
|
lock (outputReport)
|
||||||
{
|
{
|
||||||
if (synchronous)
|
if (synchronous)
|
||||||
{
|
{
|
||||||
|
outputRumble = false;
|
||||||
outputReportBuffer.CopyTo(outputReport, 0);
|
outputReportBuffer.CopyTo(outputReport, 0);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!writeOutput())
|
if (!writeOutput())
|
||||||
{
|
{
|
||||||
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> encountered synchronous write failure: " + Marshal.GetLastWin32Error());
|
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> encountered synchronous write failure: " + Marshal.GetLastWin32Error());
|
||||||
ds4Output.Abort();
|
quitOutputThread = true;
|
||||||
ds4Output.Join();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -587,18 +855,25 @@ namespace DS4Windows
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool output = false;
|
bool output = false;
|
||||||
for (int i = 0; !output && i < outputReport.Length; i++)
|
for (int i = 0, arlen = outputReport.Length; !output && i < arlen; i++)
|
||||||
output = outputReport[i] != outputReportBuffer[i];
|
output = outputReport[i] != outputReportBuffer[i];
|
||||||
|
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
|
outputRumble = true;
|
||||||
outputReportBuffer.CopyTo(outputReport, 0);
|
outputReportBuffer.CopyTo(outputReport, 0);
|
||||||
Monitor.Pulse(outputReport);
|
Monitor.Pulse(outputReport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quitOutputThread)
|
||||||
|
{
|
||||||
|
StopOutputUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisconnectBT()
|
public bool DisconnectBT(bool callRemoval = false)
|
||||||
{
|
{
|
||||||
if (Mac != null)
|
if (Mac != null)
|
||||||
{
|
{
|
||||||
@ -613,38 +888,94 @@ namespace DS4Windows
|
|||||||
// parse hex byte in reverse order
|
// parse hex byte in reverse order
|
||||||
btAddr[5 - i] = Convert.ToByte(sbytes[i], 16);
|
btAddr[5 - i] = Convert.ToByte(sbytes[i], 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
long lbtAddr = BitConverter.ToInt64(btAddr, 0);
|
long lbtAddr = BitConverter.ToInt64(btAddr, 0);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
// Wait for output report to be written
|
||||||
|
lock (outputReport)
|
||||||
|
{
|
||||||
NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS p = new NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS();
|
NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS p = new NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS();
|
||||||
p.dwSize = Marshal.SizeOf(typeof(NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS));
|
p.dwSize = Marshal.SizeOf(typeof(NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS));
|
||||||
IntPtr searchHandle = NativeMethods.BluetoothFindFirstRadio(ref p, ref btHandle);
|
IntPtr searchHandle = NativeMethods.BluetoothFindFirstRadio(ref p, ref btHandle);
|
||||||
int bytesReturned = 0;
|
int bytesReturned = 0;
|
||||||
bool success = false;
|
|
||||||
while (!success && btHandle != IntPtr.Zero)
|
while (!success && btHandle != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
success = NativeMethods.DeviceIoControl(btHandle, IOCTL_BTH_DISCONNECT_DEVICE, ref lbtAddr, 8, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero);
|
success = NativeMethods.DeviceIoControl(btHandle, IOCTL_BTH_DISCONNECT_DEVICE, ref lbtAddr, 8, IntPtr.Zero, 0, ref bytesReturned, IntPtr.Zero);
|
||||||
NativeMethods.CloseHandle(btHandle);
|
NativeMethods.CloseHandle(btHandle);
|
||||||
if (!success)
|
if (!success)
|
||||||
|
{
|
||||||
if (!NativeMethods.BluetoothFindNextRadio(searchHandle, ref btHandle))
|
if (!NativeMethods.BluetoothFindNextRadio(searchHandle, ref btHandle))
|
||||||
btHandle = IntPtr.Zero;
|
btHandle = IntPtr.Zero;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NativeMethods.BluetoothFindRadioClose(searchHandle);
|
NativeMethods.BluetoothFindRadioClose(searchHandle);
|
||||||
Console.WriteLine("Disconnect successful: " + success);
|
Console.WriteLine("Disconnect successful: " + success);
|
||||||
|
}
|
||||||
|
|
||||||
success = true; // XXX return value indicates failure, but it still works?
|
success = true; // XXX return value indicates failure, but it still works?
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
IsDisconnecting = true;
|
IsDisconnecting = true;
|
||||||
StopOutputUpdate();
|
StopOutputUpdate();
|
||||||
if (Removal != null)
|
|
||||||
Removal(this, EventArgs.Empty);
|
if (callRemoval)
|
||||||
|
{
|
||||||
|
uiContext.Send(new SendOrPostCallback(delegate (object state)
|
||||||
|
{
|
||||||
|
Removal?.Invoke(this, EventArgs.Empty);
|
||||||
|
}), null);
|
||||||
|
|
||||||
|
//Removal?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DisconnectDongle(bool remove = false)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
byte[] disconnectReport = new byte[65];
|
||||||
|
disconnectReport[0] = 0xe2;
|
||||||
|
disconnectReport[1] = 0x02;
|
||||||
|
Array.Clear(disconnectReport, 2, 63);
|
||||||
|
|
||||||
|
lock (outputReport)
|
||||||
|
{
|
||||||
|
result = hDevice.WriteFeatureReport(disconnectReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result && remove)
|
||||||
|
{
|
||||||
|
isDisconnecting = true;
|
||||||
|
StopOutputUpdate();
|
||||||
|
|
||||||
|
uiContext.Send(new SendOrPostCallback(delegate (object state4)
|
||||||
|
{
|
||||||
|
Removal?.Invoke(this, EventArgs.Empty);
|
||||||
|
}), null);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (Removal != null)
|
||||||
|
Removal(this, EventArgs.Empty);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (result && !remove)
|
||||||
|
{
|
||||||
|
isRemoved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private DS4HapticState testRumble = new DS4HapticState();
|
private DS4HapticState testRumble = new DS4HapticState();
|
||||||
|
|
||||||
public void setRumble(byte rightLightFastMotor, byte leftHeavySlowMotor)
|
public void setRumble(byte rightLightFastMotor, byte leftHeavySlowMotor)
|
||||||
{
|
{
|
||||||
testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor;
|
testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor;
|
||||||
@ -675,8 +1006,8 @@ namespace DS4Windows
|
|||||||
public void getExposedState(DS4StateExposed expState, DS4State state)
|
public void getExposedState(DS4StateExposed expState, DS4State state)
|
||||||
{
|
{
|
||||||
cState.CopyTo(state);
|
cState.CopyTo(state);
|
||||||
expState.Accel = accel;
|
expState.setAccel(accel);
|
||||||
expState.Gyro = gyro;
|
expState.setGyro(gyro);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getCurrentState(DS4State state)
|
public void getCurrentState(DS4State state)
|
||||||
@ -720,26 +1051,30 @@ namespace DS4Windows
|
|||||||
// Use the "most recently set" haptic state for each of light bar/motor.
|
// Use the "most recently set" haptic state for each of light bar/motor.
|
||||||
private void setHapticState()
|
private void setHapticState()
|
||||||
{
|
{
|
||||||
int i = 0;
|
|
||||||
DS4Color lightBarColor = LightBarColor;
|
DS4Color lightBarColor = LightBarColor;
|
||||||
byte lightBarFlashDurationOn = LightBarOnDuration, lightBarFlashDurationOff = LightBarOffDuration;
|
byte lightBarFlashDurationOn = LightBarOnDuration, lightBarFlashDurationOff = LightBarOffDuration;
|
||||||
byte rumbleMotorStrengthLeftHeavySlow = LeftHeavySlowRumble, rumbleMotorStrengthRightLightFast = rightLightFastRumble;
|
byte rumbleMotorStrengthLeftHeavySlow = LeftHeavySlowRumble, rumbleMotorStrengthRightLightFast = rightLightFastRumble;
|
||||||
foreach (DS4HapticState haptic in hapticState)
|
int hapticLen = hapticState.Length;
|
||||||
|
for (int i=0; i < hapticLen; i++)
|
||||||
{
|
{
|
||||||
if (i++ == hapticStackIndex)
|
DS4HapticState haptic = hapticState[i];
|
||||||
|
if (i == hapticStackIndex)
|
||||||
break; // rest haven't been used this time
|
break; // rest haven't been used this time
|
||||||
|
|
||||||
if (haptic.IsLightBarSet())
|
if (haptic.IsLightBarSet())
|
||||||
{
|
{
|
||||||
lightBarColor = haptic.LightBarColor;
|
lightBarColor = haptic.LightBarColor;
|
||||||
lightBarFlashDurationOn = haptic.LightBarFlashDurationOn;
|
lightBarFlashDurationOn = haptic.LightBarFlashDurationOn;
|
||||||
lightBarFlashDurationOff = haptic.LightBarFlashDurationOff;
|
lightBarFlashDurationOff = haptic.LightBarFlashDurationOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haptic.IsRumbleSet())
|
if (haptic.IsRumbleSet())
|
||||||
{
|
{
|
||||||
rumbleMotorStrengthLeftHeavySlow = haptic.RumbleMotorStrengthLeftHeavySlow;
|
rumbleMotorStrengthLeftHeavySlow = haptic.RumbleMotorStrengthLeftHeavySlow;
|
||||||
rumbleMotorStrengthRightLightFast = haptic.RumbleMotorStrengthRightLightFast;
|
rumbleMotorStrengthRightLightFast = haptic.RumbleMotorStrengthRightLightFast;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LightBarColor = lightBarColor;
|
LightBarColor = lightBarColor;
|
||||||
LightBarOnDuration = lightBarFlashDurationOn;
|
LightBarOnDuration = lightBarFlashDurationOn;
|
||||||
LightBarOffDuration = lightBarFlashDurationOff;
|
LightBarOffDuration = lightBarFlashDurationOff;
|
||||||
@ -749,12 +1084,14 @@ namespace DS4Windows
|
|||||||
|
|
||||||
public void pushHapticState(DS4HapticState hs)
|
public void pushHapticState(DS4HapticState hs)
|
||||||
{
|
{
|
||||||
if (hapticStackIndex == hapticState.Length)
|
int hapsLen = hapticState.Length;
|
||||||
|
if (hapticStackIndex == hapsLen)
|
||||||
{
|
{
|
||||||
DS4HapticState[] newHaptics = new DS4HapticState[hapticState.Length + 1];
|
DS4HapticState[] newHaptics = new DS4HapticState[hapsLen + 1];
|
||||||
Array.Copy(hapticState, newHaptics, hapticState.Length);
|
Array.Copy(hapticState, newHaptics, hapsLen);
|
||||||
hapticState = newHaptics;
|
hapticState = newHaptics;
|
||||||
}
|
}
|
||||||
|
|
||||||
hapticState[hapticStackIndex++] = hs;
|
hapticState[hapticStackIndex++] = hs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,5 +1100,15 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
return Mac;
|
return Mac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void runRemoval()
|
||||||
|
{
|
||||||
|
Removal?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeReportHandlers()
|
||||||
|
{
|
||||||
|
this.Report = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.Length - 1);
|
deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.Length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deviceInstanceId;
|
return deviceInstanceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,10 +37,18 @@ namespace DS4Windows
|
|||||||
// Sort Bluetooth first in case USB is also connected on the same controller.
|
// Sort Bluetooth first in case USB is also connected on the same controller.
|
||||||
hDevices = hDevices.OrderBy<HidDevice, ConnectionType>((HidDevice d) => { return DS4Device.HidConnectionType(d); });
|
hDevices = hDevices.OrderBy<HidDevice, ConnectionType>((HidDevice d) => { return DS4Device.HidConnectionType(d); });
|
||||||
|
|
||||||
foreach (HidDevice hDevice in hDevices)
|
List<HidDevice> tempList = hDevices.ToList();
|
||||||
|
int devCount = tempList.Count();
|
||||||
|
string devicePlural = "device" + (devCount == 0 || devCount > 1 ? "s" : "");
|
||||||
|
//Log.LogToGui("Found " + devCount + " possible " + devicePlural + ". Examining " + devicePlural + ".", false);
|
||||||
|
|
||||||
|
for (int i = 0; i < devCount; i++)
|
||||||
|
//foreach (HidDevice hDevice in hDevices)
|
||||||
{
|
{
|
||||||
|
HidDevice hDevice = tempList[i];
|
||||||
if (DevicePaths.Contains(hDevice.DevicePath))
|
if (DevicePaths.Contains(hDevice.DevicePath))
|
||||||
continue; // BT/USB endpoint already open once
|
continue; // BT/USB endpoint already open once
|
||||||
|
|
||||||
if (!hDevice.IsOpen)
|
if (!hDevice.IsOpen)
|
||||||
{
|
{
|
||||||
hDevice.OpenDevice(isExclusiveMode);
|
hDevice.OpenDevice(isExclusiveMode);
|
||||||
@ -59,6 +68,7 @@ namespace DS4Windows
|
|||||||
startInfo.Verb = "runas";
|
startInfo.Verb = "runas";
|
||||||
startInfo.Arguments = "re-enabledevice " + devicePathToInstanceId(hDevice.DevicePath);
|
startInfo.Arguments = "re-enabledevice " + devicePathToInstanceId(hDevice.DevicePath);
|
||||||
Process child = Process.Start(startInfo);
|
Process child = Process.Start(startInfo);
|
||||||
|
|
||||||
if (!child.WaitForExit(5000))
|
if (!child.WaitForExit(5000))
|
||||||
{
|
{
|
||||||
child.Kill();
|
child.Kill();
|
||||||
@ -81,21 +91,22 @@ namespace DS4Windows
|
|||||||
if (isExclusiveMode && !hDevice.IsOpen)
|
if (isExclusiveMode && !hDevice.IsOpen)
|
||||||
hDevice.OpenDevice(false);
|
hDevice.OpenDevice(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hDevice.IsOpen)
|
if (hDevice.IsOpen)
|
||||||
{
|
{
|
||||||
if (Devices.ContainsKey(hDevice.readSerial()))
|
string serial = hDevice.readSerial();
|
||||||
|
bool validSerial = !serial.Equals("00:00:00:00:00:00");
|
||||||
|
if (Devices.ContainsKey(serial))
|
||||||
continue; // happens when the BT endpoint already is open and the USB is plugged into the same host
|
continue; // happens when the BT endpoint already is open and the USB is plugged into the same host
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DS4Device ds4Device = new DS4Device(hDevice);
|
DS4Device ds4Device = new DS4Device(hDevice);
|
||||||
ds4Device.Removal += On_Removal;
|
//ds4Device.Removal += On_Removal;
|
||||||
Devices.Add(ds4Device.MacAddress, ds4Device);
|
Devices.Add(ds4Device.MacAddress, ds4Device);
|
||||||
DevicePaths.Add(hDevice.DevicePath);
|
DevicePaths.Add(hDevice.DevicePath);
|
||||||
ds4Device.StartUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +142,15 @@ namespace DS4Windows
|
|||||||
lock (Devices)
|
lock (Devices)
|
||||||
{
|
{
|
||||||
IEnumerable<DS4Device> devices = getDS4Controllers();
|
IEnumerable<DS4Device> devices = getDS4Controllers();
|
||||||
foreach (DS4Device device in devices)
|
//foreach (DS4Device device in devices)
|
||||||
|
for (int i = 0, devCount = devices.Count(); i < devCount; i++)
|
||||||
{
|
{
|
||||||
|
DS4Device device = devices.ElementAt(i);
|
||||||
device.StopUpdate();
|
device.StopUpdate();
|
||||||
|
//device.runRemoval();
|
||||||
device.HidDevice.CloseDevice();
|
device.HidDevice.CloseDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
Devices.Clear();
|
Devices.Clear();
|
||||||
DevicePaths.Clear();
|
DevicePaths.Clear();
|
||||||
}
|
}
|
||||||
@ -188,6 +203,9 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
throw new Exception("Error disabling device, error code = " + Marshal.GetLastWin32Error());
|
throw new Exception("Error disabling device, error code = " + Marshal.GetLastWin32Error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.Threading.Thread.Sleep(50);
|
||||||
|
|
||||||
propChangeParams.stateChange = NativeMethods.DICS_ENABLE;
|
propChangeParams.stateChange = NativeMethods.DICS_ENABLE;
|
||||||
success = NativeMethods.SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInfoData, ref propChangeParams, Marshal.SizeOf(propChangeParams));
|
success = NativeMethods.SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInfoData, ref propChangeParams, Marshal.SizeOf(propChangeParams));
|
||||||
if (!success)
|
if (!success)
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
@ -17,6 +14,9 @@ namespace DS4Windows
|
|||||||
public byte FrameCounter; // 0, 1, 2...62, 63, 0....
|
public byte FrameCounter; // 0, 1, 2...62, 63, 0....
|
||||||
public byte TouchPacketCounter; // we break these out automatically
|
public byte TouchPacketCounter; // we break these out automatically
|
||||||
public byte Battery; // 0 for charging, 10/20/30/40/50/60/70/80/90/100 for percentage of full
|
public byte Battery; // 0 for charging, 10/20/30/40/50/60/70/80/90/100 for percentage of full
|
||||||
|
public double LSAngle; // Calculated bearing of the LS X,Y coordinates
|
||||||
|
public double RSAngle; // Calculated bearing of the RS X,Y coordinates
|
||||||
|
public static readonly int DEFAULT_AXISDIR_VALUE = 127;
|
||||||
|
|
||||||
public DS4State()
|
public DS4State()
|
||||||
{
|
{
|
||||||
@ -29,6 +29,8 @@ namespace DS4Windows
|
|||||||
FrameCounter = 255; // only actually has 6 bits, so this is a null indicator
|
FrameCounter = 255; // only actually has 6 bits, so this is a null indicator
|
||||||
TouchPacketCounter = 255; // 8 bits, no great junk value
|
TouchPacketCounter = 255; // 8 bits, no great junk value
|
||||||
Battery = 0;
|
Battery = 0;
|
||||||
|
LSAngle = 0.0;
|
||||||
|
RSAngle = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DS4State(DS4State state)
|
public DS4State(DS4State state)
|
||||||
@ -65,6 +67,8 @@ namespace DS4Windows
|
|||||||
RY = state.RY;
|
RY = state.RY;
|
||||||
FrameCounter = state.FrameCounter;
|
FrameCounter = state.FrameCounter;
|
||||||
Battery = state.Battery;
|
Battery = state.Battery;
|
||||||
|
LSAngle = state.LSAngle;
|
||||||
|
RSAngle = state.RSAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DS4State Clone()
|
public DS4State Clone()
|
||||||
@ -106,7 +110,19 @@ namespace DS4Windows
|
|||||||
state.RY = RY;
|
state.RY = RY;
|
||||||
state.FrameCounter = FrameCounter;
|
state.FrameCounter = FrameCounter;
|
||||||
state.Battery = Battery;
|
state.Battery = Battery;
|
||||||
|
state.LSAngle = LSAngle;
|
||||||
|
state.RSAngle = RSAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void calculateStickAngles()
|
||||||
|
{
|
||||||
|
double lsangle = Math.Atan2((LX - 127), -(LY - 127));
|
||||||
|
lsangle = (lsangle >= 0 ? lsangle : (2 * Math.PI + lsangle)) * 180 / Math.PI;
|
||||||
|
LSAngle = lsangle;
|
||||||
|
|
||||||
|
double rsangle = Math.Atan2((RX - 127), -(RY - 127));
|
||||||
|
rsangle = (rsangle >= 0 ? rsangle : (2 * Math.PI + rsangle)) * 180 / Math.PI;
|
||||||
|
RSAngle = rsangle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
public class DS4StateExposed
|
public class DS4StateExposed
|
||||||
@ -48,8 +44,17 @@ namespace DS4Windows
|
|||||||
|
|
||||||
/// <summary> Holds raw DS4 input data from 14 to 19 </summary>
|
/// <summary> Holds raw DS4 input data from 14 to 19 </summary>
|
||||||
public byte[] Accel { set { accel = value; } }
|
public byte[] Accel { set { accel = value; } }
|
||||||
|
public void setAccel(byte[] value)
|
||||||
|
{
|
||||||
|
accel = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Holds raw DS4 input data from 20 to 25 </summary>
|
/// <summary> Holds raw DS4 input data from 20 to 25 </summary>
|
||||||
public byte[] Gyro { set { gyro = value; } }
|
public byte[] Gyro { set { gyro = value; } }
|
||||||
|
public void setGyro(byte[] value)
|
||||||
|
{
|
||||||
|
gyro = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Yaw leftward/counter-clockwise/turn to port or larboard side </summary>
|
/// <summary> Yaw leftward/counter-clockwise/turn to port or larboard side </summary>
|
||||||
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
||||||
@ -63,11 +68,28 @@ namespace DS4Windows
|
|||||||
/// <summary> R side of controller upward </summary>
|
/// <summary> R side of controller upward </summary>
|
||||||
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
||||||
public int GyroX { get { return (short)((ushort)(gyro[0] << 8) | gyro[1]) / 64; } }
|
public int GyroX { get { return (short)((ushort)(gyro[0] << 8) | gyro[1]) / 64; } }
|
||||||
|
|
||||||
|
public int getGyroX()
|
||||||
|
{
|
||||||
|
return (short)((ushort)(gyro[0] << 8) | gyro[1]) / 64;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> touchpad and button face side of controller upward </summary>
|
/// <summary> touchpad and button face side of controller upward </summary>
|
||||||
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
||||||
public int GyroY { get { return (short)((ushort)(gyro[2] << 8) | gyro[3]) / 64; } }
|
public int GyroY { get { return (short)((ushort)(gyro[2] << 8) | gyro[3]) / 64; } }
|
||||||
|
|
||||||
|
public int getGyroY()
|
||||||
|
{
|
||||||
|
return (short)((ushort)(gyro[2] << 8) | gyro[3]) / 64;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Audio/expansion ports upward and light bar/shoulders/bumpers/USB port downward </summary>
|
/// <summary> Audio/expansion ports upward and light bar/shoulders/bumpers/USB port downward </summary>
|
||||||
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
|
||||||
public int GyroZ { get { return (short)((ushort)(gyro[4] << 8) | gyro[5]) / 64; } }
|
public int GyroZ { get { return (short)((ushort)(gyro[4] << 8) | gyro[5]) / 64; } }
|
||||||
|
|
||||||
|
public int getGyroZ()
|
||||||
|
{
|
||||||
|
return (short)((ushort)(gyro[4] << 8) | gyro[5]) / 64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
public class TouchpadEventArgs : EventArgs
|
public class TouchpadEventArgs : EventArgs
|
||||||
|
@ -30,9 +30,12 @@
|
|||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>
|
||||||
|
</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartupObject>DS4Windows.Program</StartupObject>
|
<StartupObject>DS4Windows.Program</StartupObject>
|
||||||
@ -52,7 +55,33 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="JetBrains.Annotations, Version=10.2.1.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TaskScheduler.2.5.23\lib\net40\JetBrains.Annotations.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Win32.TaskScheduler, Version=2.5.23.0, Culture=neutral, PublicKeyToken=0d013ddd5178a2ae, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TaskScheduler.2.5.23\lib\net40\Microsoft.Win32.TaskScheduler.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.IO.Compression" />
|
<Reference Include="System.IO.Compression" />
|
||||||
@ -72,6 +101,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="DS4Control\ControlSerivce.cs" />
|
<Compile Include="DS4Control\ControlSerivce.cs" />
|
||||||
<Compile Include="DS4Control\DS4LightBar.cs" />
|
<Compile Include="DS4Control\DS4LightBar.cs" />
|
||||||
|
<Compile Include="DS4Control\DS4StateFieldMapping.cs" />
|
||||||
<Compile Include="DS4Control\InputMethods.cs" />
|
<Compile Include="DS4Control\InputMethods.cs" />
|
||||||
<Compile Include="DS4Control\ITouchpadBehaviour.cs" />
|
<Compile Include="DS4Control\ITouchpadBehaviour.cs" />
|
||||||
<Compile Include="DS4Control\Log.cs" />
|
<Compile Include="DS4Control\Log.cs" />
|
||||||
@ -98,6 +128,7 @@
|
|||||||
<Compile Include="DS4Control\X360Device.designer.cs">
|
<Compile Include="DS4Control\X360Device.designer.cs">
|
||||||
<DependentUpon>X360Device.cs</DependentUpon>
|
<DependentUpon>X360Device.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="DS4Library\DS4Audio.cs" />
|
||||||
<Compile Include="DS4Library\DS4Device.cs" />
|
<Compile Include="DS4Library\DS4Device.cs" />
|
||||||
<Compile Include="DS4Library\DS4Devices.cs" />
|
<Compile Include="DS4Library\DS4Devices.cs" />
|
||||||
<Compile Include="DS4Library\DS4Sixaxis.cs" />
|
<Compile Include="DS4Library\DS4Sixaxis.cs" />
|
||||||
@ -1004,6 +1035,7 @@
|
|||||||
<EmbeddedResource Include="Properties\Resources.zh-hans.resx" />
|
<EmbeddedResource Include="Properties\Resources.zh-hans.resx" />
|
||||||
<EmbeddedResource Include="Properties\Resources.zh-Hant.resx" />
|
<EmbeddedResource Include="Properties\Resources.zh-Hant.resx" />
|
||||||
<None Include="app.manifest" />
|
<None Include="app.manifest" />
|
||||||
|
<None Include="packages.config" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
@ -1034,7 +1066,7 @@
|
|||||||
</COMReference>
|
</COMReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="HidLibrary\LICENSE.htm" />
|
<Content Include="HidLibrary\LICENSE" />
|
||||||
<Content Include="Resources\360 fades.png" />
|
<Content Include="Resources\360 fades.png" />
|
||||||
<None Include="Resources\360 map.png" />
|
<None Include="Resources\360 map.png" />
|
||||||
<None Include="Resources\360 highlight.png" />
|
<None Include="Resources\360 highlight.png" />
|
||||||
@ -1117,6 +1149,7 @@
|
|||||||
<Content Include="Resources\xbox_360_controller.png" />
|
<Content Include="Resources\xbox_360_controller.png" />
|
||||||
<Content Include="Resources\Y.png" />
|
<Content Include="Resources\Y.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
@ -83,6 +83,25 @@ namespace DS4Windows
|
|||||||
IsExclusive = isExclusive;
|
IsExclusive = isExclusive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenFileStream(int reportSize)
|
||||||
|
{
|
||||||
|
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||||
|
{
|
||||||
|
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, reportSize, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFileStreamOpen()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if (fileStream != null)
|
||||||
|
{
|
||||||
|
result = !fileStream.SafeFileHandle.IsInvalid && !fileStream.SafeFileHandle.IsClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void CloseDevice()
|
public void CloseDevice()
|
||||||
{
|
{
|
||||||
if (!IsOpen) return;
|
if (!IsOpen) return;
|
||||||
@ -110,6 +129,17 @@ namespace DS4Windows
|
|||||||
return NativeMethods.HidD_GetInputReport(safeReadHandle, data, data.Length);
|
return NativeMethods.HidD_GetInputReport(safeReadHandle, data, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool WriteFeatureReport(byte[] data)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if (IsOpen && safeReadHandle != null)
|
||||||
|
{
|
||||||
|
result = NativeMethods.HidD_SetFeature(safeReadHandle, data, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static HidDeviceAttributes GetDeviceAttributes(SafeFileHandle hidHandle)
|
private static HidDeviceAttributes GetDeviceAttributes(SafeFileHandle hidHandle)
|
||||||
{
|
{
|
||||||
@ -129,21 +159,37 @@ namespace DS4Windows
|
|||||||
NativeMethods.HidP_GetCaps(preparsedDataPointer, ref capabilities);
|
NativeMethods.HidP_GetCaps(preparsedDataPointer, ref capabilities);
|
||||||
NativeMethods.HidD_FreePreparsedData(preparsedDataPointer);
|
NativeMethods.HidD_FreePreparsedData(preparsedDataPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HidDeviceCapabilities(capabilities);
|
return new HidDeviceCapabilities(capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeFileStreamIO()
|
private void closeFileStreamIO()
|
||||||
{
|
{
|
||||||
if (fileStream != null)
|
if (fileStream != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
fileStream.Close();
|
fileStream.Close();
|
||||||
|
}
|
||||||
|
catch (IOException) { }
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
}
|
||||||
|
|
||||||
fileStream = null;
|
fileStream = null;
|
||||||
Console.WriteLine("Close fs");
|
Console.WriteLine("Close fs");
|
||||||
if (safeReadHandle != null && !safeReadHandle.IsInvalid)
|
if (safeReadHandle != null && !safeReadHandle.IsInvalid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!safeReadHandle.IsClosed)
|
||||||
{
|
{
|
||||||
safeReadHandle.Close();
|
safeReadHandle.Close();
|
||||||
Console.WriteLine("Close sh");
|
Console.WriteLine("Close sh");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (IOException) { }
|
||||||
|
}
|
||||||
|
|
||||||
safeReadHandle = null;
|
safeReadHandle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +219,7 @@ namespace DS4Windows
|
|||||||
return ReadStatus.ReadError;
|
return ReadStatus.ReadError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadStatus ReadFile(byte[] inputBuffer)
|
public ReadStatus ReadFile(byte[] inputBuffer)
|
||||||
{
|
{
|
||||||
if (safeReadHandle == null)
|
if (safeReadHandle == null)
|
||||||
@ -202,10 +249,10 @@ 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);
|
||||||
@ -242,8 +289,45 @@ 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 +369,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 +388,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 +426,11 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
if (isExclusive)
|
if (isExclusive)
|
||||||
{
|
{
|
||||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OpenExisting, 0, 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, 0, 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)
|
||||||
|
18
DS4Windows/HidLibrary/LICENSE
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Copyright (c) 2010 Ultraviolet Catastrophe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -1,739 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog: http://ogp.me/ns/fb/githubog#">
|
|
||||||
<meta charset='utf-8'>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>HidLibrary/LICENSE at master · mikeobrien/HidLibrary · GitHub</title>
|
|
||||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" />
|
|
||||||
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" />
|
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-114.png" />
|
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114.png" />
|
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-144.png" />
|
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144.png" />
|
|
||||||
<link rel="logo" type="image/svg" href="https://github-media-downloads.s3.amazonaws.com/github-logo.svg" />
|
|
||||||
<meta property="og:image" content="https://github.global.ssl.fastly.net/images/modules/logos_page/Octocat.png">
|
|
||||||
<meta name="hostname" content="github-fe124-cp1-prd.iad.github.net">
|
|
||||||
<meta name="ruby" content="ruby 2.1.0p0-github-tcmalloc (60139581e1) [x86_64-linux]">
|
|
||||||
<link rel="assets" href="https://github.global.ssl.fastly.net/">
|
|
||||||
<link rel="conduit-xhr" href="https://ghconduit.com:25035/">
|
|
||||||
<link rel="xhr-socket" href="/_sockets" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<meta name="msapplication-TileImage" content="/windows-tile.png" />
|
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
|
||||||
<meta name="selected-link" value="repo_source" data-pjax-transient />
|
|
||||||
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="collector-cdn.github.com" name="octolytics-script-host" /><meta content="github" name="octolytics-app-id" /><meta content="87178203:4B92:28E6A2:52D598B8" name="octolytics-dimension-request_id" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
||||||
|
|
||||||
<meta content="authenticity_token" name="csrf-param" />
|
|
||||||
<meta content="AAeSffXRAam6Bf/AzN/4KUjR6SAPkbVO9N7hC8xppV4=" name="csrf-token" />
|
|
||||||
|
|
||||||
<link href="https://github.global.ssl.fastly.net/assets/github-4b925c759ed9bc7974bc328563cd4a70197d6ac9.css" media="all" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="https://github.global.ssl.fastly.net/assets/github2-0598952211c73091a719781ed3c02cad780eac93.css" media="all" rel="stylesheet" type="text/css" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="https://github.global.ssl.fastly.net/assets/frameworks-e075736093c12b6b7444888c0c54d072c23c2a9a.js" type="text/javascript"></script>
|
|
||||||
<script src="https://github.global.ssl.fastly.net/assets/github-bf24f7542f2bfe4c53cfbd818e3480f9e3c9b969.js" type="text/javascript"></script>
|
|
||||||
|
|
||||||
<meta http-equiv="x-pjax-version" content="a69fa8c704f4aa3b75677a6903ec30ee">
|
|
||||||
|
|
||||||
<link data-pjax-transient rel='permalink' href='/mikeobrien/HidLibrary/blob/ea06e067816f81d4a27847f97d6da5cb89b9ae81/LICENSE'>
|
|
||||||
<meta property="og:title" content="HidLibrary"/>
|
|
||||||
<meta property="og:type" content="githubog:gitrepository"/>
|
|
||||||
<meta property="og:url" content="https://github.com/mikeobrien/HidLibrary"/>
|
|
||||||
<meta property="og:image" content="https://github.global.ssl.fastly.net/images/gravatars/gravatar-user-420.png"/>
|
|
||||||
<meta property="og:site_name" content="GitHub"/>
|
|
||||||
<meta property="og:description" content="HidLibrary - This library enables you to enumerate and communicate with Hid compatible USB devices in .NET."/>
|
|
||||||
|
|
||||||
<meta name="description" content="HidLibrary - This library enables you to enumerate and communicate with Hid compatible USB devices in .NET." />
|
|
||||||
|
|
||||||
<meta content="187817" name="octolytics-dimension-user_id" /><meta content="mikeobrien" name="octolytics-dimension-user_login" /><meta content="830324" name="octolytics-dimension-repository_id" /><meta content="mikeobrien/HidLibrary" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="830324" name="octolytics-dimension-repository_network_root_id" /><meta content="mikeobrien/HidLibrary" name="octolytics-dimension-repository_network_root_nwo" />
|
|
||||||
<link href="https://github.com/mikeobrien/HidLibrary/commits/master.atom" rel="alternate" title="Recent Commits to HidLibrary:master" type="application/atom+xml" />
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<body class="logged_out env-production windows vis-public page-blob">
|
|
||||||
<div class="wrapper">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="header header-logged-out">
|
|
||||||
<div class="container clearfix">
|
|
||||||
|
|
||||||
<a class="header-logo-wordmark" href="https://github.com/">
|
|
||||||
<span class="mega-octicon octicon-logo-github"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="header-actions">
|
|
||||||
<a class="button primary" href="/join">Sign up</a>
|
|
||||||
<a class="button signin" href="/login?return_to=%2Fmikeobrien%2FHidLibrary%2Fblob%2Fmaster%2FLICENSE">Sign in</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="command-bar js-command-bar in-repository">
|
|
||||||
|
|
||||||
<ul class="top-nav">
|
|
||||||
<li class="explore"><a href="/explore">Explore</a></li>
|
|
||||||
<li class="features"><a href="/features">Features</a></li>
|
|
||||||
<li class="enterprise"><a href="https://enterprise.github.com/">Enterprise</a></li>
|
|
||||||
<li class="blog"><a href="/blog">Blog</a></li>
|
|
||||||
</ul>
|
|
||||||
<form accept-charset="UTF-8" action="/search" class="command-bar-form" id="top_search_form" method="get">
|
|
||||||
|
|
||||||
<input type="text" data-hotkey="/ s" name="q" id="js-command-bar-field" placeholder="Search or type a command" tabindex="1" autocapitalize="off"
|
|
||||||
|
|
||||||
|
|
||||||
data-repo="mikeobrien/HidLibrary"
|
|
||||||
data-branch="master"
|
|
||||||
data-sha="59d7991355c6403ce0fd98f568483f054e942d8f"
|
|
||||||
>
|
|
||||||
|
|
||||||
<input type="hidden" name="nwo" value="mikeobrien/HidLibrary" />
|
|
||||||
|
|
||||||
<div class="select-menu js-menu-container js-select-menu search-context-select-menu">
|
|
||||||
<span class="minibutton select-menu-button js-menu-target">
|
|
||||||
<span class="js-select-button">This repository</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="select-menu-modal-holder js-menu-content js-navigation-container">
|
|
||||||
<div class="select-menu-modal">
|
|
||||||
|
|
||||||
<div class="select-menu-item js-navigation-item js-this-repository-navigation-item selected">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<input type="radio" class="js-search-this-repository" name="search_target" value="repository" checked="checked" />
|
|
||||||
<div class="select-menu-item-text js-select-button-text">This repository</div>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
|
|
||||||
<div class="select-menu-item js-navigation-item js-all-repositories-navigation-item">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<input type="radio" name="search_target" value="global" />
|
|
||||||
<div class="select-menu-item-text js-select-button-text">All repositories</div>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="octicon help tooltipped downwards" title="Show command bar help">
|
|
||||||
<span class="octicon octicon-question"></span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
<input type="hidden" name="ref" value="cmdform">
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="site" itemscope itemtype="http://schema.org/WebPage">
|
|
||||||
|
|
||||||
<div class="pagehead repohead instapaper_ignore readability-menu">
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
|
|
||||||
<ul class="pagehead-actions">
|
|
||||||
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="/login?return_to=%2Fmikeobrien%2FHidLibrary"
|
|
||||||
class="minibutton with-count js-toggler-target star-button tooltipped upwards"
|
|
||||||
title="You must be signed in to use this feature" rel="nofollow">
|
|
||||||
<span class="octicon octicon-star"></span>Star
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="social-count js-social-count" href="/mikeobrien/HidLibrary/stargazers">
|
|
||||||
58
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="/login?return_to=%2Fmikeobrien%2FHidLibrary"
|
|
||||||
class="minibutton with-count js-toggler-target fork-button tooltipped upwards"
|
|
||||||
title="You must be signed in to fork a repository" rel="nofollow">
|
|
||||||
<span class="octicon octicon-git-branch"></span>Fork
|
|
||||||
</a>
|
|
||||||
<a href="/mikeobrien/HidLibrary/network" class="social-count">
|
|
||||||
25
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h1 itemscope itemtype="http://data-vocabulary.org/Breadcrumb" class="entry-title public">
|
|
||||||
<span class="repo-label"><span>public</span></span>
|
|
||||||
<span class="mega-octicon octicon-repo"></span>
|
|
||||||
<span class="author">
|
|
||||||
<a href="/mikeobrien" class="url fn" itemprop="url" rel="author"><span itemprop="title">mikeobrien</span></a>
|
|
||||||
</span>
|
|
||||||
<span class="repohead-name-divider">/</span>
|
|
||||||
<strong><a href="/mikeobrien/HidLibrary" class="js-current-repository js-repo-home-link">HidLibrary</a></strong>
|
|
||||||
|
|
||||||
<span class="page-context-loader">
|
|
||||||
<img alt="Octocat-spinner-32" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</h1>
|
|
||||||
</div><!-- /.container -->
|
|
||||||
</div><!-- /.repohead -->
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="repository-with-sidebar repo-container ">
|
|
||||||
|
|
||||||
<div class="repository-sidebar">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="sunken-menu vertical-right repo-nav js-repo-nav js-repository-container-pjax js-octicon-loaders">
|
|
||||||
<div class="sunken-menu-contents">
|
|
||||||
<ul class="sunken-menu-group">
|
|
||||||
<li class="tooltipped leftwards" title="Code">
|
|
||||||
<a href="/mikeobrien/HidLibrary" aria-label="Code" class="selected js-selected-navigation-item sunken-menu-item" data-gotokey="c" data-pjax="true" data-selected-links="repo_source repo_downloads repo_commits repo_tags repo_branches /mikeobrien/HidLibrary">
|
|
||||||
<span class="octicon octicon-code"></span> <span class="full-word">Code</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Issues">
|
|
||||||
<a href="/mikeobrien/HidLibrary/issues" aria-label="Issues" class="js-selected-navigation-item sunken-menu-item js-disable-pjax" data-gotokey="i" data-selected-links="repo_issues /mikeobrien/HidLibrary/issues">
|
|
||||||
<span class="octicon octicon-issue-opened"></span> <span class="full-word">Issues</span>
|
|
||||||
<span class='counter'>20</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Pull Requests">
|
|
||||||
<a href="/mikeobrien/HidLibrary/pulls" aria-label="Pull Requests" class="js-selected-navigation-item sunken-menu-item js-disable-pjax" data-gotokey="p" data-selected-links="repo_pulls /mikeobrien/HidLibrary/pulls">
|
|
||||||
<span class="octicon octicon-git-pull-request"></span> <span class="full-word">Pull Requests</span>
|
|
||||||
<span class='counter'>1</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Wiki">
|
|
||||||
<a href="/mikeobrien/HidLibrary/wiki" aria-label="Wiki" class="js-selected-navigation-item sunken-menu-item" data-pjax="true" data-selected-links="repo_wiki /mikeobrien/HidLibrary/wiki">
|
|
||||||
<span class="octicon octicon-book"></span> <span class="full-word">Wiki</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
</ul>
|
|
||||||
<div class="sunken-menu-separator"></div>
|
|
||||||
<ul class="sunken-menu-group">
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Pulse">
|
|
||||||
<a href="/mikeobrien/HidLibrary/pulse" aria-label="Pulse" class="js-selected-navigation-item sunken-menu-item" data-pjax="true" data-selected-links="pulse /mikeobrien/HidLibrary/pulse">
|
|
||||||
<span class="octicon octicon-pulse"></span> <span class="full-word">Pulse</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Graphs">
|
|
||||||
<a href="/mikeobrien/HidLibrary/graphs" aria-label="Graphs" class="js-selected-navigation-item sunken-menu-item" data-pjax="true" data-selected-links="repo_graphs repo_contributors /mikeobrien/HidLibrary/graphs">
|
|
||||||
<span class="octicon octicon-graph"></span> <span class="full-word">Graphs</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
|
|
||||||
<li class="tooltipped leftwards" title="Network">
|
|
||||||
<a href="/mikeobrien/HidLibrary/network" aria-label="Network" class="js-selected-navigation-item sunken-menu-item js-disable-pjax" data-selected-links="repo_network /mikeobrien/HidLibrary/network">
|
|
||||||
<span class="octicon octicon-git-branch"></span> <span class="full-word">Network</span>
|
|
||||||
<img alt="Octocat-spinner-32" class="mini-loader" height="16" src="https://github.global.ssl.fastly.net/images/spinners/octocat-spinner-32.gif" width="16" />
|
|
||||||
</a> </li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="only-with-full-nav">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="clone-url open"
|
|
||||||
data-protocol-type="http"
|
|
||||||
data-url="/users/set_protocol?protocol_selector=http&protocol_type=clone">
|
|
||||||
<h3><strong>HTTPS</strong> clone URL</h3>
|
|
||||||
<div class="clone-url-box">
|
|
||||||
<input type="text" class="clone js-url-field"
|
|
||||||
value="https://github.com/mikeobrien/HidLibrary.git" readonly="readonly">
|
|
||||||
|
|
||||||
<span class="js-zeroclipboard url-box-clippy minibutton zeroclipboard-button" data-clipboard-text="https://github.com/mikeobrien/HidLibrary.git" data-copied-hint="copied!" title="copy to clipboard"><span class="octicon octicon-clippy"></span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="clone-url "
|
|
||||||
data-protocol-type="subversion"
|
|
||||||
data-url="/users/set_protocol?protocol_selector=subversion&protocol_type=clone">
|
|
||||||
<h3><strong>Subversion</strong> checkout URL</h3>
|
|
||||||
<div class="clone-url-box">
|
|
||||||
<input type="text" class="clone js-url-field"
|
|
||||||
value="https://github.com/mikeobrien/HidLibrary" readonly="readonly">
|
|
||||||
|
|
||||||
<span class="js-zeroclipboard url-box-clippy minibutton zeroclipboard-button" data-clipboard-text="https://github.com/mikeobrien/HidLibrary" data-copied-hint="copied!" title="copy to clipboard"><span class="octicon octicon-clippy"></span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p class="clone-options">You can clone with
|
|
||||||
<a href="#" class="js-clone-selector" data-protocol="http">HTTPS</a>,
|
|
||||||
or <a href="#" class="js-clone-selector" data-protocol="subversion">Subversion</a>.
|
|
||||||
<span class="octicon help tooltipped upwards" title="Get help on which URL is right for you.">
|
|
||||||
<a href="https://help.github.com/articles/which-remote-url-should-i-use">
|
|
||||||
<span class="octicon octicon-question"></span>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<a href="http://windows.github.com" class="minibutton sidebar-button">
|
|
||||||
<span class="octicon octicon-device-desktop"></span>
|
|
||||||
Clone in Desktop
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="/mikeobrien/HidLibrary/archive/master.zip"
|
|
||||||
class="minibutton sidebar-button"
|
|
||||||
title="Download this repository as a zip file"
|
|
||||||
rel="nofollow">
|
|
||||||
<span class="octicon octicon-cloud-download"></span>
|
|
||||||
Download ZIP
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div><!-- /.repository-sidebar -->
|
|
||||||
|
|
||||||
<div id="js-repo-pjax-container" class="repository-content context-loader-container" data-pjax-container>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- blob contrib key: blob_contributors:v21:cd71f166ab60e838fa56ed6b9690fbfd -->
|
|
||||||
|
|
||||||
<p title="This is a placeholder element" class="js-history-link-replace hidden"></p>
|
|
||||||
|
|
||||||
<a href="/mikeobrien/HidLibrary/find/master" data-pjax data-hotkey="t" class="js-show-file-finder" style="display:none">Show File Finder</a>
|
|
||||||
|
|
||||||
<div class="file-navigation">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="select-menu js-menu-container js-select-menu" >
|
|
||||||
<span class="minibutton select-menu-button js-menu-target" data-hotkey="w"
|
|
||||||
data-master-branch="master"
|
|
||||||
data-ref="master"
|
|
||||||
role="button" aria-label="Switch branches or tags" tabindex="0">
|
|
||||||
<span class="octicon octicon-git-branch"></span>
|
|
||||||
<i>branch:</i>
|
|
||||||
<span class="js-select-button">master</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax>
|
|
||||||
|
|
||||||
<div class="select-menu-modal">
|
|
||||||
<div class="select-menu-header">
|
|
||||||
<span class="select-menu-title">Switch branches/tags</span>
|
|
||||||
<span class="octicon octicon-remove-close js-menu-close"></span>
|
|
||||||
</div> <!-- /.select-menu-header -->
|
|
||||||
|
|
||||||
<div class="select-menu-filters">
|
|
||||||
<div class="select-menu-text-filter">
|
|
||||||
<input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
|
|
||||||
</div>
|
|
||||||
<div class="select-menu-tabs">
|
|
||||||
<ul>
|
|
||||||
<li class="select-menu-tab">
|
|
||||||
<a href="#" data-tab-filter="branches" class="js-select-menu-tab">Branches</a>
|
|
||||||
</li>
|
|
||||||
<li class="select-menu-tab">
|
|
||||||
<a href="#" data-tab-filter="tags" class="js-select-menu-tab">Tags</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div><!-- /.select-menu-tabs -->
|
|
||||||
</div><!-- /.select-menu-filters -->
|
|
||||||
|
|
||||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches">
|
|
||||||
|
|
||||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="select-menu-item js-navigation-item selected">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/blob/master/LICENSE"
|
|
||||||
data-name="master"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="master">master</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="select-menu-no-results">Nothing to show</div>
|
|
||||||
</div> <!-- /.select-menu-list -->
|
|
||||||
|
|
||||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
|
|
||||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.23.0/LICENSE"
|
|
||||||
data-name="v3.2.23.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.23.0">v3.2.23.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.22.0/LICENSE"
|
|
||||||
data-name="v3.2.22.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.22.0">v3.2.22.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.20.0/LICENSE"
|
|
||||||
data-name="v3.2.20.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.20.0">v3.2.20.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.19.0/LICENSE"
|
|
||||||
data-name="v3.2.19.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.19.0">v3.2.19.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.18.0/LICENSE"
|
|
||||||
data-name="v3.2.18.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.18.0">v3.2.18.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.17.0/LICENSE"
|
|
||||||
data-name="v3.2.17.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.17.0">v3.2.17.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.16.0/LICENSE"
|
|
||||||
data-name="v3.2.16.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.16.0">v3.2.16.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.12.0/LICENSE"
|
|
||||||
data-name="v3.2.12.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.12.0">v3.2.12.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.11.0/LICENSE"
|
|
||||||
data-name="v3.2.11.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.11.0">v3.2.11.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.10.0/LICENSE"
|
|
||||||
data-name="v3.2.10.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.10.0">v3.2.10.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.9.0/LICENSE"
|
|
||||||
data-name="v3.2.9.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.9.0">v3.2.9.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.8.0/LICENSE"
|
|
||||||
data-name="v3.2.8.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.8.0">v3.2.8.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.7.0/LICENSE"
|
|
||||||
data-name="v3.2.7.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.7.0">v3.2.7.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.6.0/LICENSE"
|
|
||||||
data-name="v3.2.6.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.6.0">v3.2.6.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.5.0/LICENSE"
|
|
||||||
data-name="v3.2.5.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.5.0">v3.2.5.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.4.0/LICENSE"
|
|
||||||
data-name="v3.2.4.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.4.0">v3.2.4.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.2.3.0/LICENSE"
|
|
||||||
data-name="v3.2.3.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.2.3.0">v3.2.3.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/v3.0.5/LICENSE"
|
|
||||||
data-name="v3.0.5"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="v3.0.5">v3.0.5</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
<div class="select-menu-item js-navigation-item ">
|
|
||||||
<span class="select-menu-item-icon octicon octicon-check"></span>
|
|
||||||
<a href="/mikeobrien/HidLibrary/tree/hidlibrary-v3.2.2.0/LICENSE"
|
|
||||||
data-name="hidlibrary-v3.2.2.0"
|
|
||||||
data-skip-pjax="true"
|
|
||||||
rel="nofollow"
|
|
||||||
class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target"
|
|
||||||
title="hidlibrary-v3.2.2.0">hidlibrary-v3.2.2.0</a>
|
|
||||||
</div> <!-- /.select-menu-item -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="select-menu-no-results">Nothing to show</div>
|
|
||||||
</div> <!-- /.select-menu-list -->
|
|
||||||
|
|
||||||
</div> <!-- /.select-menu-modal -->
|
|
||||||
</div> <!-- /.select-menu-modal-holder -->
|
|
||||||
</div> <!-- /.select-menu -->
|
|
||||||
|
|
||||||
<div class="breadcrumb">
|
|
||||||
<span class='repo-root js-repo-root'><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/mikeobrien/HidLibrary" data-branch="master" data-direction="back" data-pjax="true" itemscope="url"><span itemprop="title">HidLibrary</span></a></span></span><span class="separator"> / </span><strong class="final-path">LICENSE</strong> <span class="js-zeroclipboard minibutton zeroclipboard-button" data-clipboard-text="LICENSE" data-copied-hint="copied!" title="copy to clipboard"><span class="octicon octicon-clippy"></span></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="commit file-history-tease">
|
|
||||||
<img class="main-avatar" height="24" src="https://2.gravatar.com/avatar/15505f4513a7f05d16b71bde610827c5?d=https%3A%2F%2Fidenticons.github.com%2F3469cadaa0686184b49895d4249a3480.png&r=x&s=140" width="24" />
|
|
||||||
<span class="author"><a href="/mikeobrien" rel="author">mikeobrien</a></span>
|
|
||||||
<time class="js-relative-date" datetime="2010-08-11T07:50:59-07:00" title="2010-08-11 07:50:59">August 11, 2010</time>
|
|
||||||
<div class="commit-title">
|
|
||||||
<a href="/mikeobrien/HidLibrary/commit/57632b64175c0a06b3214027cb325704d3210ec9" class="message" data-pjax="true" title="Initial commit">Initial commit</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="participation">
|
|
||||||
<p class="quickstat"><a href="#blob_contributors_box" rel="facebox"><strong>1</strong> contributor</a></p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div id="blob_contributors_box" style="display:none">
|
|
||||||
<h2 class="facebox-header">Users who have contributed to this file</h2>
|
|
||||||
<ul class="facebox-user-list">
|
|
||||||
<li class="facebox-user-list-item">
|
|
||||||
<img height="24" src="https://2.gravatar.com/avatar/15505f4513a7f05d16b71bde610827c5?d=https%3A%2F%2Fidenticons.github.com%2F3469cadaa0686184b49895d4249a3480.png&r=x&s=140" width="24" />
|
|
||||||
<a href="/mikeobrien">mikeobrien</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="files" class="bubble">
|
|
||||||
<div class="file">
|
|
||||||
<div class="meta">
|
|
||||||
<div class="info">
|
|
||||||
<span class="icon"><b class="octicon octicon-file-text"></b></span>
|
|
||||||
<span class="mode" title="File Mode">file</span>
|
|
||||||
<span>18 lines (15 sloc)</span>
|
|
||||||
<span>1.094 kb</span>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<div class="button-group">
|
|
||||||
<a class="minibutton tooltipped leftwards"
|
|
||||||
href="http://windows.github.com" title="Open this file in GitHub for Windows">
|
|
||||||
<span class="octicon octicon-device-desktop"></span> Open
|
|
||||||
</a>
|
|
||||||
<a class="minibutton disabled tooltipped leftwards" href="#"
|
|
||||||
title="You must be signed in to make or propose changes">Edit</a>
|
|
||||||
<a href="/mikeobrien/HidLibrary/raw/master/LICENSE" class="button minibutton " id="raw-url">Raw</a>
|
|
||||||
<a href="/mikeobrien/HidLibrary/blame/master/LICENSE" class="button minibutton ">Blame</a>
|
|
||||||
<a href="/mikeobrien/HidLibrary/commits/master/LICENSE" class="button minibutton " rel="nofollow">History</a>
|
|
||||||
</div><!-- /.button-group -->
|
|
||||||
<a class="minibutton danger disabled empty-icon tooltipped leftwards" href="#"
|
|
||||||
title="You must be signed in to make or propose changes">
|
|
||||||
Delete
|
|
||||||
</a>
|
|
||||||
</div><!-- /.actions -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="blob-wrapper data type-text js-blob-data">
|
|
||||||
<table class="file-code file-diff">
|
|
||||||
<tr class="file-code-line">
|
|
||||||
<td class="blob-line-nums">
|
|
||||||
<span id="L1" rel="#L1">1</span>
|
|
||||||
<span id="L2" rel="#L2">2</span>
|
|
||||||
<span id="L3" rel="#L3">3</span>
|
|
||||||
<span id="L4" rel="#L4">4</span>
|
|
||||||
<span id="L5" rel="#L5">5</span>
|
|
||||||
<span id="L6" rel="#L6">6</span>
|
|
||||||
<span id="L7" rel="#L7">7</span>
|
|
||||||
<span id="L8" rel="#L8">8</span>
|
|
||||||
<span id="L9" rel="#L9">9</span>
|
|
||||||
<span id="L10" rel="#L10">10</span>
|
|
||||||
<span id="L11" rel="#L11">11</span>
|
|
||||||
<span id="L12" rel="#L12">12</span>
|
|
||||||
<span id="L13" rel="#L13">13</span>
|
|
||||||
<span id="L14" rel="#L14">14</span>
|
|
||||||
<span id="L15" rel="#L15">15</span>
|
|
||||||
<span id="L16" rel="#L16">16</span>
|
|
||||||
<span id="L17" rel="#L17">17</span>
|
|
||||||
<span id="L18" rel="#L18">18</span>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td class="blob-line-code">
|
|
||||||
<div class="code-body highlight"><pre><div class='line' id='LC1'>Copyright (c) 2010 Ultraviolet Catastrophe</div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'>Permission is hereby granted, free of charge, to any person obtaining a copy </div><div class='line' id='LC4'>of this software and associated documentation files (the "Software"), to deal </div><div class='line' id='LC5'>in the Software without restriction, including without limitation the rights </div><div class='line' id='LC6'>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell </div><div class='line' id='LC7'>copies of the Software, and to permit persons to whom the Software is furnished </div><div class='line' id='LC8'>to do so, subject to the following conditions:</div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'>The above copyright notice and this permission notice shall be included in all </div><div class='line' id='LC11'>copies or substantial portions of the Software.</div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, </div><div class='line' id='LC14'>INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A </div><div class='line' id='LC15'>PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT </div><div class='line' id='LC16'>HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION </div><div class='line' id='LC17'>OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE </div><div class='line' id='LC18'>SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</div></pre></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="#jump-to-line" rel="facebox[.linejump]" data-hotkey="l" class="js-jump-to-line" style="display:none">Jump to Line</a>
|
|
||||||
<div id="jump-to-line" style="display:none">
|
|
||||||
<form accept-charset="UTF-8" class="js-jump-to-line-form">
|
|
||||||
<input class="linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" autofocus>
|
|
||||||
<button type="submit" class="button">Go</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- /.repo-container -->
|
|
||||||
<div class="modal-backdrop"></div>
|
|
||||||
</div><!-- /.container -->
|
|
||||||
</div><!-- /.site -->
|
|
||||||
|
|
||||||
|
|
||||||
</div><!-- /.wrapper -->
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="site-footer">
|
|
||||||
<ul class="site-footer-links right">
|
|
||||||
<li><a href="https://status.github.com/">Status</a></li>
|
|
||||||
<li><a href="http://developer.github.com">API</a></li>
|
|
||||||
<li><a href="http://training.github.com">Training</a></li>
|
|
||||||
<li><a href="http://shop.github.com">Shop</a></li>
|
|
||||||
<li><a href="/blog">Blog</a></li>
|
|
||||||
<li><a href="/about">About</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<a href="/">
|
|
||||||
<span class="mega-octicon octicon-mark-github" title="GitHub"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="site-footer-links">
|
|
||||||
<li>© 2014 <span title="0.02103s from github-fe124-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
|
|
||||||
<li><a href="/site/terms">Terms</a></li>
|
|
||||||
<li><a href="/site/privacy">Privacy</a></li>
|
|
||||||
<li><a href="/security">Security</a></li>
|
|
||||||
<li><a href="/contact">Contact</a></li>
|
|
||||||
</ul>
|
|
||||||
</div><!-- /.site-footer -->
|
|
||||||
</div><!-- /.container -->
|
|
||||||
|
|
||||||
|
|
||||||
<div class="fullscreen-overlay js-fullscreen-overlay" id="fullscreen_overlay">
|
|
||||||
<div class="fullscreen-container js-fullscreen-container">
|
|
||||||
<div class="textarea-wrap">
|
|
||||||
<textarea name="fullscreen-contents" id="fullscreen-contents" class="js-fullscreen-contents" placeholder="" data-suggester="fullscreen_suggester"></textarea>
|
|
||||||
<div class="suggester-container">
|
|
||||||
<div class="suggester fullscreen-suggester js-navigation-container" id="fullscreen_suggester"
|
|
||||||
data-url="/mikeobrien/HidLibrary/suggestions/commit">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="fullscreen-sidebar">
|
|
||||||
<a href="#" class="exit-fullscreen js-exit-fullscreen tooltipped leftwards" title="Exit Zen Mode">
|
|
||||||
<span class="mega-octicon octicon-screen-normal"></span>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="theme-switcher js-theme-switcher tooltipped leftwards"
|
|
||||||
title="Switch themes">
|
|
||||||
<span class="octicon octicon-color-mode"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="ajax-error-message" class="flash flash-error">
|
|
||||||
<span class="octicon octicon-alert"></span>
|
|
||||||
<a href="#" class="octicon octicon-remove-close close ajax-error-dismiss"></a>
|
|
||||||
Something went wrong with that request. Please try again.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -74,10 +74,10 @@ namespace DS4Windows
|
|||||||
static internal extern IntPtr CreateEvent(ref SECURITY_ATTRIBUTES securityAttributes, int bManualReset, int bInitialState, string lpName);
|
static internal extern IntPtr CreateEvent(ref SECURITY_ATTRIBUTES securityAttributes, int bManualReset, int bInitialState, string lpName);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
static internal extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
|
static internal extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, uint dwFlagsAndAttributes, int hTemplateFile);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
internal static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, Int32 hTemplateFile);
|
internal static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, Int32 hTemplateFile);
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
static internal extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
|
static internal extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using Microsoft.Win32.TaskScheduler;
|
||||||
|
|
||||||
namespace DS4Windows
|
namespace DS4Windows
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ namespace DS4Windows
|
|||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
//Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("he");
|
//Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("he");
|
||||||
for (int i = 0; i < args.Length; i++)
|
for (int i = 0, argsLen = args.Length; i < argsLen; i++)
|
||||||
{
|
{
|
||||||
string s = args[i];
|
string s = args[i];
|
||||||
if (s == "driverinstall" || s == "-driverinstall")
|
if (s == "driverinstall" || s == "-driverinstall")
|
||||||
@ -58,8 +59,21 @@ namespace DS4Windows
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (s == "runtask" || s == "-runtask")
|
||||||
|
{
|
||||||
|
TaskService ts = new TaskService();
|
||||||
|
Task tasker = ts.FindTask("RunDS4Windows");
|
||||||
|
if (tasker != null)
|
||||||
|
{
|
||||||
|
tasker.Run("");
|
||||||
|
}
|
||||||
|
|
||||||
|
Environment.ExitCode = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.LowLatency;
|
System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.LowLatency;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.High;
|
Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.High;
|
||||||
@ -68,6 +82,7 @@ namespace DS4Windows
|
|||||||
{
|
{
|
||||||
// Ignore problems raising the priority.
|
// Ignore problems raising the priority.
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// another instance is already running if OpenExsting succeeds.
|
// another instance is already running if OpenExsting succeeds.
|
||||||
@ -77,6 +92,7 @@ namespace DS4Windows
|
|||||||
return; // return immediatly.
|
return; // return immediatly.
|
||||||
}
|
}
|
||||||
catch { /* don't care about errors */ }
|
catch { /* don't care about errors */ }
|
||||||
|
|
||||||
// Create the Event handle
|
// Create the Event handle
|
||||||
threadComEvent = new EventWaitHandle(false, EventResetMode.AutoReset, SingleAppComEventName);
|
threadComEvent = new EventWaitHandle(false, EventResetMode.AutoReset, SingleAppComEventName);
|
||||||
CreateInterAppComThread();
|
CreateInterAppComThread();
|
||||||
|
@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("DS4Windows")]
|
[assembly: AssemblyProduct("DS4Windows")]
|
||||||
[assembly: AssemblyCopyright("Copyright © Scarlet.Crush Productions 2012, 2013; InhexSTER, HecticSeptic, electrobrains 2013, 2014; Jays2Kings 2013, 2014, 2015")]
|
[assembly: AssemblyCopyright("Copyright © Scarlet.Crush Productions 2012, 2013; InhexSTER, HecticSeptic, electrobrains 2013, 2014; Jays2Kings 2013, 2014, 2015, 2016; Ryochan7 2017")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.4.52")]
|
[assembly: AssemblyVersion("1.4.69")]
|
||||||
[assembly: AssemblyFileVersion("1.4.52")]
|
[assembly: AssemblyFileVersion("1.4.69")]
|
||||||
|
22
DS4Windows/Properties/Resources.Designer.cs
generated
@ -293,7 +293,7 @@ namespace DS4Windows.Properties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Color by Battey %.
|
/// Looks up a localized string similar to Color by Battery %.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ColorByBattery {
|
internal static string ColorByBattery {
|
||||||
get {
|
get {
|
||||||
@ -412,7 +412,7 @@ namespace DS4Windows.Properties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Dim by Battey %.
|
/// Looks up a localized string similar to Dim by Battery %.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string DimByBattery {
|
internal static string DimByBattery {
|
||||||
get {
|
get {
|
||||||
@ -1573,6 +1573,15 @@ namespace DS4Windows.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Tells Windows to start DS4Windows after login.
|
||||||
|
/// </summary>
|
||||||
|
internal static string RunAtStartup {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("RunAtStartup", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1945,6 +1954,15 @@ namespace DS4Windows.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to You need to run DS4Windows as the Administrator in order to activate this mode..
|
||||||
|
/// </summary>
|
||||||
|
internal static string UACTask {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("UACTask", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Unassigned.
|
/// Looks up a localized string similar to Unassigned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -263,7 +263,7 @@
|
|||||||
<value>Charging: *number*%</value>
|
<value>Charging: *number*%</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ColorByBattery" xml:space="preserve">
|
<data name="ColorByBattery" xml:space="preserve">
|
||||||
<value>Color by Battey %</value>
|
<value>Color by Battery %</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Connecting" xml:space="preserve">
|
<data name="Connecting" xml:space="preserve">
|
||||||
<value>Connecting...</value>
|
<value>Connecting...</value>
|
||||||
@ -296,7 +296,7 @@
|
|||||||
<value>Delete Profile?</value>
|
<value>Delete Profile?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DimByBattery" xml:space="preserve">
|
<data name="DimByBattery" xml:space="preserve">
|
||||||
<value>Dim by Battey %</value>
|
<value>Dim by Battery %</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Disconnected" xml:space="preserve">
|
<data name="Disconnected" xml:space="preserve">
|
||||||
<value>Disconnected</value>
|
<value>Disconnected</value>
|
||||||
@ -775,4 +775,10 @@
|
|||||||
<data name="SelectMacro" xml:space="preserve">
|
<data name="SelectMacro" xml:space="preserve">
|
||||||
<value>Select a macro</value>
|
<value>Select a macro</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="RunAtStartup" xml:space="preserve">
|
||||||
|
<value>Tells Windows to start DS4Windows after login</value>
|
||||||
|
</data>
|
||||||
|
<data name="UACTask" xml:space="preserve">
|
||||||
|
<value>You need to run DS4Windows as the Administrator in order to activate this mode.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 573 B |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 928 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 350 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 791 B |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 859 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 561 B |
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 527 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 575 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 520 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 500 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 500 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 519 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 520 B |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 586 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 1010 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 550 B |
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 125 KiB |