/// <summary> /// Compare to another state. /// </summary> public static string[] CompareTo(CustomDiState oldState, CustomDiState newState, MapCode mappingTo) { if (oldState == null) { throw new ArgumentNullException(nameof(oldState)); } if (newState == null) { throw new ArgumentNullException(nameof(newState)); } var list = new List <string>(); list.AddRange(CompareAxisAndSliders(oldState.Axis, newState.Axis, "Axis", mappingTo)); list.AddRange(CompareAxisAndSliders(oldState.Sliders, newState.Sliders, "Slider", mappingTo)); // Compare Buttons if (oldState.Buttons.Length == newState.Buttons.Length) { for (int i = 0; i < oldState.Buttons.Length; i++) { if (oldState.Buttons[i] != newState.Buttons[i]) { list.Add(string.Format("Button {0}", i + 1)); } } } ; // Compare POVs. if (oldState.Povs.Length == newState.Povs.Length) { for (int i = 0; i < oldState.Povs.Length; i++) { if (oldState.Povs[i] != newState.Povs[i]) { //list.Add(string.Format("DPad {0}", i + 1)); var v = newState.Povs[0]; if ((DPadEnum)v == DPadEnum.Up) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Up.ToString())); } if ((DPadEnum)v == DPadEnum.Right) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Right.ToString())); } if ((DPadEnum)v == DPadEnum.Down) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Down.ToString())); } if ((DPadEnum)v == DPadEnum.Left) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Left.ToString())); } } } } ; return(list.ToArray()); }
/// <summary> /// Compare to another state. /// </summary> /// <param name="state"></param> /// <returns></returns> public string[] CompareTo(CustomDiState oldState, CustomDiState state) { var list = new List <string>(); list.AddRange(CompareAxisAndSliders(oldState.Axis, state.Axis, "Axis")); list.AddRange(CompareAxisAndSliders(oldState.Sliders, state.Sliders, "Slider")); // Compare Buttons if (oldState.Buttons.Length == state.Buttons.Length) { for (int i = 0; i < oldState.Buttons.Length; i++) { if (oldState.Buttons[i] != state.Buttons[i]) { list.Add(string.Format("Button {0}", i + 1)); } } } ; // Compare POVs. if (oldState.Povs.Length == state.Povs.Length) { for (int i = 0; i < oldState.Povs.Length; i++) { if (oldState.Povs[i] != state.Povs[i]) { //list.Add(string.Format("DPad {0}", i + 1)); var v = state.Povs[0]; if ((DPadEnum)v == DPadEnum.Up) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Up.ToString())); } if ((DPadEnum)v == DPadEnum.Right) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Right.ToString())); } if ((DPadEnum)v == DPadEnum.Down) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Down.ToString())); } if ((DPadEnum)v == DPadEnum.Left) { list.Add(string.Format("POV {0} {1}", i + 1, DPadEnum.Left.ToString())); } } } } ; return(list.ToArray()); }
void UpdateDiStates(UserGame game) { // Get all mapped user instances. var instanceGuids = SettingsManager.Settings.Items .Where(x => x.MapTo > (int)MapTo.None) .Select(x => x.InstanceGuid).ToArray(); // Get all connected devices. var userDevices = SettingsManager.UserDevices.Items .Where(x => instanceGuids.Contains(x.InstanceGuid) && x.IsOnline) .ToArray(); // Acquire copy of feedbacks for processing. var feedbacks = CopyAndClearFeedbacks(); for (int i = 0; i < userDevices.Count(); i++) { // Update direct input form and return actions (pressed Buttons/DPads, turned Axis/Sliders). var ud = userDevices[i]; JoystickState state = null; // Allow if not testing or testing with option enabled. var o = SettingsManager.Options; var allow = !o.TestEnabled || o.TestGetDInputStates; var isOnline = ud != null && ud.IsOnline; if (isOnline && allow) { var device = ud.Device; if (device != null) { var exceptionData = new System.Text.StringBuilder(); try { var isVirtual = ((EmulationType)game.EmulationType).HasFlag(EmulationType.Virtual); var hasForceFeedback = device.Capabilities.Flags.HasFlag(DeviceFlags.ForceFeedback); // Exclusive mode required only if force feedback is available and device is virtual there are no info about effects. var exclusiveRequired = hasForceFeedback && (isVirtual || ud.DeviceEffects == null); // If exclusive mode is required and mode is unknown or not exclusive then... if (exclusiveRequired && (!ud.IsExclusiveMode.HasValue || !ud.IsExclusiveMode.Value)) { var flags = CooperativeLevel.Background | CooperativeLevel.Exclusive; // Reacquire device in exclusive mode. exceptionData.AppendLine("Unacquire (Exclusive)..."); device.Unacquire(); exceptionData.AppendLine("SetCooperativeLevel (Exclusive)..."); device.SetCooperativeLevel(detector.DetectorForm.Handle, flags); exceptionData.AppendLine("Acquire (Exclusive)..."); device.Acquire(); ud.IsExclusiveMode = true; } // If current mode must be non exclusive and mode is unknown or exclusive then... else if (!exclusiveRequired && (!ud.IsExclusiveMode.HasValue || ud.IsExclusiveMode.Value)) { var flags = CooperativeLevel.Background | CooperativeLevel.NonExclusive; // Reacquire device in non exclusive mode so that xinput.dll can control force feedback. exceptionData.AppendLine("Unacquire (NonExclusive)..."); device.Unacquire(); exceptionData.AppendLine("SetCooperativeLevel (Exclusive)..."); device.SetCooperativeLevel(detector.DetectorForm.Handle, flags); exceptionData.AppendLine("Acquire (Acquire)..."); device.Acquire(); ud.IsExclusiveMode = false; } exceptionData.AppendFormat("device.GetCurrentState() // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); state = device.GetCurrentState(); // Fill device objects. if (ud.DeviceObjects == null) { exceptionData.AppendFormat("AppHelper.GetDeviceObjects(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); var dos = AppHelper.GetDeviceObjects(device); ud.DeviceObjects = dos; // Update masks. ud.DiAxeMask = CustomDiState.GetJoystickAxisMask(dos, device); ud.DiSliderMask = CustomDiState.GetJoystickSlidersMask(dos, device); } if (ud.DeviceEffects == null) { exceptionData.AppendFormat("AppHelper.GetDeviceEffects(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.DeviceEffects = AppHelper.GetDeviceEffects(device); } // Get PAD index this device is mapped to. var userIndex = SettingsManager.Settings.Items .Where(x => x.MapTo > (int)MapTo.None) .Where(x => x.InstanceGuid == ud.InstanceGuid) .Select(x => x.MapTo).First(); // If device support force feedback then... if (hasForceFeedback) { // Get setting related to user device. var setting = SettingsManager.Settings.Items .FirstOrDefault(x => x.MapTo == userIndex && x.InstanceGuid == ud.InstanceGuid); if (setting != null) { // Get pad setting attached to device. var ps = SettingsManager.GetPadSetting(setting.PadSettingChecksum); if (ps != null) { // If force is enabled then... if (ps.ForceEnable == "1") { if (ud.FFState == null) { ud.FFState = new Engine.ForceFeedbackState(); } // If force update supplied then... var force = feedbacks[userIndex - 1]; if (force != null || ud.FFState.Changed(ps)) { var v = new Vibration(); if (force == null) { v.LeftMotorSpeed = short.MinValue; v.RightMotorSpeed = short.MinValue; } else { v.LeftMotorSpeed = (short)ConvertHelper.ConvertRange(byte.MinValue, byte.MaxValue, short.MinValue, short.MaxValue, force.LargeMotor); v.RightMotorSpeed = (short)ConvertHelper.ConvertRange(byte.MinValue, byte.MaxValue, short.MinValue, short.MaxValue, force.SmallMotor); } // For the future: Investigate device states if force feedback is not working. // var st = ud.Device.GetForceFeedbackState(); //st == SharpDX.DirectInput.ForceFeedbackState // ud.Device.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOn); exceptionData.AppendFormat("ud.FFState.SetDeviceForces(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.FFState.SetDeviceForces(ud, device, ps, v); } } // If force state was created then... else if (ud.FFState != null) { // Stop device forces. exceptionData.AppendFormat("ud.FFState.StopDeviceForces(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.FFState.StopDeviceForces(device); ud.FFState = null; } } } } } catch (Exception ex) { ex.Data.Add("FFInfo", exceptionData.ToString()); JocysCom.ClassLibrary.Runtime.LogHelper.Current.WriteException(ex); ud.IsExclusiveMode = null; } } // If this is test device then... else if (TestDeviceHelper.ProductGuid.Equals(ud.ProductGuid)) { // Fill device objects. if (ud.DeviceObjects == null) { var dos = TestDeviceHelper.GetDeviceObjects(); ud.DeviceObjects = dos; // Update masks. ud.DiAxeMask = 0x1 | 0x2 | 0x4 | 0x8; ud.DiSliderMask = 0; } if (ud.DeviceEffects == null) { ud.DeviceEffects = new DeviceEffectItem[0]; } state = TestDeviceHelper.GetCurrentState(ud); } } ud.JoState = state ?? new JoystickState(); var newState = new CustomDiState(ud.JoState); var newTime = watch.ElapsedTicks; // Mouse needs special update. if (ud.Device != null && ud.Device.Information.Type == SharpDX.DirectInput.DeviceType.Mouse) { var mouseState = new CustomDiState(ud.JoState); if (ud.OldDiState == null) { // Make sure new state have zero values. for (int a = 0; a < newState.Axis.Length; a++) { mouseState.Axis[a] = -short.MinValue; } // Update sliders with delta. for (int s = 0; s < newState.Sliders.Length; s++) { mouseState.Sliders[s] = -short.MinValue; } } else { // This parts needs to be worked on. var ticks = (int)(newTime - ud.DiStateTime); // Update axis with delta. for (int a = 0; a < newState.Axis.Length; a++) { mouseState.Axis[a] = ticks * (newState.Axis[a] - ud.OldDiState.Axis[a]) - short.MinValue; } // Update sliders with delta. for (int s = 0; s < newState.Sliders.Length; s++) { mouseState.Sliders[s] = ticks * (newState.Sliders[s] - ud.OldDiState.Sliders[s]) - short.MinValue; } } // Assign unmodified state. ud.OldDiState = newState; ud.OldDiStateTime = ud.DiStateTime; ud.DiState = mouseState; } else { // Update state. ud.DiState = newState; } ud.DiStateTime = newTime; } }
public static JoystickState GetCurrentState(UserDevice ud) { if (watch == null) { watch = new Stopwatch(); watch.Start(); } var elapsed = watch.Elapsed; // Restart timer if out of limits. if (elapsed.TotalMilliseconds > int.MaxValue) { watch.Restart(); elapsed = watch.Elapsed; } // Acquire values. var ts = (int)elapsed.TotalSeconds; var tm = (int)elapsed.TotalMilliseconds; var state = new JoystickState(); // Set Buttons. for (int i = 0; i < ud.CapButtonCount; i++) { var currentLocation = ts % ud.CapButtonCount; // Enable button during its index. state.Buttons[i] = currentLocation == i; } // Do action for 4 seconds [0-3999] ms. var busy = 4000; var half = busy / 2; // then stay for 2 seconds idle [4000-5999] ms. var idle = 2000; // 6 = 4 + 2. var time = tm % (busy + idle); var invert = tm % ((busy + idle) * 2) > (busy + idle); // Set POVs. for (int i = 0; i < ud.CapPovCount; i++) { // Rotate POVs 360 degrees in 4 seconds forward and back. var degree = -1; if (time < busy) { // Shift busy value by half so movement starts from the centre. var value = (time + busy / 2) % busy; if (time <= half) { // Convert [ 0-1999] to [0-35999]. degree = ConvertHelper.ConvertRange(0, half - 1, 0, 35999, value); } else { // Convert [2000-3999] to [35999-0]. degree = ConvertHelper.ConvertRange(half, busy - 1, 35999, 0, value); } } state.PointOfViewControllers[i] = degree; } // Set Axis. var axis = CustomDiState.GetAxisFromState(state); // Get information about axis. var axisObjects = ud.DeviceObjects .Where(x => x.Flags.HasFlag(DeviceObjectTypeFlags.AbsoluteAxis) || x.Flags.HasFlag(DeviceObjectTypeFlags.RelativeAxis)).ToArray(); for (int i = 0; i < axisObjects.Count(); i++) { var ao = axisObjects[i]; // If axis index is even. var isEven = i % 2 == 0; var position = isEven // Default position is in the center. ? ushort.MaxValue - short.MaxValue // Default position is at the bottom. : 0; // Move axis in 4 seconds, then stay for 2 seconds idle. if (time < busy) { if (isEven) { // Convert [0-3999] to [0-2Pi]. var angle = time * 2 * Math.PI / busy; var sine = Math.Sin(angle); if (invert && isEven) { sine *= -1f; } var range = ConvertHelper.ConvertToShort((float)sine); position = ConvertHelper.ConvertRange(short.MinValue, short.MaxValue, ushort.MinValue, ushort.MaxValue, range); } else { position = time < half // Move up [0-1999]. ? ConvertHelper.ConvertRange(0, half - 1, ushort.MinValue, ushort.MaxValue, time) // Move down [2000-3999]. : ConvertHelper.ConvertRange(half, busy - 1, ushort.MaxValue, ushort.MinValue, time); } } axis[i] = position; } CustomDiState.SetStateFromAxis(state, axis); // Get sliders array. var sliders = CustomDiState.GetSlidersFromState(state); // Set sliders. for (int i = 0; i < sliders.Length; i++) { var isEven = i % 2 == 0; var position = isEven // Default position is in the center. ? ushort.MaxValue - short.MaxValue // Default position is at the bottom. : 0; // Move slider in 4 seconds, then stay for 2 seconds idle. if (time < busy) { if (isEven) { // Convert [0-3999] to [0-2Pi]. var angle = time * 2 * Math.PI / busy; var sine = Math.Sin(angle); if (invert && isEven) { sine *= -1f; } var range = ConvertHelper.ConvertToShort((float)sine); position = ConvertHelper.ConvertRange(short.MinValue, short.MaxValue, ushort.MinValue, ushort.MaxValue, range); } else { position = time < half // Move up. ? ConvertHelper.ConvertRange(0, half - 1, ushort.MinValue, ushort.MaxValue, time) // Move down. : ConvertHelper.ConvertRange(half, busy - 1, ushort.MaxValue, ushort.MinValue, time); } } sliders[i] = position; } CustomDiState.SetStateFromSliders(state, sliders); // Return state. return(state); }
/// <summary> /// Called when recording is in progress. /// </summary> /// <param name="state">Current direct input activity.</param> /// <returns>True if recording stopped, otherwise false.</returns> public bool StopRecording(CustomDiState state = null) { lock (recordingLock) { // If recording is not in progress then return false. if (!Recording) { recordingSnapshot = null; return(false); } // If recording snapshot was not created yet then... else if (recordingSnapshot == null) { // Make snapshot out of the first state during recording. recordingSnapshot = state; return(false); } // Get actions by comparing initial snapshot with current state. var actions = CompareTo(recordingSnapshot, state); string action = null; // Must stop recording if null passed. var stop = actions == null; // if at least one action was recorded then... if (!stop && actions.Length > 0) { // If this is DPad ComboBox then... if (_Map.PropertyName == SettingName.DPad) { // Get first action suitable for DPad var dPadAction = actions.FirstOrDefault(x => dPadRx.IsMatch(x)); if (dPadAction != null) { action = dPadRx.Match(dPadAction).Groups[0].Value; stop = true; } } else { // Get first recorded action. action = actions[0]; stop = true; } } // If recording must stop then... if (stop) { var box = ((ComboBox)_Map.Control); Recording = false; RecordingTimer.Stop(); // If stop was initiated before action was recorded then... if (string.IsNullOrEmpty(action)) { box.Items.Clear(); } else { // If suitable action was recorded then... SettingsManager.Current.SetComboBoxValue(box, action); // Save setting and notify if value changed. SettingsManager.Current.RaiseSettingsChanged(box); } box.ForeColor = SystemColors.WindowText; } return(stop); } }
/// <summary> /// Called when recording is in progress. /// </summary> /// <param name="state">Current direct input activity.</param> /// <returns>True if recording stopped, otherwise false.</returns> public bool StopRecording(CustomDiState state = null) { lock (recordingLock) { // If recording is not in progress then return false. if (!Recording) { recordingSnapshot = null; return(false); } // Must stop recording if null state passed i.e. probably ESC key was pressed. var stop = state == null; string action = null; var map = CurrentMap; var code = map.Code; var box = (ComboBox)map.Control; if (state != null) { // If recording snapshot was not created yet then... if (recordingSnapshot == null) { // Make snapshot out of the first state during recording. recordingSnapshot = state; return(false); } var actions = state == null ? Array.Empty <string>() // Get actions by comparing initial snapshot with current state. : Recorder.CompareTo(recordingSnapshot, state, map.Code); // if recording and at least one action was recorded then... if (!stop && actions.Length > 0) { MapType type; int index; SettingsConverter.TryParseTextValue(actions[0], out type, out index); // If this is Thumb Up, Left, Right, Down and axis was mapped. if (SettingsConverter.ThumbDirections.Contains(code) && SettingsConverter.IsAxis(type)) { // Make full axis. type = SettingsConverter.ToFull(type); var isUp = code == MapCode.LeftThumbUp || code == MapCode.RightThumbUp; var isLeft = code == MapCode.LeftThumbLeft || code == MapCode.RightThumbLeft; var isRight = code == MapCode.LeftThumbRight || code == MapCode.RightThumbRight; var isDown = code == MapCode.LeftThumbDown || code == MapCode.RightThumbDown; // Invert. if (isLeft || isDown) { type = SettingsConverter.Invert(type); } var newCode = code; var isLeftThumb = SettingsConverter.LeftThumbCodes.Contains(code); if (isRight || isLeft) { newCode = isLeftThumb ? MapCode.LeftThumbAxisX : MapCode.RightThumbAxisX; } if (isUp || isDown) { newCode = isLeftThumb ? MapCode.LeftThumbAxisY : MapCode.RightThumbAxisY; } // Change destination control. var rMap = SettingsManager.Current.SettingsMap.First(x => x.MapTo == map.MapTo && x.Code == newCode); box = (ComboBox)rMap.Control; action = SettingsConverter.ToTextValue(type, index); stop = true; } // If this is DPad ComboBox then... else if (code == MapCode.DPad) { // Get first action suitable for DPad Regex dPadRx = new Regex("(POV [0-9]+)"); var dPadAction = actions.FirstOrDefault(x => dPadRx.IsMatch(x)); if (dPadAction != null) { action = dPadRx.Match(dPadAction).Groups[0].Value; stop = true; } } else { // Get first recorded action. action = actions[0]; stop = true; } } } // If recording must stop then... if (stop) { Recording = false; CurrentMap = null; // If stop was initiated before action was recorded then... if (string.IsNullOrEmpty(action)) { box.Items.Clear(); } else { // If suitable action was recorded then... SettingsManager.Current.SetComboBoxValue(box, action); // Save setting and notify if value changed. SettingsManager.Current.RaiseSettingsChanged(box); } //box.ForeColor = SystemColors.WindowText; } return(stop); } }
void UpdateDiStates(UserGame game, DeviceDetector detector) { // Get all mapped user devices. var userDevices = SettingsManager.GetMappedDevices(game?.FileName); // Acquire copy of feedbacks for processing. var feedbacks = CopyAndClearFeedbacks(); for (int i = 0; i < userDevices.Count(); i++) { // Update direct input form and return actions (pressed Buttons/DPads, turned Axis/Sliders). var ud = userDevices[i]; JoystickState state = null; JoystickUpdate[] update = null; // Allow if not testing or testing with option enabled. var o = SettingsManager.Options; var allow = !o.TestEnabled || o.TestGetDInputStates; // Note: manager.IsDeviceAttached() use a lot of CPU resources. var isAttached = ud != null && ud.IsOnline; // && manager.IsDeviceAttached(ud.InstanceGuid); if (isAttached && allow) { var device = ud.Device; if (device != null) { var exceptionData = new System.Text.StringBuilder(); try { if (o.UseDeviceBufferedData && device.Properties.BufferSize == 0) { // Set BufferSize in order to use buffered data. device.Properties.BufferSize = 128; } var isVirtual = ((EmulationType)game.EmulationType).HasFlag(EmulationType.Virtual); var hasForceFeedback = device.Capabilities.Flags.HasFlag(DeviceFlags.ForceFeedback); // Exclusive mode required only if force feedback is available and device is virtual there are no info about effects. var exclusiveRequired = hasForceFeedback && (isVirtual || ud.DeviceEffects == null); // If exclusive mode is required and mode is unknown or not exclusive then... if (exclusiveRequired && (!ud.IsExclusiveMode.HasValue || !ud.IsExclusiveMode.Value)) { var flags = CooperativeLevel.Background | CooperativeLevel.Exclusive; // Reacquire device in exclusive mode. exceptionData.AppendLine("Unacquire (Exclusive)..."); device.Unacquire(); exceptionData.AppendLine("SetCooperativeLevel (Exclusive)..."); device.SetCooperativeLevel(detector.DetectorForm.Handle, flags); exceptionData.AppendLine("Acquire (Exclusive)..."); device.Acquire(); ud.IsExclusiveMode = true; } // If current mode must be non exclusive and mode is unknown or exclusive then... else if (!exclusiveRequired && (!ud.IsExclusiveMode.HasValue || ud.IsExclusiveMode.Value)) { var flags = CooperativeLevel.Background | CooperativeLevel.NonExclusive; // Reacquire device in non exclusive mode so that xinput.dll can control force feedback. exceptionData.AppendLine("Unacquire (NonExclusive)..."); device.Unacquire(); exceptionData.AppendLine("SetCooperativeLevel (Exclusive)..."); device.SetCooperativeLevel(detector.DetectorForm.Handle, flags); exceptionData.AppendLine("Acquire (Acquire)..."); device.Acquire(); ud.IsExclusiveMode = false; } exceptionData.AppendFormat("device.GetCurrentState() // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); // Polling - Retrieves data from polled objects on a DirectInput device. // Some devices require pooling (For example original "Xbox Controller S" with XBCD drivers). // If the device does not require polling, calling this method has no effect. // If a device that requires polling is not polled periodically, no new data is received from the device. // Calling this method causes DirectInput to update the device state, generate input // events (if buffered data is enabled), and set notification events (if notification is enabled). device.Poll(); if (o.UseDeviceBufferedData && device.Properties.BufferSize > 0) { // Get buffered data. update = device.GetBufferedData(); } // Get device state. state = device.GetCurrentState(); // Fill device objects. if (ud.DeviceObjects == null) { exceptionData.AppendFormat("AppHelper.GetDeviceObjects(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); var dos = AppHelper.GetDeviceObjects(device); ud.DeviceObjects = dos; // Update masks. int axisMask = 0; int actuatorMask = 0; int actuatorCount = 0; if (ud.CapType == (int)SharpDX.DirectInput.DeviceType.Mouse) { CustomDiState.GetMouseAxisMask(dos, device, out axisMask); } else { CustomDiState.GetJoystickAxisMask(dos, device, out axisMask, out actuatorMask, out actuatorCount); } ud.DiAxeMask = axisMask; // Contains information about which axis have force feedback actuator attached. ud.DiActuatorMask = actuatorMask; ud.DiActuatorCount = actuatorCount; CustomDiState.GetJoystickSlidersMask(dos, device); } if (ud.DeviceEffects == null) { exceptionData.AppendFormat("AppHelper.GetDeviceEffects(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.DeviceEffects = AppHelper.GetDeviceEffects(device); } // If device support force feedback then... if (hasForceFeedback) { // Get setting related to user device. var setting = SettingsManager.UserSettings.ItemsToArraySyncronized() .FirstOrDefault(x => x.InstanceGuid == ud.InstanceGuid); // If device is mapped to controller then... if (setting != null && setting.MapTo > (int)MapTo.None) { // Get pad setting attached to device. var ps = SettingsManager.GetPadSetting(setting.PadSettingChecksum); if (ps != null) { // If force is enabled then... if (ps.ForceEnable == "1") { if (ud.FFState == null) { ud.FFState = new Engine.ForceFeedbackState(); } // If force update supplied then... var force = feedbacks[(int)setting.MapTo - 1]; if (force != null || ud.FFState.Changed(ps)) { var v = new Vibration(); if (force == null) { v.LeftMotorSpeed = short.MinValue; v.RightMotorSpeed = short.MinValue; } else { v.LeftMotorSpeed = (short)ConvertHelper.ConvertRange(byte.MinValue, byte.MaxValue, short.MinValue, short.MaxValue, force.LargeMotor); v.RightMotorSpeed = (short)ConvertHelper.ConvertRange(byte.MinValue, byte.MaxValue, short.MinValue, short.MaxValue, force.SmallMotor); } // For the future: Investigate device states if force feedback is not working. // var st = ud.Device.GetForceFeedbackState(); //st == SharpDX.DirectInput.ForceFeedbackState // ud.Device.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOn); exceptionData.AppendFormat("ud.FFState.SetDeviceForces(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.FFState.SetDeviceForces(ud, device, ps, v); } } // If force state was created then... else if (ud.FFState != null) { // Stop device forces. exceptionData.AppendFormat("ud.FFState.StopDeviceForces(device) // ud.IsExclusiveMode = {0}", ud.IsExclusiveMode).AppendLine(); ud.FFState.StopDeviceForces(device); ud.FFState = null; } } } } } catch (Exception ex) { var dex = ex as SharpDXException; if (dex != null && dex.ResultCode == SharpDX.DirectInput.ResultCode.InputLost) { // Ignore error. } else if (dex != null && dex.ResultCode == SharpDX.DirectInput.ResultCode.NotAcquired) { // Ignore error } else if (dex != null && dex.ResultCode == SharpDX.DirectInput.ResultCode.Unplugged) { // Ignore error } else { var cx = new DInputException("UpdateDiStates Exception", ex); cx.Data.Add("FFInfo", exceptionData.ToString()); JocysCom.ClassLibrary.Runtime.LogHelper.Current.WriteException(cx); } ud.IsExclusiveMode = null; } } // If this is test device then... else if (TestDeviceHelper.ProductGuid.Equals(ud.ProductGuid)) { // Fill device objects. if (ud.DeviceObjects == null) { var dos = TestDeviceHelper.GetDeviceObjects(); ud.DeviceObjects = dos; // Update masks. ud.DiAxeMask = 0x1 | 0x2 | 0x4 | 0x8; ud.DiSliderMask = 0; } if (ud.DeviceEffects == null) { ud.DeviceEffects = new DeviceEffectItem[0]; } state = TestDeviceHelper.GetCurrentState(ud); } } ud.JoState = state; ud.JoUpdate = update; if (state != null) { var newState = new CustomDiState(ud.JoState); var newUpdates = update?.Select(x => new CustomDiUpdate(x)).ToArray(); // If updates from buffer supplied and old state is available then... if (newUpdates != null && newUpdates.Count(x => x.Type == MapType.Button) > 1 && ud.DiState != null) { // Analyse if state must be modified. for (int b = 0; b < newState.Buttons.Length; b++) { var oldPresseed = ud.DiState.Buttons[b]; var newPresseed = newState.Buttons[b]; // If button state was not changed. if (oldPresseed == newPresseed) { // But buffer contains press then... var wasPressed = newUpdates.Count(x => x.Type == MapType.Button && x.Index == b) > 1; if (wasPressed) { // Invert state and give chance for the game to recognize the press. newState.Buttons[b] = !newState.Buttons[b]; } } } } var newTime = watch.ElapsedTicks; // Remember old state. ud.OldDiState = ud.DiState; ud.OldDiUpdates = ud.DiUpdates; ud.OldDiStateTime = ud.DiStateTime; // Update state. ud.DiState = newState; ud.DiUpdates = newUpdates; ud.DiStateTime = newTime; // Mouse needs special update. if (ud.Device != null && ud.Device.Information.Type == SharpDX.DirectInput.DeviceType.Mouse) { // If original state is missing then... if (ud.OrgDiState == null) { // Store current values. ud.OrgDiState = newState; ud.OrgDiStateTime = newTime; // Make sure new states have zero values. for (int a = 0; a < newState.Axis.Length; a++) { newState.Axis[a] = -short.MinValue; } for (int s = 0; s < newState.Sliders.Length; s++) { newState.Sliders[s] = -short.MinValue; } } var mouseState = new CustomDiState(new JoystickState()); // Clone button values. Array.Copy(newState.Buttons, mouseState.Buttons, mouseState.Buttons.Length); // //-------------------------------------------------------- // // Map mouse acceleration to axis position. Good for FPS control. // //-------------------------------------------------------- // // This parts needs to be worked on. // //var ticks = (int)(newTime - ud.DiStateTime); // // Update axis with delta. // //for (int a = 0; a < newState.Axis.Length; a++) // // mouseState.Axis[a] = ticks * (newState.Axis[a] - ud.OldDiState.Axis[a]) - short.MinValue; // // Update sliders with delta. // //for (int s = 0; s < newState.Sliders.Length; s++) // // mouseState.Sliders[s] = ticks * (newState.Sliders[s] - ud.OldDiState.Sliders[s]) - short.MinValue; //-------------------------------------------------------- // Map mouse position to axis position. Good for car wheel controls. //-------------------------------------------------------- Calc(ud.OrgDiState.Axis, newState.Axis, mouseState.Axis); Calc(ud.OrgDiState.Sliders, newState.Sliders, mouseState.Sliders); ud.DiState = mouseState; } } } }