Merged Electrobrains DS4Windows, Hectic's options, imporved custom mapping

This commit is contained in:
jays2kings 2014-03-29 01:29:08 -04:00
parent df43fd0d74
commit 768fdd0260
31 changed files with 895 additions and 801 deletions

View File

@ -13,10 +13,14 @@ namespace DS4Control
private DS4State s = new DS4State();
private bool buttonLock; // Toggled with a two-finger touchpad push, we accept and absorb button input without any fingers on a touchpad, helping with drag-and-drop.
private DS4Device dev = null;
private readonly MouseCursor cursor;
private readonly MouseWheel wheel;
public ButtonMouse(int deviceID, DS4Device d)
{
deviceNum = deviceID;
dev = d;
cursor = new MouseCursor(deviceNum);
wheel = new MouseWheel(deviceNum);
}
public override string ToString()
@ -26,56 +30,36 @@ namespace DS4Control
public void touchesMoved(object sender, TouchpadEventArgs arg)
{
if (arg.touches.Length == 1)
{
double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0;
int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX));
int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY));
InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY);
}
else if (arg.touches.Length == 2)
{
Touch lastT0 = arg.touches[0].previousTouch;
Touch lastT1 = arg.touches[1].previousTouch;
Touch T0 = arg.touches[0];
Touch T1 = arg.touches[1];
//mouse wheel 120 == 1 wheel click according to Windows API
int lastMidX = (lastT0.hwX + lastT1.hwX) / 2, lastMidY = (lastT0.hwY + lastT1.hwY) / 2,
currentMidX = (T0.hwX + T1.hwX) / 2, currentMidY = (T0.hwY + T1.hwY) / 2; // XXX Will controller swap touch IDs?
double coefficient = Global.getScrollSensitivity(deviceNum);
// Adjust for touch distance: "standard" distance is 960 pixels, i.e. half the width. Scroll farther if fingers are farther apart, and vice versa, in linear proportion.
double touchXDistance = T1.hwX - T0.hwX, touchYDistance = T1.hwY - T0.hwY, touchDistance = Math.Sqrt(touchXDistance * touchXDistance + touchYDistance * touchYDistance);
coefficient *= touchDistance / 960.0;
InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX)));
}
synthesizeMouseButtons(false);
}
public void untouched()
{
if (buttonLock)
synthesizeMouseButtons(false);
else
cursor.touchesMoved(arg);
wheel.touchesMoved(arg);
dev.getCurrentState(s);
synthesizeMouseButtons(false);
}
public void touchUnchanged(object sender, EventArgs unused)
{
dev.getCurrentState(s);
if (buttonLock || s.Touch1 || s.Touch2)
synthesizeMouseButtons(false);
}
public void touchesBegan(object sender, TouchpadEventArgs arg)
{
cursor.touchesBegan(arg);
wheel.touchesBegan(arg);
dev.getCurrentState(s);
synthesizeMouseButtons(false);
}
public void touchesEnded(object sender, TouchpadEventArgs arg)
{
dev.getCurrentState(s);
if (!buttonLock)
synthesizeMouseButtons(true);
else
dev.getCurrentState(s);
}
private void synthesizeMouseButtons(bool justRelease)
{
dev.getCurrentState(s);
bool previousLeftButton = leftButton, previousMiddleButton = middleButton, previousRightButton = rightButton;
if (justRelease)
{
@ -113,17 +97,20 @@ namespace DS4Control
{
if (upperDown)
{
mapTouchPad(DS4Controls.TouchUpper, true);
if (!mapTouchPad(DS4Controls.TouchUpper, true))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP);
upperDown = false;
}
if (leftDown)
{
mapTouchPad(DS4Controls.TouchButton, true);
if (!mapTouchPad(DS4Controls.TouchButton, true))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP);
leftDown = false;
}
if (rightDown)
{
mapTouchPad(DS4Controls.TouchMulti, true);
if (!mapTouchPad(DS4Controls.TouchMulti, true))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP);
rightDown = false;
}
dev.setRumble(0, 0);
@ -134,7 +121,8 @@ namespace DS4Control
byte leftRumble, rightRumble;
if (arg.touches == null) //No touches, finger on upper portion of touchpad
{
mapTouchPad(DS4Controls.TouchUpper, false);
if (!mapTouchPad(DS4Controls.TouchUpper, false))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN);
upperDown = true;
leftRumble = rightRumble = 127;
}
@ -142,23 +130,23 @@ namespace DS4Control
{
if (isLeft(arg.touches[0]))
{
mapTouchPad(DS4Controls.TouchButton, false);
if (!mapTouchPad(DS4Controls.TouchButton, false))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN);
leftDown = true;
leftRumble = 63;
rightRumble = 0;
}
else if (isRight(arg.touches[0]))
{
mapTouchPad(DS4Controls.TouchMulti, false);
if (!mapTouchPad(DS4Controls.TouchMulti, false))
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN);
rightDown = true;
leftRumble = 0;
rightRumble = 63;
}
else
{
mapTouchPad(DS4Controls.TouchUpper, false); // ambiguous = same as upper
upperDown = true;
leftRumble = rightRumble = 127;
leftRumble = rightRumble = 0; // Ignore ambiguous pushes.
}
}
else

View File

@ -5,7 +5,7 @@ using System.Text;
using DS4Library;
namespace DS4Control
{
public class Control: IDisposable
public class Control
{
X360Device x360Bus;
DS4Device[] DS4Controllers = new DS4Device[4];
@ -38,6 +38,17 @@ namespace DS4Control
}
}
private void WarnExclusiveModeFailure(DS4Device device)
{
if (DS4Devices.isExclusiveMode && !device.IsExclusive)
{
String message = "Warning: Could not open DS4 " + device.MacAddress + " exclusively. " +
"You must quit other applications like Steam, Uplay before activating the 'Hide DS4 Controller' option.";
LogDebug(message);
Log.LogToTray(message);
}
}
public bool Start()
{
if (x360Bus.Open() && x360Bus.Start())
@ -53,33 +64,29 @@ namespace DS4Control
int ind = 0;
foreach (DS4Device device in devices)
{
LogDebug("Found Controller: " + device.MacAddress);
if (device.MacAddress == "00:00:00:00:00:00")
{
LogDebug("WARNING: If you are seing all zeroes as controller ID");
LogDebug("You might be running not fully supported BT dongle");
LogDebug("Only some basic functionality is enabled");
}
LogDebug("Found Controller: " + device.MacAddress + " (" + device.ConnectionType + ")");
WarnExclusiveModeFailure(device);
DS4Controllers[ind] = device;
device.Removal += this.On_DS4Removal;
TPadModeSwitcher m_switcher = new TPadModeSwitcher(device, ind);
m_switcher.Debug += OnDebug;
m_switcher.setMode(Global.getTouchEnabled(ind) ? 1 : 0);
modeSwitcher[ind] = m_switcher;
DS4Color color = Global.loadColor(ind);
device.LightBarColor = color;
x360Bus.Plugin(ind + 1);
device.Report += this.On_Report;
m_switcher.setMode(Global.getTouchEnabled(ind) ? 1 : 0);
ind++;
LogDebug("Controller: " + device.MacAddress + " is ready to use");
Log.LogToTray("Controller: " + device.MacAddress + " is ready to use");
if (ind >= 4)
if (ind >= 4) // out of Xinput devices!
break;
}
}
catch (Exception e)
{
LogDebug(e.Message);
Log.LogToTray(e.Message);
}
running = true;
@ -106,19 +113,28 @@ namespace DS4Control
LogDebug("Stopping DS4 Controllers");
DS4Devices.stopControllers();
LogDebug("Stopped DS4 Tool");
Global.ControllerStatusChanged(this);
}
return true;
}
private volatile bool justRemoved; // inhibits HotPlug temporarily when a device is being torn down
public bool HotPlug()
{
if (running)
{
if (justRemoved)
{
justRemoved = false;
System.Threading.Thread.Sleep(200);
}
DS4Devices.findControllers();
IEnumerable<DS4Device> devices = DS4Devices.getDS4Controllers();
foreach (DS4Device device in devices)
{
if (device.IsDisconnecting)
continue;
if (((Func<bool>)delegate
{
for (Int32 Index = 0; Index < DS4Controllers.Length; Index++)
@ -131,15 +147,19 @@ namespace DS4Control
for (Int32 Index = 0; Index < DS4Controllers.Length; Index++)
if (DS4Controllers[Index] == null)
{
LogDebug("Found Controller: " + device.MacAddress + " (" + device.ConnectionType + ")");
WarnExclusiveModeFailure(device);
DS4Controllers[Index] = device;
device.Removal += this.On_DS4Removal;
TPadModeSwitcher m_switcher = new TPadModeSwitcher(device, Index);
m_switcher.Debug += OnDebug;
modeSwitcher[Index] = m_switcher;
m_switcher.setMode(Global.getTouchEnabled(Index) ? 1 : 0);
device.LightBarColor = Global.loadColor(Index);
device.Report += this.On_Report;
x360Bus.Plugin(Index + 1);
m_switcher.setMode(Global.getTouchEnabled(Index) ? 1 : 0);
LogDebug("Controller: " + device.MacAddress + " is ready to use");
Log.LogToTray("Controller: " + device.MacAddress + " is ready to use");
break;
}
}
@ -152,7 +172,21 @@ namespace DS4Control
if (DS4Controllers[index] != null)
{
DS4Device d = DS4Controllers[index];
return d.MacAddress + ", Battery = " + d.Battery + "%," + " Touchpad = " + modeSwitcher[index].ToString() + " (" + d.ConnectionType + ")";
if (!d.IsAlive())
return null; // awaiting the first battery charge indication
String battery;
if (d.Charging)
{
if (d.Battery >= 100)
battery = "fully-charged";
else
battery = "charging at ~" + d.Battery + "%";
}
else
{
battery = "draining at ~" + d.Battery + "%";
}
return d.MacAddress + " (" + d.ConnectionType + "), Battery is " + battery + ", Touchpad in " + modeSwitcher[index].ToString();
}
else
return null;
@ -168,11 +202,13 @@ namespace DS4Control
ind = i;
if (ind != -1)
{
justRemoved = true;
x360Bus.Unplug(ind + 1);
LogDebug("Controller " + device.MacAddress + " was removed or lost connection");
Log.LogToTray("Controller " + device.MacAddress + " was removed or lost connection");
DS4Controllers[ind] = null;
modeSwitcher[ind] = null;
Global.ControllerStatusChanged(this);
}
}
@ -189,36 +225,39 @@ namespace DS4Control
if (ind!=-1)
{
DS4State cState;
device.getExposedState(ExposedState[ind], CurrentState[ind]);
DS4State cState = CurrentState[ind];
device.getPreviousState(PreviousState[ind]);
DS4State pState = PreviousState[ind];
if (modeSwitcher[ind].getCurrentMode() is ButtonMouse)
{
device.getExposedState(ExposedState[ind], CurrentState[ind]);
cState = CurrentState[ind];
ButtonMouse mode = (ButtonMouse)modeSwitcher[ind].getCurrentMode();
if (!cState.Touch1 && !cState.Touch2 && !cState.TouchButton)
mode.untouched();
cState = mode.getDS4State();
// XXX so disgusting, need to virtualize this again
mode.getDS4State().Copy(cState);
}
else
{
device.getExposedState(ExposedState[ind], CurrentState[ind]);
cState = CurrentState[ind];
}
device.getPreviousState(PreviousState[ind]);
DS4State pState = PreviousState[ind];
CheckForHotkeys(ind, cState, pState);
DS4LightBar.updateBatteryStatus(cState.Battery, device, ind);
if (Global.getHasCustomKeysorButtons(ind))
{
Mapping.mapButtons(cState, pState, MappedState[ind]);
cState = MappedState[ind];
}
// Update the GUI/whatever.
DS4LightBar.updateLightBar(device, ind);
if (pState.Battery != cState.Battery)
Global.ControllerStatusChanged(this);
x360Bus.Parse(cState, processingData[ind].Report, ind);
// We push the translated Xinput state, and simultaneously we
// pull back any possible rumble data coming from Xinput consumers.
if (x360Bus.Report(processingData[ind].Report, processingData[ind].Rumble))
{
Byte Big = (Byte)(processingData[ind].Rumble[3]);
@ -272,16 +311,5 @@ namespace DS4Control
heavyBoosted = 255;
DS4Controllers[deviceNum].setRumble((byte)lightBoosted, (byte)heavyBoosted);
}
public DS4Device getDS4Controller(int deviceNum)
{
return DS4Controllers[deviceNum];
}
//CA1001 TypesThatOwnDisposableFieldsShouldBeDisposable
public void Dispose()
{
x360Bus.Dispose();
}
}
}

View File

@ -9,9 +9,14 @@ namespace DS4Control
public class MouseCursorOnly : ITouchpadBehaviour
{
private int deviceNum;
private readonly MouseCursor cursor;
private readonly MouseWheel wheel;
public MouseCursorOnly(int deviceID)
{
deviceNum = deviceID;
cursor = new MouseCursor(deviceNum);
wheel = new MouseWheel(deviceNum);
}
public override string ToString()
@ -21,16 +26,15 @@ namespace DS4Control
public void touchesMoved(object sender, TouchpadEventArgs arg)
{
if (arg.touches.Length == 1)
{
double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0;
int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX));
int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY));
InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY);
}
cursor.touchesMoved(arg);
wheel.touchesMoved(arg);
}
public void touchesBegan(object sender, TouchpadEventArgs arg) { }
public void touchesBegan(object sender, TouchpadEventArgs arg)
{
cursor.touchesBegan(arg);
wheel.touchesBegan(arg);
}
public void touchesEnded(object sender, TouchpadEventArgs arg) { }
@ -38,6 +42,6 @@ namespace DS4Control
public void touchButtonDown(object sender, TouchpadEventArgs arg) { }
public void untouched(object sender, TouchpadEventArgs nullUnused) { }
public void touchUnchanged(object sender, EventArgs unused) { }
}
}

View File

@ -45,6 +45,8 @@
<Compile Include="Log.cs" />
<Compile Include="CursorOnlyMode.cs" />
<Compile Include="DragMouse.cs" />
<Compile Include="MouseCursor.cs" />
<Compile Include="MouseWheel.cs" />
<Compile Include="TouchpadDisabled.cs" />
<Compile Include="TPadModeSwitcher.cs" />
<Compile Include="DS4LightBar.cs" />

View File

@ -9,7 +9,7 @@ namespace DS4Control
{
private readonly static byte[/* Light On duration */, /* Light Off duration */] BatteryIndicatorDurations =
{
{ 255, 255 }, // 0 doesn't happen
{ 0, 0 }, // 0 is for "charging" OR anything sufficiently-"charged"
{ 28, 252 },
{ 56, 224 },
{ 84, 196 },
@ -18,46 +18,77 @@ namespace DS4Control
{ 168, 112 },
{ 196, 84 },
{ 224, 56}, // on 80% of the time at 80, etc.
{ 252, 28 }, // on 90% of the time at 90
{ 0, 0 } // no flash at 100
{ 252, 28 } // on 90% of the time at 90
};
static double[] counters = new double[4];
public static void updateBatteryStatus(int battery, DS4Device device, int deviceNum)
public static void updateLightBar(DS4Device device, int deviceNum)
{
DS4Color color;
if (Global.getLedAsBatteryIndicator(deviceNum))
{
byte[] fullColor = {
Global.loadColor(deviceNum).red,
Global.loadColor(deviceNum).green,
Global.loadColor(deviceNum).blue
if (device.Charging == false || device.Battery >= 100) // when charged, don't show the charging animation
{
DS4Color fullColor = new DS4Color
{
red = Global.loadColor(deviceNum).red,
green = Global.loadColor(deviceNum).green,
blue = Global.loadColor(deviceNum).blue
};
// New Setting
DS4Color color = Global.loadLowColor(deviceNum);
byte[] lowColor = { color.red, color.green, color.blue };
uint ratio = (uint)battery;
color = Global.getTransitionedColor(lowColor, fullColor, ratio);
device.LightBarColor = color;
color = Global.loadLowColor(deviceNum);
DS4Color lowColor = new DS4Color
{
red = color.red,
green = color.green,
blue = color.blue
};
color = Global.getTransitionedColor(lowColor, fullColor, (uint)device.Battery);
}
else // Display rainbow when charging.
{
counters[deviceNum]++;
double theta = Math.PI * 2.0 * counters[deviceNum] / 1800.0;
const double brightness = Math.PI; // small brightness numbers (far from max 128.0) mean less light steps and slower output reports; also, the lower the brightness the faster you can charge
color = new DS4Color
{
red = (byte)(brightness * Math.Sin(theta) + brightness - 0.5),
green = (byte)(brightness * Math.Sin(theta + (Math.PI * 2.0) / 3.0) + brightness - 0.5),
blue = (byte)(brightness * Math.Sin(theta + 2.0 * (Math.PI * 2.0) / 3.0) + brightness - 0.5)
};
}
}
else
{
DS4Color color = Global.loadColor(deviceNum);
device.LightBarColor = color;
color = Global.loadColor(deviceNum);
}
DS4HapticState haptics = new DS4HapticState
{
LightBarColor = color
};
if (haptics.IsLightBarSet())
{
if (Global.getFlashWhenLowBattery(deviceNum))
{
device.LightBarOnDuration = BatteryIndicatorDurations[battery / 10, 0];
device.LightBarOffDuration = BatteryIndicatorDurations[battery / 10, 1];
int level = device.Battery / 10;
if (level >= 10)
level = 0; // all values of ~0% or >~100% are rendered the same
haptics.LightBarFlashDurationOn = BatteryIndicatorDurations[level, 0];
haptics.LightBarFlashDurationOff = BatteryIndicatorDurations[level, 1];
}
else
{
device.LightBarOffDuration = device.LightBarOnDuration = 0;
haptics.LightBarFlashDurationOff = haptics.LightBarFlashDurationOn = 0;
}
}
else
{
haptics.LightBarExplicitlyOff = true;
}
device.pushHapticState(haptics);
}
}
}

View File

@ -8,10 +8,12 @@ using System.Threading;
namespace DS4Control
{
class DragMouse: Mouse, IDisposable
class DragMouse: Mouse
{
protected bool leftClick = false;
protected Timer timer;
private readonly MouseCursor cursor;
private readonly MouseWheel wheel;
public DragMouse(int deviceID):base(deviceID)
{
@ -22,6 +24,8 @@ namespace DS4Control
}, null,
System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
cursor = new MouseCursor(deviceNum);
wheel = new MouseWheel(deviceNum);
}
public override string ToString()
@ -29,44 +33,9 @@ namespace DS4Control
return "Drag Mode";
}
public override void touchesMoved(object sender, TouchpadEventArgs arg)
{
if (arg.touches.Length == 1)
{
double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0;
int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX));
int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY));
InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY);
}
else if (arg.touches.Length == 2 && !leftClick)
{
Touch lastT0 = arg.touches[0].previousTouch;
Touch lastT1 = arg.touches[1].previousTouch;
Touch T0 = arg.touches[0];
Touch T1 = arg.touches[1];
//mouse wheel 120 == 1 wheel click according to Windows API
int lastMidX = (lastT0.hwX + lastT1.hwX) / 2, lastMidY = (lastT0.hwY + lastT1.hwY) / 2,
currentMidX = (T0.hwX + T1.hwX) / 2, currentMidY = (T0.hwY + T1.hwY) / 2; // XXX Will controller swap touch IDs?
double coefficient = Global.getScrollSensitivity(deviceNum);
// Adjust for touch distance: "standard" distance is 960 pixels, i.e. half the width. Scroll farther if fingers are farther apart, and vice versa, in linear proportion.
double touchXDistance = T1.hwX - T0.hwX, touchYDistance = T1.hwY - T0.hwY, touchDistance = Math.Sqrt(touchXDistance * touchXDistance + touchYDistance * touchYDistance);
coefficient *= touchDistance / 960.0;
InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX)));
}
else
{
double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0;
int mouseDeltaX = (int)(sensitivity * (arg.touches[1].deltaX));
int mouseDeltaY = (int)(sensitivity * (arg.touches[1].deltaY));
InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY);
}
}
public override void touchesBegan(object sender, TouchpadEventArgs arg)
{
pastTime = arg.timeStamp;
firstTouch = arg.touches[0];
base.touchesBegan(sender, arg);
if (leftClick)
timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
}
@ -139,11 +108,5 @@ namespace DS4Control
leftClick = true;
}
}
//CA1001 TypesThatOwnDisposableFieldsShouldBeDisposable
public void Dispose()
{
timer.Dispose();
}
}
}

View File

@ -12,5 +12,6 @@ namespace DS4Control
void touchButtonUp(object sender, TouchpadEventArgs arg);
void touchButtonDown(object sender, TouchpadEventArgs arg);
void touchesEnded(object sender, TouchpadEventArgs arg);
void touchUnchanged(object sender, EventArgs unused);
}
}

View File

@ -40,8 +40,6 @@ namespace DS4Control
MappedState.LY = 127;
MappedState.RX = 127;
MappedState.RY = 127;
int MouseDeltaX = 0;
int MouseDeltaY = 0;
foreach (KeyValuePair<DS4Controls, X360Controls> customButton in Global.getCustomButtons())
{
@ -183,34 +181,6 @@ namespace DS4Control
else if (PrevOn && !CurOn)
InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP);
break;
case X360Controls.MouseUp:
if (MouseDeltaY == 0)
{
MouseDeltaY = calculateRelativeMouseDelta(customButton.Key, cState, prevState);
MouseDeltaY = -Math.Abs(MouseDeltaY);
}
break;
case X360Controls.MouseDown:
if (MouseDeltaY == 0)
{
MouseDeltaY = calculateRelativeMouseDelta(customButton.Key, cState, prevState);
MouseDeltaY = Math.Abs(MouseDeltaY);
}
break;
case X360Controls.MouseLeft:
if (MouseDeltaX == 0)
{
MouseDeltaX = calculateRelativeMouseDelta(customButton.Key, cState, prevState);
MouseDeltaX = -Math.Abs(MouseDeltaX);
}
break;
case X360Controls.MouseRight:
if (MouseDeltaX == 0)
{
MouseDeltaX = calculateRelativeMouseDelta(customButton.Key, cState, prevState);
MouseDeltaX = Math.Abs(MouseDeltaX);
}
break;
case X360Controls.Unbound:
resetToDefaultValue(customButton.Key, MappedState);
break;
@ -225,54 +195,6 @@ namespace DS4Control
MappedState.RX = cState.RX;
if (!RY)
MappedState.RY = cState.RY;
InputMethods.MoveCursorBy(MouseDeltaX, MouseDeltaY);
}
private static int calculateRelativeMouseDelta(DS4Controls control, DS4State cState, DS4State pState)
{
int axisVal = -1;
int DEAD_ZONE = 10;
float SPEED_MULTIPLIER = 0.000004f;
bool positive = false;
float deltaTime = cState.ReportTimeStamp.Ticks - pState.ReportTimeStamp.Ticks;
switch (control)
{
case DS4Controls.LXNeg:
axisVal = cState.LX;
break;
case DS4Controls.LXPos:
positive = true;
axisVal = cState.LX;
break;
case DS4Controls.RXNeg:
axisVal = cState.RX;
break;
case DS4Controls.RXPos:
positive = true;
axisVal = cState.RX;
break;
case DS4Controls.LYNeg:
axisVal = cState.LY;
break;
case DS4Controls.LYPos:
positive = true;
axisVal = cState.LY;
break;
case DS4Controls.RYNeg:
axisVal = cState.RY;
break;
case DS4Controls.RYPos:
positive = true;
axisVal = cState.RY;
break;
}
axisVal = axisVal - 127;
int delta = 0;
if ( (!positive && axisVal < -DEAD_ZONE ) || (positive && axisVal > DEAD_ZONE))
{
delta = (int)(float) (axisVal * SPEED_MULTIPLIER * deltaTime);
}
return delta;
}
public static bool compare(byte b1, byte b2)

View File

@ -11,11 +11,15 @@ namespace DS4Control
protected DateTime pastTime;
protected Touch firstTouch;
protected int deviceNum;
private readonly MouseCursor cursor;
private readonly MouseWheel wheel;
protected bool rightClick = false;
public Mouse(int deviceID)
{
deviceNum = deviceID;
cursor = new MouseCursor(deviceNum);
wheel = new MouseWheel(deviceNum);
}
public override string ToString()
@ -25,39 +29,23 @@ namespace DS4Control
public virtual void touchesMoved(object sender, TouchpadEventArgs arg)
{
if (arg.touches.Length == 1)
{
double sensitivity = Global.getTouchSensitivity(deviceNum) / 100.0;
int mouseDeltaX = (int)(sensitivity * (arg.touches[0].deltaX));
int mouseDeltaY = (int)(sensitivity * (arg.touches[0].deltaY));
InputMethods.MoveCursorBy(mouseDeltaX, mouseDeltaY);
}
else if (arg.touches.Length == 2)
{
Touch lastT0 = arg.touches[0].previousTouch;
Touch lastT1 = arg.touches[1].previousTouch;
Touch T0 = arg.touches[0];
Touch T1 = arg.touches[1];
//mouse wheel 120 == 1 wheel click according to Windows API
int lastMidX = (lastT0.hwX + lastT1.hwX) / 2, lastMidY = (lastT0.hwY + lastT1.hwY) / 2,
currentMidX = (T0.hwX + T1.hwX) / 2, currentMidY = (T0.hwY + T1.hwY) / 2; // XXX Will controller swap touch IDs?
double coefficient = Global.getScrollSensitivity(deviceNum);
// Adjust for touch distance: "standard" distance is 960 pixels, i.e. half the width. Scroll farther if fingers are farther apart, and vice versa, in linear proportion.
double touchXDistance = T1.hwX - T0.hwX, touchYDistance = T1.hwY - T0.hwY, touchDistance = Math.Sqrt(touchXDistance * touchXDistance + touchYDistance * touchYDistance);
coefficient *= touchDistance / 960.0;
InputMethods.MouseWheel((int)(coefficient * (lastMidY - currentMidY)), (int)(coefficient * (currentMidX - lastMidX)));
}
cursor.touchesMoved(arg);
wheel.touchesMoved(arg);
//Log.LogToGui("moved to " + arg.touches[0].hwX + "," + arg.touches[0].hwY);
}
public virtual void touchesBegan(object sender, TouchpadEventArgs arg)
{
cursor.touchesBegan(arg);
wheel.touchesBegan(arg);
pastTime = arg.timeStamp;
firstTouch = arg.touches[0];
//Log.LogToGui("began at " + arg.touches[0].hwX + "," + arg.touches[0].hwY);
}
public virtual void touchesEnded(object sender, TouchpadEventArgs arg)
{
//Log.LogToGui("ended at " + arg.touches[0].hwX + "," + arg.touches[0].hwY);
if (Global.getTapSensitivity(deviceNum) != 0)
{
DateTime test = arg.timeStamp;
@ -111,6 +99,8 @@ namespace DS4Control
}
}
public void touchUnchanged(object sender, EventArgs unused) { }
protected bool mapTouchPad(DS4Controls padControl, bool release = false)
{
ushort key = Global.getCustomKey(padControl);

View File

@ -12,8 +12,7 @@ namespace DS4Control
public enum DS4KeyType : byte { None = 0, ScanCode = 1, Repeat = 2 }; //Increment by exponents of 2*, starting at 2^0
public enum Ds3PadId : byte { None = 0xFF, One = 0x00, Two = 0x01, Three = 0x02, Four = 0x03, All = 0x04 };
public enum DS4Controls : byte { LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, L1, L2, L3, R1, R2, R3, Square, Triangle, Circle, Cross, DpadUp, DpadRight, DpadDown, DpadLeft, PS, TouchButton, TouchUpper, TouchMulti, Share, Options };
public enum X360Controls : byte { LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, LB, LT, LS, RB, RT, RS, X, Y, B, A, DpadUp, DpadRight, DpadDown, DpadLeft, Guide, Back, Start, LeftMouse, RightMouse, MiddleMouse, Unbound,
MouseLeft, MouseRight, MouseDown, MouseUp};
public enum X360Controls : byte { LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, LB, LT, LS, RB, RT, RS, X, Y, B, A, DpadUp, DpadRight, DpadDown, DpadLeft, Guide, Back, Start, LeftMouse, RightMouse, MiddleMouse, Unbound };
public class DebugEventArgs : EventArgs
{
@ -82,6 +81,13 @@ namespace DS4Control
protected static BackingStore m_Config = new BackingStore();
protected static Int32 m_IdleTimeout = 600000;
public static event EventHandler<EventArgs> ControllerStatusChange; // called when a controller is added/removed/battery or touchpad mode changes/etc.
public static void ControllerStatusChanged(object sender)
{
if (ControllerStatusChange != null)
ControllerStatusChange(sender, EventArgs.Empty);
}
public static DS4Color loadColor(int device)
{
DS4Color color = new DS4Color();
@ -327,22 +333,12 @@ namespace DS4Control
byte bdif = (byte)(bmax - bmin);
return (byte)(bmin + (bdif * ratio / 100));
}
public static DS4Color getTransitionedColor(byte[] c1, byte[] c2, uint ratio)
{
DS4Color color = new DS4Color();
color.red = 255;
color.green = 255;
color.blue = 255;
uint r = ratio % 101;
if (c1.Length != 3 || c2.Length != 3 || ratio < 0)
{
return color;
}
color.red = applyRatio(c1[0], c2[0], ratio);
color.green = applyRatio(c1[1], c2[1], ratio);
color.blue = applyRatio(c1[2], c2[2], ratio);
return color;
public static DS4Color getTransitionedColor(DS4Color c1, DS4Color c2, uint ratio)
{;
c1.red = applyRatio(c1.red, c2.red, ratio);
c1.green = applyRatio(c1.green, c2.green, ratio);
c1.blue = applyRatio(c1.blue, c2.blue, ratio);
return c1;
}
}
@ -655,10 +651,6 @@ namespace DS4Control
case "Click": return X360Controls.LeftMouse;
case "Right Click": return X360Controls.RightMouse;
case "Middle Click": return X360Controls.MiddleMouse;
case "Mouse Up": return X360Controls.MouseUp;
case "Mouse Down": return X360Controls.MouseDown;
case "Mouse Left": return X360Controls.MouseLeft;
case "Mouse Right": return X360Controls.MouseRight;
case "(Unbound)": return X360Controls.Unbound;
}

View File

@ -29,6 +29,7 @@ namespace DS4Control
device.Touchpad.TouchesBegan -= currentMode.touchesBegan;
device.Touchpad.TouchesMoved -= currentMode.touchesMoved;
device.Touchpad.TouchesEnded -= currentMode.touchesEnded;
device.Touchpad.TouchUnchanged -= currentMode.touchUnchanged;
setMode(ind);
}
@ -40,9 +41,11 @@ namespace DS4Control
device.Touchpad.TouchesBegan += tmode.touchesBegan;
device.Touchpad.TouchesMoved += tmode.touchesMoved;
device.Touchpad.TouchesEnded += tmode.touchesEnded;
device.Touchpad.TouchUnchanged += tmode.touchUnchanged;
currentTypeInd = ind;
LogDebug("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString());
Log.LogToTray("Touchpad mode for " + device.MacAddress + " is now " + tmode.ToString());
Global.ControllerStatusChanged(this);
}
public override string ToString()

View File

@ -25,6 +25,6 @@ namespace DS4Control
public void touchButtonDown(object sender, TouchpadEventArgs arg) { }
public void untouched(object sender, TouchpadEventArgs nullUnused) { }
public void touchUnchanged(object sender, EventArgs unused) { }
}
}

View File

@ -23,7 +23,28 @@ namespace DS4Library
public byte blue;
}
public enum ConnectionType : byte { USB, BT };
public enum ConnectionType : byte { BT, USB }; // Prioritize Bluetooth when both are connected.
/**
* The haptics engine uses a stack of these states representing the light bar and rumble motor settings.
* It (will) handle composing them and the details of output report management.
*/
public struct DS4HapticState
{
public DS4Color LightBarColor;
public bool LightBarExplicitlyOff;
public byte LightBarFlashDurationOn, LightBarFlashDurationOff;
public byte RumbleMotorStrengthLeftHeavySlow, RumbleMotorStrengthRightLightFast;
public bool RumbleMotorsExplicitlyOff;
public bool IsLightBarSet()
{
return LightBarExplicitlyOff || LightBarColor.red != 0 || LightBarColor.green != 0 || LightBarColor.blue != 0;
}
public bool IsRumbleSet()
{
return RumbleMotorsExplicitlyOff || RumbleMotorStrengthLeftHeavySlow != 0 || RumbleMotorStrengthRightLightFast != 0;
}
}
public class DS4Device
{
@ -36,31 +57,30 @@ namespace DS4Library
private ConnectionType conType;
private byte[] accel = new byte[6];
private byte[] gyro = new byte[6];
private byte[] inputReport = new byte[64];
private byte[] inputReport;
private byte[] btInputReport = null;
private byte[] outputReport = null;
private byte[] outputReportBuffer, outputReport;
private readonly DS4Touchpad touchpad = null;
private byte rightLightFastRumble;
private byte leftHeavySlowRumble;
private DS4Color ligtBarColor;
private byte ledFlashOn, ledFlashOff;
private bool isDirty = false;
private Thread updaterThread = null;
private Thread ds4Input, ds4Output;
private int battery;
private int idleTimeout = 1200;
private DateTime lastActive = DateTime.Now;
private bool charging;
public event EventHandler<EventArgs> Report = null;
public event EventHandler<EventArgs> Removal = null;
public int IdleTimeout { get { return idleTimeout; }
set { idleTimeout = value; } }
public HidDevice HidDevice { get { return hDevice; } }
public bool IsExclusive { get { return HidDevice.IsExclusive; } }
public bool IsDisconnecting { get; private set; }
public string MacAddress { get { return Mac; } }
public ConnectionType ConnectionType { get { return conType; } }
public int Battery { get { return battery; } }
public bool Charging { get { return charging; } }
public byte RightLightFastRumble
{
@ -69,7 +89,6 @@ namespace DS4Library
{
if (value == rightLightFastRumble) return;
rightLightFastRumble = value;
isDirty = true;
}
}
@ -80,7 +99,6 @@ namespace DS4Library
{
if (value == leftHeavySlowRumble) return;
leftHeavySlowRumble = value;
isDirty = true;
}
}
@ -92,7 +110,6 @@ namespace DS4Library
if (ligtBarColor.red != value.red || ligtBarColor.green != value.green || ligtBarColor.blue != value.blue)
{
ligtBarColor = value;
isDirty = true;
}
}
}
@ -105,7 +122,6 @@ namespace DS4Library
if (ledFlashOn != value)
{
ledFlashOn = value;
isDirty = true;
}
}
}
@ -118,41 +134,51 @@ namespace DS4Library
if (ledFlashOff != value)
{
ledFlashOff = value;
isDirty = true;
}
}
}
public DS4Touchpad Touchpad { get { return touchpad; } }
public static ConnectionType HidConnectionType(HidDevice hidDevice)
{
return hidDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT;
}
public DS4Device(HidDevice hidDevice)
{
hDevice = hidDevice;
hDevice.MonitorDeviceEvents = true;
conType = hDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT;
conType = HidConnectionType(hDevice);
Mac = hDevice.readSerial();
if (conType == ConnectionType.USB)
{
inputReport = new byte[64];
outputReport = new byte[hDevice.Capabilities.OutputReportByteLength];
outputReportBuffer = new byte[hDevice.Capabilities.OutputReportByteLength];
}
else
{
btInputReport = new byte[BT_INPUT_REPORT_LENGTH];
inputReport = new byte[btInputReport.Length - 2];
outputReport = new byte[BT_OUTPUT_REPORT_LENGTH];
outputReportBuffer = new byte[BT_OUTPUT_REPORT_LENGTH];
}
touchpad = new DS4Touchpad();
isDirty = true;
sendOutputReport();
}
public void StartUpdate()
{
if (updaterThread == null)
if (ds4Input == null)
{
updaterThread = new Thread(updateCurrentState);
updaterThread.Name = "DS4 Update thread :" + Mac;
Console.WriteLine(updaterThread.Name + " has started");
updaterThread.Start();
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> start");
sendOutputReport(true); // request the particular kind of input report we want
ds4Output = new Thread(performDs4Output);
ds4Output.Name = "DS4 Output thread: " + Mac;
ds4Output.Start();
ds4Input = new Thread(performDs4Input);
ds4Input.Name = "DS4 Input thread: " + Mac;
ds4Input.Start();
}
else
Console.WriteLine("Thread already running for DS4: " + Mac);
@ -160,12 +186,29 @@ namespace DS4Library
public void StopUpdate()
{
if (updaterThread.ThreadState != System.Threading.ThreadState.Stopped || updaterThread.ThreadState != System.Threading.ThreadState.Aborted)
if (ds4Input.ThreadState != System.Threading.ThreadState.Stopped || ds4Input.ThreadState != System.Threading.ThreadState.Aborted)
{
try
{
updaterThread.Abort();
updaterThread = null;
ds4Input.Abort();
ds4Input.Join();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
StopOutputUpdate();
}
private void StopOutputUpdate()
{
if (ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
{
try
{
ds4Output.Abort();
ds4Output.Join();
}
catch (Exception e)
{
@ -174,28 +217,61 @@ namespace DS4Library
}
}
private void updateCurrentState()
private bool writeOutput()
{
if (conType == ConnectionType.BT)
{
return hDevice.WriteOutputReportViaControl(outputReport);
}
else
{
return hDevice.WriteOutputReportViaInterrupt(outputReport, 8);
}
}
private void performDs4Output()
{
lock (outputReport)
{
while (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.
else
Monitor.Wait(outputReport);
}
}
}
/** Is the device alive and receiving valid sensor input reports? */
public bool IsAlive()
{
return priorInputReport30 != 0xff;
}
private byte priorInputReport30 = 0xff;
private void performDs4Input()
{
while (true)
{
if (conType != ConnectionType.USB)
if (hDevice.ReadFile(btInputReport) == HidDevice.ReadStatus.Success)
{
Array.Copy(btInputReport, 2, inputReport, 0, 64);
Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
}
else
{
isDirty = true;
sendOutputReport(); // not sure why but without this Windows
//will not mark timed out controller as disonnected
if (Removal != null)
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect");
sendOutputReport(true); // Kick Windows into noticing the disconnection.
StopOutputUpdate();
if (!IsDisconnecting && Removal != null)
Removal(this, EventArgs.Empty);
return;
}
else if (hDevice.ReadFile(inputReport) != HidDevice.ReadStatus.Success)
{
if (Removal != null)
StopOutputUpdate();
if (!IsDisconnecting && Removal != null)
Removal(this, EventArgs.Empty);
return;
}
@ -204,11 +280,11 @@ namespace DS4Library
//Received incorrect report, skip it
continue;
}
lock (cState)
{
DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
resetHapticState();
if (cState == null)
cState = new DS4State();
cState.ReportTimeStamp = utcNow;
cState.LX = inputReport[1];
cState.LY = inputReport[2];
cState.RX = inputReport[3];
@ -256,95 +332,110 @@ namespace DS4Library
cState.PS = ((byte)inputReport[7] & (1 << 0)) != 0;
cState.TouchButton = (inputReport[7] & (1 << 2 - 1)) != 0;
cState.FrameCounter = (byte)(inputReport[7] >> 2);
// Store Gyro and Accel values
Array.Copy(inputReport, 14, accel, 0, 6);
Array.Copy(inputReport, 20, gyro, 0, 6);
int charge = 0;
if (conType == ConnectionType.USB)
charging = (inputReport[30] & 0x10) != 0;
battery = (inputReport[30] & 0x0f) * 10;
cState.Battery = (byte)battery;
if (inputReport[30] != priorInputReport30)
{
charge = (inputReport[30] - 16) * 10;
if (charge > 100)
charge = 100;
priorInputReport30 = inputReport[30];
Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
}
else
// XXX DS4State mapping needs fixup, turn touches into an array[4] of structs. And include the touchpad details there instead.
for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
{
charge = (inputReport[30] + 1) * 10;
if (charge > 100)
charge = 100;
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.Touch1Identifier = (byte)(inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
cState.Touch2 = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected
cState.Touch2Identifier = (byte)(inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
// Even when idling there is still a touch packet indicating no touch 1 or 2
touchpad.handleTouchpad(inputReport, cState, touchOffset);
}
cState.Battery = charge;
battery = charge;
cState.Touch1 = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET] >> 7) != 0 ? false : true; // >= 1 touch detected
cState.Touch2 = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET] >> 7) != 0 ? false : true; // 2 touches detected
cState.ReportTimeStamp = DateTime.UtcNow;
}
if (ConnectionType == ConnectionType.BT && !isIdle(cState))
/* Debug output of incoming HID data:
if (cState.L2 == 0xff && cState.R2 == 0xff)
{
lastActive = DateTime.Now;
}
if (ConnectionType == ConnectionType.BT && lastActive + TimeSpan.FromSeconds(idleTimeout) < DateTime.Now)
Console.Write(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + ">");
for (int i = 0; i < inputReport.Length; i++)
Console.Write(" " + inputReport[i].ToString("x2"));
Console.WriteLine();
} */
if (conType == ConnectionType.BT && (!pState.PS || !pState.Options) && cState.PS && cState.Options)
{
DisconnectBT();
}
touchpad.handleTouchpad(inputReport, cState);
sendOutputReport();
if ((!pState.PS || !pState.Options) && cState.PS && cState.Options)
{
DisconnectBT();
if (DisconnectBT())
return; // all done
}
// XXX fix initialization ordering so the null checks all go away
if (Report != null)
Report(this, EventArgs.Empty);
lock (pState)
{
sendOutputReport(false);
if (pState == null)
pState = new DS4State();
cState.Copy(pState);
}
}
}
private void sendOutputReport()
{
if (isDirty)
private void sendOutputReport(bool synchronous)
{
setTestRumble();
setHapticState();
if (conType == ConnectionType.BT)
{
outputReport[0] = 0x11;
outputReport[1] = 128;
outputReport[3] = 0xff;
outputReport[6] = rightLightFastRumble; //fast motor
outputReport[7] = leftHeavySlowRumble; //slow motor
outputReport[8] = LightBarColor.red; //red
outputReport[9] = LightBarColor.green; //green
outputReport[10] = LightBarColor.blue; //blue
outputReport[11] = ledFlashOn; //flash on duration
outputReport[12] = ledFlashOff; //flash off duration
if (hDevice.WriteOutputReportViaControl(outputReport))
isDirty = false;
outputReportBuffer[0] = 0x11;
outputReportBuffer[1] = 0x80;
outputReportBuffer[3] = 0xff;
outputReportBuffer[6] = rightLightFastRumble; //fast motor
outputReportBuffer[7] = leftHeavySlowRumble; //slow motor
outputReportBuffer[8] = LightBarColor.red; //red
outputReportBuffer[9] = LightBarColor.green; //green
outputReportBuffer[10] = LightBarColor.blue; //blue
outputReportBuffer[11] = ledFlashOn; //flash on duration
outputReportBuffer[12] = ledFlashOff; //flash off duration
}
else
{
outputReport[0] = 0x5;
outputReport[1] = 0xFF;
outputReport[4] = rightLightFastRumble; //fast motor
outputReport[5] = leftHeavySlowRumble; //slow motor
outputReport[6] = LightBarColor.red; //red
outputReport[7] = LightBarColor.green; //green
outputReport[8] = LightBarColor.blue; //blue
outputReport[9] = ledFlashOn; //flash on duration
outputReport[10] = ledFlashOff; //flash off duration
if (hDevice.WriteOutputReportViaInterrupt(outputReport))
outputReportBuffer[0] = 0x05;
outputReportBuffer[1] = 0xff;
outputReportBuffer[4] = rightLightFastRumble; //fast motor
outputReportBuffer[5] = leftHeavySlowRumble; //slow motor
outputReportBuffer[6] = LightBarColor.red; //red
outputReportBuffer[7] = LightBarColor.green; //green
outputReportBuffer[8] = LightBarColor.blue; //blue
outputReportBuffer[9] = ledFlashOn; //flash on duration
outputReportBuffer[10] = ledFlashOff; //flash off duration
}
lock (outputReport)
{
isDirty = false;
if (synchronous)
{
outputReportBuffer.CopyTo(outputReport, 0);
try
{
writeOutput();
}
catch
{
// If it's dead already, don't worry about it.
}
}
else
{
bool output = false;
for (int i = 0; !output && i < outputReport.Length; i++)
output = outputReport[i] != outputReportBuffer[i];
if (output)
{
outputReportBuffer.CopyTo(outputReport, 0);
Monitor.Pulse(outputReport);
}
}
}
@ -367,7 +458,6 @@ namespace DS4Library
}
long lbtAddr = BitConverter.ToInt64(btAddr, 0);
NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS p = new NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS();
p.dwSize = Marshal.SizeOf(typeof(NativeMethods.BLUETOOTH_FIND_RADIO_PARAMS));
IntPtr searchHandle = NativeMethods.BluetoothFindFirstRadio(ref p, ref btHandle);
@ -383,53 +473,47 @@ namespace DS4Library
}
NativeMethods.BluetoothFindRadioClose(searchHandle);
Console.WriteLine("Disconnect successul: " + success);
Console.WriteLine("Disconnect successful: " + success);
success = true; // XXX return value indicates failure, but it still works?
if(success)
{
IsDisconnecting = true;
StopOutputUpdate();
if (Removal != null)
Removal(this, EventArgs.Empty);
}
return success;
}
return false;
}
public void setLightbarColor(byte red, byte green, byte blue)
{
if (red != ligtBarColor.red || green != ligtBarColor.green || blue != ligtBarColor.blue)
{
isDirty = true;
ligtBarColor.red = red;
ligtBarColor.green = green;
ligtBarColor.blue = blue;
}
}
public void setLightbarDuration(byte onDuration, byte offDuration)
{
LightBarOffDuration = offDuration;
LightBarOnDuration = onDuration;
}
private DS4HapticState testRumble = new DS4HapticState();
public void setRumble(byte rightLightFastMotor, byte leftHeavySlowMotor)
{
RightLightFastRumble = rightLightFastMotor;
LeftHeavySlowRumble = leftHeavySlowMotor;
testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor;
testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor;
testRumble.RumbleMotorsExplicitlyOff = rightLightFastMotor == 0 && leftHeavySlowMotor == 0;
}
private void setTestRumble()
{
if (testRumble.IsRumbleSet())
{
pushHapticState(testRumble);
if (testRumble.RumbleMotorsExplicitlyOff)
testRumble.RumbleMotorsExplicitlyOff = false;
}
}
public DS4State getCurrentState()
{
lock (cState)
{
return cState.Clone();
}
}
public DS4State getPreviousState()
{
lock (pState)
{
return pState.Clone();
}
}
public void getExposedState(DS4StateExposed expState, DS4State state)
{
@ -439,38 +523,61 @@ namespace DS4Library
}
public void getCurrentState(DS4State state)
{
lock (cState)
{
cState.Copy(state);
}
}
public void getPreviousState(DS4State state)
{
lock (pState)
{
pState.Copy(state);
}
private DS4HapticState[] hapticState = new DS4HapticState[1];
private int hapticStackIndex = 0;
private void resetHapticState()
{
hapticStackIndex = 0;
}
private bool isIdle(DS4State cState)
// Use the "most recently set" haptic state for each of light bar/motor.
private void setHapticState()
{
if (cState.Square || cState.Cross || cState.Circle || cState.Triangle)
return false;
if (cState.DpadUp || cState.DpadLeft || cState.DpadDown || cState.DpadRight)
return false;
if (cState.L3 || cState.R3 || cState.L1 || cState.R1 || cState.Share || cState.Options)
return false;
if (cState.L2 != 0 || cState.R2 != 0)
return false;
if (Math.Abs(cState.LX - 127) > 10 || (Math.Abs(cState.LY - 127) > 10 ))
return false;
if (Math.Abs(cState.RX - 127) > 10 || (Math.Abs(cState.RY - 127) > 10))
return false;
if (cState.Touch1 || cState.Touch2 || cState.TouchButton)
return false;
return true;
int i = 0;
DS4Color lightBarColor = LightBarColor;
byte lightBarFlashDurationOn = LightBarOnDuration, lightBarFlashDurationOff = LightBarOffDuration;
byte rumbleMotorStrengthLeftHeavySlow = LeftHeavySlowRumble, rumbleMotorStrengthRightLightFast = rightLightFastRumble;
foreach (DS4HapticState haptic in hapticState)
{
if (i++ == hapticStackIndex)
break; // rest haven't been used this time
if (haptic.IsLightBarSet())
{
lightBarColor = haptic.LightBarColor;
lightBarFlashDurationOn = haptic.LightBarFlashDurationOn;
lightBarFlashDurationOff = haptic.LightBarFlashDurationOff;
}
if (haptic.IsRumbleSet())
{
rumbleMotorStrengthLeftHeavySlow = haptic.RumbleMotorStrengthLeftHeavySlow;
rumbleMotorStrengthRightLightFast = haptic.RumbleMotorStrengthRightLightFast;
}
}
LightBarColor = lightBarColor;
LightBarOnDuration = lightBarFlashDurationOn;
LightBarOffDuration = lightBarFlashDurationOff;
LeftHeavySlowRumble = rumbleMotorStrengthLeftHeavySlow;
RightLightFastRumble = rumbleMotorStrengthRightLightFast;
}
public void pushHapticState(DS4HapticState hs)
{
if (hapticStackIndex == hapticState.Length)
{
DS4HapticState[] newHaptics = new DS4HapticState[hapticState.Length + 1];
Array.Copy(hapticState, newHaptics, hapticState.Length);
hapticState = newHaptics;
}
hapticState[hapticStackIndex++] = hs;
}
override

View File

@ -8,6 +8,7 @@ namespace DS4Library
public class DS4Devices
{
private static Dictionary<string, DS4Device> Devices = new Dictionary<string, DS4Device>();
private static HashSet<String> DevicePaths = new HashSet<String>();
public static bool isExclusiveMode = false;
//enumerates ds4 controllers in the system
@ -17,30 +18,33 @@ namespace DS4Library
{
int[] pid = { 0x5C4 };
IEnumerable<HidDevice> hDevices = HidDevices.Enumerate(0x054C, pid);
// Sort Bluetooth first in case USB is also connected on the same controller.
hDevices = hDevices.OrderBy<HidDevice, ConnectionType>((HidDevice d) => { return DS4Device.HidConnectionType(d); });
foreach (HidDevice hDevice in hDevices)
{
if (DevicePaths.Contains(hDevice.DevicePath))
continue; // BT/USB endpoint already open once
if (!hDevice.IsOpen)
{
hDevice.OpenDevice(isExclusiveMode);
// TODO in exclusive mode, try to hold both open when both are connected
if (isExclusiveMode && !hDevice.IsOpen)
hDevice.OpenDevice(false);
}
if (hDevice.IsOpen)
{
byte[] buffer = new byte[38];
buffer[0] = 0x2;
hDevice.readFeatureData(buffer);
if (Devices.ContainsKey(hDevice.readSerial()))
continue;
continue; // happens when the BT endpoint already is open and the USB is plugged into the same host
else
{
DS4Device ds4Device = new DS4Device(hDevice);
ds4Device.StartUpdate();
ds4Device.Removal += On_Removal;
Devices.Add(ds4Device.MacAddress, ds4Device);
DevicePaths.Add(hDevice.DevicePath);
ds4Device.StartUpdate();
}
}
else
{
throw new Exception("ERROR: Can't open DS4 Controller. Try quitting other applications like Steam, Uplay, etc.)");
}
}
}
@ -49,6 +53,8 @@ namespace DS4Library
//allows to get DS4Device by specifying unique MAC address
//format for MAC address is XX:XX:XX:XX:XX:XX
public static DS4Device getDS4Controller(string mac)
{
lock (Devices)
{
DS4Device device = null;
try
@ -58,14 +64,22 @@ namespace DS4Library
catch (ArgumentNullException) { }
return device;
}
}
//returns DS4 controllers that were found and are running
public static IEnumerable<DS4Device> getDS4Controllers()
{
return Devices.Values;
lock (Devices)
{
DS4Device[] controllers = new DS4Device[Devices.Count];
Devices.Values.CopyTo(controllers, 0);
return controllers;
}
}
public static void stopControllers()
{
lock (Devices)
{
IEnumerable<DS4Device> devices = getDS4Controllers();
foreach (DS4Device device in devices)
@ -74,6 +88,8 @@ namespace DS4Library
device.HidDevice.CloseDevice();
}
Devices.Clear();
DevicePaths.Clear();
}
}
//called when devices is diconnected, timed out or has input reading failure
@ -84,6 +100,7 @@ namespace DS4Library
DS4Device device = (DS4Device)sender;
device.HidDevice.CloseDevice();
Devices.Remove(device.MacAddress);
DevicePaths.Remove(device.HidDevice.DevicePath);
}
}
}

View File

@ -7,27 +7,33 @@ namespace DS4Library
{
public class DS4State
{
public DateTime ReportTimeStamp;
public bool Square, Triangle, Circle, Cross;
public bool DpadUp, DpadDown, DpadLeft, DpadRight;
public bool L1, L3, R1, R3;
public bool Share, Options, PS, Touch1, Touch2, TouchButton;
public byte Touch1Identifier, Touch2Identifier;
public byte LX, RX, LY, RY, L2, R2;
public int Battery;
public DateTime ReportTimeStamp;
public byte FrameCounter; // 0, 1, 2...62, 63, 0....
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 DS4State()
{
ReportTimeStamp = DateTime.UtcNow;
Square = Triangle = Circle = Cross = false;
DpadUp = DpadDown = DpadLeft = DpadRight = false;
L1 = L3 = R1 = R3 = false;
Share = Options = PS = Touch1 = Touch2 = TouchButton = false;
LX = RX = LY = RY = 127;
L2 = R2 = 0;
FrameCounter = 255; // only actually has 6 bits, so this is a null indicator
TouchPacketCounter = 255; // 8 bits, no great junk value
Battery = 0;
}
public DS4State(DS4State state)
{
ReportTimeStamp = state.ReportTimeStamp;
Square = state.Square;
Triangle = state.Triangle;
Circle = state.Circle;
@ -46,14 +52,17 @@ namespace DS4Library
Options = state.Options;
PS = state.PS;
Touch1 = state.Touch1;
Touch1Identifier = state.Touch1Identifier;
Touch2 = state.Touch2;
Touch2Identifier = state.Touch2Identifier;
TouchButton = state.TouchButton;
TouchPacketCounter = state.TouchPacketCounter;
LX = state.LX;
RX = state.RX;
LY = state.LY;
RY = state.RY;
FrameCounter = state.FrameCounter;
Battery = state.Battery;
ReportTimeStamp = state.ReportTimeStamp;
}
public DS4State Clone()
@ -63,6 +72,7 @@ namespace DS4Library
public void Copy(DS4State state)
{
state.ReportTimeStamp = ReportTimeStamp;
state.Square = Square;
state.Triangle = Triangle;
state.Circle = Circle;
@ -81,14 +91,17 @@ namespace DS4Library
state.Options = Options;
state.PS = PS;
state.Touch1 = Touch1;
state.Touch1Identifier = Touch1Identifier;
state.Touch2 = Touch2;
state.Touch2Identifier = Touch2Identifier;
state.TouchButton = TouchButton;
state.TouchPacketCounter = TouchPacketCounter;
state.LX = LX;
state.RX = RX;
state.LY = LY;
state.RY = RY;
state.FrameCounter = FrameCounter;
state.Battery = Battery;
state.ReportTimeStamp = ReportTimeStamp;
}
}

View File

@ -53,21 +53,21 @@ namespace DS4Library
/// <summary> Pitch upward/backward </summary>
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
public int AccelX { get { return (UInt16)(accel[0] << 8) | accel[1]; } }
public int AccelX { get { return (Int16)((UInt16)(accel[0] << 8) | accel[1]); } }
/// <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>
public int AccelY { get { return (UInt16)(accel[2] << 8) | accel[3]; } }
public int AccelY { get { return (Int16)((UInt16)(accel[2] << 8) | accel[3]); } }
/// <summary> roll left/L side of controller down/starboard raising up </summary>
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
public int AccelZ { get { return (UInt16)(accel[4] << 8) | accel[5]; } }
public int AccelZ { get { return (Int16)((UInt16)(accel[4] << 8) | accel[5]); } }
/// <summary> R side of controller upward </summary>
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
public int GyroX { get { return (UInt16)(gyro[0] << 8) | gyro[1]; } }
public int GyroX { get { return (Int16)((UInt16)(gyro[0] << 8) | gyro[1]); } }
/// <summary> touchpad and button face side of controller upward </summary>
/// <remarks> Add double the previous result to this delta and divide by three.</remarks>
public int GyroY { get { return (UInt16)(gyro[2] << 8) | gyro[3]; } }
public int GyroY { get { return (Int16)((UInt16)(gyro[2] << 8) | gyro[3]); } }
/// <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>
public int GyroZ { get { return (UInt16)(gyro[4] << 8) | gyro[5]; } }
public int GyroZ { get { return (Int16)((UInt16)(gyro[4] << 8) | gyro[5]); } }
}
}

View File

@ -8,11 +8,10 @@ namespace DS4Library
public class TouchpadEventArgs : EventArgs
{
public readonly Touch[] touches = null;
public readonly System.DateTime timeStamp;
public readonly bool touchButtonPressed;
public readonly DateTime timeStamp;
public TouchpadEventArgs(DateTime timeStamp, bool tButtonDown, Touch t0, Touch t1 = null)
public TouchpadEventArgs(System.DateTime utcTimestamp, bool tButtonDown, Touch t0, Touch t1 = null)
{
this.timeStamp = timeStamp;
if (t1 != null)
{
touches = new Touch[2];
@ -25,6 +24,7 @@ namespace DS4Library
touches[0] = t0;
}
touchButtonPressed = tButtonDown;
this.timeStamp = utcTimestamp;
}
}
@ -49,128 +49,161 @@ namespace DS4Library
public class DS4Touchpad
{
public event EventHandler<TouchpadEventArgs> TouchesBegan = null;
public event EventHandler<TouchpadEventArgs> TouchesMoved = null;
public event EventHandler<TouchpadEventArgs> TouchesEnded = null;
public event EventHandler<TouchpadEventArgs> TouchButtonDown = null;
public event EventHandler<TouchpadEventArgs> TouchButtonUp = null;
public readonly static int TOUCHPAD_DATA_OFFSET = 35;
internal static int lastTouchPadX, lastTouchPadY,
lastTouchPadX2, lastTouchPadY2; // tracks 0, 1 or 2 touches; we maintain touch 1 and 2 separately
internal static bool lastTouchPadIsDown;
internal static bool lastIsActive;
internal static bool lastIsActive2;
internal static byte lastTouchID, lastTouchID2;
public event EventHandler<TouchpadEventArgs> TouchesBegan = null; // finger one or two landed (or both, or one then two, or two then one; any touches[] count increase)
public event EventHandler<TouchpadEventArgs> TouchesMoved = null; // deltaX/deltaY are set because one or both fingers were already down on a prior sensor reading
public event EventHandler<TouchpadEventArgs> TouchesEnded = null; // all fingers lifted
public event EventHandler<TouchpadEventArgs> TouchButtonDown = null; // touchpad pushed down until the button clicks
public event EventHandler<TouchpadEventArgs> TouchButtonUp = null; // touchpad button released
public event EventHandler<EventArgs> TouchUnchanged = null; // no status change for the touchpad itself... but other sensors may have changed, or you may just want to do some processing
public void handleTouchpad(byte[] data, DS4State sensors)
public readonly static int TOUCHPAD_DATA_OFFSET = 35;
internal int lastTouchPadX1, lastTouchPadY1,
lastTouchPadX2, lastTouchPadY2; // tracks 0, 1 or 2 touches; we maintain touch 1 and 2 separately
internal bool lastTouchPadIsDown;
internal bool lastIsActive1, lastIsActive2;
internal byte lastTouchID1, lastTouchID2;
internal byte[] previousPacket = new byte[8];
// We check everything other than the not bothering with not-very-useful TouchPacketCounter.
private bool PacketChanged(byte[] data, int touchPacketOffset)
{
bool changed = false;
for (int i = 0; i < previousPacket.Length; i++)
{
byte oldValue = previousPacket[i];
previousPacket[i] = data[i + TOUCHPAD_DATA_OFFSET + touchPacketOffset];
if (previousPacket[i] != oldValue)
changed = true;
}
return changed;
}
public void handleTouchpad(byte[] data, DS4State sensors, int touchPacketOffset = 0)
{
bool touchPadIsDown = sensors.TouchButton;
byte touchID = (byte)(data[0 + TOUCHPAD_DATA_OFFSET] & 0x7F);
byte touchID2 = (byte)(data[4 + TOUCHPAD_DATA_OFFSET] & 0x7F);
int currentX = data[1 + TOUCHPAD_DATA_OFFSET] + ((data[2 + TOUCHPAD_DATA_OFFSET] & 0xF) * 255);
int currentY = ((data[2 + TOUCHPAD_DATA_OFFSET] & 0xF0) >> 4) + (data[3 + TOUCHPAD_DATA_OFFSET] * 16);
int currentX2 = data[5 + TOUCHPAD_DATA_OFFSET] + ((data[6 + TOUCHPAD_DATA_OFFSET] & 0xF) * 255);
int currentY2 = ((data[6 + TOUCHPAD_DATA_OFFSET] & 0xF0) >> 4) + (data[7 + TOUCHPAD_DATA_OFFSET] * 16);
if (!PacketChanged(data, touchPacketOffset) && touchPadIsDown == lastTouchPadIsDown)
{
if (TouchUnchanged != null)
TouchUnchanged(this, EventArgs.Empty);
return;
}
if (sensors.Touch1)
byte touchID1 = (byte)(data[0 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0x7F);
byte touchID2 = (byte)(data[4 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0x7F);
int currentX1 = data[1 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] + ((data[2 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0xF) * 255);
int currentY1 = ((data[2 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0xF0) >> 4) + (data[3 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] * 16);
int currentX2 = data[5 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] + ((data[6 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0xF) * 255);
int currentY2 = ((data[6 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] & 0xF0) >> 4) + (data[7 + TOUCHPAD_DATA_OFFSET + touchPacketOffset] * 16);
TouchpadEventArgs args;
if (sensors.Touch1 || sensors.Touch2)
{
if (!lastTouchPadIsDown && touchPadIsDown && TouchButtonDown != null)
if ((sensors.Touch1 && !lastIsActive1) || (sensors.Touch2 && !lastIsActive2))
{
TouchpadEventArgs args = null;
Touch t0 = new Touch(currentX, currentY, touchID);
if (sensors.Touch2)
if (TouchesBegan != null)
{
Touch t1 = new Touch(currentX2, currentY2, touchID2);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
if (sensors.Touch1 && sensors.Touch2)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1), new Touch(currentX2, currentY2, touchID2));
else if (sensors.Touch1)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1));
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX2, currentY2, touchID2));
TouchesBegan(this, args);
}
}
else if (sensors.Touch1 == lastIsActive1 && sensors.Touch2 == lastIsActive2 && TouchesMoved != null)
{
Touch tPrev, t0, t1;
if (sensors.Touch1 && sensors.Touch2)
{
tPrev = new Touch(lastTouchPadX1, lastTouchPadY1, lastTouchID1);
t0 = new Touch(currentX1, currentY1, touchID1, tPrev);
tPrev = new Touch(lastTouchPadX2, lastTouchPadY2, lastTouchID2);
t1 = new Touch(currentX2, currentY2, touchID2, tPrev);
}
else if (sensors.Touch1)
{
tPrev = new Touch(lastTouchPadX1, lastTouchPadY1, lastTouchID1);
t0 = new Touch(currentX1, currentY1, touchID1, tPrev);
t1 = null;
}
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0);
{
tPrev = new Touch(lastTouchPadX2, lastTouchPadY2, lastTouchID2);
t0 = new Touch(currentX2, currentY2, touchID2, tPrev);
t1 = null;
}
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
TouchesMoved(this, args);
}
if (!lastTouchPadIsDown && touchPadIsDown && TouchButtonDown != null)
{
if (sensors.Touch1 && sensors.Touch2)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1), new Touch(currentX2, currentY2, touchID2));
else if (sensors.Touch1)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1));
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX2, currentY2, touchID2));
TouchButtonDown(this, args);
}
else if (lastTouchPadIsDown && !touchPadIsDown && TouchButtonUp != null)
{
TouchpadEventArgs args = null;
Touch t0 = new Touch(currentX, currentY, touchID);
if (sensors.Touch2)
{
Touch t1 = new Touch(currentX2, currentY2, touchID2);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
}
if (sensors.Touch1 && sensors.Touch2)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1), new Touch(currentX2, currentY2, touchID2));
else if (sensors.Touch1)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX1, currentY1, touchID1));
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(currentX2, currentY2, touchID2));
TouchButtonUp(this, args);
}
if (!lastIsActive || (sensors.Touch2 && !lastIsActive2))
if (sensors.Touch1)
{
TouchpadEventArgs args = null;
Touch t0 = new Touch(currentX, currentY, touchID);
if (sensors.Touch2 && !lastIsActive2)
lastTouchPadX1 = currentX1;
lastTouchPadY1 = currentY1;
}
if (sensors.Touch2)
{
Touch t1 = new Touch(currentX2, currentY2, touchID2);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
}
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0);
if (TouchesBegan != null)
TouchesBegan(this, args);
}
else if (lastIsActive)
{
if (TouchesMoved != null)
{
TouchpadEventArgs args = null;
Touch t0Prev = new Touch(lastTouchPadX, lastTouchPadY, lastTouchID);
Touch t0 = new Touch(currentX, currentY, touchID, t0Prev);
if (sensors.Touch1 && sensors.Touch2)
{
Touch t1Prev = new Touch(lastTouchPadX2, lastTouchPadY2, lastTouchID2);
Touch t1 = new Touch(currentX2, currentY2, touchID2, t1Prev);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
}
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0);
TouchesMoved(this, args);
}
}
lastTouchPadX = currentX;
lastTouchPadY = currentY;
lastTouchPadX2 = currentX2;
lastTouchPadY2 = currentY2;
}
lastTouchPadIsDown = touchPadIsDown;
}
else
{
if (lastIsActive)
{
TouchpadEventArgs args = null;
Touch t0 = new Touch(currentX, currentY, touchID);
if (lastIsActive2)
{
Touch t1 = new Touch(currentX2, currentY2, touchID2);
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0, t1);
}
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, t0);
if (TouchesEnded != null)
TouchesEnded(this, args);
}
if (touchPadIsDown && !lastTouchPadIsDown && TouchButtonDown != null)
if (touchPadIsDown && !lastTouchPadIsDown)
{
if (TouchButtonDown != null)
TouchButtonDown(this, new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, null, null));
}
else if (!touchPadIsDown && lastTouchPadIsDown && TouchButtonUp != null)
else if (!touchPadIsDown && lastTouchPadIsDown)
{
if (TouchButtonUp != null)
TouchButtonUp(this, new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, null, null));
}
if ((lastIsActive1 || lastIsActive2) && TouchesEnded != null)
{
if (lastIsActive1 && lastIsActive2)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(lastTouchPadX1, lastTouchPadY1, touchID1), new Touch(lastTouchPadX2, lastTouchPadY2, touchID2));
else if (lastIsActive1)
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(lastTouchPadX1, lastTouchPadY1, touchID1));
else
args = new TouchpadEventArgs(sensors.ReportTimeStamp, sensors.TouchButton, new Touch(lastTouchPadX2, lastTouchPadY2, touchID2));
TouchesEnded(this, args);
}
}
lastIsActive = sensors.Touch1;
lastIsActive1 = sensors.Touch1;
lastIsActive2 = sensors.Touch2;
lastTouchID = touchID;
lastTouchID1 = touchID1;
lastTouchID2 = touchID2;
lastTouchPadIsDown = touchPadIsDown;
}

View File

@ -13,13 +13,9 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
if (disposing && (components != null))
{
if (components != null)
components.Dispose();
//CA2213 Disposable fields should be disposed
if (rootHub != null)
rootHub.Dispose();
}
base.Dispose(disposing);
}

View File

@ -35,7 +35,7 @@
//
// OkButton
//
this.OkButton.Location = new System.Drawing.Point(113, 202);
this.OkButton.Location = new System.Drawing.Point(260, 118);
this.OkButton.Name = "OkButton";
this.OkButton.Size = new System.Drawing.Size(75, 23);
this.OkButton.TabIndex = 0;
@ -52,28 +52,27 @@
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ReadOnly = true;
this.textBox1.Size = new System.Drawing.Size(260, 155);
this.textBox1.Size = new System.Drawing.Size(260, 61);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "DS4 Tool 1.3 RC3\r\n\r\nCreated By:\r\nArtur Dzmitryieu(InhexSTER)\r\nelectrobrains\r\nHect" +
"icSeptic\r\nJays2Kings\r\n\r\nBased on DS3 Scp Server from\r\nScarlet.Crush";
this.textBox1.Text = "DS4Windows is Open Source software!\r\n\r\nInsert link to GPL here (at some point.)";
this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(59, 175);
this.linkLabel1.Location = new System.Drawing.Point(9, 86);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(183, 13);
this.linkLabel1.Size = new System.Drawing.Size(324, 13);
this.linkLabel1.TabIndex = 2;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "https://code.google.com/p/ds4-tool/";
this.linkLabel1.Text = "https://code.google.com/r/brianfundakowskifeldman-ds4windows/";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// AboutBox
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 230);
this.ClientSize = new System.Drawing.Size(347, 153);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.OkButton);

View File

@ -28,7 +28,7 @@ namespace ScpServer
private void AboutBox_Load(object sender, EventArgs e)
{
linkLabel1.Links.Add(0,35,"https://code.google.com/p/ds4-tool/");
linkLabel1.Links.Add(0, linkLabel1.Text.Length, "https://code.google.com/r/brianfundakowskifeldman-ds4windows/");
}
}
}

View File

@ -62,6 +62,8 @@
this.bnRX2 = new System.Windows.Forms.Button();
this.bnL3 = new System.Windows.Forms.Button();
this.bnR3 = new System.Windows.Forms.Button();
this.TouchTip = new System.Windows.Forms.Label();
this.ReapTip = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
this.SuspendLayout();
//
@ -300,7 +302,7 @@
this.bnDown.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnDown.Location = new System.Drawing.Point(85, 184);
this.bnDown.Name = "bnDown";
this.bnDown.Size = new System.Drawing.Size(19, 22);
this.bnDown.Size = new System.Drawing.Size(19, 29);
this.bnDown.TabIndex = 53;
this.bnDown.Text = "Down Button";
this.bnDown.UseVisualStyleBackColor = false;
@ -318,7 +320,7 @@
this.bnRight.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnRight.Location = new System.Drawing.Point(106, 164);
this.bnRight.Name = "bnRight";
this.bnRight.Size = new System.Drawing.Size(21, 18);
this.bnRight.Size = new System.Drawing.Size(27, 22);
this.bnRight.TabIndex = 53;
this.bnRight.Text = "Right Button";
this.bnRight.UseVisualStyleBackColor = false;
@ -336,7 +338,7 @@
this.bnLeft.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnLeft.Location = new System.Drawing.Point(57, 163);
this.bnLeft.Name = "bnLeft";
this.bnLeft.Size = new System.Drawing.Size(26, 20);
this.bnLeft.Size = new System.Drawing.Size(26, 23);
this.bnLeft.TabIndex = 53;
this.bnLeft.Text = "Left Button";
this.bnLeft.UseVisualStyleBackColor = false;
@ -352,9 +354,9 @@
this.bnOptions.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control;
this.bnOptions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.bnOptions.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnOptions.Location = new System.Drawing.Point(283, 125);
this.bnOptions.Location = new System.Drawing.Point(286, 121);
this.bnOptions.Name = "bnOptions";
this.bnOptions.Size = new System.Drawing.Size(13, 22);
this.bnOptions.Size = new System.Drawing.Size(19, 30);
this.bnOptions.TabIndex = 53;
this.bnOptions.Text = "Start";
this.bnOptions.UseVisualStyleBackColor = false;
@ -370,9 +372,9 @@
this.bnShare.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control;
this.bnShare.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.bnShare.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnShare.Location = new System.Drawing.Point(131, 127);
this.bnShare.Location = new System.Drawing.Point(131, 124);
this.bnShare.Name = "bnShare";
this.bnShare.Size = new System.Drawing.Size(12, 23);
this.bnShare.Size = new System.Drawing.Size(14, 29);
this.bnShare.TabIndex = 53;
this.bnShare.Text = "Back";
this.bnShare.UseVisualStyleBackColor = false;
@ -388,9 +390,9 @@
this.bnTouchpad.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control;
this.bnTouchpad.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.bnTouchpad.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnTouchpad.Location = new System.Drawing.Point(151, 131);
this.bnTouchpad.Location = new System.Drawing.Point(151, 161);
this.bnTouchpad.Name = "bnTouchpad";
this.bnTouchpad.Size = new System.Drawing.Size(64, 56);
this.bnTouchpad.Size = new System.Drawing.Size(128, 26);
this.bnTouchpad.TabIndex = 53;
this.bnTouchpad.Text = "Click";
this.bnTouchpad.UseVisualStyleBackColor = false;
@ -426,7 +428,7 @@
this.bnTouchUpper.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnTouchUpper.Location = new System.Drawing.Point(150, 104);
this.bnTouchUpper.Name = "bnTouchUpper";
this.bnTouchUpper.Size = new System.Drawing.Size(125, 26);
this.bnTouchUpper.Size = new System.Drawing.Size(129, 32);
this.bnTouchUpper.TabIndex = 53;
this.bnTouchUpper.Text = "Middle Click";
this.bnTouchUpper.UseVisualStyleBackColor = false;
@ -442,9 +444,9 @@
this.bnTouchMulti.FlatAppearance.MouseOverBackColor = System.Drawing.SystemColors.Control;
this.bnTouchMulti.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.bnTouchMulti.ForeColor = System.Drawing.SystemColors.WindowText;
this.bnTouchMulti.Location = new System.Drawing.Point(215, 131);
this.bnTouchMulti.Location = new System.Drawing.Point(151, 135);
this.bnTouchMulti.Name = "bnTouchMulti";
this.bnTouchMulti.Size = new System.Drawing.Size(64, 56);
this.bnTouchMulti.Size = new System.Drawing.Size(128, 26);
this.bnTouchMulti.TabIndex = 53;
this.bnTouchMulti.Text = "Right Click";
this.bnTouchMulti.UseVisualStyleBackColor = false;
@ -471,12 +473,11 @@
//
this.lbControls.FormattingEnabled = true;
this.lbControls.Items.AddRange(new object[] {
"<Press a button, then a key to assign>"});
"<Click a button, then a key/item to assign>"});
this.lbControls.Location = new System.Drawing.Point(418, 67);
this.lbControls.Name = "lbControls";
this.lbControls.Size = new System.Drawing.Size(248, 212);
this.lbControls.TabIndex = 54;
this.lbControls.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
//
// bnLY2
//
@ -640,12 +641,36 @@
this.bnR3.Text = "Right Stick";
this.bnR3.UseVisualStyleBackColor = false;
//
// TouchTip
//
this.TouchTip.AutoSize = true;
this.TouchTip.Location = new System.Drawing.Point(164, 34);
this.TouchTip.Name = "TouchTip";
this.TouchTip.Size = new System.Drawing.Size(109, 52);
this.TouchTip.TabIndex = 55;
this.TouchTip.Text = "Touchpad:\r\nTop: Upper Pad \r\nMiddle: Multi-Touch \r\nBottom: Single Touch";
this.TouchTip.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.TouchTip.Visible = false;
//
// ReapTip
//
this.ReapTip.AutoSize = true;
this.ReapTip.Location = new System.Drawing.Point(134, 59);
this.ReapTip.Name = "ReapTip";
this.ReapTip.Size = new System.Drawing.Size(169, 26);
this.ReapTip.TabIndex = 55;
this.ReapTip.Text = "Double Tap a key to toggle repeat\r\n(Excludes TouchPad)";
this.ReapTip.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.ReapTip.Visible = false;
//
// CustomMapping
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
this.ClientSize = new System.Drawing.Size(684, 310);
this.Controls.Add(this.ReapTip);
this.Controls.Add(this.TouchTip);
this.Controls.Add(this.pictureBox);
this.Controls.Add(this.lbControls);
this.Controls.Add(this.cbScanCode);
@ -728,5 +753,7 @@
private System.Windows.Forms.Button bnRX2;
private System.Windows.Forms.Button bnL3;
private System.Windows.Forms.Button bnR3;
private System.Windows.Forms.Label TouchTip;
private System.Windows.Forms.Label ReapTip;
}
}

View File

@ -16,7 +16,7 @@ namespace ScpServer
{
private int device;
private bool handleNextKeyPress = false;
private bool MouseMoveAdded = false;
private bool ReapTipShown = false;
private List<ComboBox> comboBoxes = new List<ComboBox>();
private List<Button> buttons = new List<Button>();
private Dictionary<string, string> defaults = new Dictionary<string, string>();
@ -46,11 +46,10 @@ namespace ScpServer
// Add events here (easier for modification/addition)
((Button)control).Enter += new System.EventHandler(this.EnterCommand);
((Button)control).KeyDown += new System.Windows.Forms.KeyEventHandler(this.KeyDownCommand);
((Button)control).Enter += new System.EventHandler(this.TopofListChanged);
((Button)control).KeyDown += new System.Windows.Forms.KeyEventHandler(this.TopofListChanged);
//((Button)control).Enter += new System.EventHandler(this.TopofListChanged);
//((Button)control).KeyDown += new System.Windows.Forms.KeyEventHandler(this.TopofListChanged);
((Button)control).KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.KeyPressCommand);
((Button)control).PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.PreviewKeyDownCommand);
//lbControls.Items.Add(((Button)control).Text);
lbControls.SelectedIndexChanged += new System.EventHandler(this.SelectedIndexChangedCommand);
}
}
@ -64,7 +63,9 @@ namespace ScpServer
{
if (sender is Button)
{
ReapTip.Visible = false;
lbControls.SetSelected(0, true);
//
for (int i = 1; i < lbControls.Items.Count; i++)
if (lbControls.Items[i].ToString().Contains(" (default)"))
{
@ -160,6 +161,8 @@ namespace ScpServer
lbControls.Items.Insert(1, temp);
break;
}
break;
}
if (((Button)sender).Name.Contains("bnLX") || ((Button)sender).Name.Contains("bnLY") || ((Button)sender).Name.Contains("bnRX") || ((Button)sender).Name.Contains("bnRY"))
{
lbControls.Items.Insert(2, "Mouse Right");
@ -167,8 +170,20 @@ namespace ScpServer
lbControls.Items.Insert(2, "Mouse Down");
lbControls.Items.Insert(2, "Mouse Up");
}
break;
if (((Button)sender).Name.Contains("Touch"))
TouchTip.Visible = true;
else
{
if (ReapTipShown == false)
{
ReapTip.Visible = true;
ReapTipShown = true;
}
TouchTip.Visible = false;
}
if (((Button)sender).Text != "Save" && ((Button)sender).Text != "Load")
lbControls.Items[0] = ((Button)sender).Text;
}
private void PreviewKeyDownCommand(object sender, PreviewKeyDownEventArgs e)
@ -238,8 +253,8 @@ namespace ScpServer
}
private void SelectedIndexChangedCommand(object sender, EventArgs e)
{
if (lastSelectedBn != null)
if (lbControls.SelectedIndex > 0)
{
if (lastSelectedBn.Text != lbControls.Items[lbControls.SelectedIndex].ToString())
{
if (lbControls.Items[lbControls.SelectedIndex].ToString().Contains(" (default)"))
@ -252,7 +267,6 @@ namespace ScpServer
lastSelectedBn.Tag = lbControls.Items[lbControls.SelectedIndex].ToString();
}
}
}
private void cbRepeat_CheckedChanged(object sender, EventArgs e)
{
if (!lastSelectedBn.Name.Contains("Touch") && (lastSelectedBn.Tag is int || lastSelectedBn.Tag is UInt16))
@ -322,10 +336,6 @@ namespace ScpServer
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}

View File

@ -11,8 +11,7 @@
<AssemblyName>DS4Tool</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>C:\Users\Jonathan\Documents\Projects\DS4Builds\</PublishUrl>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
@ -22,11 +21,10 @@
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<AutorunEnabled>true</AutorunEnabled>
<ApplicationRevision>1</ApplicationRevision>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -55,18 +53,6 @@
<PropertyGroup>
<StartupObject>ScpServer.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>82841E533FB15D122F1D1941E6264C09CDDD60F1</ManifestCertificateThumbprint>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>DS4Tool_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -87,7 +73,6 @@
<DependentUpon>AboutBox.cs</DependentUpon>
</Compile>
<Compile Include="AdvancedColorDialog.cs" />
<Compile Include="AdvancedComboBox.cs" />
<Compile Include="CustomMapping.cs">
<SubType>Form</SubType>
</Compile>
@ -108,12 +93,6 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReadInputForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ReadInputForm.Designer.cs">
<DependentUpon>ReadInputForm.cs</DependentUpon>
</Compile>
<Compile Include="ScpForm.cs">
<SubType>Form</SubType>
</Compile>
@ -143,13 +122,9 @@
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="ReadInputForm.resx">
<DependentUpon>ReadInputForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="ScpForm.resx">
<DependentUpon>ScpForm.cs</DependentUpon>
</EmbeddedResource>
<None Include="DS4Tool_TemporaryKey.pfx" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -194,16 +169,12 @@
<None Include="Resources\28.png" />
<None Include="Resources\29.png" />
<Content Include="Resources\3.png" />
<None Include="Resources\30.png" />
<None Include="Resources\31.png" />
<Content Include="Resources\4.png" />
<Content Include="Resources\5.png" />
<Content Include="Resources\6.png" />
<Content Include="Resources\7.png" />
<Content Include="Resources\8.png" />
<Content Include="Resources\9.png" />
<None Include="Resources\DS4 More Red %28small%29.png" />
<None Include="Resources\DS4 Control Shadows %28small%29.png" />
<Content Include="Resources\DS4.ico" />
<Content Include="Resources\Scp_All.ico" />
</ItemGroup>

View File

@ -118,86 +118,65 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="_10" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\10.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Stop" xml:space="preserve">
<value>Stop</value>
<comment>To be localized.</comment>
</data>
<data name="_15" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\15.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_9" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\9.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_13" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\13.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="DS4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DS4.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Start" xml:space="preserve">
<value>Start</value>
<comment>To be localized.</comment>
</data>
<data name="_19" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\19.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="Stop" xml:space="preserve">
<value>Stop</value>
<comment>To be localized.</comment>
</data>
<data name="_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_10" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\10.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_11" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\11.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_12" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\12.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_13" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\13.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_14" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\14.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_15" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\15.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_22" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\22.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_16" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_7" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\7.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_12" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\12.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_17" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\17.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_18" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\18.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_19" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\19.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_20" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\20.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_21" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\21.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_17" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\17.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="_22" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\22.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_23" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\23.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_8" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\8.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_6" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="DS4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DS4.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_24" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -216,4 +195,25 @@
<data name="_29" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\29.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_6" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_7" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\7.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_8" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\8.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="_9" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\9.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -13,13 +13,9 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
if (disposing && (components != null))
{
if (components != null)
components.Dispose();
//CA2213 Disposable fields should be disposed
if (rootHub != null)
rootHub.Dispose();
}
base.Dispose(disposing);
}
@ -93,7 +89,8 @@
//
// tmrUpdate
//
this.tmrUpdate.Tick += new System.EventHandler(this.tmrUpdate_Tick);
this.tmrUpdate.Interval = 1;
this.tmrUpdate.Tick += new System.EventHandler(this.ControllerStatusChange);
//
// pnlButton
//
@ -330,7 +327,7 @@
this.Controls.Add(this.pnlStatus);
this.MinimumSize = new System.Drawing.Size(750, 192);
this.Name = "ScpForm";
this.Text = "DS4 to XInput Mapper 1.3 RC4 - J2K Build";
this.Text = "DS4Windows 1.0 Alpha (2014-03-28.1)";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form_Close);
this.Load += new System.EventHandler(this.Form_Load);
this.Resize += new System.EventHandler(this.Form_Resize);
@ -348,6 +345,7 @@
private System.Windows.Forms.ListView lvDebug;
private System.Windows.Forms.ColumnHeader chTime;
private System.Windows.Forms.ColumnHeader chData;
private System.Windows.Forms.Timer tmrUpdate;
private System.Windows.Forms.Panel pnlButton;
private System.Windows.Forms.Button btnStop;
private System.Windows.Forms.Button btnStartStop;
@ -367,7 +365,6 @@
private System.Windows.Forms.Label lbLastMessage;
private System.Windows.Forms.LinkLabel lnkControllers;
private System.Windows.Forms.Button AboutButton;
private System.Windows.Forms.Timer tmrUpdate;
}
}

View File

@ -35,7 +35,7 @@ namespace ScpServer
protected void ShowNotification(object sender, DebugEventArgs args)
{
notifyIcon1.BalloonTipText = args.Data;
notifyIcon1.BalloonTipTitle = "DS4 Tool";
notifyIcon1.BalloonTipTitle = "DS4Windows";
notifyIcon1.ShowBalloonTip(1);
}
@ -45,15 +45,13 @@ namespace ScpServer
{
notifyIcon1.Visible = true;
this.Hide();
//hide in taskbar
this.ShowInTaskbar = false;
}
else if (FormWindowState.Normal == this.WindowState)
{
notifyIcon1.Visible = false;
//show in taskbar
this.Show();
this.ShowInTaskbar = true;
}
//Added last message alternative
if (this.Height > 220)
@ -83,13 +81,11 @@ namespace ScpServer
rootHub.Debug += On_Debug;
Log.GuiLog += On_Debug;
Log.TrayIconLog += ShowNotification;
tmrUpdate.Enabled = true;
// tmrUpdate.Enabled = true; TODO remove tmrUpdate and leave tick()
Global.Load();
hideDS4CheckBox.CheckedChanged -= hideDS4CheckBox_CheckedChanged;
hideDS4CheckBox.Checked = Global.getUseExclusiveMode();
hideDS4CheckBox.CheckedChanged += hideDS4CheckBox_CheckedChanged;
if (btnStartStop.Enabled)
btnStartStop_Click(sender, e);
// New settings
this.Width = Global.getFormWidth();
@ -104,8 +100,10 @@ namespace ScpServer
Form_Resize(sender, e);
}
Global.loadCustomMapping(0);
Global.ControllerStatusChange += ControllerStatusChange;
ControllerStatusChanged();
if (btnStartStop.Enabled)
btnStartStop_Clicked();
}
protected void Form_Close(object sender, FormClosingEventArgs e)
{
@ -116,6 +114,10 @@ namespace ScpServer
}
protected void btnStartStop_Click(object sender, EventArgs e)
{
btnStartStop_Clicked();
}
protected void btnStartStop_Clicked()
{
if (btnStartStop.Text == Properties.Resources.Start
&& rootHub.Start())
@ -156,17 +158,23 @@ namespace ScpServer
base.WndProc(ref m);
}
protected void tmrUpdate_Tick(object sender, EventArgs e)
{
delegate void ControllerStatusChangedDelegate(object sender, EventArgs e);
protected void ControllerStatusChange(object sender, EventArgs e)
{
if (InvokeRequired)
Invoke(new ControllerStatusChangedDelegate(ControllerStatusChange), new object[] { sender, e });
else
ControllerStatusChanged();
}
protected void ControllerStatusChanged()
{
// If controllers are detected, but not checked, automatically check #1
bool checkFirst = true;
bool optionsEnabled = false;
for (Int32 Index = 0; Index < Pad.Length; Index++)
{
string contollerInfo = rootHub.getDS4ControllerInfo(Index);
Pad[Index].Text = contollerInfo;
Pad[Index].Text = rootHub.getDS4ControllerInfo(Index);
if (Pad[Index].Text != null && Pad[Index].Text != "")
{
Pad[Index].Enabled = true;
@ -237,8 +245,8 @@ namespace ScpServer
module.Dispose();
Global.setUseExclusiveMode(hideDS4CheckBox.Checked);
btnStartStop_Click(sender, e);
btnStartStop_Click(sender, e);
btnStartStop_Clicked();
btnStartStop_Clicked();
Global.Save();
}
private void startMinimizedCheckBox_CheckedChanged(object sender, EventArgs e)

View File

@ -62,6 +62,7 @@ namespace HidLibrary
public SafeFileHandle safeReadHandle { get; private set; }
public FileStream fileStream { get; private set; }
public bool IsOpen { get; private set; }
public bool IsExclusive { get; private set; }
public bool IsConnected { get { return HidDevices.IsConnected(_devicePath); } }
public bool IsTimedOut { get { return idleTicks > 5; } }
public string Description { get { return _description; } }
@ -93,7 +94,7 @@ namespace HidLibrary
if (IsOpen) return;
try
{
if (safeReadHandle == null)
if (safeReadHandle == null || safeReadHandle.IsInvalid)
safeReadHandle = OpenHandle(_devicePath, isExclusive);
}
catch (Exception exception)
@ -103,6 +104,7 @@ namespace HidLibrary
}
IsOpen = !safeReadHandle.IsInvalid;
IsExclusive = isExclusive;
}
public void CloseDevice()
@ -327,15 +329,7 @@ namespace HidLibrary
}
}
public bool WriteFile(byte[] buffer)
{
uint bytesWritten = 0;
if ( NativeMethods.WriteFile(safeReadHandle.DangerousGetHandle(), buffer, (uint)buffer.Length, out bytesWritten, IntPtr.Zero) && bytesWritten > 0)
return true;
else
return false;
}
public bool WriteOutputReportViaInterrupt(byte[] outputBuffer)
public bool WriteOutputReportViaInterrupt(byte[] outputBuffer, int timeout)
{
try
{
@ -409,8 +403,6 @@ namespace HidLibrary
byte[] buffer = new byte[126];
NativeMethods.HidD_GetSerialNumberString(safeReadHandle.DangerousGetHandle(), buffer, (ulong)buffer.Length);
string MACAddr = System.Text.Encoding.Unicode.GetString(buffer).Replace("\0", string.Empty).ToUpper();
if (MACAddr == null || MACAddr == String.Empty)
MACAddr = "000000000000";
MACAddr = String.Format("{0}{1}:{2}{3}:{4}{5}:{6}{7}:{8}{9}:{10}{11}",
MACAddr[0], MACAddr[1], MACAddr[2], MACAddr[3], MACAddr[4],
MACAddr[5], MACAddr[6], MACAddr[7], MACAddr[8],

View File

@ -66,7 +66,7 @@ namespace HidLibrary
static internal extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);
[DllImport("kernel32.dll")]
static internal extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
static internal extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped);
internal const int DBT_DEVICEARRIVAL = 0x8000;
internal const int DBT_DEVICEREMOVECOMPLETE = 0x8004;