/// <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)); }
/// <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); }
/// <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); }
/// <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); }