diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs index 8a78649..15a735b 100644 --- a/DS4Windows/DS4Control/ControlService.cs +++ b/DS4Windows/DS4Control/ControlService.cs @@ -387,9 +387,12 @@ namespace DS4Windows DS4LightBar.defaultLight = false; //foreach (DS4Device device in devices) - for (int i = 0, devCount = devices.Count(); i < devCount; i++) + //for (int i = 0, devCount = devices.Count(); i < devCount; i++) + int i = 0; + for (var devEnum = devices.GetEnumerator(); devEnum.MoveNext(); i++) { - DS4Device device = devices.ElementAt(i); + DS4Device device = devEnum.Current; + //DS4Device device = devices.ElementAt(i); if (showlog) LogDebug(Properties.Resources.FoundController + device.getMacAddress() + " (" + device.getConnectionType() + ")"); @@ -410,8 +413,9 @@ namespace DS4Windows { ProfilePath[i] = OlderProfilePath[i]; } - LoadProfile(i, false, this, false, false); + touchPad[i] = new Mouse(i, device); + LoadProfile(i, false, this, false, false); device.LightBarColor = getMainColor(i); if (!getDInputOnly(i) && device.isSynced()) @@ -439,7 +443,7 @@ namespace DS4Windows this.On_Report(sender, e, tempIdx); }; - EventHandler tempEvnt = (sender, args) => + DS4Device.ReportHandler tempEvnt = (sender, args) => { DualShockPadMeta padDetail = new DualShockPadMeta(); GetPadDetailForIdx(tempIdx, ref padDetail); @@ -594,9 +598,11 @@ namespace DS4Windows DS4Devices.findControllers(); IEnumerable devices = DS4Devices.getDS4Controllers(); //foreach (DS4Device device in devices) - for (int i = 0, devlen = devices.Count(); i < devlen; i++) + //for (int i = 0, devlen = devices.Count(); i < devlen; i++) + for (var devEnum = devices.GetEnumerator(); devEnum.MoveNext();) { - DS4Device device = devices.ElementAt(i); + DS4Device device = devEnum.Current; + //DS4Device device = devices.ElementAt(i); if (device.isDisconnectingStatus()) continue; @@ -638,8 +644,8 @@ namespace DS4Windows ProfilePath[Index] = OlderProfilePath[Index]; } - LoadProfile(Index, false, this, false, false); touchPad[Index] = new Mouse(Index, device); + LoadProfile(Index, false, this, false, false); device.LightBarColor = getMainColor(Index); int tempIdx = Index; @@ -648,7 +654,7 @@ namespace DS4Windows this.On_Report(sender, e, tempIdx); }; - EventHandler tempEvnt = (sender, args) => + DS4Device.ReportHandler tempEvnt = (sender, args) => { DualShockPadMeta padDetail = new DualShockPadMeta(); GetPadDetailForIdx(tempIdx, ref padDetail); @@ -1077,9 +1083,10 @@ namespace DS4Windows private string[] tempStrings = new string[4] { string.Empty, string.Empty, string.Empty, string.Empty }; // Called every time a new input report has arrived - protected virtual void On_Report(object sender, EventArgs e, int ind) + //protected virtual void On_Report(object sender, EventArgs e, int ind) + protected virtual void On_Report(DS4Device device, EventArgs e, int ind) { - DS4Device device = (DS4Device)sender; + //DS4Device device = (DS4Device)sender; if (ind != -1) { diff --git a/DS4Windows/DS4Control/DS4LightBar.cs b/DS4Windows/DS4Control/DS4LightBar.cs index 0a146c6..5e72314 100644 --- a/DS4Windows/DS4Control/DS4LightBar.cs +++ b/DS4Windows/DS4Control/DS4LightBar.cs @@ -47,9 +47,9 @@ namespace DS4Windows { if (getLedAsBatteryIndicator(deviceNum)) { - DS4Color fullColor = getCustomColor(deviceNum); - DS4Color lowColor = getLowColor(deviceNum); - color = getTransitionedColor(lowColor, fullColor, device.getBattery()); + ref DS4Color fullColor = ref getCustomColor(deviceNum); + ref DS4Color lowColor = ref getLowColor(deviceNum); + color = getTransitionedColor(ref lowColor, ref fullColor, device.getBattery()); } else color = getCustomColor(deviceNum); @@ -83,9 +83,9 @@ namespace DS4Windows } else if (getLedAsBatteryIndicator(deviceNum)) { - DS4Color fullColor = getMainColor(deviceNum); - DS4Color lowColor = getLowColor(deviceNum); - color = getTransitionedColor(lowColor, fullColor, device.getBattery()); + ref DS4Color fullColor = ref getMainColor(deviceNum); + ref DS4Color lowColor = ref getLowColor(deviceNum); + color = getTransitionedColor(ref lowColor, ref fullColor, device.getBattery()); } else { @@ -95,7 +95,7 @@ namespace DS4Windows if (device.getBattery() <= getFlashAt(deviceNum) && !defaultLight && !device.isCharging()) { - DS4Color flashColor = getFlashColor(deviceNum); + ref DS4Color flashColor = ref getFlashColor(deviceNum); if (!(flashColor.red == 0 && flashColor.green == 0 && flashColor.blue == 0)) @@ -144,7 +144,8 @@ namespace DS4Windows } } - color = getTransitionedColor(color, new DS4Color(0, 0, 0), ratio); + DS4Color tempCol = new DS4Color(0, 0, 0); + color = getTransitionedColor(ref color, ref tempCol, ratio); } } @@ -159,11 +160,16 @@ namespace DS4Windows double ratio = 100.0 * (botratio / topratio), elapsed = ratio; if (ratio >= 50.0 && ratio < 100.0) { - color = getTransitionedColor(color, new DS4Color(0, 0, 0), + DS4Color emptyCol = new DS4Color(0, 0, 0); + color = getTransitionedColor(ref color, ref emptyCol, (uint)(-100.0 * (elapsed = 0.02 * (ratio - 50.0)) * (elapsed - 2.0))); } else if (ratio >= 100.0) - color = getTransitionedColor(color, new DS4Color(0, 0, 0), 100.0); + { + DS4Color emptyCol = new DS4Color(0, 0, 0); + color = getTransitionedColor(ref color, ref emptyCol, 100.0); + } + } if (device.isCharging() && device.getBattery() < 100) @@ -217,7 +223,8 @@ namespace DS4Windows } } - color = getTransitionedColor(color, new DS4Color(0, 0, 0), ratio); + DS4Color emptyCol = new DS4Color(0, 0, 0); + color = getTransitionedColor(ref color, ref emptyCol, ratio); break; } case 2: @@ -257,9 +264,22 @@ namespace DS4Windows float rumble = device.getLeftHeavySlowRumble() / 2.55f; byte max = Max(color.red, Max(color.green, color.blue)); if (device.getLeftHeavySlowRumble() > 100) - color = getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), rumble); + { + DS4Color maxCol = new DS4Color(max, max, 0); + DS4Color redCol = new DS4Color(255, 0, 0); + color = getTransitionedColor(ref maxCol, ref redCol, rumble); + } + else - color = getTransitionedColor(color, getTransitionedColor(new DS4Color(max, max, 0), new DS4Color(255, 0, 0), 39.6078f), device.getLeftHeavySlowRumble()); + { + DS4Color maxCol = new DS4Color(max, max, 0); + DS4Color redCol = new DS4Color(255, 0, 0); + DS4Color tempCol = getTransitionedColor(ref maxCol, + ref redCol, 39.6078f); + color = getTransitionedColor(ref color, ref tempCol, + device.getLeftHeavySlowRumble()); + } + } DS4HapticState haptics = new DS4HapticState diff --git a/DS4Windows/DS4Control/DS4StateFieldMapping.cs b/DS4Windows/DS4Control/DS4StateFieldMapping.cs index 2eb3daa..d99e472 100644 --- a/DS4Windows/DS4Control/DS4StateFieldMapping.cs +++ b/DS4Windows/DS4Control/DS4StateFieldMapping.cs @@ -63,93 +63,100 @@ namespace DS4Windows public void populateFieldMapping(DS4State cState, DS4StateExposed exposeState, Mouse tp, bool priorMouse = false) { - axisdirs[(int)DS4Controls.LXNeg] = cState.LX; - axisdirs[(int)DS4Controls.LXPos] = cState.LX; - axisdirs[(int)DS4Controls.LYNeg] = cState.LY; - axisdirs[(int)DS4Controls.LYPos] = cState.LY; + unchecked + { + axisdirs[(int)DS4Controls.LXNeg] = cState.LX; + axisdirs[(int)DS4Controls.LXPos] = cState.LX; + axisdirs[(int)DS4Controls.LYNeg] = cState.LY; + axisdirs[(int)DS4Controls.LYPos] = cState.LY; - axisdirs[(int)DS4Controls.RXNeg] = cState.RX; - axisdirs[(int)DS4Controls.RXPos] = cState.RX; - axisdirs[(int)DS4Controls.RYNeg] = cState.RY; - axisdirs[(int)DS4Controls.RYPos] = cState.RY; + axisdirs[(int)DS4Controls.RXNeg] = cState.RX; + axisdirs[(int)DS4Controls.RXPos] = cState.RX; + axisdirs[(int)DS4Controls.RYNeg] = cState.RY; + axisdirs[(int)DS4Controls.RYPos] = cState.RY; - triggers[(int)DS4Controls.L2] = cState.L2; - triggers[(int)DS4Controls.R2] = cState.R2; + triggers[(int)DS4Controls.L2] = cState.L2; + triggers[(int)DS4Controls.R2] = cState.R2; - buttons[(int)DS4Controls.L1] = cState.L1; - buttons[(int)DS4Controls.L3] = cState.L3; - buttons[(int)DS4Controls.R1] = cState.R1; - buttons[(int)DS4Controls.R3] = cState.R3; + buttons[(int)DS4Controls.L1] = cState.L1; + buttons[(int)DS4Controls.L3] = cState.L3; + buttons[(int)DS4Controls.R1] = cState.R1; + buttons[(int)DS4Controls.R3] = cState.R3; - buttons[(int)DS4Controls.Cross] = cState.Cross; - buttons[(int)DS4Controls.Triangle] = cState.Triangle; - buttons[(int)DS4Controls.Circle] = cState.Circle; - buttons[(int)DS4Controls.Square] = cState.Square; - buttons[(int)DS4Controls.PS] = cState.PS; - buttons[(int)DS4Controls.Options] = cState.Options; - buttons[(int)DS4Controls.Share] = cState.Share; + buttons[(int)DS4Controls.Cross] = cState.Cross; + buttons[(int)DS4Controls.Triangle] = cState.Triangle; + buttons[(int)DS4Controls.Circle] = cState.Circle; + buttons[(int)DS4Controls.Square] = cState.Square; + buttons[(int)DS4Controls.PS] = cState.PS; + buttons[(int)DS4Controls.Options] = cState.Options; + buttons[(int)DS4Controls.Share] = cState.Share; - buttons[(int)DS4Controls.DpadUp] = cState.DpadUp; - buttons[(int)DS4Controls.DpadRight] = cState.DpadRight; - buttons[(int)DS4Controls.DpadDown] = cState.DpadDown; - buttons[(int)DS4Controls.DpadLeft] = cState.DpadLeft; + buttons[(int)DS4Controls.DpadUp] = cState.DpadUp; + buttons[(int)DS4Controls.DpadRight] = cState.DpadRight; + buttons[(int)DS4Controls.DpadDown] = cState.DpadDown; + buttons[(int)DS4Controls.DpadLeft] = cState.DpadLeft; - buttons[(int)DS4Controls.TouchLeft] = tp != null ? (!priorMouse ? tp.leftDown : tp.priorLeftDown) : false; - buttons[(int)DS4Controls.TouchRight] = tp != null ? (!priorMouse ? tp.rightDown : tp.priorRightDown) : false; - buttons[(int)DS4Controls.TouchUpper] = tp != null ? (!priorMouse ? tp.upperDown : tp.priorUpperDown) : false; - buttons[(int)DS4Controls.TouchMulti] = tp != null ? (!priorMouse ? tp.multiDown : tp.priorMultiDown) : false; + buttons[(int)DS4Controls.TouchLeft] = tp != null ? (!priorMouse ? tp.leftDown : tp.priorLeftDown) : false; + buttons[(int)DS4Controls.TouchRight] = tp != null ? (!priorMouse ? tp.rightDown : tp.priorRightDown) : false; + buttons[(int)DS4Controls.TouchUpper] = tp != null ? (!priorMouse ? tp.upperDown : tp.priorUpperDown) : false; + buttons[(int)DS4Controls.TouchMulti] = tp != null ? (!priorMouse ? tp.multiDown : tp.priorMultiDown) : false; - int sixAxisX = -exposeState.getOutputAccelX(); - gryodirs[(int)DS4Controls.GyroXPos] = sixAxisX > 0 ? sixAxisX : 0; - gryodirs[(int)DS4Controls.GyroXNeg] = sixAxisX < 0 ? sixAxisX : 0; + int sixAxisX = -exposeState.getOutputAccelX(); + gryodirs[(int)DS4Controls.GyroXPos] = sixAxisX > 0 ? sixAxisX : 0; + gryodirs[(int)DS4Controls.GyroXNeg] = sixAxisX < 0 ? sixAxisX : 0; - int sixAxisZ = exposeState.getOutputAccelZ(); - gryodirs[(int)DS4Controls.GyroZPos] = sixAxisZ > 0 ? sixAxisZ : 0; - gryodirs[(int)DS4Controls.GyroZNeg] = sixAxisZ < 0 ? sixAxisZ : 0; + int sixAxisZ = exposeState.getOutputAccelZ(); + gryodirs[(int)DS4Controls.GyroZPos] = sixAxisZ > 0 ? sixAxisZ : 0; + gryodirs[(int)DS4Controls.GyroZNeg] = sixAxisZ < 0 ? sixAxisZ : 0; - swipedirs[(int)DS4Controls.SwipeLeft] = tp != null ? (!priorMouse ? tp.swipeLeftB : tp.priorSwipeLeftB) : (byte)0; - swipedirs[(int)DS4Controls.SwipeRight] = tp != null ? (!priorMouse ? tp.swipeRightB : tp.priorSwipeRightB) : (byte)0; - swipedirs[(int)DS4Controls.SwipeUp] = tp != null ? (!priorMouse ? tp.swipeUpB : tp.priorSwipeUpB) : (byte)0; - swipedirs[(int)DS4Controls.SwipeDown] = tp != null ? (!priorMouse ? tp.swipeDownB : tp.priorSwipeDownB) : (byte)0; + swipedirs[(int)DS4Controls.SwipeLeft] = tp != null ? (!priorMouse ? tp.swipeLeftB : tp.priorSwipeLeftB) : (byte)0; + swipedirs[(int)DS4Controls.SwipeRight] = tp != null ? (!priorMouse ? tp.swipeRightB : tp.priorSwipeRightB) : (byte)0; + swipedirs[(int)DS4Controls.SwipeUp] = tp != null ? (!priorMouse ? tp.swipeUpB : tp.priorSwipeUpB) : (byte)0; + swipedirs[(int)DS4Controls.SwipeDown] = tp != null ? (!priorMouse ? tp.swipeDownB : tp.priorSwipeDownB) : (byte)0; - swipedirbools[(int)DS4Controls.SwipeLeft] = tp != null ? (!priorMouse ? tp.swipeLeft : tp.priorSwipeLeft) : false; - swipedirbools[(int)DS4Controls.SwipeRight] = tp != null ? (!priorMouse ? tp.swipeRight : tp.priorSwipeRight) : false; - swipedirbools[(int)DS4Controls.SwipeUp] = tp != null ? (!priorMouse ? tp.swipeUp : tp.priorSwipeUp) : false; - swipedirbools[(int)DS4Controls.SwipeDown] = tp != null ? (!priorMouse ? tp.swipeDown : tp.priorSwipeDown) : false; + swipedirbools[(int)DS4Controls.SwipeLeft] = tp != null ? (!priorMouse ? tp.swipeLeft : tp.priorSwipeLeft) : false; + swipedirbools[(int)DS4Controls.SwipeRight] = tp != null ? (!priorMouse ? tp.swipeRight : tp.priorSwipeRight) : false; + swipedirbools[(int)DS4Controls.SwipeUp] = tp != null ? (!priorMouse ? tp.swipeUp : tp.priorSwipeUp) : false; + swipedirbools[(int)DS4Controls.SwipeDown] = tp != null ? (!priorMouse ? tp.swipeDown : tp.priorSwipeDown) : false; + } + } public void populateState(DS4State state) { - state.LX = axisdirs[(int)DS4Controls.LXNeg]; - state.LX = axisdirs[(int)DS4Controls.LXPos]; - state.LY = axisdirs[(int)DS4Controls.LYNeg]; - state.LY = axisdirs[(int)DS4Controls.LYPos]; + unchecked + { + state.LX = axisdirs[(int)DS4Controls.LXNeg]; + state.LX = axisdirs[(int)DS4Controls.LXPos]; + state.LY = axisdirs[(int)DS4Controls.LYNeg]; + state.LY = axisdirs[(int)DS4Controls.LYPos]; - state.RX = axisdirs[(int)DS4Controls.RXNeg]; - state.RX = axisdirs[(int)DS4Controls.RXPos]; - state.RY = axisdirs[(int)DS4Controls.RYNeg]; - state.RY = axisdirs[(int)DS4Controls.RYPos]; + state.RX = axisdirs[(int)DS4Controls.RXNeg]; + state.RX = axisdirs[(int)DS4Controls.RXPos]; + state.RY = axisdirs[(int)DS4Controls.RYNeg]; + state.RY = axisdirs[(int)DS4Controls.RYPos]; - state.L2 = triggers[(int)DS4Controls.L2]; - state.R2 = triggers[(int)DS4Controls.R2]; + state.L2 = triggers[(int)DS4Controls.L2]; + state.R2 = triggers[(int)DS4Controls.R2]; - state.L1 = buttons[(int)DS4Controls.L1]; - state.L3 = buttons[(int)DS4Controls.L3]; - state.R1 = buttons[(int)DS4Controls.R1]; - state.R3 = buttons[(int)DS4Controls.R3]; + state.L1 = buttons[(int)DS4Controls.L1]; + state.L3 = buttons[(int)DS4Controls.L3]; + state.R1 = buttons[(int)DS4Controls.R1]; + state.R3 = buttons[(int)DS4Controls.R3]; - state.Cross = buttons[(int)DS4Controls.Cross]; - state.Triangle = buttons[(int)DS4Controls.Triangle]; - state.Circle = buttons[(int)DS4Controls.Circle]; - state.Square = buttons[(int)DS4Controls.Square]; - state.PS = buttons[(int)DS4Controls.PS]; - state.Options = buttons[(int)DS4Controls.Options]; - state.Share = buttons[(int)DS4Controls.Share]; + state.Cross = buttons[(int)DS4Controls.Cross]; + state.Triangle = buttons[(int)DS4Controls.Triangle]; + state.Circle = buttons[(int)DS4Controls.Circle]; + state.Square = buttons[(int)DS4Controls.Square]; + state.PS = buttons[(int)DS4Controls.PS]; + state.Options = buttons[(int)DS4Controls.Options]; + state.Share = buttons[(int)DS4Controls.Share]; - state.DpadUp = buttons[(int)DS4Controls.DpadUp]; - state.DpadRight = buttons[(int)DS4Controls.DpadRight]; - state.DpadDown = buttons[(int)DS4Controls.DpadDown]; - state.DpadLeft = buttons[(int)DS4Controls.DpadLeft]; + state.DpadUp = buttons[(int)DS4Controls.DpadUp]; + state.DpadRight = buttons[(int)DS4Controls.DpadRight]; + state.DpadDown = buttons[(int)DS4Controls.DpadDown]; + state.DpadLeft = buttons[(int)DS4Controls.DpadLeft]; + } } } } diff --git a/DS4Windows/DS4Control/ITouchpadBehaviour.cs b/DS4Windows/DS4Control/ITouchpadBehaviour.cs index d175391..80a4343 100644 --- a/DS4Windows/DS4Control/ITouchpadBehaviour.cs +++ b/DS4Windows/DS4Control/ITouchpadBehaviour.cs @@ -4,12 +4,12 @@ namespace DS4Windows { interface ITouchpadBehaviour { - void touchesBegan(object sender, TouchpadEventArgs arg); - void touchesMoved(object sender, TouchpadEventArgs arg); - void touchButtonUp(object sender, TouchpadEventArgs arg); - void touchButtonDown(object sender, TouchpadEventArgs arg); - void touchesEnded(object sender, TouchpadEventArgs arg); - void sixaxisMoved(object sender, SixAxisEventArgs unused); - void touchUnchanged(object sender, EventArgs unused); + void touchesBegan(DS4Touchpad sender, TouchpadEventArgs arg); + void touchesMoved(DS4Touchpad sender, TouchpadEventArgs arg); + void touchButtonUp(DS4Touchpad sender, TouchpadEventArgs arg); + void touchButtonDown(DS4Touchpad sender, TouchpadEventArgs arg); + void touchesEnded(DS4Touchpad sender, TouchpadEventArgs arg); + void sixaxisMoved(DS4SixAxis sender, SixAxisEventArgs unused); + void touchUnchanged(DS4Touchpad sender, EventArgs unused); } } diff --git a/DS4Windows/DS4Control/Mapping.cs b/DS4Windows/DS4Control/Mapping.cs index d663640..5851706 100644 --- a/DS4Windows/DS4Control/Mapping.cs +++ b/DS4Windows/DS4Control/Mapping.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Diagnostics; using static DS4Windows.Global; +using System.Drawing; // Point struct namespace DS4Windows { @@ -40,9 +42,11 @@ namespace DS4Windows //foreach (KeyPresses kp in keyPresses.Values) Dictionary.ValueCollection keyValues = keyPresses.Values; - for (int i = 0, kpCount = keyValues.Count; i < kpCount; i++) + for (var keyEnum = keyValues.GetEnumerator(); keyEnum.MoveNext();) + //for (int i = 0, kpCount = keyValues.Count; i < kpCount; i++) { - KeyPresses kp = keyValues.ElementAt(i); + //KeyPresses kp = keyValues.ElementAt(i); + KeyPresses kp = keyEnum.Current; kp.previous = kp.current; if (performClear) { @@ -58,6 +62,25 @@ namespace DS4Windows public bool[] dev = new bool[4]; } + struct ControlToXInput + { + public DS4Controls ds4input; + public DS4Controls xoutput; + + public ControlToXInput(DS4Controls input, DS4Controls output) + { + ds4input = input; xoutput = output; + } + } + + static Queue[] customMapQueue = new Queue[4] + { + new Queue(), new Queue(), + new Queue(), new Queue() + }; + + static ReaderWriterLockSlim syncStateLock = new ReaderWriterLockSlim(); + public static SyntheticState globalState = new SyntheticState(); public static SyntheticState[] deviceState = new SyntheticState[4] { new SyntheticState(), new SyntheticState(), new SyntheticState(), @@ -171,204 +194,207 @@ namespace DS4Windows public static void Commit(int device) { SyntheticState state = deviceState[device]; - lock (globalState) + syncStateLock.EnterWriteLock(); + + globalState.currentClicks.leftCount += state.currentClicks.leftCount - state.previousClicks.leftCount; + globalState.currentClicks.middleCount += state.currentClicks.middleCount - state.previousClicks.middleCount; + globalState.currentClicks.rightCount += state.currentClicks.rightCount - state.previousClicks.rightCount; + globalState.currentClicks.fourthCount += state.currentClicks.fourthCount - state.previousClicks.fourthCount; + globalState.currentClicks.fifthCount += state.currentClicks.fifthCount - state.previousClicks.fifthCount; + globalState.currentClicks.wUpCount += state.currentClicks.wUpCount - state.previousClicks.wUpCount; + globalState.currentClicks.wDownCount += state.currentClicks.wDownCount - state.previousClicks.wDownCount; + globalState.currentClicks.toggleCount += state.currentClicks.toggleCount - state.previousClicks.toggleCount; + globalState.currentClicks.toggle = state.currentClicks.toggle; + + if (globalState.currentClicks.toggleCount != 0 && globalState.previousClicks.toggleCount == 0 && globalState.currentClicks.toggle) { - globalState.currentClicks.leftCount += state.currentClicks.leftCount - state.previousClicks.leftCount; - globalState.currentClicks.middleCount += state.currentClicks.middleCount - state.previousClicks.middleCount; - globalState.currentClicks.rightCount += state.currentClicks.rightCount - state.previousClicks.rightCount; - globalState.currentClicks.fourthCount += state.currentClicks.fourthCount - state.previousClicks.fourthCount; - globalState.currentClicks.fifthCount += state.currentClicks.fifthCount - state.previousClicks.fifthCount; - globalState.currentClicks.wUpCount += state.currentClicks.wUpCount - state.previousClicks.wUpCount; - globalState.currentClicks.wDownCount += state.currentClicks.wDownCount - state.previousClicks.wDownCount; - globalState.currentClicks.toggleCount += state.currentClicks.toggleCount - state.previousClicks.toggleCount; - globalState.currentClicks.toggle = state.currentClicks.toggle; + if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN); + if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN); + if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 1); + if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 2); + } + else if (globalState.currentClicks.toggleCount != 0 && globalState.previousClicks.toggleCount == 0 && !globalState.currentClicks.toggle) + { + if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP); + if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP); + if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 1); + if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 2); + } - if (globalState.currentClicks.toggleCount != 0 && globalState.previousClicks.toggleCount == 0 && globalState.currentClicks.toggle) + if (globalState.currentClicks.toggleCount == 0 && globalState.previousClicks.toggleCount == 0) + { + if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); + else if (globalState.currentClicks.leftCount == 0 && globalState.previousClicks.leftCount != 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); + + if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN); + else if (globalState.currentClicks.middleCount == 0 && globalState.previousClicks.middleCount != 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP); + + if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN); + else if (globalState.currentClicks.rightCount == 0 && globalState.previousClicks.rightCount != 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP); + + if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 1); + else if (globalState.currentClicks.fourthCount == 0 && globalState.previousClicks.fourthCount != 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 1); + + if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 2); + else if (globalState.currentClicks.fifthCount == 0 && globalState.previousClicks.fifthCount != 0) + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 2); + + if (globalState.currentClicks.wUpCount != 0 && globalState.previousClicks.wUpCount == 0) { - if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); - if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN); - if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN); - if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 1); - if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 2); + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, 120); + oldnow = DateTime.UtcNow; + wheel = 120; } - else if (globalState.currentClicks.toggleCount != 0 && globalState.previousClicks.toggleCount == 0 && !globalState.currentClicks.toggle) + else if (globalState.currentClicks.wUpCount == 0 && globalState.previousClicks.wUpCount != 0) + wheel = 0; + + if (globalState.currentClicks.wDownCount != 0 && globalState.previousClicks.wDownCount == 0) { - if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); - if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP); - if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP); - if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 1); - if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 2); - } - - if (globalState.currentClicks.toggleCount == 0 && globalState.previousClicks.toggleCount == 0) - { - if (globalState.currentClicks.leftCount != 0 && globalState.previousClicks.leftCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTDOWN); - else if (globalState.currentClicks.leftCount == 0 && globalState.previousClicks.leftCount != 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_LEFTUP); - - if (globalState.currentClicks.middleCount != 0 && globalState.previousClicks.middleCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEDOWN); - else if (globalState.currentClicks.middleCount == 0 && globalState.previousClicks.middleCount != 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_MIDDLEUP); - - if (globalState.currentClicks.rightCount != 0 && globalState.previousClicks.rightCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTDOWN); - else if (globalState.currentClicks.rightCount == 0 && globalState.previousClicks.rightCount != 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_RIGHTUP); - - if (globalState.currentClicks.fourthCount != 0 && globalState.previousClicks.fourthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 1); - else if (globalState.currentClicks.fourthCount == 0 && globalState.previousClicks.fourthCount != 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 1); - - if (globalState.currentClicks.fifthCount != 0 && globalState.previousClicks.fifthCount == 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONDOWN, 2); - else if (globalState.currentClicks.fifthCount == 0 && globalState.previousClicks.fifthCount != 0) - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_XBUTTONUP, 2); - - if (globalState.currentClicks.wUpCount != 0 && globalState.previousClicks.wUpCount == 0) - { - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, 120); - oldnow = DateTime.UtcNow; - wheel = 120; - } - else if (globalState.currentClicks.wUpCount == 0 && globalState.previousClicks.wUpCount != 0) - wheel = 0; - - if (globalState.currentClicks.wDownCount != 0 && globalState.previousClicks.wDownCount == 0) - { - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, -120); - oldnow = DateTime.UtcNow; - wheel = -120; - } - if (globalState.currentClicks.wDownCount == 0 && globalState.previousClicks.wDownCount != 0) - wheel = 0; + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, -120); + oldnow = DateTime.UtcNow; + wheel = -120; } + if (globalState.currentClicks.wDownCount == 0 && globalState.previousClicks.wDownCount != 0) + wheel = 0; + } - if (wheel != 0) //Continue mouse wheel movement + if (wheel != 0) //Continue mouse wheel movement + { + DateTime now = DateTime.UtcNow; + if (now >= oldnow + TimeSpan.FromMilliseconds(100) && !pressagain) { - DateTime now = DateTime.UtcNow; - if (now >= oldnow + TimeSpan.FromMilliseconds(100) && !pressagain) - { - oldnow = now; - InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, wheel); - } + oldnow = now; + InputMethods.MouseEvent(InputMethods.MOUSEEVENTF_WHEEL, wheel); } + } - // Merge and synthesize all key presses/releases that are present in this device's mapping. - // TODO what about the rest? e.g. repeat keys really ought to be on some set schedule - Dictionary.KeyCollection kvpKeys = state.keyPresses.Keys; - //foreach (KeyValuePair kvp in state.keyPresses) - for (int i = 0, keyCount = kvpKeys.Count; i < keyCount; i++) + // Merge and synthesize all key presses/releases that are present in this device's mapping. + // TODO what about the rest? e.g. repeat keys really ought to be on some set schedule + Dictionary.KeyCollection kvpKeys = state.keyPresses.Keys; + //foreach (KeyValuePair kvp in state.keyPresses) + //for (int i = 0, keyCount = kvpKeys.Count; i < keyCount; i++) + for (var keyEnum = kvpKeys.GetEnumerator(); keyEnum.MoveNext();) + { + //UInt16 kvpKey = kvpKeys.ElementAt(i); + UInt16 kvpKey = keyEnum.Current; + SyntheticState.KeyPresses kvpValue = state.keyPresses[kvpKey]; + + SyntheticState.KeyPresses gkp; + if (globalState.keyPresses.TryGetValue(kvpKey, out gkp)) { - UInt16 kvpKey = kvpKeys.ElementAt(i); - SyntheticState.KeyPresses kvpValue = state.keyPresses[kvpKey]; - - SyntheticState.KeyPresses gkp; - if (globalState.keyPresses.TryGetValue(kvpKey, out gkp)) + gkp.current.vkCount += kvpValue.current.vkCount - kvpValue.previous.vkCount; + gkp.current.scanCodeCount += kvpValue.current.scanCodeCount - kvpValue.previous.scanCodeCount; + gkp.current.repeatCount += kvpValue.current.repeatCount - kvpValue.previous.repeatCount; + gkp.current.toggle = kvpValue.current.toggle; + gkp.current.toggleCount += kvpValue.current.toggleCount - kvpValue.previous.toggleCount; + } + else + { + gkp = new SyntheticState.KeyPresses(); + gkp.current = kvpValue.current; + globalState.keyPresses[kvpKey] = gkp; + } + if (gkp.current.toggleCount != 0 && gkp.previous.toggleCount == 0 && gkp.current.toggle) + { + if (gkp.current.scanCodeCount != 0) + InputMethods.performSCKeyPress(kvpKey); + else + InputMethods.performKeyPress(kvpKey); + } + else if (gkp.current.toggleCount != 0 && gkp.previous.toggleCount == 0 && !gkp.current.toggle) + { + if (gkp.previous.scanCodeCount != 0) // use the last type of VK/SC + InputMethods.performSCKeyRelease(kvpKey); + else + InputMethods.performKeyRelease(kvpKey); + } + else if (gkp.current.vkCount + gkp.current.scanCodeCount != 0 && gkp.previous.vkCount + gkp.previous.scanCodeCount == 0) + { + if (gkp.current.scanCodeCount != 0) { - gkp.current.vkCount += kvpValue.current.vkCount - kvpValue.previous.vkCount; - gkp.current.scanCodeCount += kvpValue.current.scanCodeCount - kvpValue.previous.scanCodeCount; - gkp.current.repeatCount += kvpValue.current.repeatCount - kvpValue.previous.repeatCount; - gkp.current.toggle = kvpValue.current.toggle; - gkp.current.toggleCount += kvpValue.current.toggleCount - kvpValue.previous.toggleCount; + oldnow = DateTime.UtcNow; + InputMethods.performSCKeyPress(kvpKey); + pressagain = false; + keyshelddown = kvpKey; } else { - gkp = new SyntheticState.KeyPresses(); - gkp.current = kvpValue.current; - globalState.keyPresses[kvpKey] = gkp; + oldnow = DateTime.UtcNow; + InputMethods.performKeyPress(kvpKey); + pressagain = false; + keyshelddown = kvpKey; } - if (gkp.current.toggleCount != 0 && gkp.previous.toggleCount == 0 && gkp.current.toggle) + } + else if (gkp.current.toggleCount != 0 || gkp.previous.toggleCount != 0 || gkp.current.repeatCount != 0 || // repeat or SC/VK transition + ((gkp.previous.scanCodeCount == 0) != (gkp.current.scanCodeCount == 0))) //repeat keystroke after 500ms + { + if (keyshelddown == kvpKey) { - if (gkp.current.scanCodeCount != 0) - InputMethods.performSCKeyPress(kvpKey); - else - InputMethods.performKeyPress(kvpKey); - } - else if (gkp.current.toggleCount != 0 && gkp.previous.toggleCount == 0 && !gkp.current.toggle) - { - if (gkp.previous.scanCodeCount != 0) // use the last type of VK/SC - InputMethods.performSCKeyRelease(kvpKey); - else - InputMethods.performKeyRelease(kvpKey); - } - else if (gkp.current.vkCount + gkp.current.scanCodeCount != 0 && gkp.previous.vkCount + gkp.previous.scanCodeCount == 0) - { - if (gkp.current.scanCodeCount != 0) + DateTime now = DateTime.UtcNow; + if (now >= oldnow + TimeSpan.FromMilliseconds(500) && !pressagain) { - oldnow = DateTime.UtcNow; - InputMethods.performSCKeyPress(kvpKey); - pressagain = false; - keyshelddown = kvpKey; + oldnow = now; + pressagain = true; } - else + if (pressagain && gkp.current.scanCodeCount != 0) { - oldnow = DateTime.UtcNow; - InputMethods.performKeyPress(kvpKey); - pressagain = false; - keyshelddown = kvpKey; - } - } - else if (gkp.current.toggleCount != 0 || gkp.previous.toggleCount != 0 || gkp.current.repeatCount != 0 || // repeat or SC/VK transition - ((gkp.previous.scanCodeCount == 0) != (gkp.current.scanCodeCount == 0))) //repeat keystroke after 500ms - { - if (keyshelddown == kvpKey) - { - DateTime now = DateTime.UtcNow; - if (now >= oldnow + TimeSpan.FromMilliseconds(500) && !pressagain) + now = DateTime.UtcNow; + if (now >= oldnow + TimeSpan.FromMilliseconds(25) && pressagain) { oldnow = now; - pressagain = true; - } - if (pressagain && gkp.current.scanCodeCount != 0) - { - now = DateTime.UtcNow; - if (now >= oldnow + TimeSpan.FromMilliseconds(25) && pressagain) - { - oldnow = now; - InputMethods.performSCKeyPress(kvpKey); - } - } - else if (pressagain) - { - now = DateTime.UtcNow; - if (now >= oldnow + TimeSpan.FromMilliseconds(25) && pressagain) - { - oldnow = now; - InputMethods.performKeyPress(kvpKey); - } + InputMethods.performSCKeyPress(kvpKey); } } - } - if ((gkp.current.toggleCount == 0 && gkp.previous.toggleCount == 0) && gkp.current.vkCount + gkp.current.scanCodeCount == 0 && gkp.previous.vkCount + gkp.previous.scanCodeCount != 0) - { - if (gkp.previous.scanCodeCount != 0) // use the last type of VK/SC + else if (pressagain) { - InputMethods.performSCKeyRelease(kvpKey); - pressagain = false; - } - else - { - InputMethods.performKeyRelease(kvpKey); - pressagain = false; + now = DateTime.UtcNow; + if (now >= oldnow + TimeSpan.FromMilliseconds(25) && pressagain) + { + oldnow = now; + InputMethods.performKeyPress(kvpKey); + } } } } - globalState.SaveToPrevious(false); + if ((gkp.current.toggleCount == 0 && gkp.previous.toggleCount == 0) && gkp.current.vkCount + gkp.current.scanCodeCount == 0 && gkp.previous.vkCount + gkp.previous.scanCodeCount != 0) + { + if (gkp.previous.scanCodeCount != 0) // use the last type of VK/SC + { + InputMethods.performSCKeyRelease(kvpKey); + pressagain = false; + } + else + { + InputMethods.performKeyRelease(kvpKey); + pressagain = false; + } + } } + globalState.SaveToPrevious(false); + + syncStateLock.ExitWriteLock(); state.SaveToPrevious(true); } @@ -822,6 +848,15 @@ namespace DS4Windows dState.LX = (byte)(outputX * capX + 128.0); dState.LY = (byte)(outputY * capY + 128.0); } + else if (lsOutCurveMode == 4) + { + double absX = Math.Abs(tempX); + double absY = Math.Abs(tempY); + double outputX = absX * (absX - 2.0); + double outputY = absY * (absY - 2.0); + dState.LX = (byte)(-1.0 * outputX * signX * capX + 128.0); + dState.LY = (byte)(-1.0 * outputY * signY * capY + 128.0); + } } int rsOutCurveMode = rsOutCurveModeArray[device] = getRsOutCurveMode(device); @@ -884,6 +919,15 @@ namespace DS4Windows dState.RX = (byte)(outputX * capX + 128.0); dState.RY = (byte)(outputY * capY + 128.0); } + else if (rsOutCurveMode == 4) + { + double absX = Math.Abs(tempX); + double absY = Math.Abs(tempY); + double outputX = absX * (absX - 2.0); + double outputY = absY * (absY - 2.0); + dState.RX = (byte)(-1.0 * outputX * signX * capX + 128.0); + dState.RY = (byte)(-1.0 * outputY * signY * capY + 128.0); + } } int l2OutCurveMode = tempIntArray[device] = getL2OutCurveMode(device); @@ -900,6 +944,11 @@ namespace DS4Windows double output = temp * temp * temp; dState.L2 = (byte)(output * 255.0); } + else if (l2OutCurveMode == 3) + { + double output = temp * (temp - 2.0); + dState.L2 = (byte)(-1.0 * output * 255.0); + } } int r2OutCurveMode = tempIntArray[device] = getR2OutCurveMode(device); @@ -916,6 +965,11 @@ namespace DS4Windows double output = temp * temp * temp; dState.R2 = (byte)(output * 255.0); } + else if (r2OutCurveMode == 3) + { + double output = temp * (temp - 2.0); + dState.R2 = (byte)(-1.0 * output * 255.0); + } } bool sOff = tempBool = isUsingSAforMouse(device); @@ -991,6 +1045,13 @@ namespace DS4Windows result = (int)(output * 128.0); dState.Motion.outputAccelX = result; } + else if (sxOutCurveMode == 3) + { + double abs = Math.Abs(temp); + double output = abs * (abs - 2.0); + dState.Motion.outputAccelX = (byte)(-1.0 * output * + sign * 128.0); + } } int szOutCurveMode = tempIntArray[device] = getSZOutCurveMode(device); @@ -1010,6 +1071,13 @@ namespace DS4Windows result = (int)(output * 128.0); dState.Motion.outputAccelZ = result; } + else if (szOutCurveMode == 3) + { + double abs = Math.Abs(temp); + double output = abs * (abs - 2.0); + dState.Motion.outputAccelZ = (byte)(-1.0 * output * + sign * 128.0); + } } } @@ -1117,10 +1185,6 @@ namespace DS4Windows Mouse tp, ControlService ctrl) { /* TODO: This method is slow sauce. Find ways to speed up action execution */ - MappedState.LX = 128; - MappedState.LY = 128; - MappedState.RX = 128; - MappedState.RY = 128; double tempMouseDeltaX = 0.0; double tempMouseDeltaY = 0.0; int mouseDeltaX = 0; @@ -1139,16 +1203,18 @@ namespace DS4Windows MapCustomAction(device, cState, MappedState, eState, tp, ctrl, fieldMapping, outputfieldMapping); if (ctrl.DS4Controllers[device] == null) return; - cState.CopyTo(MappedState); + //cState.CopyTo(MappedState); - Dictionary tempControlDict = new Dictionary(); + //Dictionary tempControlDict = new Dictionary(); //MultiValueDict tempControlDict = new MultiValueDict(); DS4Controls usingExtra = DS4Controls.None; List tempSettingsList = getDS4CSettings(device); //foreach (DS4ControlSettings dcs in getDS4CSettings(device)) - for (int settingIndex = 0, arlen = tempSettingsList.Count; settingIndex < arlen; settingIndex++) + //for (int settingIndex = 0, arlen = tempSettingsList.Count; settingIndex < arlen; settingIndex++) + for (var settingEnum = tempSettingsList.GetEnumerator(); settingEnum.MoveNext();) { - DS4ControlSettings dcs = tempSettingsList[settingIndex]; + //DS4ControlSettings dcs = tempSettingsList[settingIndex]; + DS4ControlSettings dcs = settingEnum.Current; object action = null; DS4ControlSettings.ActionType actionType = 0; DS4KeyType keyType = DS4KeyType.None; @@ -1306,7 +1372,8 @@ namespace DS4Windows if (xboxControl >= X360Controls.LXNeg && xboxControl <= X360Controls.Start) { DS4Controls tempDS4Control = reverseX360ButtonMapping[(int)xboxControl]; - tempControlDict.Add(dcs.control, tempDS4Control); + customMapQueue[device].Enqueue(new ControlToXInput(dcs.control, tempDS4Control)); + //tempControlDict.Add(dcs.control, tempDS4Control); } else if (xboxControl >= X360Controls.LeftMouse && xboxControl <= X360Controls.WDOWN) { @@ -1433,7 +1500,6 @@ namespace DS4Windows { if (getBoolActionMapping2(device, dcs.control, cState, eState, tp, fieldMapping)) { - resetToDefaultValue2(dcs.control, MappedState, outputfieldMapping); if (!pressedonce[keyvalue]) { deviceState.currentClicks.toggle = !deviceState.currentClicks.toggle; @@ -1451,6 +1517,58 @@ namespace DS4Windows resetToDefaultValue2(dcs.control, MappedState, outputfieldMapping); } } + else + { + DS4StateFieldMapping.ControlType controlType = DS4StateFieldMapping.mappedType[(int)dcs.control]; + if (controlType == DS4StateFieldMapping.ControlType.AxisDir) + //if (dcs.control > DS4Controls.None && dcs.control < DS4Controls.L1) + { + //int current = (int)dcs.control; + //outputfieldMapping.axisdirs[current] = fieldMapping.axisdirs[current]; + customMapQueue[device].Enqueue(new ControlToXInput(dcs.control, dcs.control)); + } + } + } + + Queue tempControl = customMapQueue[device]; + unchecked + { + for (int i = 0, len = tempControl.Count; i < len; i++) + //while(tempControl.Any()) + { + ControlToXInput tempMap = tempControl.Dequeue(); + int controlNum = (int)tempMap.ds4input; + int tempOutControl = (int)tempMap.xoutput; + if (tempMap.xoutput >= DS4Controls.LXNeg && tempMap.xoutput <= DS4Controls.RYPos) + { + const byte axisDead = 128; + DS4StateFieldMapping.ControlType controlType = DS4StateFieldMapping.mappedType[tempOutControl]; + bool alt = controlType == DS4StateFieldMapping.ControlType.AxisDir && tempOutControl % 2 == 0 ? true : false; + byte axisMapping = getXYAxisMapping2(device, tempMap.ds4input, cState, eState, tp, fieldMapping, alt); + if (axisMapping != axisDead) + { + int controlRelation = tempOutControl % 2 == 0 ? tempOutControl - 1 : tempOutControl + 1; + outputfieldMapping.axisdirs[tempOutControl] = axisMapping; + outputfieldMapping.axisdirs[controlRelation] = axisMapping; + } + } + else + { + if (tempMap.xoutput == DS4Controls.L2 || tempMap.xoutput == DS4Controls.R2) + { + const byte axisZero = 0; + byte axisMapping = getByteMapping2(device, tempMap.ds4input, cState, eState, tp, fieldMapping); + if (axisMapping != axisZero) + outputfieldMapping.triggers[tempOutControl] = axisMapping; + } + else + { + bool value = getBoolMapping2(device, tempMap.ds4input, cState, eState, tp, fieldMapping); + if (value) + outputfieldMapping.buttons[tempOutControl] = value; + } + } + } } outputfieldMapping.populateState(MappedState); @@ -1484,172 +1602,9 @@ namespace DS4Windows if (macroControl[24]) MappedState.RY = 0; } - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.LXNeg), device, cState, eState, tp, fieldMapping), DS4Controls.LXNeg)) - tempControlDict[DS4Controls.LXNeg] = DS4Controls.LXNeg; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.LXPos), device, cState, eState, tp, fieldMapping), DS4Controls.LXPos)) - tempControlDict[DS4Controls.LXPos] = DS4Controls.LXPos; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.LYNeg), device, cState, eState, tp, fieldMapping), DS4Controls.LYNeg)) - tempControlDict[DS4Controls.LYNeg] = DS4Controls.LYNeg; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.LYPos), device, cState, eState, tp, fieldMapping), DS4Controls.LYPos)) - tempControlDict[DS4Controls.LYPos] = DS4Controls.LYPos; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.RXNeg), device, cState, eState, tp, fieldMapping), DS4Controls.RXNeg)) - tempControlDict[DS4Controls.RXNeg] = DS4Controls.RXNeg; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.RXPos), device, cState, eState, tp, fieldMapping), DS4Controls.RXPos)) - tempControlDict[DS4Controls.RXPos] = DS4Controls.RXPos; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.RYNeg), device, cState, eState, tp, fieldMapping), DS4Controls.RYNeg)) - tempControlDict[DS4Controls.RYNeg] = DS4Controls.RYNeg; - - if (IfAxisIsNotModified(device, ShiftTrigger2(GetDS4STrigger(device, DS4Controls.RYPos), device, cState, eState, tp, fieldMapping), DS4Controls.RYPos)) - tempControlDict[DS4Controls.RYPos] = DS4Controls.RYPos; - - Dictionary.KeyCollection controlKeys = tempControlDict.Keys; - //Dictionary>.KeyCollection controlKeys = tempControlDict.Keys; - - //foreach (KeyValuePair entry in tempControlDict) - for (int i = 0, keyCount = controlKeys.Count; i < keyCount; i++) + if (GetSASteeringWheelEmulationAxis(device) != SASteeringWheelEmulationAxisType.None) { - DS4Controls key = controlKeys.ElementAt(i); - DS4Controls dc = tempControlDict[key]; - //DS4Controls key = entry.Key; - //DS4Controls dc = entry.Value; - - if (getBoolActionMapping2(device, key, cState, eState, tp, fieldMapping, true)) - { - if (dc >= DS4Controls.Square && dc <= DS4Controls.Cross) - { - switch (dc) - { - case DS4Controls.Cross: MappedState.Cross = true; break; - case DS4Controls.Circle: MappedState.Circle = true; break; - case DS4Controls.Square: MappedState.Square = true; break; - case DS4Controls.Triangle: MappedState.Triangle = true; break; - default: break; - } - } - else if (dc >= DS4Controls.L1 && dc <= DS4Controls.R3) - { - switch (dc) - { - case DS4Controls.L1: MappedState.L1 = true; break; - case DS4Controls.L2: MappedState.L2 = getByteMapping2(device, key, cState, eState, tp, fieldMapping); break; - case DS4Controls.L3: MappedState.L3 = true; break; - case DS4Controls.R1: MappedState.R1 = true; break; - case DS4Controls.R2: MappedState.R2 = getByteMapping2(device, key, cState, eState, tp, fieldMapping); break; - case DS4Controls.R3: MappedState.R3 = true; break; - default: break; - } - } - else if (dc >= DS4Controls.DpadUp && dc <= DS4Controls.DpadLeft) - { - switch (dc) - { - case DS4Controls.DpadUp: MappedState.DpadUp = true; break; - case DS4Controls.DpadRight: MappedState.DpadRight = true; break; - case DS4Controls.DpadLeft: MappedState.DpadLeft = true; break; - case DS4Controls.DpadDown: MappedState.DpadDown = true; break; - default: break; - } - } - else if (dc >= DS4Controls.LXNeg && dc <= DS4Controls.RYPos) - { - switch (dc) - { - case DS4Controls.LXNeg: - case DS4Controls.LXPos: - { - if (MappedState.LX == 128) - { - if (dc == DS4Controls.LXNeg) - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping); - MappedState.LX = axisMapping; - } - else - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping, true); - MappedState.LX = axisMapping; - } - } - - break; - } - case DS4Controls.LYNeg: - case DS4Controls.LYPos: - { - if (MappedState.LY == 128) - { - if (dc == DS4Controls.LYNeg) - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping); - MappedState.LY = axisMapping; - } - else - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping, true); - MappedState.LY = axisMapping; - } - } - - break; - } - case DS4Controls.RXNeg: - case DS4Controls.RXPos: - { - if (MappedState.RX == 128) - { - if (dc == DS4Controls.RXNeg) - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping); - MappedState.RX = axisMapping; - } - else - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping, true); - MappedState.RX = axisMapping; - } - } - - break; - } - case DS4Controls.RYNeg: - case DS4Controls.RYPos: - { - if (MappedState.RY == 128) - { - if (dc == DS4Controls.RYNeg) - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping); - MappedState.RY = axisMapping; - } - else - { - byte axisMapping = getXYAxisMapping2(device, key, cState, eState, tp, fieldMapping, true); - MappedState.RY = axisMapping; - } - } - - break; - } - default: break; - } - } - else - { - switch (dc) - { - case DS4Controls.Options: MappedState.Options = true; break; - case DS4Controls.Share: MappedState.Share = true; break; - case DS4Controls.PS: MappedState.PS = true; break; - default: break; - } - } - } + MappedState.SASteeringWheelEmulationUnit = Mapping.Scale360degreeGyroAxis(device, eState, ctrl); } calculateFinalMouseMovement(ref tempMouseDeltaX, ref tempMouseDeltaY, @@ -1713,7 +1668,7 @@ namespace DS4Windows for (int i = 0, arlen = action.trigger.Count; i < arlen; i++) { DS4Controls dc = action.trigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { subtriggeractivated = false; break; @@ -1737,7 +1692,7 @@ namespace DS4Windows for (int i = 0, arlen = action.trigger.Count; i < arlen; i++) { DS4Controls dc = action.trigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { subtriggeractivated = false; break; @@ -1756,7 +1711,7 @@ namespace DS4Windows for (int i = 0, arlen = action.trigger.Count; i < arlen; i++) { DS4Controls dc = action.trigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { subtriggeractivated = false; break; @@ -1778,7 +1733,7 @@ namespace DS4Windows for (int i = 0, arlen = action.trigger.Count; i < arlen; i++) { DS4Controls dc = action.trigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { triggeractivated = false; break; @@ -1794,7 +1749,7 @@ namespace DS4Windows for (int i = 0, arlen = action.uTrigger.Count; i < arlen; i++) { DS4Controls dc = action.uTrigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { utriggeractivated = false; break; @@ -1960,12 +1915,31 @@ namespace DS4Windows } DS4Color empty = new DS4Color(byte.Parse(dets[3]), byte.Parse(dets[4]), byte.Parse(dets[5])); DS4Color full = new DS4Color(byte.Parse(dets[6]), byte.Parse(dets[7]), byte.Parse(dets[8])); - DS4Color trans = getTransitionedColor(empty, full, d.Battery); + DS4Color trans = getTransitionedColor(ref empty, ref full, d.Battery); if (fadetimer[device] < 100) - DS4LightBar.forcedColor[device] = getTransitionedColor(lastColor[device], trans, fadetimer[device] += 2); + DS4LightBar.forcedColor[device] = getTransitionedColor(ref lastColor[device], ref trans, fadetimer[device] += 2); } actionDone[index].dev[device] = true; } + else if (action.typeID == SpecialAction.ActionTypeId.SASteeringWheelEmulationCalibrate) + { + actionFound = true; + + DS4Device d = ctrl.DS4Controllers[device]; + // If controller is not already in SASteeringWheelCalibration state then enable it now. If calibration is active then complete it (commit calibration values) + if (d.WheelRecalibrateActiveState == 0 && DateTime.UtcNow > (action.firstTap + TimeSpan.FromMilliseconds(3000))) + { + action.firstTap = DateTime.UtcNow; + d.WheelRecalibrateActiveState = 1; // Start calibration process + } + else if (d.WheelRecalibrateActiveState == 2 && DateTime.UtcNow > (action.firstTap + TimeSpan.FromMilliseconds(3000))) + { + action.firstTap = DateTime.UtcNow; + d.WheelRecalibrateActiveState = 3; // Complete calibration process + } + + actionDone[index].dev[device] = true; + } } else { @@ -2043,13 +2017,13 @@ namespace DS4Windows //previousFieldMapping = new DS4StateFieldMapping(tempPrevState, eState, tp, true); } - bool activeCur = getBoolMapping2(device, action.trigger[0], cState, eState, tp, fieldMapping); - bool activePrev = getBoolMapping2(device, action.trigger[0], tempPrevState, eState, tp, previousFieldMapping); + bool activeCur = getBoolSpecialActionMapping(device, action.trigger[0], cState, eState, tp, fieldMapping); + bool activePrev = getBoolSpecialActionMapping(device, action.trigger[0], tempPrevState, eState, tp, previousFieldMapping); if (activeCur && !activePrev) { // pressed down action.pastTime = DateTime.UtcNow; - if (action.pastTime <= (action.firstTap + TimeSpan.FromMilliseconds(100))) + if (action.pastTime <= (action.firstTap + TimeSpan.FromMilliseconds(150))) { action.tappedOnce = tappedOnce = false; action.secondtouchbegin = secondtouchbegin = true; @@ -2182,7 +2156,7 @@ namespace DS4Windows for (int i = 0, uTrigLen = action.uTrigger.Count; i < uTrigLen; i++) { DS4Controls dc = action.uTrigger[i]; - if (!getBoolMapping2(device, dc, cState, eState, tp, fieldMapping)) + if (!getBoolSpecialActionMapping(device, dc, cState, eState, tp, fieldMapping)) { utriggeractivated = false; break; @@ -3116,6 +3090,62 @@ namespace DS4Windows return result; } + private static bool getBoolSpecialActionMapping(int device, DS4Controls control, + DS4State cState, DS4StateExposed eState, Mouse tp, DS4StateFieldMapping fieldMap) + { + bool result = false; + + int controlNum = (int)control; + DS4StateFieldMapping.ControlType controlType = DS4StateFieldMapping.mappedType[controlNum]; + if (controlType == DS4StateFieldMapping.ControlType.Button) + { + result = fieldMap.buttons[controlNum]; + } + else if (controlType == DS4StateFieldMapping.ControlType.AxisDir) + { + byte axisValue = fieldMap.axisdirs[controlNum]; + + switch (control) + { + case DS4Controls.LXNeg: result = cState.LX < 128 - 55; break; + case DS4Controls.LYNeg: result = cState.LY < 128 - 55; break; + case DS4Controls.RXNeg: result = cState.RX < 128 - 55; break; + case DS4Controls.RYNeg: result = cState.RY < 128 - 55; break; + default: result = axisValue > 128 + 55; break; + } + } + else if (controlType == DS4StateFieldMapping.ControlType.Trigger) + { + result = fieldMap.triggers[controlNum] > 100; + } + else if (controlType == DS4StateFieldMapping.ControlType.Touch) + { + result = fieldMap.buttons[controlNum]; + } + else if (controlType == DS4StateFieldMapping.ControlType.SwipeDir) + { + result = fieldMap.swipedirbools[controlNum]; + } + else if (controlType == DS4StateFieldMapping.ControlType.GyroDir) + { + bool sOff = isUsingSAforMouse(device); + bool safeTest = false; + + switch (control) + { + case DS4Controls.GyroXPos: safeTest = fieldMap.gryodirs[controlNum] > 67; break; + case DS4Controls.GyroXNeg: safeTest = fieldMap.gryodirs[controlNum] < -67; break; + case DS4Controls.GyroZPos: safeTest = fieldMap.gryodirs[controlNum] > 67; break; + case DS4Controls.GyroZNeg: safeTest = fieldMap.gryodirs[controlNum] < -67; break; + default: break; + } + + result = sOff == false ? safeTest : false; + } + + return result; + } + private static bool getBoolActionMapping2(int device, DS4Controls control, DS4State cState, DS4StateExposed eState, Mouse tp, DS4StateFieldMapping fieldMap, bool analog = false) { @@ -3214,215 +3244,6 @@ namespace DS4Windows return result; } - /* TODO: Possibly remove usage of this version of the method */ - public static bool getBoolActionMapping(int device, DS4Controls control, - DS4State cState, DS4StateExposed eState, Mouse tp, bool analog=false) - { - bool result = false; - - if (control >= DS4Controls.Square && control <= DS4Controls.Cross) - { - switch (control) - { - case DS4Controls.Cross: result = cState.Cross; break; - case DS4Controls.Square: result = cState.Square; break; - case DS4Controls.Triangle: result = cState.Triangle; break; - case DS4Controls.Circle: result = cState.Circle; break; - default: break; - } - } - else if (control >= DS4Controls.L1 && control <= DS4Controls.R3) - { - switch (control) - { - case DS4Controls.L1: result = cState.L1; break; - case DS4Controls.R1: result = cState.R1; break; - case DS4Controls.L2: result = cState.L2 > 0; break; - case DS4Controls.R2: result = cState.R2 > 0; break; - case DS4Controls.L3: result = cState.L3; break; - case DS4Controls.R3: result = cState.R3; break; - default: break; - } - } - else if (control >= DS4Controls.DpadUp && control <= DS4Controls.DpadLeft) - { - switch (control) - { - case DS4Controls.DpadUp: result = cState.DpadUp; break; - case DS4Controls.DpadDown: result = cState.DpadDown; break; - case DS4Controls.DpadLeft: result = cState.DpadLeft; break; - case DS4Controls.DpadRight: result = cState.DpadRight; break; - default: break; - } - } - else if (control >= DS4Controls.LXNeg && control <= DS4Controls.RYPos) - { - switch (control) - { - case DS4Controls.LXNeg: - { - if (!analog) - { - double angle = cState.LSAngle; - result = cState.LX < 128 && (angle >= 112.5 && angle <= 247.5); - } - else - { - result = cState.LX < 128; - } - - break; - } - case DS4Controls.LYNeg: - { - if (!analog) - { - double angle = cState.LSAngle; - result = cState.LY < 128 && (angle >= 22.5 && angle <= 157.5); - } - else - { - result = cState.LY < 128; - } - - break; - } - case DS4Controls.RXNeg: - { - if (!analog) - { - double angle = cState.RSAngle; - result = cState.RX < 128 && (angle >= 112.5 && angle <= 247.5); - } - else - { - result = cState.RX < 128; - } - - break; - } - case DS4Controls.RYNeg: - { - if (!analog) - { - double angle = cState.RSAngle; - result = cState.RY < 128 && (angle >= 22.5 && angle <= 157.5); - } - else - { - result = cState.RY < 128; - } - - break; - } - case DS4Controls.LXPos: - { - if (!analog) - { - double angle = cState.LSAngle; - result = cState.LX > 128 && (angle <= 67.5 || angle >= 292.5); - } - else - { - result = cState.LX > 128; - } - - break; - } - case DS4Controls.LYPos: - { - if (!analog) - { - double angle = cState.LSAngle; - result = cState.LY > 128 && (angle >= 202.5 && angle <= 337.5); - } - else - { - result = cState.LY > 128; - } - - break; - } - case DS4Controls.RXPos: - { - if (!analog) - { - double angle = cState.RSAngle; - result = cState.RX > 128 && (angle <= 67.5 || angle >= 292.5); - } - else - { - result = cState.RX > 128; - } - - break; - } - case DS4Controls.RYPos: - { - if (!analog) - { - double angle = cState.RSAngle; - result = cState.RY > 128 && (angle >= 202.5 && angle <= 337.5); - } - else - { - result = cState.RY > 128; - } - - break; - } - default: break; - } - } - else if (control >= DS4Controls.TouchLeft && control <= DS4Controls.TouchRight) - { - switch (control) - { - case DS4Controls.TouchLeft: result = (tp != null ? tp.leftDown : false); break; - case DS4Controls.TouchRight: result = (tp != null ? tp.rightDown : false); break; - case DS4Controls.TouchMulti: result = (tp != null ? tp.multiDown : false); break; - case DS4Controls.TouchUpper: result = (tp != null ? tp.upperDown : false); break; - default: break; - } - } - else if (control >= DS4Controls.SwipeLeft && control <= DS4Controls.SwipeDown) - { - switch (control) - { - case DS4Controls.SwipeUp: result = (tp != null && tp.swipeUp); break; - case DS4Controls.SwipeDown: result = (tp != null && tp.swipeDown); break; - case DS4Controls.SwipeLeft: result = (tp != null && tp.swipeLeft); break; - case DS4Controls.SwipeRight: result = (tp != null && tp.swipeRight); break; - default: break; - } - } - else if (control >= DS4Controls.GyroXPos && control <= DS4Controls.GyroZNeg) - { - bool sOff = isUsingSAforMouse(device); - - switch (control) - { - case DS4Controls.GyroXPos: result = !sOff ? SXSens[device] * eState.AccelX > 67 : false; break; - case DS4Controls.GyroXNeg: result = !sOff ? SXSens[device] * eState.AccelX < -67 : false; break; - case DS4Controls.GyroZPos: result = !sOff ? SZSens[device] * eState.AccelZ > 67 : false; break; - case DS4Controls.GyroZNeg: result = !sOff ? SZSens[device] * eState.AccelZ < -67 : false; break; - default: break; - } - } - else - { - switch (control) - { - case DS4Controls.PS: result = cState.PS; break; - case DS4Controls.Share: result = cState.Share; break; - case DS4Controls.Options: result = cState.Options; break; - default: break; - } - } - - return result; - } - public static bool getBoolButtonMapping(bool stateButton) { return stateButton; @@ -3446,9 +3267,9 @@ namespace DS4Windows private static byte getXYAxisMapping2(int device, DS4Controls control, DS4State cState, DS4StateExposed eState, Mouse tp, DS4StateFieldMapping fieldMap, bool alt = false) { + const byte falseVal = 128; byte result = 0; byte trueVal = 0; - byte falseVal = 128; if (alt) trueVal = 255; @@ -3466,11 +3287,11 @@ namespace DS4Windows switch (control) { - case DS4Controls.LXNeg: if (!alt) result = cState.LX; else result = (byte)(255 - cState.LX); break; - case DS4Controls.LYNeg: if (!alt) result = cState.LY; else result = (byte)(255 - cState.LY); break; - case DS4Controls.RXNeg: if (!alt) result = cState.RX; else result = (byte)(255 - cState.RX); break; - case DS4Controls.RYNeg: if (!alt) result = cState.RY; else result = (byte)(255 - cState.RY); break; - default: if (!alt) result = (byte)(255 - axisValue); else result = axisValue; break; + case DS4Controls.LXNeg: if (!alt) result = axisValue < falseVal ? axisValue : falseVal; else result = axisValue < falseVal ? (byte)(255 - axisValue) : falseVal; break; + case DS4Controls.LYNeg: if (!alt) result = axisValue < falseVal ? axisValue : falseVal; else result = axisValue < falseVal ? (byte)(255 - axisValue) : falseVal; break; + case DS4Controls.RXNeg: if (!alt) result = axisValue < falseVal ? axisValue : falseVal; else result = axisValue < falseVal ? (byte)(255 - axisValue) : falseVal; break; + case DS4Controls.RYNeg: if (!alt) result = axisValue < falseVal ? axisValue : falseVal; else result = axisValue < falseVal ? (byte)(255 - axisValue) : falseVal; break; + default: if (!alt) result = axisValue > falseVal ? (byte)(255 - axisValue) : falseVal; else result = axisValue > falseVal ? axisValue : falseVal; break; } } else if (controlType == DS4StateFieldMapping.ControlType.Trigger) @@ -3715,5 +3536,427 @@ namespace DS4Windows fieldMap.buttons[controlNum] = false; } } + + + // SA steering wheel emulation mapping + + private const int C_WHEEL_ANGLE_PRECISION = 10; // Precision of SA angle in 1/10 of degrees + + private static readonly DS4Color calibrationColor_0 = new DS4Color { red = 0xA0, green = 0x00, blue = 0x00 }; + private static readonly DS4Color calibrationColor_1 = new DS4Color { red = 0xFF, green = 0xFF, blue = 0x00 }; + private static readonly DS4Color calibrationColor_2 = new DS4Color { red = 0x00, green = 0x50, blue = 0x50 }; + private static readonly DS4Color calibrationColor_3 = new DS4Color { red = 0x00, green = 0xC0, blue = 0x00 }; + + private static DateTime latestDebugMsgTime; + private static string latestDebugData; + private static void LogToGuiSACalibrationDebugMsg(string data, bool forceOutput = false) + { + // Print debug calibration log messages only once per 2 secs to avoid flooding the log receiver + DateTime curTime = DateTime.Now; + if (forceOutput || ((TimeSpan)(curTime - latestDebugMsgTime)).TotalSeconds > 2) + { + latestDebugMsgTime = curTime; + if (data != latestDebugData) + { + AppLogger.LogToGui(data, false); + latestDebugData = data; + } + } + } + + // Return number of bits set in a value + protected static int CountNumOfSetBits(int bitValue) + { + int count = 0; + while (bitValue != 0) + { + count++; + bitValue &= (bitValue - 1); + } + return count; + } + + // Calculate and return the angle of the controller as -180...0...+180 value. + private static Int32 CalculateControllerAngle(int gyroAccelX, int gyroAccelZ, DS4Device controller) + { + Int32 result; + + if (gyroAccelX == controller.wheelCenterPoint.X && Math.Abs(gyroAccelZ - controller.wheelCenterPoint.Y) <= 1) + { + // When the current gyro position is "close enough" the wheel center point then no need to go through the hassle of calculating an angle + result = 0; + } + else + { + // Calculate two vectors based on "circle center" (ie. circle represents the 360 degree wheel turn and wheelCenterPoint and currentPosition vectors both start from circle center). + // To improve accuracy both left and right turns use a decicated calibration "circle" because DS4 gyro and DoItYourselfWheelRig may return slightly different SA sensor values depending on the tilt direction (well, only one or two degree difference so nothing major). + Point vectorAB; + Point vectorCD; + + if (gyroAccelX >= controller.wheelCenterPoint.X) + { + // "DS4 gyro wheel" tilted to right + vectorAB = new Point(controller.wheelCenterPoint.X - controller.wheelCircleCenterPointRight.X, controller.wheelCenterPoint.Y - controller.wheelCircleCenterPointRight.Y); + vectorCD = new Point(gyroAccelX - controller.wheelCircleCenterPointRight.X, gyroAccelZ - controller.wheelCircleCenterPointRight.Y); + } + else + { + // "DS4 gyro wheel" tilted to left + vectorAB = new Point(controller.wheelCenterPoint.X - controller.wheelCircleCenterPointLeft.X, controller.wheelCenterPoint.Y - controller.wheelCircleCenterPointLeft.Y); + vectorCD = new Point(gyroAccelX - controller.wheelCircleCenterPointLeft.X, gyroAccelZ - controller.wheelCircleCenterPointLeft.Y); + } + + // Calculate dot product and magnitude of vectors (center vector and the current tilt vector) + double dotProduct = vectorAB.X * vectorCD.X + vectorAB.Y * vectorCD.Y; + double magAB = Math.Sqrt(vectorAB.X * vectorAB.X + vectorAB.Y * vectorAB.Y); + double magCD = Math.Sqrt(vectorCD.X * vectorCD.X + vectorCD.Y * vectorCD.Y); + + // Calculate angle between vectors and convert radian to degrees + if (magAB == 0 || magCD == 0) + { + result = 0; + } + else + { + double angle = Math.Acos(dotProduct / (magAB * magCD)); + result = Convert.ToInt32(Global.Clamp( + -180.0 * C_WHEEL_ANGLE_PRECISION, + Math.Round((angle * (180.0 / Math.PI)), 1) * C_WHEEL_ANGLE_PRECISION, + 180.0 * C_WHEEL_ANGLE_PRECISION) + ); + } + + // Left turn is -180..0 and right turn 0..180 degrees + if (gyroAccelX < controller.wheelCenterPoint.X) result = -result; + } + + return result; + } + + // Calibrate sixaxis steering wheel emulation. Use DS4Windows configuration screen to start a calibration or press a special action key (if defined) + private static void SAWheelEmulationCalibration(int device, DS4StateExposed exposedState, ControlService ctrl, DS4State currentDeviceState, DS4Device controller) + { + int gyroAccelX, gyroAccelZ; + int result; + + gyroAccelX = exposedState.getAccelX(); + gyroAccelZ = exposedState.getAccelZ(); + + // State 0=Normal mode (ie. calibration process is not running), 1=Activating calibration, 2=Calibration process running, 3=Completing calibration, 4=Cancelling calibration + if (controller.WheelRecalibrateActiveState == 1) + { + AppLogger.LogToGui($"Controller {ctrl.x360Bus.FirstController + device} activated re-calibration of SA steering wheel emulation", false); + + controller.WheelRecalibrateActiveState = 2; + + controller.wheelPrevPhysicalAngle = 0; + controller.wheelPrevFullAngle = 0; + controller.wheelFullTurnCount = 0; + + // Clear existing calibration value and use current position as "center" point. + // This initial center value may be off-center because of shaking the controller while button was pressed. The value will be overriden with correct value once controller is stabilized and hold still few secs at the center point + controller.wheelCenterPoint.X = gyroAccelX; + controller.wheelCenterPoint.Y = gyroAccelZ; + controller.wheel90DegPointRight.X = gyroAccelX + 20; + controller.wheel90DegPointLeft.X = gyroAccelX - 20; + + // Clear bitmask for calibration points. All three calibration points need to be set before re-calibration process is valid + controller.wheelCalibratedAxisBitmask = DS4Device.WheelCalibrationPoint.None; + + controller.wheelPrevRecalibrateTime = new DateTime(2500, 1, 1); + } + else if (controller.WheelRecalibrateActiveState == 3) + { + AppLogger.LogToGui($"Controller {ctrl.x360Bus.FirstController + device} completed the calibration of SA steering wheel emulation. center=({controller.wheelCenterPoint.X}, {controller.wheelCenterPoint.Y}) 90L=({controller.wheel90DegPointLeft.X}, {controller.wheel90DegPointLeft.Y}) 90R=({controller.wheel90DegPointRight.X}, {controller.wheel90DegPointRight.Y})", false); + + // If any of the calibration points (center, left 90deg, right 90deg) are missing then reset back to default calibration values + if (((controller.wheelCalibratedAxisBitmask & DS4Device.WheelCalibrationPoint.All) == DS4Device.WheelCalibrationPoint.All)) + Global.SaveControllerConfigs(controller); + else + controller.wheelCenterPoint.X = controller.wheelCenterPoint.Y = 0; + + controller.WheelRecalibrateActiveState = 0; + controller.wheelPrevRecalibrateTime = DateTime.Now; + } + else if (controller.WheelRecalibrateActiveState == 4) + { + AppLogger.LogToGui($"Controller {ctrl.x360Bus.FirstController + device} cancelled the calibration of SA steering wheel emulation.", false); + + controller.WheelRecalibrateActiveState = 0; + controller.wheelPrevRecalibrateTime = DateTime.Now; + } + + if (controller.WheelRecalibrateActiveState > 0) + { + // Cross "X" key pressed. Set calibration point when the key is released and controller hold steady for a few seconds + if (currentDeviceState.Cross == true) controller.wheelPrevRecalibrateTime = DateTime.Now; + + // Make sure controller is hold steady (velocity of gyro axis) to avoid misaligments and set calibration few secs after the "X" key was released + if (Math.Abs(currentDeviceState.Motion.angVelPitch) < 0.5 && Math.Abs(currentDeviceState.Motion.angVelYaw) < 0.5 && Math.Abs(currentDeviceState.Motion.angVelRoll) < 0.5 + && ((TimeSpan)(DateTime.Now - controller.wheelPrevRecalibrateTime)).TotalSeconds > 1) + { + controller.wheelPrevRecalibrateTime = new DateTime(2500, 1, 1); + + if (controller.wheelCalibratedAxisBitmask == DS4Device.WheelCalibrationPoint.None) + { + controller.wheelCenterPoint.X = gyroAccelX; + controller.wheelCenterPoint.Y = gyroAccelZ; + + controller.wheelCalibratedAxisBitmask |= DS4Device.WheelCalibrationPoint.Center; + } + else if (controller.wheel90DegPointRight.X < gyroAccelX) + { + controller.wheel90DegPointRight.X = gyroAccelX; + controller.wheel90DegPointRight.Y = gyroAccelZ; + controller.wheelCircleCenterPointRight.X = controller.wheelCenterPoint.X; + controller.wheelCircleCenterPointRight.Y = controller.wheel90DegPointRight.Y; + + controller.wheelCalibratedAxisBitmask |= DS4Device.WheelCalibrationPoint.Right90; + } + else if (controller.wheel90DegPointLeft.X > gyroAccelX) + { + controller.wheel90DegPointLeft.X = gyroAccelX; + controller.wheel90DegPointLeft.Y = gyroAccelZ; + controller.wheelCircleCenterPointLeft.X = controller.wheelCenterPoint.X; + controller.wheelCircleCenterPointLeft.Y = controller.wheel90DegPointLeft.Y; + + controller.wheelCalibratedAxisBitmask |= DS4Device.WheelCalibrationPoint.Left90; + } + } + + // Show lightbar color feedback how the calibration process is proceeding. + // red / yellow / blue / green = No calibration anchors/one anchor/two anchors/all three anchors calibrated when color turns to green (center, 90DegLeft, 90DegRight). + int bitsSet = CountNumOfSetBits((int)controller.wheelCalibratedAxisBitmask); + if (bitsSet >= 3) DS4LightBar.forcedColor[device] = calibrationColor_3; + else if (bitsSet == 2) DS4LightBar.forcedColor[device] = calibrationColor_2; + else if (bitsSet == 1) DS4LightBar.forcedColor[device] = calibrationColor_1; + else DS4LightBar.forcedColor[device] = calibrationColor_0; + + result = CalculateControllerAngle(gyroAccelX, gyroAccelZ, controller); + + // Force lightbar flashing when controller is currently at calibration point (user can verify the calibration before accepting it by looking at flashing lightbar) + if (((controller.wheelCalibratedAxisBitmask & DS4Device.WheelCalibrationPoint.Center) != 0 && Math.Abs(result) <= 1 * C_WHEEL_ANGLE_PRECISION) + || ((controller.wheelCalibratedAxisBitmask & DS4Device.WheelCalibrationPoint.Left90) != 0 && result <= -89 * C_WHEEL_ANGLE_PRECISION && result >= -91 * C_WHEEL_ANGLE_PRECISION) + || ((controller.wheelCalibratedAxisBitmask & DS4Device.WheelCalibrationPoint.Right90) != 0 && result >= 89 * C_WHEEL_ANGLE_PRECISION && result <= 91 * C_WHEEL_ANGLE_PRECISION) + || ((controller.wheelCalibratedAxisBitmask & DS4Device.WheelCalibrationPoint.Left90) != 0 && Math.Abs(result) >= 179 * C_WHEEL_ANGLE_PRECISION)) + DS4LightBar.forcedFlash[device] = 2; + else + DS4LightBar.forcedFlash[device] = 0; + + DS4LightBar.forcelight[device] = true; + + LogToGuiSACalibrationDebugMsg($"Calibration values ({gyroAccelX}, {gyroAccelZ}) angle={result / (1.0 * C_WHEEL_ANGLE_PRECISION)}\n"); + } + else + { + // Re-calibration completed or cancelled. Set lightbar color back to normal color + DS4LightBar.forcedFlash[device] = 0; + DS4LightBar.forcedColor[device] = Global.getMainColor(device); + DS4LightBar.forcelight[device] = false; + DS4LightBar.updateLightBar(controller, device); + } + } + + protected static Int32 Scale360degreeGyroAxis(int device, DS4StateExposed exposedState, ControlService ctrl) + { + unchecked + { + DS4Device controller; + DS4State currentDeviceState; + + int gyroAccelX, gyroAccelZ; + int result; + + controller = ctrl.DS4Controllers[device]; + if (controller == null) return 0; + + currentDeviceState = controller.getCurrentStateRef(); + + // If calibration is active then do the calibration process instead of the normal "angle calculation" + if (controller.WheelRecalibrateActiveState > 0) + { + SAWheelEmulationCalibration(device, exposedState, ctrl, currentDeviceState, controller); + + // Return center wheel position while SA wheel emuation is being calibrated + return 0; + } + + // Do nothing if connection is active but the actual DS4 controller is still missing or not yet synchronized + if (!controller.Synced) + return 0; + + gyroAccelX = exposedState.getAccelX(); + gyroAccelZ = exposedState.getAccelZ(); + + // If calibration values are missing then use "educated guesses" about good starting values + if (controller.wheelCenterPoint.IsEmpty) + { + if (!Global.LoadControllerConfigs(controller)) + { + AppLogger.LogToGui($"Controller {ctrl.x360Bus.FirstController + device} sixaxis steering wheel calibration data missing. It is recommended to run steering wheel calibration process by pressing SASteeringWheelEmulationCalibration special action key. Using estimated values until the controller is calibrated at least once.", false); + + // Use current controller position as "center point". Assume DS4Windows was started while controller was hold in center position (yes, dangerous assumption but can't do much until controller is calibrated) + controller.wheelCenterPoint.X = gyroAccelX; + controller.wheelCenterPoint.Y = gyroAccelZ; + + controller.wheel90DegPointRight.X = controller.wheelCenterPoint.X + 113; + controller.wheel90DegPointRight.Y = controller.wheelCenterPoint.Y + 110; + + controller.wheel90DegPointLeft.X = controller.wheelCenterPoint.X - 127; + controller.wheel90DegPointLeft.Y = controller.wheel90DegPointRight.Y; + } + + controller.wheelCircleCenterPointRight.X = controller.wheelCenterPoint.X; + controller.wheelCircleCenterPointRight.Y = controller.wheel90DegPointRight.Y; + controller.wheelCircleCenterPointLeft.X = controller.wheelCenterPoint.X; + controller.wheelCircleCenterPointLeft.Y = controller.wheel90DegPointLeft.Y; + + AppLogger.LogToGui($"Controller {ctrl.x360Bus.FirstController + device} steering wheel emulation calibration values. Center=({controller.wheelCenterPoint.X}, {controller.wheelCenterPoint.Y}) 90L=({controller.wheel90DegPointLeft.X}, {controller.wheel90DegPointLeft.Y}) 90R=({controller.wheel90DegPointRight.X}, {controller.wheel90DegPointRight.Y}) Range={Global.GetSASteeringWheelEmulationRange(device)}", false); + controller.wheelPrevRecalibrateTime = DateTime.Now; + } + + + int maxRangeRight = Global.GetSASteeringWheelEmulationRange(device) / 2 * C_WHEEL_ANGLE_PRECISION; + int maxRangeLeft = -maxRangeRight; + + result = CalculateControllerAngle(gyroAccelX, gyroAccelZ, controller); + + // Apply deadzone (SA X-deadzone value). This code assumes that 20deg is the max deadzone anyone ever might wanna use (in practice effective deadzone + // is probably just few degrees by using SXDeadZone values 0.01...0.05) + double sxDead = getSXDeadzone(device); + if (sxDead > 0) + { + int sxDeadInt = Convert.ToInt32(20.0 * C_WHEEL_ANGLE_PRECISION * sxDead); + if (Math.Abs(result) <= sxDeadInt) + { + result = 0; + } + else + { + // Smooth steering angle based on deadzone range instead of just clipping the deadzone gap + result -= (result < 0 ? -sxDeadInt : sxDeadInt); + } + } + + // If wrapped around from +180 to -180 side (or vice versa) then SA steering wheel keeps on turning beyond 360 degrees (if range is >360). + // Keep track of how many times the steering wheel has been turned beyond the full 360 circle and clip the result to max range. + int wheelFullTurnCount = controller.wheelFullTurnCount; + if (controller.wheelPrevPhysicalAngle < 0 && result > 0) + { + if ((result - controller.wheelPrevPhysicalAngle) > 180 * C_WHEEL_ANGLE_PRECISION) + { + if (maxRangeRight > 360/2 * C_WHEEL_ANGLE_PRECISION) + wheelFullTurnCount--; + else + result = maxRangeLeft; + } + } + else if (controller.wheelPrevPhysicalAngle > 0 && result < 0) + { + if ((controller.wheelPrevPhysicalAngle - result) > 180 * C_WHEEL_ANGLE_PRECISION) + { + if (maxRangeRight > 360/2 * C_WHEEL_ANGLE_PRECISION) + wheelFullTurnCount++; + else + result = maxRangeRight; + } + } + controller.wheelPrevPhysicalAngle = result; + + if (wheelFullTurnCount != 0) + { + // Adjust value of result (steering wheel angle) based on num of full 360 turn counts + result += (wheelFullTurnCount * 180 * C_WHEEL_ANGLE_PRECISION * 2); + } + + // If the new angle is more than 180 degrees further away then this is probably bogus value (controller shaking too much and gyro and velocity sensors went crazy). + // Accept the new angle only when the new angle is within a "stability threshold", otherwise use the previous full angle value and wait for controller to be stabilized. + if (Math.Abs(result - controller.wheelPrevFullAngle) <= 180 * C_WHEEL_ANGLE_PRECISION) + { + controller.wheelPrevFullAngle = result; + controller.wheelFullTurnCount = wheelFullTurnCount; + } + else + { + result = controller.wheelPrevFullAngle; + } + + result = Mapping.ClampInt(maxRangeLeft, result, maxRangeRight); + + // Debug log output of SA sensor values + //LogToGuiSACalibrationDebugMsg($"DBG gyro=({gyroAccelX}, {gyroAccelZ}) output=({exposedState.OutputAccelX}, {exposedState.OutputAccelZ}) PitRolYaw=({currentDeviceState.Motion.gyroPitch}, {currentDeviceState.Motion.gyroRoll}, {currentDeviceState.Motion.gyroYaw}) VelPitRolYaw=({currentDeviceState.Motion.angVelPitch}, {currentDeviceState.Motion.angVelRoll}, {currentDeviceState.Motion.angVelYaw}) angle={result / (1.0 * C_WHEEL_ANGLE_PRECISION)} fullTurns={controller.wheelFullTurnCount}", false); + + // Apply anti-deadzone (SA X-antideadzone value) + double sxAntiDead = getSXAntiDeadzone(device); + + switch (Global.GetSASteeringWheelEmulationAxis(device)) + { + case SASteeringWheelEmulationAxisType.LX: + case SASteeringWheelEmulationAxisType.LY: + case SASteeringWheelEmulationAxisType.RX: + case SASteeringWheelEmulationAxisType.RY: + // DS4 thumbstick axis output (-32768..32767 raw value range) + //return (((result - maxRangeLeft) * (32767 - (-32768))) / (maxRangeRight - maxRangeLeft)) + (-32768); + if (result == 0) return 0; + + if (sxAntiDead > 0) + { + sxAntiDead *= 32767; + if (result < 0) return (((result - maxRangeLeft) * (-Convert.ToInt32(sxAntiDead) - (-32768))) / (0 - maxRangeLeft)) + (-32768); + else return (((result - 0) * (32767 - (Convert.ToInt32(sxAntiDead)))) / (maxRangeRight - 0)) + (Convert.ToInt32(sxAntiDead)); + } + else + { + return (((result - maxRangeLeft) * (32767 - (-32768))) / (maxRangeRight - maxRangeLeft)) + (-32768); + } + + case SASteeringWheelEmulationAxisType.L2R2: + // DS4 Trigger axis output. L2+R2 triggers share the same axis in x360 xInput/DInput controller, + // so L2+R2 steering output supports only 360 turn range (-255..255 raw value range in the shared trigger axis) + // return (((result - (-180)) * (255 - (-255))) / (180 - (-180))) + (-255); + if (result == 0) return 0; + + result = Convert.ToInt32(Math.Round(result / (1.0 * C_WHEEL_ANGLE_PRECISION))); + if (result < 0) result = -181 - result; + + if (sxAntiDead > 0) + { + sxAntiDead *= 255; + if (result < 0) return (((result - (-180)) * (-Convert.ToInt32(sxAntiDead) - (-255))) / (0 - (-180))) + (-255); + else return (((result - (0)) * (255 - (Convert.ToInt32(sxAntiDead)))) / (180 - (0))) + (Convert.ToInt32(sxAntiDead)); + } + else + { + return (((result - (-180)) * (255 - (-255))) / (180 - (-180))) + (-255); + } + + case SASteeringWheelEmulationAxisType.VJoy1X: + case SASteeringWheelEmulationAxisType.VJoy1Y: + case SASteeringWheelEmulationAxisType.VJoy1Z: + case SASteeringWheelEmulationAxisType.VJoy2X: + case SASteeringWheelEmulationAxisType.VJoy2Y: + case SASteeringWheelEmulationAxisType.VJoy2Z: + // SASteeringWheelEmulationAxisType.VJoy1X/VJoy1Y/VJoy1Z/VJoy2X/VJoy2Y/VJoy2Z VJoy axis output (0..32767 raw value range by default) + // return (((result - maxRangeLeft) * (32767 - (-0))) / (maxRangeRight - maxRangeLeft)) + (-0); + if (result == 0) return 16384; + + if (sxAntiDead > 0) + { + sxAntiDead *= 16384; + if (result < 0) return (((result - maxRangeLeft) * (16384 - Convert.ToInt32(sxAntiDead) - (-0))) / (0 - maxRangeLeft)) + (-0); + else return (((result - 0) * (32767 - (16384 + Convert.ToInt32(sxAntiDead)))) / (maxRangeRight - 0)) + (16384 + Convert.ToInt32(sxAntiDead)); + } + else + { + return (((result - maxRangeLeft) * (32767 - (-0))) / (maxRangeRight - maxRangeLeft)) + (-0); + } + + default: + // Should never come here, but C# case statement syntax requires DEFAULT handler + return 0; + } + } + } + } } diff --git a/DS4Windows/DS4Control/Mouse.cs b/DS4Windows/DS4Control/Mouse.cs index 701021c..f780b63 100644 --- a/DS4Windows/DS4Control/Mouse.cs +++ b/DS4Windows/DS4Control/Mouse.cs @@ -23,6 +23,7 @@ namespace DS4Windows public bool priorLeftDown, priorRightDown, priorUpperDown, priorMultiDown; protected DS4Controls pushed = DS4Controls.None; protected Mapping.Click clicked = Mapping.Click.None; + public int CursorGyroDead { get => cursor.GyroCursorDeadZone; set => cursor.GyroCursorDeadZone = value; } internal const int TRACKBALL_INIT_FICTION = 10; internal const int TRACKBALL_MASS = 45; @@ -57,10 +58,20 @@ namespace DS4Windows trackballAccel = TRACKBALL_RADIUS * friction / TRACKBALL_INERTIA; } - bool triggeractivated = false; - bool useReverseRatchet = false; + public void ResetToggleGyroM() + { + currentToggleGyroM = false; + } - public virtual void sixaxisMoved(object sender, SixAxisEventArgs arg) + bool triggeractivated = false; + bool previousTriggerActivated = false; + bool useReverseRatchet = false; + bool toggleGyroMouse = true; + public bool ToggleGyroMouse { get => toggleGyroMouse; + set { toggleGyroMouse = value; ResetToggleGyroM(); } } + bool currentToggleGyroM = false; + + public virtual void sixaxisMoved(DS4SixAxis sender, SixAxisEventArgs arg) { if (Global.isUsingSAforMouse(deviceNum) && Global.getGyroSensitivity(deviceNum) > 0) { @@ -90,6 +101,21 @@ namespace DS4Windows } } + if (toggleGyroMouse) + { + if (triggeractivated && triggeractivated != previousTriggerActivated) + { + currentToggleGyroM = !currentToggleGyroM; + } + + previousTriggerActivated = triggeractivated; + triggeractivated = currentToggleGyroM; + } + else + { + previousTriggerActivated = triggeractivated; + } + if (useReverseRatchet && triggeractivated) cursor.sixaxisMoved(arg); else if (!useReverseRatchet && !triggeractivated) @@ -130,7 +156,7 @@ namespace DS4Windows } private bool tempBool = false; - public virtual void touchesMoved(object sender, TouchpadEventArgs arg) + public virtual void touchesMoved(DS4Touchpad sender, TouchpadEventArgs arg) { s = dev.getCurrentStateRef(); @@ -184,7 +210,7 @@ namespace DS4Windows synthesizeMouseButtons(); } - public virtual void touchesBegan(object sender, TouchpadEventArgs arg) + public virtual void touchesBegan(DS4Touchpad sender, TouchpadEventArgs arg) { if (!Global.UseTPforControls[deviceNum]) { @@ -217,7 +243,7 @@ namespace DS4Windows synthesizeMouseButtons(); } - public virtual void touchesEnded(object sender, TouchpadEventArgs arg) + public virtual void touchesEnded(DS4Touchpad sender, TouchpadEventArgs arg) { s = dev.getCurrentStateRef(); slideright = slideleft = false; @@ -349,7 +375,7 @@ namespace DS4Windows return t.hwX >= 1920 * 2 / 5; } - public virtual void touchUnchanged(object sender, EventArgs unused) + public virtual void touchUnchanged(DS4Touchpad sender, EventArgs unused) { s = dev.getCurrentStateRef(); @@ -419,6 +445,7 @@ namespace DS4Windows } public bool dragging, dragging2; + private void synthesizeMouseButtons() { if (Global.GetDS4Action(deviceNum, DS4Controls.TouchLeft, false) == null && leftDown) @@ -464,7 +491,7 @@ namespace DS4Windows } } - public virtual void touchButtonUp(object sender, TouchpadEventArgs arg) + public virtual void touchButtonUp(DS4Touchpad sender, TouchpadEventArgs arg) { pushed = DS4Controls.None; upperDown = leftDown = rightDown = multiDown = false; @@ -474,7 +501,7 @@ namespace DS4Windows synthesizeMouseButtons(); } - public virtual void touchButtonDown(object sender, TouchpadEventArgs arg) + public virtual void touchButtonDown(DS4Touchpad sender, TouchpadEventArgs arg) { if (arg.touches == null) upperDown = true; diff --git a/DS4Windows/DS4Control/MouseCursor.cs b/DS4Windows/DS4Control/MouseCursor.cs index e437403..3cd0444 100644 --- a/DS4Windows/DS4Control/MouseCursor.cs +++ b/DS4Windows/DS4Control/MouseCursor.cs @@ -21,7 +21,7 @@ namespace DS4Windows private Direction hDirection = Direction.Neutral, vDirection = Direction.Neutral; private const double GYRO_MOUSE_COEFFICIENT = 0.0095; - private const int GYRO_MOUSE_DEADZONE = 10; + public const int GYRO_MOUSE_DEADZONE = 10; private const double GYRO_MOUSE_OFFSET = 0.1463; private const double GYRO_SMOOTH_MOUSE_OFFSET = 0.14698; private const double TOUCHPAD_MOUSE_OFFSET = 0.015; @@ -30,8 +30,9 @@ namespace DS4Windows private double[] xSmoothBuffer = new double[SMOOTH_BUFFER_LEN]; private double[] ySmoothBuffer = new double[SMOOTH_BUFFER_LEN]; private int smoothBufferTail = 0; + private int gyroCursorDeadZone = GYRO_MOUSE_DEADZONE; + public int GyroCursorDeadZone { get => gyroCursorDeadZone; set => gyroCursorDeadZone = value; } - double coefficient = 0.0; double verticalScale = 0.0; @@ -80,8 +81,8 @@ namespace DS4Windows vRemainder = 0.0; } - int deadzoneX = (int)Math.Abs(normX * GYRO_MOUSE_DEADZONE); - int deadzoneY = (int)Math.Abs(normY * GYRO_MOUSE_DEADZONE); + int deadzoneX = (int)Math.Abs(normX * gyroCursorDeadZone); + int deadzoneY = (int)Math.Abs(normY * gyroCursorDeadZone); if (Math.Abs(deltaX) > deadzoneX) { diff --git a/DS4Windows/DS4Control/ScpUtil.cs b/DS4Windows/DS4Control/ScpUtil.cs index f8ff2fa..6cfcc3f 100644 --- a/DS4Windows/DS4Control/ScpUtil.cs +++ b/DS4Windows/DS4Control/ScpUtil.cs @@ -20,6 +20,8 @@ namespace DS4Windows public enum DS4Controls : byte { None, LXNeg, LXPos, LYNeg, LYPos, RXNeg, RXPos, RYNeg, RYPos, L1, L2, L3, R1, R2, R3, Square, Triangle, Circle, Cross, DpadUp, DpadRight, DpadDown, DpadLeft, PS, TouchLeft, TouchUpper, TouchMulti, TouchRight, Share, Options, GyroXPos, GyroXNeg, GyroZPos, GyroZNeg, SwipeLeft, SwipeRight, SwipeUp, SwipeDown }; public enum X360Controls : byte { None, 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, FourthMouse, FifthMouse, WUP, WDOWN, MouseUp, MouseDown, MouseLeft, MouseRight, Unbound }; + public enum SASteeringWheelEmulationAxisType: byte { None = 0, LX, LY, RX, RY, L2R2, VJoy1X, VJoy1Y, VJoy1Z, VJoy2X, VJoy2Y, VJoy2Z }; + public class DS4ControlSettings { public DS4Controls control; @@ -270,6 +272,7 @@ namespace DS4Windows m_Config.m_Profile = appdatapath + "\\Profiles.xml"; m_Config.m_Actions = appdatapath + "\\Actions.xml"; m_Config.m_linkedProfiles = Global.appdatapath + "\\LinkedProfiles.xml"; + m_Config.m_controllerConfigs = Global.appdatapath + "\\ControllerConfigs.xml"; } /// @@ -730,6 +733,18 @@ namespace DS4Windows m_Config.SetSaTriggerCond(index, text); } + public static SASteeringWheelEmulationAxisType[] SASteeringWheelEmulationAxis => m_Config.sASteeringWheelEmulationAxis; + public static SASteeringWheelEmulationAxisType GetSASteeringWheelEmulationAxis(int index) + { + return m_Config.sASteeringWheelEmulationAxis[index]; + } + + public static int[] SASteeringWheelEmulationRange => m_Config.sASteeringWheelEmulationRange; + public static int GetSASteeringWheelEmulationRange(int index) + { + return m_Config.sASteeringWheelEmulationRange[index]; + } + public static int[][] TouchDisInvertTriggers => m_Config.touchDisInvertTriggers; public static int[] getTouchDisInvertTriggers(int index) { @@ -778,28 +793,43 @@ namespace DS4Windows return m_Config.gyroMouseHorizontalAxis[index]; } - public static DS4Color[] MainColor => m_Config.m_Leds; - public static DS4Color getMainColor(int index) + public static int[] GyroMouseDeadZone => m_Config.gyroMouseDZ; + public static int GetGyroMouseDeadZone(int index) { - return m_Config.m_Leds[index]; + return m_Config.gyroMouseDZ[index]; + } + + public static void SetGyroMouseDeadZone(int index, int value, ControlService control) + { + m_Config.SetGyroMouseDZ(index, value, control); + } + + public static bool[] GyroMouseToggle => m_Config.gyroMouseToggle; + public static void SetGyroMouseToggle(int index, bool value, ControlService control) + => m_Config.SetGyroMouseToggle(index, value, control); + + public static DS4Color[] MainColor => m_Config.m_Leds; + public static ref DS4Color getMainColor(int index) + { + return ref m_Config.m_Leds[index]; } public static DS4Color[] LowColor => m_Config.m_LowLeds; - public static DS4Color getLowColor(int index) + public static ref DS4Color getLowColor(int index) { - return m_Config.m_LowLeds[index]; + return ref m_Config.m_LowLeds[index]; } public static DS4Color[] ChargingColor => m_Config.m_ChargingLeds; - public static DS4Color getChargingColor(int index) + public static ref DS4Color getChargingColor(int index) { - return m_Config.m_ChargingLeds[index]; + return ref m_Config.m_ChargingLeds[index]; } public static DS4Color[] CustomColor => m_Config.m_CustomLeds; - public static DS4Color getCustomColor(int index) + public static ref DS4Color getCustomColor(int index) { - return m_Config.m_CustomLeds[index]; + return ref m_Config.m_CustomLeds[index]; } public static bool[] UseCustomLed => m_Config.useCustomLeds; @@ -809,9 +839,9 @@ namespace DS4Windows } public static DS4Color[] FlashColor => m_Config.m_FlashLeds; - public static DS4Color getFlashColor(int index) + public static ref DS4Color getFlashColor(int index) { - return m_Config.m_FlashLeds[index]; + return ref m_Config.m_FlashLeds[index]; } public static byte[] TapSensitivity => m_Config.tapSensitivity; @@ -1297,6 +1327,30 @@ namespace DS4Windows return m_Config.LoadLinkedProfiles(); } + public static bool SaveControllerConfigs(DS4Device device = null) + { + if (device != null) + return m_Config.SaveControllerConfigsForDevice(device); + + for (int idx = 0; idx < ControlService.DS4_CONTROLLER_COUNT; idx++) + if (Program.rootHub.DS4Controllers[idx] != null) + m_Config.SaveControllerConfigsForDevice(Program.rootHub.DS4Controllers[idx]); + + return true; + } + + public static bool LoadControllerConfigs(DS4Device device = null) + { + if (device != null) + return m_Config.LoadControllerConfigsForDevice(device); + + for (int idx = 0; idx < ControlService.DS4_CONTROLLER_COUNT; idx++) + if (Program.rootHub.DS4Controllers[idx] != null) + m_Config.LoadControllerConfigsForDevice(Program.rootHub.DS4Controllers[idx]); + + return true; + } + private static byte applyRatio(byte b1, byte b2, double r) { if (r > 100.0) @@ -1304,17 +1358,20 @@ namespace DS4Windows else if (r < 0.0) r = 0.0; - r /= 100.0; - return (byte)Math.Round((b1 * (1 - r) + b2 * r), 0); + r *= 0.01; + return (byte)Math.Round((b1 * (1 - r)) + b2 * r, 0); } - public static DS4Color getTransitionedColor(DS4Color c1, DS4Color c2, double ratio) + public static DS4Color getTransitionedColor(ref DS4Color c1, ref DS4Color c2, double ratio) { //Color cs = Color.FromArgb(c1.red, c1.green, c1.blue); - 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; + DS4Color cs = new DS4Color + { + red = applyRatio(c1.red, c2.red, ratio), + green = applyRatio(c1.green, c2.green, ratio), + blue = applyRatio(c1.blue, c2.blue, ratio) + }; + return cs; } private static Color applyRatio(Color c1, Color c2, uint r) @@ -1395,6 +1452,7 @@ namespace DS4Windows public String m_Profile = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + "\\Profiles.xml"; public String m_Actions = Global.appdatapath + "\\Actions.xml"; public string m_linkedProfiles = Global.appdatapath + "\\LinkedProfiles.xml"; + public string m_controllerConfigs = Global.appdatapath + "\\ControllerConfigs.xml"; protected XmlDocument m_Xdoc = new XmlDocument(); // fifth value used for options, not fifth controller @@ -1437,6 +1495,11 @@ namespace DS4Windows public int[] flashAt = new int[5] { 0, 0, 0, 0, 0 }; public bool[] mouseAccel = new bool[5] { true, true, true, true, true }; public int[] btPollRate = new int[5] { 4, 4, 4, 4, 4 }; + public int[] gyroMouseDZ = new int[5] { MouseCursor.GYRO_MOUSE_DEADZONE, MouseCursor.GYRO_MOUSE_DEADZONE, + MouseCursor.GYRO_MOUSE_DEADZONE, MouseCursor.GYRO_MOUSE_DEADZONE, + MouseCursor.GYRO_MOUSE_DEADZONE }; + public bool[] gyroMouseToggle = new bool[5] { false, false, false, + false, false }; public int[] lsOutCurveMode = new int[5] { 0, 0, 0, 0, 0 }; public int[] rsOutCurveMode = new int[5] { 0, 0, 0, 0, 0 }; public int[] l2OutCurveMode = new int[5] { 0, 0, 0, 0, 0 }; @@ -1494,6 +1557,8 @@ namespace DS4Windows public bool[] useSAforMouse = new bool[5] { false, false, false, false, false }; public string[] sATriggers = new string[5] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty }; public bool[] sATriggerCond = new bool[5] { true, true, true, true, true }; + public SASteeringWheelEmulationAxisType[] sASteeringWheelEmulationAxis = new SASteeringWheelEmulationAxisType[5] { SASteeringWheelEmulationAxisType.None, SASteeringWheelEmulationAxisType.None, SASteeringWheelEmulationAxisType.None, SASteeringWheelEmulationAxisType.None, SASteeringWheelEmulationAxisType.None }; + public int[] sASteeringWheelEmulationRange = new int[5] { 360, 360, 360, 360, 360 }; public int[][] touchDisInvertTriggers = new int[5][] { new int[1] { -1 }, new int[1] { -1 }, new int[1] { -1 }, new int[1] { -1 }, new int[1] { -1 } }; public int[] lsCurve = new int[5] { 0, 0, 0, 0, 0 }; @@ -1579,6 +1644,7 @@ namespace DS4Windows case 1: result = "enhanced-precision"; break; case 2: result = "quadratic"; break; case 3: result = "cubic"; break; + case 4: result = "easeout-quad"; break; default: break; } @@ -1594,6 +1660,7 @@ namespace DS4Windows case "enhanced-precision": id = 1; break; case "quadratic": id = 2; break; case "cubic": id = 3; break; + case "easeout-quad": id = 4; break; default: break; } @@ -1608,6 +1675,7 @@ namespace DS4Windows case 0: break; case 1: result = "quadratic"; break; case 2: result = "cubic"; break; + case 3: result = "easeout-quad"; break; default: break; } @@ -1622,6 +1690,7 @@ namespace DS4Windows case "linear": id = 0; break; case "quadratic": id = 1; break; case "cubic": id = 2; break; + case "easeout-quad": id = 3; break; default: break; } @@ -1652,6 +1721,20 @@ namespace DS4Windows sATriggerCond[index] = SaTriggerCondValue(text); } + public void SetGyroMouseDZ(int index, int value, ControlService control) + { + gyroMouseDZ[index] = value; + if (index < 4 && control.touchPad[index] != null) + control.touchPad[index].CursorGyroDead = value; + } + + public void SetGyroMouseToggle(int index, bool value, ControlService control) + { + gyroMouseToggle[index] = value; + if (index < 4 && control.touchPad[index] != null) + control.touchPad[index].ToggleGyroMouse = value; + } + public bool SaveProfile(int device, string propath) { bool Saved = true; @@ -1740,6 +1823,8 @@ namespace DS4Windows XmlNode xmlUseSAforMouse = m_Xdoc.CreateNode(XmlNodeType.Element, "UseSAforMouse", null); xmlUseSAforMouse.InnerText = useSAforMouse[device].ToString(); Node.AppendChild(xmlUseSAforMouse); XmlNode xmlSATriggers = m_Xdoc.CreateNode(XmlNodeType.Element, "SATriggers", null); xmlSATriggers.InnerText = sATriggers[device].ToString(); Node.AppendChild(xmlSATriggers); XmlNode xmlSATriggerCond = m_Xdoc.CreateNode(XmlNodeType.Element, "SATriggerCond", null); xmlSATriggerCond.InnerText = SaTriggerCondString(sATriggerCond[device]); Node.AppendChild(xmlSATriggerCond); + XmlNode xmlSASteeringWheelEmulationAxis = m_Xdoc.CreateNode(XmlNodeType.Element, "SASteeringWheelEmulationAxis", null); xmlSASteeringWheelEmulationAxis.InnerText = sASteeringWheelEmulationAxis[device].ToString("G"); Node.AppendChild(xmlSASteeringWheelEmulationAxis); + XmlNode xmlSASteeringWheelEmulationRange = m_Xdoc.CreateNode(XmlNodeType.Element, "SASteeringWheelEmulationRange", null); xmlSASteeringWheelEmulationRange.InnerText = sASteeringWheelEmulationRange[device].ToString(); Node.AppendChild(xmlSASteeringWheelEmulationRange); XmlNode xmlTouchDisInvTriggers = m_Xdoc.CreateNode(XmlNodeType.Element, "TouchDisInvTriggers", null); string tempTouchDisInv = string.Join(",", touchDisInvertTriggers[device]); @@ -1753,6 +1838,8 @@ namespace DS4Windows XmlNode xmlGyroSmoothWeight = m_Xdoc.CreateNode(XmlNodeType.Element, "GyroSmoothingWeight", null); xmlGyroSmoothWeight.InnerText = Convert.ToInt32(gyroSmoothWeight[device] * 100).ToString(); Node.AppendChild(xmlGyroSmoothWeight); XmlNode xmlGyroSmoothing = m_Xdoc.CreateNode(XmlNodeType.Element, "GyroSmoothing", null); xmlGyroSmoothing.InnerText = gyroSmoothing[device].ToString(); Node.AppendChild(xmlGyroSmoothing); XmlNode xmlGyroMouseHAxis = m_Xdoc.CreateNode(XmlNodeType.Element, "GyroMouseHAxis", null); xmlGyroMouseHAxis.InnerText = gyroMouseHorizontalAxis[device].ToString(); Node.AppendChild(xmlGyroMouseHAxis); + XmlNode xmlGyroMouseDZ = m_Xdoc.CreateNode(XmlNodeType.Element, "GyroMouseDeadZone", null); xmlGyroMouseDZ.InnerText = gyroMouseDZ[device].ToString(); Node.AppendChild(xmlGyroMouseDZ); + XmlNode xmlGyroMouseToggle = m_Xdoc.CreateNode(XmlNodeType.Element, "GyroMouseToggle", null); xmlGyroMouseToggle.InnerText = gyroMouseToggle[device].ToString(); Node.AppendChild(xmlGyroMouseToggle); XmlNode xmlLSC = m_Xdoc.CreateNode(XmlNodeType.Element, "LSCurve", null); xmlLSC.InnerText = lsCurve[device].ToString(); Node.AppendChild(xmlLSC); XmlNode xmlRSC = m_Xdoc.CreateNode(XmlNodeType.Element, "RSCurve", null); xmlRSC.InnerText = rsCurve[device].ToString(); Node.AppendChild(xmlRSC); XmlNode xmlProfileActions = m_Xdoc.CreateNode(XmlNodeType.Element, "ProfileActions", null); xmlProfileActions.InnerText = string.Join("/", profileActions[device]); Node.AppendChild(xmlProfileActions); @@ -2562,7 +2649,6 @@ namespace DS4Windows catch { dinputOnly[device] = false; missingSetting = true; } bool oldUseDInputOnly = Global.useDInputOnly[device]; - Global.useDInputOnly[device] = dinputOnly[device]; // Only change xinput devices under certain conditions. Avoid // performing this upon program startup before loading devices. @@ -2578,20 +2664,14 @@ namespace DS4Windows { if (dinputOnly[device] == true) { - Global.useDInputOnly[device] = true; xinputPlug = false; xinputStatus = true; } else if (synced && isAlive) { - Global.useDInputOnly[device] = false; xinputPlug = true; xinputStatus = true; } - else if (!synced) - { - Global.useDInputOnly[device] = true; - } } } } @@ -2616,7 +2696,14 @@ namespace DS4Windows try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/SATriggerCond"); sATriggerCond[device] = SaTriggerCondValue(Item.InnerText); } catch { sATriggerCond[device] = true; missingSetting = true; } - try { + try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/SASteeringWheelEmulationAxis"); SASteeringWheelEmulationAxisType.TryParse(Item.InnerText, out sASteeringWheelEmulationAxis[device]); } + catch { sASteeringWheelEmulationAxis[device] = SASteeringWheelEmulationAxisType.None; missingSetting = true; } + + try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/SASteeringWheelEmulationRange"); int.TryParse(Item.InnerText, out sASteeringWheelEmulationRange[device]); } + catch { sASteeringWheelEmulationRange[device] = 360; missingSetting = true; } + + try + { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/TouchDisInvTriggers"); string[] triggers = Item.InnerText.Split(','); int temp = -1; @@ -2652,6 +2739,17 @@ namespace DS4Windows try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/GyroMouseHAxis"); int temp = 0; int.TryParse(Item.InnerText, out temp); gyroMouseHorizontalAxis[device] = Math.Min(Math.Max(0, temp), 1); } catch { gyroMouseHorizontalAxis[device] = 0; missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/GyroMouseDeadZone"); int.TryParse(Item.InnerText, out int temp); + SetGyroMouseDZ(device, temp, control); } + catch { SetGyroMouseDZ(device, MouseCursor.GYRO_MOUSE_DEADZONE, control); missingSetting = true; } + + try + { + Item = m_Xdoc.SelectSingleNode("/" + rootname + "/GyroMouseToggle"); bool.TryParse(Item.InnerText, out bool temp); + SetGyroMouseToggle(device, temp, control); + } + catch { SetGyroMouseToggle(device, false, control); missingSetting = true; } + try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/LSCurve"); int.TryParse(Item.InnerText, out lsCurve[device]); } catch { lsCurve[device] = 0; missingSetting = true; } @@ -2942,12 +3040,14 @@ namespace DS4Windows { control.x360controls[device] = new Nefarius.ViGEm.Client.Targets.Xbox360Controller(control.vigemTestClient); control.x360controls[device].Connect(); + Global.useDInputOnly[device] = false; AppLogger.LogToGui("X360 Controller # " + (device + 1) + " connected", false); } else if (xinputStatus && !xinputPlug) { control.x360controls[device].Disconnect(); control.x360controls[device] = null; + Global.useDInputOnly[device] = true; AppLogger.LogToGui("X360 Controller # " + (device + 1) + " unplugged", false); } @@ -3239,6 +3339,10 @@ namespace DS4Windows el.AppendChild(m_Xdoc.CreateElement("Type")).InnerText = "MultiAction"; el.AppendChild(m_Xdoc.CreateElement("Details")).InnerText = details; break; + case 8: + el.AppendChild(m_Xdoc.CreateElement("Type")).InnerText = "SASteeringWheelEmulationCalibrate"; + el.AppendChild(m_Xdoc.CreateElement("Details")).InnerText = details; + break; } if (edit) @@ -3358,6 +3462,14 @@ namespace DS4Windows { actions.Add(new SpecialAction(name, controls, type, details)); } + else if (type == "SASteeringWheelEmulationCalibrate") + { + double doub; + if (double.TryParse(details, out doub)) + actions.Add(new SpecialAction(name, controls, type, "", doub)); + else + actions.Add(new SpecialAction(name, controls, type, "")); + } } } catch { saved = false; } @@ -3442,9 +3554,11 @@ namespace DS4Windows linkedXdoc.AppendChild(Node); Dictionary.KeyCollection serials = linkedProfiles.Keys; - for (int i = 0, itemCount = linkedProfiles.Count; i < itemCount; i++) + //for (int i = 0, itemCount = linkedProfiles.Count; i < itemCount; i++) + for (var serialEnum = serials.GetEnumerator(); serialEnum.MoveNext();) { - string serial = serials.ElementAt(i); + //string serial = serials.ElementAt(i); + string serial = serialEnum.Current; string profile = linkedProfiles[serial]; XmlElement link = linkedXdoc.CreateElement("MAC" + serial); link.InnerText = profile; @@ -3463,6 +3577,107 @@ namespace DS4Windows return saved; } + public bool createControllerConfigs() + { + bool saved = true; + XmlDocument configXdoc = new XmlDocument(); + XmlNode Node; + + Node = configXdoc.CreateXmlDeclaration("1.0", "utf-8", string.Empty); + configXdoc.AppendChild(Node); + + Node = configXdoc.CreateComment(string.Format(" Controller config data. {0} ", DateTime.Now)); + configXdoc.AppendChild(Node); + + Node = configXdoc.CreateWhitespace("\r\n"); + configXdoc.AppendChild(Node); + + Node = configXdoc.CreateNode(XmlNodeType.Element, "Controllers", ""); + configXdoc.AppendChild(Node); + + try { configXdoc.Save(m_controllerConfigs); } + catch (UnauthorizedAccessException) { AppLogger.LogToGui("Unauthorized Access - Save failed to path: " + m_controllerConfigs, false); saved = false; } + + return saved; + } + + public bool LoadControllerConfigsForDevice(DS4Device device) + { + bool loaded = false; + + if (device == null) return false; + if (!File.Exists(m_controllerConfigs)) createControllerConfigs(); + + try + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(m_controllerConfigs); + + XmlNode node = xmlDoc.SelectSingleNode("/Controllers/Controller[@Mac=\"" + device.getMacAddress() + "\"]"); + if (node != null) + { + Int32 intValue; + if (Int32.TryParse(node["wheelCenterPoint"].InnerText.Split(',')[0], out intValue)) device.wheelCenterPoint.X = intValue; + if (Int32.TryParse(node["wheelCenterPoint"].InnerText.Split(',')[1], out intValue)) device.wheelCenterPoint.Y = intValue; + if (Int32.TryParse(node["wheel90DegPointLeft"].InnerText.Split(',')[0], out intValue)) device.wheel90DegPointLeft.X = intValue; + if (Int32.TryParse(node["wheel90DegPointLeft"].InnerText.Split(',')[1], out intValue)) device.wheel90DegPointLeft.Y = intValue; + if (Int32.TryParse(node["wheel90DegPointRight"].InnerText.Split(',')[0], out intValue)) device.wheel90DegPointRight.X = intValue; + if (Int32.TryParse(node["wheel90DegPointRight"].InnerText.Split(',')[1], out intValue)) device.wheel90DegPointRight.Y = intValue; + + loaded = true; + } + } + catch + { + AppLogger.LogToGui("ControllerConfigs.xml can't be found.", false); + loaded = false; + } + + return loaded; + } + + public bool SaveControllerConfigsForDevice(DS4Device device) + { + bool saved = true; + + if (device == null) return false; + if (!File.Exists(m_controllerConfigs)) createControllerConfigs(); + + try + { + //XmlNode node = null; + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(m_controllerConfigs); + + XmlNode node = xmlDoc.SelectSingleNode("/Controllers/Controller[@Mac=\"" + device.getMacAddress() + "\"]"); + if (node == null) + { + XmlNode xmlControllersNode = xmlDoc.SelectSingleNode("/Controllers"); + XmlElement el = xmlDoc.CreateElement("Controller"); + el.SetAttribute("Mac", device.getMacAddress()); + + el.AppendChild(xmlDoc.CreateElement("wheelCenterPoint")); + el.AppendChild(xmlDoc.CreateElement("wheel90DegPointLeft")); + el.AppendChild(xmlDoc.CreateElement("wheel90DegPointRight")); + + node = xmlControllersNode.AppendChild(el); + } + + node["wheelCenterPoint"].InnerText = $"{device.wheelCenterPoint.X},{device.wheelCenterPoint.Y}"; + node["wheel90DegPointLeft"].InnerText = $"{device.wheel90DegPointLeft.X},{device.wheel90DegPointLeft.Y}"; + node["wheel90DegPointRight"].InnerText = $"{device.wheel90DegPointRight.X},{device.wheel90DegPointRight.Y}"; + + xmlDoc.Save(m_controllerConfigs); + } + catch (UnauthorizedAccessException) + { + AppLogger.LogToGui("Unauthorized Access - Save failed to path: " + m_controllerConfigs, false); + saved = false; + } + + return saved; + } + public void UpdateDS4CSetting(int deviceNum, string buttonName, bool shift, object action, string exts, DS4KeyType kt, int trigger = 0) { DS4Controls dc; @@ -3535,7 +3750,7 @@ namespace DS4Windows DS4ControlSettings dcs = ds4settings[deviceNum][index]; if (shift) { - return dcs.shiftTrigger; + return dcs.shiftAction; } else { @@ -3555,7 +3770,7 @@ namespace DS4Windows DS4ControlSettings dcs = ds4settings[deviceNum][index]; if (shift) { - return dcs.shiftTrigger; + return dcs.shiftAction; } else { @@ -3763,6 +3978,8 @@ namespace DS4Windows useSAforMouse[device] = false; sATriggers[device] = string.Empty; sATriggerCond[device] = true; + sASteeringWheelEmulationAxis[device] = SASteeringWheelEmulationAxisType.None; + sASteeringWheelEmulationRange[device] = 360; touchDisInvertTriggers[device] = new int[1] { -1 }; lsCurve[device] = rsCurve[device] = 0; gyroSensitivity[device] = 100; @@ -3784,7 +4001,7 @@ namespace DS4Windows public class SpecialAction { - public enum ActionTypeId { None, Key, Program, Profile, Macro, DisconnectBT, BatteryCheck, MultiAction, XboxGameDVR } + public enum ActionTypeId { None, Key, Program, Profile, Macro, DisconnectBT, BatteryCheck, MultiAction, XboxGameDVR, SASteeringWheelEmulationCalibrate } public string name; public List trigger = new List(); @@ -3902,6 +4119,10 @@ namespace DS4Windows type = "MultiAction"; this.details = string.Join(",", macros); } + else if (type == "SASteeringWheelEmulationCalibrate") + { + typeID = ActionTypeId.SASteeringWheelEmulationCalibrate; + } else this.details = details; diff --git a/DS4Windows/DS4Control/X360Device.cs b/DS4Windows/DS4Control/X360Device.cs index f5f02f8..256d817 100644 --- a/DS4Windows/DS4Control/X360Device.cs +++ b/DS4Windows/DS4Control/X360Device.cs @@ -100,7 +100,7 @@ namespace DS4Windows Output[4] = (Byte)(device + firstController); Output[9] = 0x14; - for (int i = 10, outLen = Output.Length; i < outLen; i++) + for (int i = 10; i < 28; i++) { Output[i] = 0; } @@ -127,13 +127,78 @@ namespace DS4Windows if (state.PS) Output[11] |= (Byte)(1 << 2); // Guide + SASteeringWheelEmulationAxisType steeringWheelMappedAxis = Global.GetSASteeringWheelEmulationAxis(device); + Int32 ThumbLX; + Int32 ThumbLY; + Int32 ThumbRX; + Int32 ThumbRY; + Output[12] = state.L2; // Left Trigger Output[13] = state.R2; // Right Trigger - Int32 ThumbLX = Scale(state.LX, false); - Int32 ThumbLY = Scale(state.LY, true); - Int32 ThumbRX = Scale(state.RX, false); - Int32 ThumbRY = Scale(state.RY, true); + switch(steeringWheelMappedAxis) + { + case SASteeringWheelEmulationAxisType.None: + ThumbLX = Scale(state.LX, false); + ThumbLY = Scale(state.LY, true); + ThumbRX = Scale(state.RX, false); + ThumbRY = Scale(state.RY, true); + break; + + case SASteeringWheelEmulationAxisType.LX: + ThumbLX = state.SASteeringWheelEmulationUnit; + ThumbLY = Scale(state.LY, true); + ThumbRX = Scale(state.RX, false); + ThumbRY = Scale(state.RY, true); + break; + + case SASteeringWheelEmulationAxisType.LY: + ThumbLX = Scale(state.LX, false); + ThumbLY = state.SASteeringWheelEmulationUnit; + ThumbRX = Scale(state.RX, false); + ThumbRY = Scale(state.RY, true); + break; + + case SASteeringWheelEmulationAxisType.RX: + ThumbLX = Scale(state.LX, false); + ThumbLY = Scale(state.LY, true); + ThumbRX = state.SASteeringWheelEmulationUnit; + ThumbRY = Scale(state.RY, true); + break; + + case SASteeringWheelEmulationAxisType.RY: + ThumbLX = Scale(state.LX, false); + ThumbLY = Scale(state.LY, true); + ThumbRX = Scale(state.RX, false); + ThumbRY = state.SASteeringWheelEmulationUnit; + break; + + case SASteeringWheelEmulationAxisType.L2R2: + Output[12] = Output[13] = 0; + if (state.SASteeringWheelEmulationUnit >= 0) Output[12] = (Byte)state.SASteeringWheelEmulationUnit; + else Output[13] = (Byte)state.SASteeringWheelEmulationUnit; + goto case SASteeringWheelEmulationAxisType.None; + + case SASteeringWheelEmulationAxisType.VJoy1X: + case SASteeringWheelEmulationAxisType.VJoy2X: + DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_X); + goto case SASteeringWheelEmulationAxisType.None; + + case SASteeringWheelEmulationAxisType.VJoy1Y: + case SASteeringWheelEmulationAxisType.VJoy2Y: + DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Y); + goto case SASteeringWheelEmulationAxisType.None; + + case SASteeringWheelEmulationAxisType.VJoy1Z: + case SASteeringWheelEmulationAxisType.VJoy2Z: + DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Z); + goto case SASteeringWheelEmulationAxisType.None; + + default: + // Should never come here but just in case use the NONE case as default handler.... + goto case SASteeringWheelEmulationAxisType.None; + } + Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX Output[15] = (Byte)((ThumbLX >> 8) & 0xFF); Output[16] = (Byte)((ThumbLY >> 0) & 0xFF); // LY diff --git a/DS4Windows/DS4Forms/DS4Form.cs b/DS4Windows/DS4Forms/DS4Form.cs index bb68dde..5a2fd2b 100644 --- a/DS4Windows/DS4Forms/DS4Form.cs +++ b/DS4Windows/DS4Forms/DS4Form.cs @@ -63,7 +63,7 @@ namespace DS4Windows { "DS4Windows v" + FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion, string.Empty, string.Empty, string.Empty, string.Empty }; - private const string UPDATER_VERSION = "1.3.0"; + private const string UPDATER_VERSION = "1.3.1"; private const int WM_QUERYENDSESSION = 0x11; private const int WM_CLOSE = 0x10; internal string updaterExe = Environment.Is64BitProcess ? "DS4Updater.exe" : "DS4Updater_x86.exe"; @@ -786,7 +786,7 @@ namespace DS4Windows FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); string version = fvi.FileVersion; string newversion = File.ReadAllText(appdatapath + "\\version.txt").Trim(); - if (version.Replace(',', '.').CompareTo(newversion) != 0) + if (!string.IsNullOrWhiteSpace(newversion) && version.Replace(',', '.').CompareTo(newversion) != 0) { if ((DialogResult)this.Invoke(new Func(() => { return MessageBox.Show(Properties.Resources.DownloadVersion.Replace("*number*", newversion), @@ -2097,7 +2097,7 @@ Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); string version2 = fvi.FileVersion; string newversion2 = File.ReadAllText(appdatapath + "\\version.txt").Trim(); - if (version2.Replace(',', '.').CompareTo(newversion2) != 0) + if (!string.IsNullOrWhiteSpace(newversion2) && version2.Replace(',', '.').CompareTo(newversion2) != 0) { if ((DialogResult)this.Invoke(new Func(() => { diff --git a/DS4Windows/DS4Forms/Options.Designer.cs b/DS4Windows/DS4Forms/Options.Designer.cs index cd9742a..f9cf0af 100644 --- a/DS4Windows/DS4Forms/Options.Designer.cs +++ b/DS4Windows/DS4Forms/Options.Designer.cs @@ -188,6 +188,11 @@ this.lbGyroXP = new System.Windows.Forms.Label(); this.bnGyroXN = new System.Windows.Forms.Button(); this.lbGyroXN = new System.Windows.Forms.Label(); + this.lblSteeringWheelEmulationAxis = new System.Windows.Forms.Label(); + this.cBSteeringWheelEmulationAxis = new System.Windows.Forms.ComboBox(); + this.lblSteeringWheelEmulationRange = new System.Windows.Forms.Label(); + this.cBSteeringWheelEmulationRange = new System.Windows.Forms.ComboBox(); + this.btnSteeringWheelEmulationCalibrate = new System.Windows.Forms.Button(); this.tCControls = new System.Windows.Forms.TabControl(); this.tPControls = new System.Windows.Forms.TabPage(); this.lBControls = new System.Windows.Forms.ListBox(); @@ -315,6 +320,11 @@ this.rBSAControls = new System.Windows.Forms.RadioButton(); this.rBSAMouse = new System.Windows.Forms.RadioButton(); this.pnlSAMouse = new System.Windows.Forms.Panel(); + this.toggleGyroMCb = new System.Windows.Forms.CheckBox(); + this.label27 = new System.Windows.Forms.Label(); + this.gyroMouseDzNUD = new System.Windows.Forms.NumericUpDown(); + this.label26 = new System.Windows.Forms.Label(); + this.triggerCondAndCombo = new System.Windows.Forms.ComboBox(); this.cBGyroMouseXAxis = new System.Windows.Forms.ComboBox(); this.label16 = new System.Windows.Forms.Label(); this.lbGyroSmooth = new System.Windows.Forms.Label(); @@ -386,8 +396,6 @@ this.optionsTouchInvStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.shareTouchInvStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.psTouchInvStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.triggerCondAndCombo = new System.Windows.Forms.ComboBox(); - this.label26 = new System.Windows.Forms.Label(); this.advColorDialog = new DS4Windows.AdvancedColorDialog(); ((System.ComponentModel.ISupportInitialize)(this.nUDRainbow)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.tBBlueBar)).BeginInit(); @@ -470,6 +478,7 @@ this.fLPSettings.SuspendLayout(); this.gBGyro.SuspendLayout(); this.pnlSAMouse.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.gyroMouseDzNUD)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroSmoothWeight)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroMouseVertScale)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroSensitivity)).BeginInit(); @@ -1856,6 +1865,11 @@ this.fLPTiltControls.Controls.Add(this.lbGyroXP); this.fLPTiltControls.Controls.Add(this.bnGyroXN); this.fLPTiltControls.Controls.Add(this.lbGyroXN); + this.fLPTiltControls.Controls.Add(this.lblSteeringWheelEmulationAxis); + this.fLPTiltControls.Controls.Add(this.cBSteeringWheelEmulationAxis); + this.fLPTiltControls.Controls.Add(this.lblSteeringWheelEmulationRange); + this.fLPTiltControls.Controls.Add(this.cBSteeringWheelEmulationRange); + this.fLPTiltControls.Controls.Add(this.btnSteeringWheelEmulationCalibrate); resources.ApplyResources(this.fLPTiltControls, "fLPTiltControls"); this.fLPTiltControls.Name = "fLPTiltControls"; // @@ -1911,6 +1925,62 @@ resources.ApplyResources(this.lbGyroXN, "lbGyroXN"); this.lbGyroXN.Name = "lbGyroXN"; // + // lblSteeringWheelEmulationAxis + // + resources.ApplyResources(this.lblSteeringWheelEmulationAxis, "lblSteeringWheelEmulationAxis"); + this.lblSteeringWheelEmulationAxis.Name = "lblSteeringWheelEmulationAxis"; + // + // cBSteeringWheelEmulationAxis + // + this.cBSteeringWheelEmulationAxis.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cBSteeringWheelEmulationAxis.FormattingEnabled = true; + this.cBSteeringWheelEmulationAxis.Items.AddRange(new object[] { + resources.GetString("cBSteeringWheelEmulationAxis.Items"), + resources.GetString("cBSteeringWheelEmulationAxis.Items1"), + resources.GetString("cBSteeringWheelEmulationAxis.Items2"), + resources.GetString("cBSteeringWheelEmulationAxis.Items3"), + resources.GetString("cBSteeringWheelEmulationAxis.Items4"), + resources.GetString("cBSteeringWheelEmulationAxis.Items5"), + resources.GetString("cBSteeringWheelEmulationAxis.Items6"), + resources.GetString("cBSteeringWheelEmulationAxis.Items7"), + resources.GetString("cBSteeringWheelEmulationAxis.Items8"), + resources.GetString("cBSteeringWheelEmulationAxis.Items9"), + resources.GetString("cBSteeringWheelEmulationAxis.Items10"), + resources.GetString("cBSteeringWheelEmulationAxis.Items11")}); + resources.ApplyResources(this.cBSteeringWheelEmulationAxis, "cBSteeringWheelEmulationAxis"); + this.cBSteeringWheelEmulationAxis.Name = "cBSteeringWheelEmulationAxis"; + this.cBSteeringWheelEmulationAxis.SelectedIndexChanged += new System.EventHandler(this.cBSteeringWheelEmulationAxis_SelectedIndexChanged); + // + // lblSteeringWheelEmulationRange + // + resources.ApplyResources(this.lblSteeringWheelEmulationRange, "lblSteeringWheelEmulationRange"); + this.lblSteeringWheelEmulationRange.Name = "lblSteeringWheelEmulationRange"; + // + // cBSteeringWheelEmulationRange + // + this.cBSteeringWheelEmulationRange.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cBSteeringWheelEmulationRange.FormattingEnabled = true; + this.cBSteeringWheelEmulationRange.Items.AddRange(new object[] { + resources.GetString("cBSteeringWheelEmulationRange.Items"), + resources.GetString("cBSteeringWheelEmulationRange.Items1"), + resources.GetString("cBSteeringWheelEmulationRange.Items2"), + resources.GetString("cBSteeringWheelEmulationRange.Items3"), + resources.GetString("cBSteeringWheelEmulationRange.Items4"), + resources.GetString("cBSteeringWheelEmulationRange.Items5"), + resources.GetString("cBSteeringWheelEmulationRange.Items6"), + resources.GetString("cBSteeringWheelEmulationRange.Items7"), + resources.GetString("cBSteeringWheelEmulationRange.Items8")}); + resources.ApplyResources(this.cBSteeringWheelEmulationRange, "cBSteeringWheelEmulationRange"); + this.cBSteeringWheelEmulationRange.Name = "cBSteeringWheelEmulationRange"; + this.cBSteeringWheelEmulationRange.SelectedIndexChanged += new System.EventHandler(this.cBSteeringWheelEmulationRange_SelectedIndexChanged); + // + // btnSteeringWheelEmulationCalibrate + // + resources.ApplyResources(this.btnSteeringWheelEmulationCalibrate, "btnSteeringWheelEmulationCalibrate"); + this.btnSteeringWheelEmulationCalibrate.Name = "btnSteeringWheelEmulationCalibrate"; + this.btnSteeringWheelEmulationCalibrate.UseVisualStyleBackColor = true; + this.btnSteeringWheelEmulationCalibrate.Click += new System.EventHandler(this.btnSteeringWheelEmulationCalibrate_Click); + // // tCControls // this.tCControls.Controls.Add(this.tPControls); @@ -3137,7 +3207,8 @@ this.cBSixaxisZOutputCurve.Items.AddRange(new object[] { resources.GetString("cBSixaxisZOutputCurve.Items"), resources.GetString("cBSixaxisZOutputCurve.Items1"), - resources.GetString("cBSixaxisZOutputCurve.Items2")}); + resources.GetString("cBSixaxisZOutputCurve.Items2"), + resources.GetString("cBSixaxisZOutputCurve.Items3")}); resources.ApplyResources(this.cBSixaxisZOutputCurve, "cBSixaxisZOutputCurve"); this.cBSixaxisZOutputCurve.Name = "cBSixaxisZOutputCurve"; this.cBSixaxisZOutputCurve.SelectedIndexChanged += new System.EventHandler(this.cBSixaxisZOutputCurve_SelectedIndexChanged); @@ -3150,7 +3221,8 @@ this.cBSixaxisXOutputCurve.Items.AddRange(new object[] { resources.GetString("cBSixaxisXOutputCurve.Items"), resources.GetString("cBSixaxisXOutputCurve.Items1"), - resources.GetString("cBSixaxisXOutputCurve.Items2")}); + resources.GetString("cBSixaxisXOutputCurve.Items2"), + resources.GetString("cBSixaxisXOutputCurve.Items3")}); resources.ApplyResources(this.cBSixaxisXOutputCurve, "cBSixaxisXOutputCurve"); this.cBSixaxisXOutputCurve.Name = "cBSixaxisXOutputCurve"; this.cBSixaxisXOutputCurve.SelectedIndexChanged += new System.EventHandler(this.cBSixaxisXOutputCurve_SelectedIndexChanged); @@ -3173,7 +3245,8 @@ this.cBR2OutputCurve.Items.AddRange(new object[] { resources.GetString("cBR2OutputCurve.Items"), resources.GetString("cBR2OutputCurve.Items1"), - resources.GetString("cBR2OutputCurve.Items2")}); + resources.GetString("cBR2OutputCurve.Items2"), + resources.GetString("cBR2OutputCurve.Items3")}); resources.ApplyResources(this.cBR2OutputCurve, "cBR2OutputCurve"); this.cBR2OutputCurve.Name = "cBR2OutputCurve"; this.cBR2OutputCurve.SelectedIndexChanged += new System.EventHandler(this.cBR2OutputCurve_SelectedIndexChanged); @@ -3186,7 +3259,8 @@ this.cBL2OutputCurve.Items.AddRange(new object[] { resources.GetString("cBL2OutputCurve.Items"), resources.GetString("cBL2OutputCurve.Items1"), - resources.GetString("cBL2OutputCurve.Items2")}); + resources.GetString("cBL2OutputCurve.Items2"), + resources.GetString("cBL2OutputCurve.Items3")}); resources.ApplyResources(this.cBL2OutputCurve, "cBL2OutputCurve"); this.cBL2OutputCurve.Name = "cBL2OutputCurve"; this.cBL2OutputCurve.SelectedIndexChanged += new System.EventHandler(this.cBL2OutputCurve_SelectedIndexChanged); @@ -3210,7 +3284,8 @@ resources.GetString("rsOutCurveComboBox.Items"), resources.GetString("rsOutCurveComboBox.Items1"), resources.GetString("rsOutCurveComboBox.Items2"), - resources.GetString("rsOutCurveComboBox.Items3")}); + resources.GetString("rsOutCurveComboBox.Items3"), + resources.GetString("rsOutCurveComboBox.Items4")}); resources.ApplyResources(this.rsOutCurveComboBox, "rsOutCurveComboBox"); this.rsOutCurveComboBox.Name = "rsOutCurveComboBox"; this.rsOutCurveComboBox.SelectedIndexChanged += new System.EventHandler(this.rsOutCurveComboBox_SelectedIndexChanged); @@ -3224,7 +3299,8 @@ resources.GetString("lsOutCurveComboBox.Items"), resources.GetString("lsOutCurveComboBox.Items1"), resources.GetString("lsOutCurveComboBox.Items2"), - resources.GetString("lsOutCurveComboBox.Items3")}); + resources.GetString("lsOutCurveComboBox.Items3"), + resources.GetString("lsOutCurveComboBox.Items4")}); resources.ApplyResources(this.lsOutCurveComboBox, "lsOutCurveComboBox"); this.lsOutCurveComboBox.Name = "lsOutCurveComboBox"; this.lsOutCurveComboBox.SelectedIndexChanged += new System.EventHandler(this.lsOutCurveComboBox_SelectedIndexChanged); @@ -3362,8 +3438,8 @@ this.gBGyro.BackColor = System.Drawing.SystemColors.Control; this.gBGyro.Controls.Add(this.rBSAControls); this.gBGyro.Controls.Add(this.rBSAMouse); - this.gBGyro.Controls.Add(this.pnlSAMouse); this.gBGyro.Controls.Add(this.fLPTiltControls); + this.gBGyro.Controls.Add(this.pnlSAMouse); resources.ApplyResources(this.gBGyro, "gBGyro"); this.gBGyro.Name = "gBGyro"; this.gBGyro.TabStop = false; @@ -3386,6 +3462,9 @@ // // pnlSAMouse // + this.pnlSAMouse.Controls.Add(this.toggleGyroMCb); + this.pnlSAMouse.Controls.Add(this.label27); + this.pnlSAMouse.Controls.Add(this.gyroMouseDzNUD); this.pnlSAMouse.Controls.Add(this.label26); this.pnlSAMouse.Controls.Add(this.triggerCondAndCombo); this.pnlSAMouse.Controls.Add(this.cBGyroMouseXAxis); @@ -3408,6 +3487,44 @@ resources.ApplyResources(this.pnlSAMouse, "pnlSAMouse"); this.pnlSAMouse.Name = "pnlSAMouse"; // + // toggleGyroMCb + // + resources.ApplyResources(this.toggleGyroMCb, "toggleGyroMCb"); + this.toggleGyroMCb.Name = "toggleGyroMCb"; + this.toggleGyroMCb.UseVisualStyleBackColor = true; + this.toggleGyroMCb.Click += new System.EventHandler(this.toggleGyroMCb_Click); + // + // label27 + // + resources.ApplyResources(this.label27, "label27"); + this.label27.Name = "label27"; + // + // gyroMouseDzNUD + // + resources.ApplyResources(this.gyroMouseDzNUD, "gyroMouseDzNUD"); + this.gyroMouseDzNUD.Name = "gyroMouseDzNUD"; + this.gyroMouseDzNUD.Value = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.gyroMouseDzNUD.ValueChanged += new System.EventHandler(this.gyroMouseDzNUD_ValueChanged); + // + // label26 + // + resources.ApplyResources(this.label26, "label26"); + this.label26.Name = "label26"; + // + // triggerCondAndCombo + // + this.triggerCondAndCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.triggerCondAndCombo.FormattingEnabled = true; + this.triggerCondAndCombo.Items.AddRange(new object[] { + resources.GetString("triggerCondAndCombo.Items"), + resources.GetString("triggerCondAndCombo.Items1")}); + resources.ApplyResources(this.triggerCondAndCombo, "triggerCondAndCombo"); + this.triggerCondAndCombo.Name = "triggerCondAndCombo"; + // // cBGyroMouseXAxis // this.cBGyroMouseXAxis.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; @@ -4110,21 +4227,6 @@ resources.ApplyResources(this.psTouchInvStripMenuItem, "psTouchInvStripMenuItem"); this.psTouchInvStripMenuItem.CheckedChanged += new System.EventHandler(this.TouchDisableInvert_CheckedChanged); // - // triggerCondAndCombo - // - this.triggerCondAndCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.triggerCondAndCombo.FormattingEnabled = true; - this.triggerCondAndCombo.Items.AddRange(new object[] { - resources.GetString("triggerCondAndCombo.Items"), - resources.GetString("triggerCondAndCombo.Items1")}); - resources.ApplyResources(this.triggerCondAndCombo, "triggerCondAndCombo"); - this.triggerCondAndCombo.Name = "triggerCondAndCombo"; - // - // label26 - // - resources.ApplyResources(this.label26, "label26"); - this.label26.Name = "label26"; - // // Options // resources.ApplyResources(this, "$this"); @@ -4234,6 +4336,7 @@ this.gBGyro.PerformLayout(); this.pnlSAMouse.ResumeLayout(false); this.pnlSAMouse.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.gyroMouseDzNUD)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroSmoothWeight)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroMouseVertScale)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nUDGyroSensitivity)).EndInit(); @@ -4614,5 +4717,13 @@ private System.Windows.Forms.CheckBox trackballCk; private System.Windows.Forms.Label label26; private System.Windows.Forms.ComboBox triggerCondAndCombo; + private System.Windows.Forms.Label lblSteeringWheelEmulationAxis; + private System.Windows.Forms.ComboBox cBSteeringWheelEmulationAxis; + private System.Windows.Forms.Label lblSteeringWheelEmulationRange; + private System.Windows.Forms.ComboBox cBSteeringWheelEmulationRange; + private System.Windows.Forms.Button btnSteeringWheelEmulationCalibrate; + private System.Windows.Forms.Label label27; + private System.Windows.Forms.NumericUpDown gyroMouseDzNUD; + private System.Windows.Forms.CheckBox toggleGyroMCb; } } \ No newline at end of file diff --git a/DS4Windows/DS4Forms/Options.cs b/DS4Windows/DS4Forms/Options.cs index 7c9aa91..48d0284 100644 --- a/DS4Windows/DS4Forms/Options.cs +++ b/DS4Windows/DS4Forms/Options.cs @@ -718,6 +718,13 @@ namespace DS4Windows nUDGyroSmoothWeight.Value = (decimal)(GyroSmoothingWeight[device]); cBGyroMouseXAxis.SelectedIndex = GyroMouseHorizontalAxis[device]; triggerCondAndCombo.SelectedIndex = SATriggerCond[device] ? 0 : 1; + gyroMouseDzNUD.Value = GyroMouseDeadZone[device]; + toggleGyroMCb.Checked = GyroMouseToggle[device]; + + cBSteeringWheelEmulationAxis.SelectedIndex = (int) GetSASteeringWheelEmulationAxis(device); + + int idxSASteeringWheelEmulationRange = cBSteeringWheelEmulationRange.Items.IndexOf(GetSASteeringWheelEmulationRange(device).ToString()); + if (idxSASteeringWheelEmulationRange >= 0) cBSteeringWheelEmulationRange.SelectedIndex = idxSASteeringWheelEmulationRange; } else { @@ -834,8 +841,12 @@ namespace DS4Windows cBGyroInvertY.Checked = false; cBGyroSmooth.Checked = false; nUDGyroSmoothWeight.Value = 0.5m; + gyroMouseDzNUD.Value = MouseCursor.GYRO_MOUSE_DEADZONE; + toggleGyroMCb.Checked = false; cBGyroMouseXAxis.SelectedIndex = 0; triggerCondAndCombo.SelectedIndex = 0; + cBSteeringWheelEmulationAxis.SelectedIndex = 0; + cBSteeringWheelEmulationRange.SelectedIndex = cBSteeringWheelEmulationRange.Items.IndexOf("360"); Set(); } @@ -873,6 +884,9 @@ namespace DS4Windows case "MultiAction": lvi.SubItems.Add(Properties.Resources.MultiAction); break; + case "SASteeringWheelEmulationCalibrate": + lvi.SubItems.Add(Properties.Resources.SASteeringWheelEmulationCalibrate); + break; } if (newp) @@ -1334,6 +1348,8 @@ namespace DS4Windows GyroSmoothing[device] = cBGyroSmooth.Checked; GyroSmoothingWeight[device] = (double)nUDGyroSmoothWeight.Value; GyroMouseHorizontalAxis[device] = cBGyroMouseXAxis.SelectedIndex; + SetGyroMouseDeadZone(device, (int)gyroMouseDzNUD.Value, Program.rootHub); + SetGyroMouseToggle(device, toggleGyroMCb.Checked, Program.rootHub); int invert = 0; if (cBGyroInvertX.Checked) @@ -2814,6 +2830,8 @@ namespace DS4Windows if (!loading) { GyroTriggerTurns[device] = gyroTriggerBehavior.Checked; + if (device < 4) + Program.rootHub.touchPad[device]?.ResetToggleGyroM(); } } @@ -2989,6 +3007,98 @@ namespace DS4Windows } } + private void cBSteeringWheelEmulationRange_SelectedIndexChanged(object sender, EventArgs e) + { + if (loading == false) + { + SASteeringWheelEmulationRange[device] = Convert.ToInt32(cBSteeringWheelEmulationRange.Items[cBSteeringWheelEmulationRange.SelectedIndex].ToString()); + } + } + + private void cBSteeringWheelEmulationAxis_SelectedIndexChanged(object sender, EventArgs e) + { + if (loading == false) + { + if (cBSteeringWheelEmulationAxis.SelectedIndex >= 0) SASteeringWheelEmulationAxis[device] = (SASteeringWheelEmulationAxisType) ((byte) cBSteeringWheelEmulationAxis.SelectedIndex); + else SASteeringWheelEmulationAxis[device] = SASteeringWheelEmulationAxisType.None; + } + } + + private void btnSteeringWheelEmulationCalibrate_Click(object sender, EventArgs e) + { + if(cBSteeringWheelEmulationAxis.SelectedIndex > 0) + { + DS4Device d; + int tempDeviceNum = (int)nUDSixaxis.Value - 1; + + d = Program.rootHub.DS4Controllers[tempDeviceNum]; + if (d != null) + { + Point origWheelCenterPoint = new Point(d.wheelCenterPoint.X, d.wheelCenterPoint.Y); + Point origWheel90DegPointLeft = new Point(d.wheel90DegPointLeft.X, d.wheel90DegPointLeft.Y); + Point origWheel90DegPointRight = new Point(d.wheel90DegPointRight.X, d.wheel90DegPointRight.Y); + + d.WheelRecalibrateActiveState = 1; + + DialogResult msgBoxResult = MessageBox.Show($"{Properties.Resources.SASteeringWheelEmulationCalibrate}.\n\n" + + $"{Properties.Resources.SASteeringWheelEmulationCalibrateInstruction1}.\n" + + $"{Properties.Resources.SASteeringWheelEmulationCalibrateInstruction2}.\n" + + $"{Properties.Resources.SASteeringWheelEmulationCalibrateInstruction3}.\n\n" + + $"{Properties.Resources.SASteeringWheelEmulationCalibrateInstruction}.\n", + Properties.Resources.SASteeringWheelEmulationCalibrate, + MessageBoxButtons.OKCancel, + MessageBoxIcon.Information, + MessageBoxDefaultButton.Button1, + 0, + false); + + if (msgBoxResult == DialogResult.OK) + { + // Accept new calibration values (State 3 is "Complete calibration" state) + d.WheelRecalibrateActiveState = 3; + } + else + { + // Cancel calibration and reset back to original calibration values + d.WheelRecalibrateActiveState = 4; + + d.wheelFullTurnCount = 0; + d.wheelCenterPoint = origWheelCenterPoint; + d.wheel90DegPointLeft = origWheel90DegPointLeft; + d.wheel90DegPointRight = origWheel90DegPointRight; + } + } + else + { + MessageBox.Show($"{Properties.Resources.SASteeringWheelEmulationCalibrateNoControllerError}."); + } + } + else + { + MessageBox.Show($"{Properties.Resources.SASteeringWheelEmulationCalibrateNoneAxisError}."); + } + } + + private void gyroMouseDzNUD_ValueChanged(object sender, EventArgs e) + { + if (loading == false) + { + SetGyroMouseDeadZone(device, (int)gyroMouseDzNUD.Value, + Program.rootHub); + } + } + + private void toggleGyroMCb_Click(object sender, EventArgs e) + { + if (loading == false) + { + if (device < 4) + { + SetGyroMouseToggle(device, toggleGyroMCb.Checked, Program.rootHub); + } + } + } + private void trackFrictionNUD_ValueChanged(object sender, EventArgs e) { if (loading == false) diff --git a/DS4Windows/DS4Forms/Options.resx b/DS4Windows/DS4Forms/Options.resx index dc50f18..d50766a 100644 --- a/DS4Windows/DS4Forms/Options.resx +++ b/DS4Windows/DS4Forms/Options.resx @@ -148,7 +148,7 @@ 0 - 30, 215 + 28, 207 39, 20 @@ -256,7 +256,7 @@ NoControl - 6, 191 + 6, 184 111, 17 @@ -346,7 +346,7 @@ NoControl - 72, 218 + 70, 210 59, 13 @@ -2552,7 +2552,7 @@ with profile NoControl - 6, 214 + 4, 206 2, 2, 2, 2 @@ -2582,7 +2582,7 @@ with profile NoControl - 203, 214 + 201, 206 15, 13 @@ -2609,7 +2609,7 @@ with profile 1 - 151, 214 + 149, 206 43, 20 @@ -2639,7 +2639,7 @@ with profile Pulse at - 4, 133 + 6, 123 68, 21 @@ -2672,7 +2672,7 @@ with profile Color - 91, 166 + 90, 156 121, 21 @@ -2702,7 +2702,7 @@ with profile NoControl - 146, 137 + 148, 127 13, 13 @@ -2729,7 +2729,7 @@ with profile NoControl - 218, 168 + 217, 158 13, 13 @@ -2759,7 +2759,7 @@ with profile NoControl - 5, 167 + 4, 157 82, 13 @@ -2813,7 +2813,7 @@ with profile 8 - 78, 134 + 80, 124 43, 20 @@ -2837,7 +2837,7 @@ with profile 3, 3 - 272, 244 + 272, 233 247 @@ -3821,7 +3821,7 @@ with profile 3, 3, 3, 3 - 438, 455 + 438, 485 2 @@ -4057,11 +4057,209 @@ with profile 7 + + True + + + NoControl + + + 3, 116 + + + 0, 5, 0, 0 + + + 98, 18 + + + 290 + + + Steering wheel axis + + + lblSteeringWheelEmulationAxis + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fLPTiltControls + + + 8 + + + None + + + Left X-Axis + + + Left Y-Axis + + + Right X-Axis + + + Right Y-Axis + + + Trigger L+R Axis + + + VJoy1 X-Axis + + + VJoy1 Y-Axis + + + VJoy1 Z-Axis + + + VJoy2 X-Axis + + + VJoy2 Y-Axis + + + VJoy2 Z-Axis + + + 107, 119 + + + 110, 21 + + + 291 + + + cBSteeringWheelEmulationAxis + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fLPTiltControls + + + 9 + + + True + + + NoControl + + + 3, 143 + + + 0, 5, 0, 0 + + + 107, 18 + + + 292 + + + Steering wheel range + + + lblSteeringWheelEmulationRange + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fLPTiltControls + + + 10 + + + 90 + + + 180 + + + 270 + + + 360 + + + 450 + + + 720 + + + 900 + + + 1080 + + + 1440 + + + 116, 146 + + + 60, 21 + + + 293 + + + cBSteeringWheelEmulationRange + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fLPTiltControls + + + 11 + + + NoControl + + + 182, 146 + + + 75, 23 + + + 294 + + + Calibrate... + + + btnSteeringWheelEmulationCalibrate + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + fLPTiltControls + + + 12 + 4, 43 - 271, 167 + 271, 203 254 @@ -4076,7 +4274,7 @@ with profile gBGyro - 3 + 2 True @@ -4187,7 +4385,7 @@ with profile 278, 254 - 157, 186 + 157, 212 180 @@ -5921,7 +6119,7 @@ with profile 3, 3, 3, 3 - 438, 455 + 438, 485 0 @@ -5966,7 +6164,7 @@ with profile 0, 66 - 438, 389 + 438, 419 13 @@ -6155,7 +6353,7 @@ with profile 0, 0 - 438, 455 + 438, 485 15 @@ -6176,7 +6374,7 @@ with profile 4, 22 - 438, 455 + 438, 485 3 @@ -6203,7 +6401,7 @@ with profile 0, 0 - 446, 481 + 446, 511 253 @@ -6922,6 +7120,9 @@ with profile Cubic + + Easeout Quad + 221, 28 @@ -6952,6 +7153,9 @@ with profile Cubic + + Easeout Quad + 221, 1 @@ -7042,6 +7246,9 @@ with profile Cubic + + Easeout Quad + 111, 28 @@ -7072,6 +7279,9 @@ with profile Cubic + + Easeout Quad + 31, 28 @@ -7165,6 +7375,9 @@ with profile Cubic + + Easeout Quad + 111, 3 @@ -7198,6 +7411,9 @@ with profile Cubic + + Easeout Quad + 31, 2 @@ -7717,6 +7933,84 @@ with profile 1 + + True + + + 9, 187 + + + Yes + + + 59, 17 + + + 276 + + + Toggle + + + toggleGyroMCb + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pnlSAMouse + + + 0 + + + True + + + 11, 166 + + + 56, 13 + + + 275 + + + Deadzone + + + label27 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pnlSAMouse + + + 1 + + + 78, 166 + + + 43, 20 + + + 274 + + + gyroMouseDzNUD + + + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pnlSAMouse + + + 2 + True @@ -7745,7 +8039,7 @@ with profile pnlSAMouse - 0 + 3 And @@ -7754,7 +8048,7 @@ with profile Or - 165, 67 + 165, 62 73, 21 @@ -7772,7 +8066,7 @@ with profile pnlSAMouse - 1 + 4 Yaw @@ -7781,7 +8075,7 @@ with profile Roll - 170, 114 + 169, 107 74, 21 @@ -7799,7 +8093,7 @@ with profile pnlSAMouse - 2 + 5 True @@ -7808,7 +8102,7 @@ with profile NoControl - 167, 95 + 166, 91 39, 13 @@ -7829,7 +8123,7 @@ with profile pnlSAMouse - 3 + 6 True @@ -7838,7 +8132,7 @@ with profile NoControl - 8, 145 + 6, 139 60, 13 @@ -7859,7 +8153,7 @@ with profile pnlSAMouse - 4 + 7 True @@ -7868,7 +8162,7 @@ with profile NoControl - 75, 145 + 73, 139 Yes @@ -7889,7 +8183,7 @@ with profile pnlSAMouse - 5 + 8 True @@ -7898,7 +8192,7 @@ with profile NoControl - 96, 145 + 94, 139 83, 13 @@ -7919,13 +8213,13 @@ with profile pnlSAMouse - 6 + 9 False - 185, 141 + 183, 135 55, 20 @@ -7943,7 +8237,7 @@ with profile pnlSAMouse - 7 + 10 True @@ -7973,10 +8267,10 @@ with profile pnlSAMouse - 8 + 11 - 96, 93 + 95, 89 49, 20 @@ -7994,7 +8288,7 @@ with profile pnlSAMouse - 9 + 12 True @@ -8003,7 +8297,7 @@ with profile NoControl - 8, 95 + 7, 91 75, 13 @@ -8024,7 +8318,7 @@ with profile pnlSAMouse - 10 + 13 True @@ -8057,7 +8351,7 @@ with profile pnlSAMouse - 11 + 14 True @@ -8066,7 +8360,7 @@ with profile NoControl - 92, 119 + 95, 114 Yes @@ -8090,7 +8384,7 @@ with profile pnlSAMouse - 12 + 15 True @@ -8099,7 +8393,7 @@ with profile NoControl - 49, 119 + 52, 114 Yes @@ -8123,7 +8417,7 @@ with profile pnlSAMouse - 13 + 16 True @@ -8132,7 +8426,7 @@ with profile NoControl - 8, 119 + 11, 114 37, 13 @@ -8156,7 +8450,7 @@ with profile pnlSAMouse - 14 + 17 True @@ -8189,7 +8483,7 @@ with profile pnlSAMouse - 15 + 18 NoControl @@ -8219,10 +8513,10 @@ with profile pnlSAMouse - 16 + 19 - 96, 67 + 96, 62 49, 20 @@ -8240,7 +8534,7 @@ with profile pnlSAMouse - 17 + 20 True @@ -8249,7 +8543,7 @@ with profile NoControl - 8, 69 + 8, 64 82, 13 @@ -8273,16 +8567,16 @@ with profile pnlSAMouse - 18 + 21 - 6, 43 + 6, 39 2, 2, 2, 2 - 263, 170 + 263, 207 259 @@ -8297,13 +8591,13 @@ with profile gBGyro - 2 + 3 - 3, 253 + 3, 242 - 272, 224 + 272, 257 248 @@ -8678,7 +8972,7 @@ with profile 2, 2, 2, 2 - 565, 481 + 565, 511 254 @@ -8960,7 +9254,7 @@ with profile True - 102 + 25 96, 96 @@ -8969,19 +9263,16 @@ with profile True - 1011, 481 - - - NoControl + 1011, 511 4, 4, 4, 4 - 1027, 520 + 1027, 550 - 18, 94 + 18, 520 Profile Options @@ -9392,7 +9683,7 @@ with profile advColorDialog - DS4Windows.AdvancedColorDialog, DS4Windows, Version=1.5.8.0, Culture=neutral, PublicKeyToken=null + DS4Windows.AdvancedColorDialog, DS4Windows, Version=1.6.8.0, Culture=neutral, PublicKeyToken=null Options diff --git a/DS4Windows/DS4Forms/SpecActions.Designer.cs b/DS4Windows/DS4Forms/SpecActions.Designer.cs index 054a3a3..3283401 100644 --- a/DS4Windows/DS4Forms/SpecActions.Designer.cs +++ b/DS4Windows/DS4Forms/SpecActions.Designer.cs @@ -86,7 +86,6 @@ this.lbDTapDVR = new System.Windows.Forms.Label(); this.lbHoldDVR = new System.Windows.Forms.Label(); this.lbTapDVR = new System.Windows.Forms.Label(); - this.advColorDialog = new DS4Windows.AdvancedColorDialog(); ((System.ComponentModel.ISupportInitialize)(this.pBProgram)).BeginInit(); this.pnlProgram.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nUDProg)).BeginInit(); @@ -221,7 +220,8 @@ resources.GetString("cBActions.Items4"), resources.GetString("cBActions.Items5"), resources.GetString("cBActions.Items6"), - resources.GetString("cBActions.Items7")}); + resources.GetString("cBActions.Items7"), + resources.GetString("cBActions.Items8")}); resources.ApplyResources(this.cBActions, "cBActions"); this.cBActions.Name = "cBActions"; this.cBActions.SelectedIndexChanged += new System.EventHandler(this.cBActions_SelectedIndexChanged); @@ -596,13 +596,6 @@ resources.ApplyResources(this.lbTapDVR, "lbTapDVR"); this.lbTapDVR.Name = "lbTapDVR"; // - // advColorDialog - // - this.advColorDialog.AnyColor = true; - this.advColorDialog.Color = System.Drawing.Color.Blue; - this.advColorDialog.FullOpen = true; - this.advColorDialog.OnUpdateColor += new DS4Windows.AdvancedColorDialog.ColorUpdateHandler(this.advColorDialog_OnUpdateColor); - // // SpecActions // resources.ApplyResources(this, "$this"); diff --git a/DS4Windows/DS4Forms/SpecActions.cs b/DS4Windows/DS4Forms/SpecActions.cs index 3f65003..d70aa69 100644 --- a/DS4Windows/DS4Forms/SpecActions.cs +++ b/DS4Windows/DS4Forms/SpecActions.cs @@ -177,6 +177,10 @@ namespace DS4Windows cBHoldDVR.SelectedIndex = int.Parse(dets[1]); cBDTapDVR.SelectedIndex = int.Parse(dets[2]);*/ break; + case "SASteeringWheelEmulationCalibrate": + cBActions.SelectedIndex = 8; + nUDDCBT.Value = (decimal)act.delayTime; + break; } } @@ -331,6 +335,13 @@ namespace DS4Windows } break; + case 8: + action = Properties.Resources.SASteeringWheelEmulationCalibrate; + actRe = true; + if (!string.IsNullOrEmpty(oldprofilename) && oldprofilename != tBName.Text) + Global.RemoveAction(oldprofilename); + Global.SaveAction(tBName.Text, String.Join("/", controls), cBActions.SelectedIndex, Math.Round(nUDDCBT.Value, 1).ToString(), edit); + break; } if (actRe) { @@ -368,7 +379,7 @@ namespace DS4Windows pnlProgram.Visible = i == 2; pnlProfile.Visible = i == 3; pnlKeys.Visible = i == 4; - pnlDisconnectBT.Visible = i == 5; + pnlDisconnectBT.Visible = i == 5 || i == 8; // SASteeringWheelEmulationCalibrate action #8 re-uses DisconnectBT panel ("hold for X secs" detail option) pnlBatteryCheck.Visible = i == 6; pnlGameDVR.Visible = i == 7; btnSave.Enabled = i > 0; diff --git a/DS4Windows/DS4Forms/SpecActions.resx b/DS4Windows/DS4Forms/SpecActions.resx index 1df5a54..13b7a3a 100644 --- a/DS4Windows/DS4Forms/SpecActions.resx +++ b/DS4Windows/DS4Forms/SpecActions.resx @@ -796,13 +796,10 @@ - 19, 41 - - - 4, 4, 4, 4 + 14, 33 - 237, 267 + 178, 217 14 @@ -825,11 +822,8 @@ 0, 0 - - 4, 4, 4, 4 - - 204, 28 + 153, 23 16 @@ -853,13 +847,10 @@ NoControl - 1, 33 - - - 4, 4, 4, 4 + 1, 27 - 204, 28 + 153, 23 16 @@ -882,11 +873,8 @@ 0, 0 - - 4, 4, 4, 4 - - 203, 24 + 153, 21 17 @@ -913,13 +901,10 @@ NoControl - 275, 282 - - - 4, 4, 4, 4 + 206, 229 - 105, 28 + 79, 23 16 @@ -946,13 +931,10 @@ NoControl - 388, 282 - - - 4, 4, 4, 4 + 291, 229 - 91, 28 + 68, 23 16 @@ -976,13 +958,10 @@ NoControl - 16, 10 - - - 4, 0, 4, 0 + 12, 8 - 72, 16 + 54, 13 15 @@ -1009,13 +988,10 @@ Top, Left, Right - 77, 6 - - - 4, 4, 4, 4 + 58, 5 - 431, 22 + 324, 20 18 @@ -1056,14 +1032,14 @@ Mutli Action Button - - 273, 38 + + Calibration of sixaxis wheel emulation - - 4, 4, 4, 4 + + 205, 31 - 203, 24 + 153, 21 17 @@ -1093,13 +1069,10 @@ NoControl - 173, 65 - - - 4, 4, 4, 4 + 130, 53 - 31, 28 + 23, 23 Zoom @@ -1123,13 +1096,10 @@ NoControl - 4, 65 - - - 4, 0, 4, 0 + 3, 53 - 163, 28 + 122, 23 15 @@ -1159,13 +1129,10 @@ NoControl - 16, 38 - - - 4, 4, 4, 4 + 12, 31 - 243, 272 + 182, 221 257 @@ -1186,13 +1153,10 @@ NoControl - 0, 33 - - - 4, 4, 4, 4 + 0, 27 - 204, 28 + 153, 23 258 @@ -1888,13 +1852,10 @@ - 19, 41 - - - 4, 4, 4, 4 + 14, 33 - 237, 267 + 178, 217 259 @@ -1912,13 +1873,10 @@ 7 - 5, 112 - - - 4, 4, 4, 4 + 4, 91 - 196, 22 + 148, 20 264 @@ -1936,13 +1894,10 @@ 0 - 75, 4 - - - 4, 4, 4, 4 + 56, 3 - 71, 22 + 53, 20 263 @@ -1966,13 +1921,10 @@ NoControl - 4, 94 - - - 4, 0, 4, 0 + 3, 76 - 76, 17 + 57, 13 261 @@ -1999,20 +1951,17 @@ NoControl - 4, 6 - - - 4, 0, 4, 0 + 3, 5 - 63, 22 + 47, 18 261 Hold for - @Invariant + TopCenter @@ -2032,20 +1981,17 @@ NoControl - 153, 6 - - - 4, 0, 4, 0 + 115, 5 - 44, 22 + 33, 18 262 secs - @Invariant + TopCenter @@ -2062,13 +2008,10 @@ 4 - 275, 71 - - - 4, 4, 4, 4 + 206, 58 - 216, 153 + 162, 124 260 @@ -2095,13 +2038,10 @@ NoControl - 5, 37 - - - 4, 4, 4, 4 + 4, 30 - 99, 21 + 79, 17 17 @@ -2125,13 +2065,10 @@ NoControl - 0, 62 - - - 4, 0, 4, 0 + 0, 50 - 204, 28 + 153, 23 15 @@ -2152,13 +2089,10 @@ 2 - 275, 71 - - - 4, 4, 4, 4 + 206, 58 - 217, 116 + 163, 94 261 @@ -2182,13 +2116,10 @@ NoControl - 0, 68 - - - 4, 0, 4, 0 + 0, 55 - 133, 28 + 100, 23 259 @@ -2206,13 +2137,10 @@ 0 - 275, 71 - - - 4, 4, 4, 4 + 206, 58 - 215, 116 + 161, 94 262 @@ -2233,13 +2161,10 @@ 11 - 75, 4 - - - 4, 4, 4, 4 + 56, 3 - 71, 22 + 53, 20 260 @@ -2260,13 +2185,10 @@ NoControl - 4, 6 - - - 4, 0, 4, 0 + 3, 5 - 63, 22 + 47, 18 259 @@ -2293,13 +2215,10 @@ NoControl - 153, 6 - - - 4, 0, 4, 0 + 115, 5 - 44, 22 + 33, 18 259 @@ -2323,13 +2242,10 @@ 2 - 275, 71 - - - 4, 4, 4, 4 + 206, 58 - 215, 73 + 161, 59 262 @@ -2353,13 +2269,10 @@ NoControl - 7, 4 - - - 4, 4, 4, 4 + 5, 3 - 204, 28 + 153, 23 260 @@ -2386,13 +2299,10 @@ releasing unload trigger - 7, 94 - - - 4, 4, 4, 4 + 5, 76 - 203, 24 + 153, 21 17 @@ -2416,13 +2326,10 @@ NoControl - 7, 36 - - - 4, 4, 4, 4 + 5, 29 - 204, 28 + 153, 23 258 @@ -2449,13 +2356,10 @@ NoControl - 7, 75 - - - 4, 0, 4, 0 + 5, 61 - 203, 27 + 152, 22 259 @@ -2482,13 +2386,10 @@ 3 - 267, 71 - - - 4, 4, 4, 4 + 200, 58 - 215, 132 + 161, 107 263 @@ -2512,13 +2413,10 @@ NoControl - 37, 87 - - - 4, 4, 4, 4 + 28, 71 - 145, 16 + 109, 13 264 @@ -2542,13 +2440,10 @@ NoControl - 24, 31 - - - 4, 4, 4, 4 + 18, 25 - 120, 21 + 94, 17 263 @@ -2575,13 +2470,10 @@ NoControl - 24, 54 - - - 4, 4, 4, 4 + 18, 44 - 99, 21 + 77, 17 262 @@ -2608,13 +2500,10 @@ NoControl - 191, 87 - - - 4, 4, 4, 4 + 143, 71 - 17, 16 + 13, 13 261 @@ -2638,13 +2527,10 @@ NoControl - 12, 87 - - - 4, 4, 4, 4 + 9, 71 - 17, 16 + 13, 13 261 @@ -2662,13 +2548,10 @@ 4 - 75, 4 - - - 4, 4, 4, 4 + 56, 3 - 71, 22 + 53, 20 260 @@ -2689,20 +2572,17 @@ NoControl - 4, 6 - - - 4, 0, 4, 0 + 3, 5 - 63, 22 + 47, 18 259 Hold for - @Invariant + TopCenter @@ -2722,20 +2602,17 @@ NoControl - 171, 114 - - - 4, 0, 4, 0 + 128, 93 - 44, 22 + 33, 18 259 100% - @Invariant + TopRight @@ -2755,20 +2632,17 @@ NoControl - 8, 114 - - - 4, 0, 4, 0 + 6, 93 - 44, 22 + 33, 18 259 0% - @Invariant + lbEmptyBatt @@ -2785,20 +2659,17 @@ NoControl - 153, 6 - - - 4, 0, 4, 0 + 115, 5 - 44, 22 + 33, 18 259 secs - @Invariant + TopCenter @@ -2815,13 +2686,10 @@ 9 - 271, 73 - - - 4, 4, 4, 4 + 203, 59 - 215, 151 + 161, 123 264 @@ -2845,13 +2713,10 @@ NoControl - 4, 123 - - - 4, 4, 4, 4 + 3, 100 - 217, 28 + 163, 23 267 @@ -2875,13 +2740,10 @@ NoControl - 6, 73 - - - 4, 4, 4, 4 + 4, 59 - 217, 28 + 163, 23 266 @@ -2905,13 +2767,10 @@ NoControl - 6, 25 - - - 4, 4, 4, 4 + 4, 20 - 217, 28 + 163, 23 265 @@ -2938,13 +2797,10 @@ NoControl - 5, 102 - - - 4, 0, 4, 0 + 4, 83 - 132, 17 + 99, 13 263 @@ -2971,13 +2827,10 @@ NoControl - 5, 54 - - - 4, 0, 4, 0 + 4, 44 - 87, 17 + 65, 13 261 @@ -3004,13 +2857,10 @@ NoControl - 4, 4 - - - 4, 0, 4, 0 + 3, 3 - 83, 17 + 62, 13 259 @@ -3031,13 +2881,10 @@ 5 - 267, 70 - - - 4, 4, 4, 4 + 200, 57 - 228, 154 + 171, 125 264 @@ -3057,24 +2904,18 @@ 0 - - 267, 17 - True - 8, 16 + 6, 13 - 536, 325 - - - 4, 4, 4, 4 + 402, 264 SpecActions - @Invariant + cHTrigger @@ -3099,12 +2940,6 @@ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - advColorDialog - - - DS4Windows.AdvancedColorDialog, DS4Windows, Version=1.4.5.0, Culture=neutral, PublicKeyToken=null - SpecActions diff --git a/DS4Windows/DS4Library/DS4Device.cs b/DS4Windows/DS4Library/DS4Device.cs index 9dd72ec..974ea76 100644 --- a/DS4Windows/DS4Library/DS4Device.cs +++ b/DS4Windows/DS4Library/DS4Device.cs @@ -43,12 +43,12 @@ namespace DS4Windows { byte alphacolor = Math.Max(red, Math.Max(green, blue)); Color reg = Color.FromArgb(red, green, blue); - Color full = HuetoRGB(reg.GetHue(), reg.GetBrightness(), reg); + Color full = HuetoRGB(reg.GetHue(), reg.GetBrightness(), ref reg); return Color.FromArgb((alphacolor > 205 ? 255 : (alphacolor + 50)), full); } } - private Color HuetoRGB(float hue, float light, Color rgb) + private Color HuetoRGB(float hue, float light, ref Color rgb) { float L = (float)Math.Max(.5, light); float C = (1 - Math.Abs(2 * L - 1)); @@ -147,16 +147,52 @@ namespace DS4Windows return warnInterval; } + public Int32 wheelPrevPhysicalAngle = 0; + public Int32 wheelPrevFullAngle = 0; + public Int32 wheelFullTurnCount = 0; + + public Point wheelCenterPoint; + public Point wheel90DegPointLeft; + public Point wheelCircleCenterPointLeft; + public Point wheel90DegPointRight; + public Point wheelCircleCenterPointRight; + + public DateTime wheelPrevRecalibrateTime; + + private int wheelRecalibrateActiveState = 0; + public int WheelRecalibrateActiveState + { + get { return wheelRecalibrateActiveState; } + set + { + wheelRecalibrateActiveState = value; + } + } + + public enum WheelCalibrationPoint + { + None = 0, + Center = 1, + Right90 = 2, + Left90 = 4, + All = Center | Right90 | Left90 + } + public WheelCalibrationPoint wheelCalibratedAxisBitmask; + private bool exitOutputThread = false; public bool ExitOutputThread => exitOutputThread; private bool exitInputThread = false; private object exitLocker = new object(); - public event EventHandler Report = null; + public delegate void ReportHandler(DS4Device sender, TEventArgs args); + + //public event EventHandler Report = null; + public event ReportHandler Report = null; public event EventHandler Removal = null; public event EventHandler SyncChange = null; public event EventHandler SerialChange = null; - public EventHandler MotionEvent = null; + //public EventHandler MotionEvent = null; + public ReportHandler MotionEvent = null; public HidDevice HidDevice => hDevice; public bool IsExclusive => HidDevice.IsExclusive; diff --git a/DS4Windows/DS4Library/DS4Devices.cs b/DS4Windows/DS4Library/DS4Devices.cs index 09c4a53..c97ea87 100644 --- a/DS4Windows/DS4Library/DS4Devices.cs +++ b/DS4Windows/DS4Library/DS4Devices.cs @@ -179,9 +179,11 @@ namespace DS4Windows { IEnumerable devices = getDS4Controllers(); //foreach (DS4Device device in devices) - for (int i = 0, devCount = devices.Count(); i < devCount; i++) + //for (int i = 0, devCount = devices.Count(); i < devCount; i++) + for (var devEnum = devices.GetEnumerator(); devEnum.MoveNext();) { - DS4Device device = devices.ElementAt(i); + DS4Device device = devEnum.Current; + //DS4Device device = devices.ElementAt(i); device.StopUpdate(); //device.runRemoval(); device.HidDevice.CloseDevice(); @@ -248,9 +250,11 @@ namespace DS4Windows if (disabledDevCount > 0) { List disabledDevList = new List(); - for (int i = 0, arlen = disabledDevCount; i < arlen; i++) + for (var devEnum = DisabledDevices.GetEnumerator(); devEnum.MoveNext();) + //for (int i = 0, arlen = disabledDevCount; i < arlen; i++) { - HidDevice tempDev = DisabledDevices.ElementAt(i); + //HidDevice tempDev = DisabledDevices.ElementAt(i); + HidDevice tempDev = devEnum.Current; if (tempDev != null) { if (tempDev.IsOpen && tempDev.IsConnected) diff --git a/DS4Windows/DS4Library/DS4Sixaxis.cs b/DS4Windows/DS4Library/DS4Sixaxis.cs index b082fd9..403e794 100644 --- a/DS4Windows/DS4Library/DS4Sixaxis.cs +++ b/DS4Windows/DS4Library/DS4Sixaxis.cs @@ -2,6 +2,8 @@ namespace DS4Windows { + public delegate void SixAxisHandler(DS4SixAxis sender, TEventArgs args); + public class SixAxisEventArgs : EventArgs { public readonly SixAxis sixAxis; @@ -110,7 +112,8 @@ namespace DS4Windows public class DS4SixAxis { - public event EventHandler SixAccelMoved = null; + //public event EventHandler SixAccelMoved = null; + public event SixAxisHandler SixAccelMoved = null; private SixAxis sPrev = null, now = null; private CalibData[] calibrationData = new CalibData[6] { new CalibData(), new CalibData(), new CalibData(), new CalibData(), new CalibData(), new CalibData() diff --git a/DS4Windows/DS4Library/DS4State.cs b/DS4Windows/DS4Library/DS4State.cs index f3864c5..30ac51c 100644 --- a/DS4Windows/DS4Library/DS4State.cs +++ b/DS4Windows/DS4Library/DS4State.cs @@ -28,6 +28,7 @@ namespace DS4Windows public ulong totalMicroSec = 0; public SixAxis Motion = null; public static readonly int DEFAULT_AXISDIR_VALUE = 127; + public Int32 SASteeringWheelEmulationUnit; public struct TrackPadTouch { @@ -66,6 +67,7 @@ namespace DS4Windows Motion = new SixAxis(0, 0, 0, 0, 0, 0, 0.0); TrackPadTouch0.IsActive = false; TrackPadTouch1.IsActive = false; + SASteeringWheelEmulationUnit = 0; } public DS4State(DS4State state) @@ -120,6 +122,7 @@ namespace DS4Windows Motion = state.Motion; TrackPadTouch0 = state.TrackPadTouch0; TrackPadTouch1 = state.TrackPadTouch1; + SASteeringWheelEmulationUnit = state.SASteeringWheelEmulationUnit; } public DS4State Clone() @@ -179,6 +182,7 @@ namespace DS4Windows state.Motion = Motion; state.TrackPadTouch0 = TrackPadTouch0; state.TrackPadTouch1 = TrackPadTouch1; + state.SASteeringWheelEmulationUnit = SASteeringWheelEmulationUnit; } public void calculateStickAngles() diff --git a/DS4Windows/DS4Library/DS4Touchpad.cs b/DS4Windows/DS4Library/DS4Touchpad.cs index 47b0a9a..a2d7d36 100644 --- a/DS4Windows/DS4Library/DS4Touchpad.cs +++ b/DS4Windows/DS4Library/DS4Touchpad.cs @@ -52,13 +52,16 @@ namespace DS4Windows public class DS4Touchpad { - public event EventHandler TouchesBegan = null; // finger one or two landed (or both, or one then two, or two then one; any touches[] count increase) - public event EventHandler TouchesMoved = null; // deltaX/deltaY are set because one or both fingers were already down on a prior sensor reading - public event EventHandler TouchesEnded = null; // all fingers lifted - public event EventHandler TouchButtonDown = null; // touchpad pushed down until the button clicks - public event EventHandler TouchButtonUp = null; // touchpad button released - public event EventHandler 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 event EventHandler PreTouchProcess = null; // used to publish that a touch packet is about to be processed + public delegate void TouchHandler(DS4Touchpad sender, TEventArgs args); + + public event TouchHandler TouchesBegan = null; // finger one or two landed (or both, or one then two, or two then one; any touches[] count increase) + public event TouchHandler TouchesMoved = null; // deltaX/deltaY are set because one or both fingers were already down on a prior sensor reading + public event TouchHandler TouchesEnded = null; // all fingers lifted + public event TouchHandler TouchButtonDown = null; // touchpad pushed down until the button clicks + public event TouchHandler TouchButtonUp = null; // touchpad button released + public event TouchHandler 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 event TouchHandler PreTouchProcess = null; // used to publish that a touch packet is about to be processed + //public event EventHandler PreTouchProcess = null; // used to publish that a touch packet is about to be processed public readonly static int TOUCHPAD_DATA_OFFSET = 35; internal int lastTouchPadX1, lastTouchPadY1, diff --git a/DS4Windows/DS4Windows.csproj b/DS4Windows/DS4Windows.csproj index c36ee3e..226899e 100644 --- a/DS4Windows/DS4Windows.csproj +++ b/DS4Windows/DS4Windows.csproj @@ -9,7 +9,7 @@ Properties DS4Windows DS4Windows - v4.6.1 + v4.6.2 512 true @@ -82,7 +82,7 @@ MinimumRecommendedRules.ruleset WIN64 On - 7.2 + 7.3 false true 1 @@ -235,6 +235,7 @@ + DS4Form.cs Designer @@ -300,6 +301,7 @@ DS4Form.cs + Designer DS4Form.cs @@ -625,6 +627,7 @@ Options.cs + Designer Options.cs @@ -859,6 +862,7 @@ SpecActions.cs + Designer SpecActions.cs @@ -1047,7 +1051,9 @@ - + + Designer + @@ -1175,6 +1181,7 @@ true + diff --git a/DS4Windows/HidLibrary/HidDevices.cs b/DS4Windows/HidLibrary/HidDevices.cs index 00125eb..a3c35a0 100644 --- a/DS4Windows/HidLibrary/HidDevices.cs +++ b/DS4Windows/HidLibrary/HidDevices.cs @@ -46,9 +46,11 @@ namespace DS4Windows List foundDevs = new List(); int devInfoLen = devInfo.Length; IEnumerable temp = EnumerateDevices(); - for (int i = 0, len = temp.Count(); i < len; i++) + for (var devEnum = temp.GetEnumerator(); devEnum.MoveNext();) + //for (int i = 0, len = temp.Count(); i < len; i++) { - DeviceInfo x = temp.ElementAt(i); + DeviceInfo x = devEnum.Current; + //DeviceInfo x = temp.ElementAt(i); HidDevice tempDev = new HidDevice(x.Path, x.Description); bool found = false; for (int j = 0; !found && j < devInfoLen; j++) diff --git a/DS4Windows/Program.cs b/DS4Windows/Program.cs index ca1d32e..c5045d3 100644 --- a/DS4Windows/Program.cs +++ b/DS4Windows/Program.cs @@ -96,7 +96,7 @@ namespace DS4Windows //if (mutex.WaitOne(TimeSpan.Zero, true)) //{ - createControlService(); + createControlService(); //rootHub = new ControlService(); Application.EnableVisualStyles(); ds4form = new DS4Form(args); diff --git a/DS4Windows/Properties/AssemblyInfo.cs b/DS4Windows/Properties/AssemblyInfo.cs index 1497a9d..da0655c 100644 --- a/DS4Windows/Properties/AssemblyInfo.cs +++ b/DS4Windows/Properties/AssemblyInfo.cs @@ -33,7 +33,7 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.6.8")] -[assembly: AssemblyFileVersion("1.6.8")] +[assembly: AssemblyVersion("1.6.12")] +[assembly: AssemblyFileVersion("1.6.12")] [assembly: NeutralResourcesLanguage("en")] diff --git a/DS4Windows/Properties/Resources.Designer.cs b/DS4Windows/Properties/Resources.Designer.cs index 44b412b..60e5a65 100644 --- a/DS4Windows/Properties/Resources.Designer.cs +++ b/DS4Windows/Properties/Resources.Designer.cs @@ -1627,6 +1627,69 @@ namespace DS4Windows.Properties { } } + /// + /// Looks up a localized string similar to Calibration of sixaxis wheel emulation. + /// + public static string SASteeringWheelEmulationCalibrate { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All calibraton points are set when lightbar color turns to green. While turning the controller the lightbar color flashes when the controller is at calibration point. Accept calibration with OK button. + /// + public static string SASteeringWheelEmulationCalibrateInstruction { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateInstruction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (1) Center the controller, hold it steady and press "X". + /// + public static string SASteeringWheelEmulationCalibrateInstruction1 { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateInstruction1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (2) Turn to 90° left (or right) position and press "X". + /// + public static string SASteeringWheelEmulationCalibrateInstruction2 { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateInstruction2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (3) Turn to 90° right (or left) position and press "X". + /// + public static string SASteeringWheelEmulationCalibrateInstruction3 { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateInstruction3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot calibrate gyro (sixaxis) steering wheel emulation values without a controller. Connect a controller via bluetooth or usb. + /// + public static string SASteeringWheelEmulationCalibrateNoControllerError { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateNoControllerError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Gyro steering wheel emulation axis option is set to NONE (emulation is not used). Please select an axis option before calibrating the sixaxis gyro steering wheel emulation. + /// + public static string SASteeringWheelEmulationCalibrateNoneAxisError { + get { + return ResourceManager.GetString("SASteeringWheelEmulationCalibrateNoneAxisError", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/DS4Windows/Properties/Resources.fi.resx b/DS4Windows/Properties/Resources.fi.resx index e314f7d..0c79338 100644 --- a/DS4Windows/Properties/Resources.fi.resx +++ b/DS4Windows/Properties/Resources.fi.resx @@ -1,4 +1,4 @@ - +