/// <summary>
        /// Returns the current value for a given axis based off of the set axis in the axis mapping entry and the joystick state.
        /// Performs any necessary additional operations on the axis values based off of the axis configuration.
        /// </summary>
        /// <param name="mappingEntry">The mapping entry for the axis defining which axis should be used.</param>
        public float XInputGetAxisValue(AxisMappingEntry mappingEntry)
        {
            // Obtain the raw scaled value (to match XInput range) for the requested axis.
            int rawValue = GetAxisRawScaledValue(mappingEntry);

            // Process the raw axis value and return.
            return(InputProcessAxisRawValue(rawValue, mappingEntry, true));
        }
        /// <summary>
        /// Returns the current value for a given axis based off of the set axis in the axis mapping entry and the joystick state.
        /// Performs any necessary additional operations on the axis values based off of the axis configuration.
        /// </summary>
        /// <param name="mappingEntry">The mapping entry for the axis defining which axis should be used.</param>
        /// <param name="joystickState">The current state of the controller in question.</param>
        public static float DInputGetAxisValue(AxisMappingEntry mappingEntry, JoystickState joystickState)
        {
            // Obtain the raw value for the requested axis.
            int rawValue = GetAxisRawValue(mappingEntry, joystickState);

            // Process the raw axis value and return.
            return(InputProcessAxisRawValue(rawValue, mappingEntry, false));
        }
        /// <summary>
        /// Retrieves the specific intensity in terms of how far/deep an axis is pressed in.
        /// The return value should be a floating point number between -100 and 100 float.
        /// For triggers, the range is a value between 0 and 100.
        /// </summary>
        /// <remarks>
        /// This does not take into account the destination axis and reads the value
        /// of the equivalent source axis. If the user has Left Stick mapped to e.g. Right Stick
        /// and you request the right stick axis, the value will return 0 (assuming right stick is centered).
        /// </remarks>
        public float GetAxisState(ControllerAxis axis)
        {
            // Retrieve requested axis mapping entry.
            AxisMappingEntry controllerAxisMapping = InputGetMappedAxis(axis, InputMappings.AxisMapping);

            // Retrieve the intensity of the axis press-in value.
            return(XInputGetAxisValue(controllerAxisMapping));
        }
        /// <summary>
        /// Retrieves the raw value for a specified passed in requested axis in integer form.
        /// </summary>
        /// <param name="mappingEntry">The specific axis mapping entry that is to be used.</param>
        private int GetAxisRawScaledValue(AxisMappingEntry mappingEntry)
        {
            // Value for the current axis.
            int rawValue = 0;

            // Check what the mapping entry is natively within the axis mapping, and obtain the relevant raw inputs.
            if (mappingEntry == InputMappings.AxisMapping.LeftStickX)
            {
                rawValue = ControllerState.Gamepad.LeftThumbX;
            }
            else if (mappingEntry == InputMappings.AxisMapping.LeftStickY)
            {
                rawValue = -ControllerState.Gamepad.LeftThumbY;
            }
            else if (mappingEntry == InputMappings.AxisMapping.RightStickX)
            {
                rawValue = ControllerState.Gamepad.RightThumbX;
            }
            else if (mappingEntry == InputMappings.AxisMapping.RightStickY)
            {
                rawValue = -ControllerState.Gamepad.RightThumbY;
            }
            else if (mappingEntry == InputMappings.AxisMapping.LeftTrigger)
            {
                rawValue = ControllerState.Gamepad.LeftTrigger;
            }
            else if (mappingEntry == InputMappings.AxisMapping.RightTrigger)
            {
                rawValue = ControllerState.Gamepad.RightTrigger;
            }

            // Process the value to DInput Ranges
            if (!(mappingEntry == InputMappings.AxisMapping.LeftTrigger || mappingEntry == InputMappings.AxisMapping.RightTrigger))
            {
                // Axis is analog stick.
                // Scale from -32768-32767 to -100-100
                rawValue = (int)(rawValue / MaxAnalogStickRangeXinput * AxisMaxValueF);
            }
            else
            {
                // Axis is trigger.
                // Scale from 0-255 to 0-200
                rawValue = (int)(rawValue / MaxTriggerRangeXinput * AxisMaxValueF * (1.0F / DInputManager.TriggerScaleFactor));

                // Scale to -100-100 to simulate DInput.
                rawValue -= 100;
            }

            // Return the raw value.
            return(rawValue);
        }
        /// <summary>
        /// Retrieves the raw value for a specified passed in requested axis in integer form.
        /// </summary>
        /// <param name="mappingEntry">The specific axis mapping entry that is to be used.</param>
        /// <param name="joystickState">The current state of the controller in question.</param>
        private static int GetAxisRawValue(AxisMappingEntry mappingEntry, JoystickState joystickState)
        {
            // If axis source is null, and the axis is a trigger, return minimum float.
            if (mappingEntry.SourceAxis == "Null" && (mappingEntry.DestinationAxis == ControllerAxis.LeftTrigger || mappingEntry.DestinationAxis == ControllerAxis.RightTrigger))
            {
                return(DInputManager.AxisMinValue);
            }

            // Else return 0 if the axis source is null.
            if (mappingEntry.SourceAxis == "Null")
            {
                return(0);
            }

            // Return the appropriately mapped axis!
            return((int)Reflection_GetValue(joystickState, mappingEntry.SourceAxis));
        }
Example #6
0
        /// <summary>
        /// Waits for the user to move an axis and retrieves the last pressed axis.
        /// Accepts any axis as input. Returns the read-in axis.
        /// </summary>
        /// <param name="timeoutSeconds">The timeout in seconds for the controller assignment.</param>
        /// <param name="currentTimeout">The current amount of time left in seconds, use this to update the GUI.</param>
        /// <param name="mappingEntry">Specififies the mapping entry containing the axis to be remapped.</param>
        /// <param name="cancellationToken">The method polls on this boolean such that if it is set to true, the method will exit.</param>
        /// <returns>True if a new axis has been assigned to the current mapping entry.</returns>
        public bool RemapAxis(int timeoutSeconds, out float currentTimeout, AxisMappingEntry mappingEntry, ref bool cancellationToken)
        {
            // Retrieve the object type of the controller.
            Type controllerType = Controller.GetType();

            // If it's a DirectInput controller.
            if (controllerType == typeof(DInputController))
            {
                return(DInputRemapAxis(timeoutSeconds, out currentTimeout, mappingEntry, ref cancellationToken));
            }
            if (controllerType == typeof(XInputController))
            {
                return(XInputRemapAxis(timeoutSeconds, out currentTimeout, mappingEntry, ref cancellationToken));
            }

            currentTimeout = 0; return(false);
        }
        /// <summary>
        /// Returns true the input raw value is within a deadzone specified
        /// by the specific axis mapping entry.
        /// </summary>
        /// <param name="axisValue">The scaled value of the prior obtained raw axis reading: Range -100 to 100 (Sticks) or 0-100 (Triggers)</param>
        /// <param name="mappingEntry">The mapping entry for the axis defining the deadzone for the specific axis.</param>
        public static bool VerifyDeadzones(float axisValue, AxisMappingEntry mappingEntry)
        {
            // Verify Deadzones
            switch (mappingEntry.DestinationAxis)
            {
            // For all analog sticks.
            case ControllerAxis.LeftStickX:
            case ControllerAxis.LeftStickY:
            case ControllerAxis.RightStickX:
            case ControllerAxis.RightStickY:

                // Get boundaries of deadzone.
                float deadzoneMax = AxisMaxValueF / 100.0F * mappingEntry.DeadZone;
                float deadzoneMin = -(AxisMaxValueF / 100.0F) * mappingEntry.DeadZone;

                // If within boundaries, axis value is 0.
                if (axisValue < deadzoneMax && axisValue > deadzoneMin)
                {
                    return(true);
                }

                // Else break.
                break;

            // For all triggers
            case ControllerAxis.LeftTrigger:
            case ControllerAxis.RightTrigger:

                // Get max deadzone
                float deadzoneTriggerMax = AxisMaxValueF / 100.0F * mappingEntry.DeadZone;

                // If within bounds, axis value is 0.
                if (axisValue < deadzoneTriggerMax)
                {
                    return(true);
                }

                // Else break.
                break;
            }

            // If not in deadzones return false.
            return(false);
        }
        /// <summary>
        /// Processes the obtained raw value with DInput/XInput ranges and performs modifications on it such
        /// as changing the radius of the axis reading or checking for deadzones.
        /// </summary>
        /// <param name="mappingEntry">The mapping entry for the axis defining which axis should be used.</param>
        /// <param name="rawValue">The raw value obtained from the axis query..</param>
        /// <param name="isScaled">Declares whether the value is already scaled appropriately before reaching the function or not. Currently false for DInput and true for XInput.</param>
        public static float InputProcessAxisRawValue(int rawValue, AxisMappingEntry mappingEntry, bool isScaled)
        {
            // Reverse Axis if Necessary
            if (mappingEntry.IsReversed)
            {
                rawValue = -1 * rawValue;
            }

            // Scale Axis if Necessary.
            float newRawValue = rawValue;

            if (!isScaled)
            {
                newRawValue = rawValue / (float)DInputManager.AxisMaxValue * AxisMaxValueF;
            }

            // If triggers. scale to between 0 - 100 (from -100 - 100)
            switch (mappingEntry.DestinationAxis)
            {
            case ControllerAxis.LeftTrigger:
            case ControllerAxis.RightTrigger:
                newRawValue += AxisMaxValueF;
                newRawValue *= DInputManager.TriggerScaleFactor;
                break;
            }

            // If the input lays within the acceptable deadzone range, return null.
            if (VerifyDeadzones(newRawValue, mappingEntry))
            {
                return(0F);
            }

            // Scale Radius Scale Value
            newRawValue *= mappingEntry.RadiusScale;

            // Return axis value.
            return(newRawValue);
        }
        /// <summary>
        /// Returns the appropriate axis mapping entry for each individual specific axis.
        /// The axis have a 1-1 relationship (oldaxis -> new axis) and a set of properties as defined in
        /// Controller_Axis_Mapping.
        /// </summary>
        /// <param name="axis">The axis whose details we want to obtain.</param>
        /// <param name="axisMapping">The axis mapping which stores the axis details for the individual controller.</param>
        /// <returns></returns>
        public static AxisMappingEntry InputGetMappedAxis(ControllerAxis axis, AxisMapping axisMapping)
        {
            // Stores the axis configuration that is to be returned.
            AxisMappingEntry controllerAxisMapping = new AxisMappingEntry();

            // Find axis mapped to the requested controller axis.
            // Check every axis manually, until one of the axes contains the desired destination axis.
            if (IsCorrectAxisMappingEntry(axisMapping.LeftStickX, axis))
            {
                return(axisMapping.LeftStickX);
            }
            if (IsCorrectAxisMappingEntry(axisMapping.LeftStickY, axis))
            {
                return(axisMapping.LeftStickY);
            }

            if (IsCorrectAxisMappingEntry(axisMapping.RightStickX, axis))
            {
                return(axisMapping.RightStickX);
            }
            if (IsCorrectAxisMappingEntry(axisMapping.RightStickY, axis))
            {
                return(axisMapping.RightStickY);
            }

            if (IsCorrectAxisMappingEntry(axisMapping.LeftTrigger, axis))
            {
                return(axisMapping.LeftTrigger);
            }
            if (IsCorrectAxisMappingEntry(axisMapping.RightTrigger, axis))
            {
                return(axisMapping.RightTrigger);
            }

            // Retrieve empty struct if null, else the correct axis mapping.
            return(controllerAxisMapping);
        }
 /// <summary>
 /// Waits for the user to move an axis and retrieves the last pressed axis.
 /// Accepts any axis as input. Returns the read-in axis.
 /// </summary>
 /// <param name="timeoutSeconds">The timeout in seconds for the controller assignment.</param>
 /// <param name="currentTimeout">The current amount of time left in seconds, use this to update the GUI.</param>
 /// <param name="mappingEntry">Specififies the mapping entry containing the axis to be remapped.</param>
 /// <param name="cancellationToken">The method polls on this boolean such that if it is set to true, the method will exit.</param>
 /// <returns>True if a new axis has successfully been assigned by the user.</returns>
 public bool RemapAxis(int timeoutSeconds, out float currentTimeout, AxisMappingEntry mappingEntry, ref bool cancellationToken)
 {
     return(Remapper.RemapAxis(timeoutSeconds, out currentTimeout, mappingEntry, ref cancellationToken));
 }
 /// <summary>
 /// Verifies whether a passed in axis mapping entry's axis is the one requested
 /// by the user/programmer. i.e. axisMappingEntry.axis == axis
 /// </summary>
 /// <param name="axis">The requested axis to verify if there is a match with the other parameter axis of axis mapping entry.</param>
 /// <param name="axisMappingEntry">The mapping entry to check if matches the currently requested axis.</param>
 /// <returns>True if it is the correct entry, else false.</returns>
 private static bool IsCorrectAxisMappingEntry(AxisMappingEntry axisMappingEntry, ControllerAxis axis)
 {
     return(axisMappingEntry.DestinationAxis == axis);
 }
Example #12
0
        /// <summary>
        /// Remaps the axis of an XInput controller.
        /// </summary>
        private bool XInputRemapAxis(int timeoutSeconds, out float currentTimeout, AxisMappingEntry mappingEntry, ref bool cancellationToken)
        {
            // Cast Controller to DInput Controller
            XInputController xInputController = (XInputController)Controller;

            // Retrieve Joystick State
            State joystickState = xInputController.Controller.GetState();

            // Initialize Timeout
            // MillisecondsInSecond / SleepTimePolling = Amount of polls/ticks per second.
            int pollAttempts = timeoutSeconds * MillisecondsInSecond / SleepTimePolling;
            int pollCounter  = 0;

            // Get % Change for recognition of input.
            int percentDelta        = (int)(XInputController.MaxAnalogStickRangeXinput / 100.0F * PercentageAxisDelta);
            int percentDeltaTrigger = (int)(XInputController.MaxTriggerRangeXinput / 100.0F * PercentageAxisDelta);

            // Poll the controller properties.
            while (pollCounter < pollAttempts)
            {
                // Get new JoystickState
                State joystickStateNew = xInputController.Controller.GetState();

                // Get Deltas (Differences)
                int leftStickX   = joystickState.Gamepad.LeftThumbX - joystickStateNew.Gamepad.LeftThumbX;
                int leftStickY   = joystickState.Gamepad.LeftThumbY - joystickStateNew.Gamepad.LeftThumbY;
                int rightStickX  = joystickState.Gamepad.RightThumbX - joystickStateNew.Gamepad.RightThumbX;
                int rightStickY  = joystickState.Gamepad.RightTrigger - joystickStateNew.Gamepad.RightThumbY;
                int leftTrigger  = joystickState.Gamepad.LeftTrigger - joystickStateNew.Gamepad.LeftTrigger;
                int rightTrigger = joystickState.Gamepad.RightTrigger - joystickStateNew.Gamepad.RightTrigger;

                // Iterate over all axis.
                if (leftStickX < -1 * percentDelta)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftStickX; currentTimeout = 0; return(true);
                }
                if (leftStickX > percentDelta)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftStickX; currentTimeout = 0; return(true);
                }

                if (rightStickX < -1 * percentDelta)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightStickX; currentTimeout = 0; return(true);
                }
                if (rightStickX > percentDelta)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightStickX; currentTimeout = 0; return(true);
                }

                if (leftStickY < -1 * percentDelta)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftStickY; currentTimeout = 0; return(true);
                }
                if (leftStickY > percentDelta)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftStickY; currentTimeout = 0; return(true);
                }

                if (rightStickY < -1 * percentDelta)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightStickY; currentTimeout = 0; return(true);
                }
                if (rightStickY > percentDelta)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightStickY; currentTimeout = 0; return(true);
                }

                if (leftTrigger < -1 * percentDeltaTrigger)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftTrigger; currentTimeout = 0; return(true);
                }
                if (leftTrigger > percentDeltaTrigger)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.LeftTrigger; currentTimeout = 0; return(true);
                }

                if (rightTrigger < -1 * percentDeltaTrigger)
                {
                    mappingEntry.IsReversed = true; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightTrigger; currentTimeout = 0; return(true);
                }
                if (rightTrigger > percentDeltaTrigger)
                {
                    mappingEntry.IsReversed = false; mappingEntry.DestinationAxis = ControllerCommon.ControllerAxis.RightTrigger; currentTimeout = 0; return(true);
                }

                // Increase counter, calculate new time left.
                // SleepTimePolling / MillisecondsInSecond = Amount of time per 1 tick (pollCounter)
                // pollCOunter = current amount of ticks done.
                pollCounter   += 1;
                currentTimeout = (float)timeoutSeconds - (pollCounter * (SleepTimePolling / MillisecondsInSecond));

                // Check exit condition
                if (cancellationToken)
                {
                    return(false);
                }

                // Sleep
                Thread.Sleep(SleepTimePolling);
            }

            // Set current timeout (suppress compiler)
            currentTimeout = 0;
            return(false);
        }
Example #13
0
        /// <summary>
        /// Remaps the axis of a DirectInput controller.
        /// </summary>
        /// <returns>True if a new axis has been assigned to the current mapping entry.</returns>
        private bool DInputRemapAxis(int timeoutSeconds, out float currentTimeout, AxisMappingEntry mappingEntry, ref bool cancellationToken)
        {
            // Cast Controller to DInput Controller
            DInputController dInputController = (DInputController)Controller;

            // Get type of JoystickState
            Type stateType = typeof(JoystickState);

            // Retrieve Joystick State
            JoystickState joystickState = dInputController.GetCurrentState();

            // Initialize Timeout
            int pollAttempts = timeoutSeconds * MillisecondsInSecond / SleepTimePolling;
            int pollCounter  = 0;

            // Get % Change for recognition of input.
            int percentDelta = (int)(DInputManager.AxisMaxValue / 100.0F * PercentageAxisDelta);

            // If the axis is relative, instead set the delta very low, as relative acceleration based inputs cannot be scaled to a range.
            if (dInputController.Properties.AxisMode == DeviceAxisMode.Relative)
            {
                // Set low delta
                percentDelta = 50;

                // Additionally reset every property.
                foreach (PropertyInfo propertyInfo in stateType.GetProperties())
                {
                    if (propertyInfo.PropertyType == typeof(int))
                    {
                        propertyInfo.SetValue(joystickState, 0);
                    }
                }
            }

            // Poll the controller properties.
            while (pollCounter < pollAttempts)
            {
                // Get new JoystickState
                JoystickState joystickStateNew = dInputController.GetCurrentState();

                // Iterate over all properties.
                foreach (PropertyInfo propertyInfo in stateType.GetProperties())
                {
                    // If the property type is an integer. (This covers, nearly all possible axis readings and all in common controllers.)
                    if (propertyInfo.PropertyType == typeof(int))
                    {
                        // Calculate the change of value from last time.
                        int valueDelta = (int)propertyInfo.GetValue(joystickState) -
                                         (int)propertyInfo.GetValue(joystickStateNew);

                        // If the value has changed over X amount
                        if (valueDelta < -1 * percentDelta)
                        {
                            //mappingEntry.isReversed = true;
                            mappingEntry.SourceAxis = propertyInfo.Name;
                            currentTimeout          = 0;
                            return(true);
                        }

                        if (valueDelta > percentDelta)
                        {
                            //mappingEntry.isReversed = false;
                            mappingEntry.SourceAxis = propertyInfo.Name;
                            currentTimeout          = 0;
                            return(true);
                        }
                    }
                }

                // Increase counter, calculate new time left.
                pollCounter   += 1;
                currentTimeout = timeoutSeconds - pollCounter * SleepTimePolling / (float)MillisecondsInSecond;

                // Check exit condition
                if (cancellationToken)
                {
                    return(false);
                }

                // Sleep
                Thread.Sleep(SleepTimePolling);
            }

            // Set current timeout (suppress compiler)
            currentTimeout          = 0;
            mappingEntry.SourceAxis = "Null";
            return(false);
        }