예제 #1
0
파일: Recorder.cs 프로젝트: ph3na/x360ce
        /// <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());
        }
예제 #2
0
        /// <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;
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
 /// <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);
     }
 }
예제 #6
0
파일: Recorder.cs 프로젝트: ph3na/x360ce
        /// <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;
                    }
                }
            }
        }