Merge pull request #2 from Ryochan7/jay

Another attempt at keeping an experimental branch up to date with Ryochan7's fork
This commit is contained in:
Yuki-nyan 2017-05-12 00:36:10 +01:00 committed by GitHub
commit 81b58fd90a
126 changed files with 17393 additions and 12211 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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)
{ {

View 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];
}
}
}

View File

@ -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);
} }
} }
} }

View File

@ -1,7 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DS4Windows namespace DS4Windows
{ {

File diff suppressed because it is too large Load Diff

View File

@ -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();
} }

View File

@ -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;

View File

@ -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];

View File

@ -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;
} }

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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>();

View File

@ -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;
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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");
} }
} }
} }

View 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);
}
}

View File

@ -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)
{ {
@ -610,41 +885,97 @@ namespace DS4Windows
string[] sbytes = Mac.Split(':'); string[] sbytes = Mac.Split(':');
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
//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;
}
} }
} }

View File

@ -23,10 +23,11 @@ namespace DS4Windows
{ {
deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.Length - 1); deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.Length - 1);
} }
return deviceInstanceId; return deviceInstanceId;
} }
//enumerates ds4 controllers in the system // enumerates ds4 controllers in the system
public static void findControllers() public static void findControllers()
{ {
lock (Devices) lock (Devices)
@ -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)

View File

@ -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
{ {

View File

@ -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;
}
} }
} }

View File

@ -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;
}
} }
} }

View File

@ -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

View File

@ -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.

View File

@ -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)

View 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.

View File

@ -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&amp;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&amp;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&amp;r=x&amp;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&amp;r=x&amp;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 &quot;Software&quot;), 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 &quot;AS IS&quot;, 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&hellip;" 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>&copy; 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>

View File

@ -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);

View File

@ -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();

View File

@ -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")]

View File

@ -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>

View File

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 928 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Some files were not shown because too many files have changed in this diff Show More