-
Notifications
You must be signed in to change notification settings - Fork 11
Mapping Controller Buttons and Axes
An XInput-based controller follows the controller layout of an Xbox controller: buttons have names (A, B, X, Y, and so on), and analog axes are identified directly (left stick, right stick, LT, and RT). Games that natively support XInput can simply refer to controller components by name, such as by saying "press A to jump" or "the right stick controls the camera."
DirectInput, on the other hand, supports every possible form factor for a game controller: gamepads, joysticks and steering wheels, to name a few. It does not have a defined standard layout for controllers. Games generally refer to buttons by number (button 1, button 2, and so on) and analog axes by letter (X axis, Y axis, and so on), and it is up to the manufacturer of the controller to determine which physical button or axis corresponds to each number or letter, respectively. Xidi therefore implements a mapping of Xbox controller components to DirectInput controller components.
Most buttons and axes can be mapped directly from XInput to DirectInput, but the LT and RT triggers present a complication. DirectInput axes assume that the neutral (i.e. unpressed) position is at the center. This works for analog sticks and joysticks because they return to the center position when the user is not actively pushing them in a particular direction. However, LT and RT do not behave this way: the neutral position is at an extreme end, so mapping them directly to a DirectInput axis will cause games to break unless they are aware of this specific behavior or they ignore LT and RT completely.
Many games make assumptions about the controller layout, and Xidi cannot automatically determine these assumptions. Xidi therefore allows XInput controller mapping behavior to be customized. It includes several built-in types of mappers and supports custom mappers being defined in configuration files.
Xidi defines several built-in mapper types, as listed below.
-
StandardGamepad emulates old gamepads that resemble Sony PlayStation controllers, such as the Logitech RumblePad 2. As was common for these controllers, the right stick maps to the Z and Z-rotation axes. LT and RT are mapped to digital buttons; all analog functionality is removed, but the controls are usable.
-
DigitalGamepad emulates old digital-only gamepads like the Gravis GamePad Pro. All axes are digital (i.e. no analog functionality, either they are pressed to the extreme or not pressed at all). Both left stick and d-pad contribute to X and Y axes. While controllers of this type typically only had two axes, the right stick nonetheless offers Z and Z-rotation axes in digital form.
-
ExtendedGamepad is similar to StandardGamepad, except that the analog functionality of LT and RT is preserved. The X-rotation and Y-rotation axes were selected to retain the mapping of the right stick to the Z and Z-rotation axes.
-
XInputNative mirrors the previous behavior of Windows 10 when an Xbox One controller was connected. The right stick maps to X-rotation and Y-rotation, and the triggers individually map to Z and Z-rotation. This configuration broke many older games but is presented as an option to support those that require it.
-
XInputSharedTriggers mirrors the current behavior of Windows 10 when an Xbox One or Xbox 360 controller is connected. The right stick maps to X-rotation and Y-rotation, but the triggers share the Z axis. This preserves the analog functionality of the triggers but prevents them from being used independently.
Precise button and axis mappings are as below.
StandardGamepad | DigitalGamepad | ExtendedGamepad | XInputNative | XInputSharedTriggers | |
---|---|---|---|---|---|
Left Stick, Horizontal | X axis | X axis (digital) | X axis | X axis | X axis |
Left Stick, Vertical | Y axis | Y axis (digital) | Y axis | Y axis | Y axis |
Right Stick, Horizontal | Z axis | Z axis (digital) | Z axis | X-rotation axis | X-rotation axis |
Right Stick, Vertical | Z-rotation axis | Z-rotation axis (digital) | Z-rotation axis | Y-rotation axis | Y-rotation axis |
D-Pad | Point-of-view hat | X and Y axes (digital) | Point-of-view hat | Point-of-view hat | Point-of-view hat |
A | Button 1 | Button 1 | Button 1 | Button 1 | Button 1 |
B | Button 2 | Button 2 | Button 2 | Button 2 | Button 2 |
X | Button 3 | Button 3 | Button 3 | Button 3 | Button 3 |
Y | Button 4 | Button 4 | Button 4 | Button 4 | Button 4 |
LB | Button 5 | Button 5 | Button 5 | Button 5 | Button 5 |
RB | Button 6 | Button 6 | Button 6 | Button 6 | Button 6 |
LT | Button 7 | Button 7 | X-rotation axis | Z-axis | Z-axis (shared) |
RT | Button 8 | Button 8 | Y-rotation axis | Z-rotation axis | Z-axis (shared) |
Back | Button 9 | Button 9 | Button 7 | Button 7 | Button 7 |
Start | Button 10 | Button 10 | Button 8 | Button 8 | Button 8 |
LS | Button 11 | Button 11 | Button 9 | Button 9 | Button 9 |
RS | Button 12 | Button 12 | Button 10 | Button 10 | Button 10 |
Recognizing that the built-in mapper selection might not be optimal for all games, Xidi allows mapper behavior to be customized using a configuration file. A small collection of pre-made custom mapper configurations is available in the XidiGameConfigurations repository.
The simplest way to create a custom mapper is to include a configuration file section named "CustomMapper" and specify "Custom" as the desired type of mapper. An example is shown below.
[Mapper]
Type = Custom
[CustomMapper]
; Custom mapper settings go here.
It is also possible to define multiple custom mappers and give each its own name. This is done by using section names of the form "CustomMapper:name" and referencing name when specifying a mapper type. For example, to assign different custom mappers to each controller, the following configuration file could be used.
[Mapper]
Type.1 = FancyMapper1
Type.2 = Game2
Type.3 = Three
Type.4 = 4thMapper
[CustomMapper:FancyMapper1]
; Custom mapper settings for "FancyMapper1" go here.
[CustomMapper:Game2]
; Custom mapper settings for "Game2" go here.
[CustomMapper:Three]
; Custom mapper settings for "Three" go here.
[CustomMapper:4thMapper]
; Custom mapper settings for "4thMapper" go here.
Custom mappers named this way must:
- Have unique names. No two custom mappers may share the same name.
- Not be named "Custom" as this would clash with the default name of a custom mapper.
- Not have the same name as any of the built-in mappers.
Xidi will display a warning message box if it detects an error with how a custom mapper is defined. To see the details, ensure logging is turned on and consult the log file Xidi places on the desktop. Unlike for configuration file errors, Xidi will not automatically turn on logging in the event of a custom mapper definition error.
The subsections that follow describe what each "CustomMapper" configuration section should contain in order to define a custom mapper.
Configuration file sections that define custom mappers contain two types of settings: top-level settings and element mappers.
Currently the only available top-level setting is "Template" whose value is the name of any other mapper, be it built-in or custom. This has the effect of copying all of the element mappers from the template mapper to use as a starting point for the custom mapper. Individual element mappers can still be specified, and these are applied as modifications to the template. Use of a template is optional; in the absence of a template the custom mapper is built from scratch. Ordering of custom mapper definitions within the configuration file is not important. In the preceding example, "FancyMapper1" is allowed to use any of "Game2," "Three," and "4thMapper" as a template even though their definitions appear later in the configuration file. However, self-references and circular references are forbidden, and Xidi will flag an error if any such issues are detected.
An element mapper defines how Xidi should process input from a specific XInput controller element. For example, an element mapper assigned to the A button might specify that input should be routed to button 1 on a virtual controller. At the same time, another element mapper assigned to trigger LT might specify that input should be routed to the RotZ axis on the virtual controller.
The configuration below shows how to create a custom mapper that behaves the same way as StandardGamepad but modifies the button assignments of A, B, X, and Y. Ordering of the lines within each section is not important.
[CustomMapper:ModifiedStandardGamepad]
; Imports all of the element mappers from StandardGamepad.
; This line is allowed to appear anywhere in the section, including between or after the element mappers below.
Template = StandardGamepad
; These changes are applied on top of the template.
ButtonA = Button(4)
ButtonB = Button(3)
ButtonX = Button(2)
ButtonY = Button(1)
The above configuration is equivalent to the below configuration, which does the same thing but without the use of a template. Shown are all of the supported XInput controller elements to which an element mapper can be assigned. If an XInput controller element is not assigned an element mapper then all input from it is ignored.
[CustomMapper:ModifiedStandardGamepadNoTemplate]
; Because there is no template specified, every element mapper needs to be defined explicitly.
; Element mappers below are taken from StandardGamepad documentation.
StickLeftX = Axis(X)
StickLeftY = Axis(Y)
StickRightX = Axis(Z)
StickRightY = Axis(RotZ)
DpadUp = Pov(Up)
DpadDown = Pov(Down)
DpadLeft = Pov(Left)
DpadRight = Pov(Right)
ButtonLB = Button(5)
ButtonRB = Button(6)
TriggerLT = Button(7)
TriggerRT = Button(8)
ButtonBack = Button(9)
ButtonStart = Button(10)
ButtonLS = Button(11)
ButtonRS = Button(12)
; These are different from StandardGamepad, per the original purpose of this example.
ButtonA = Button(4)
ButtonB = Button(3)
ButtonX = Button(2)
ButtonY = Button(1)
It is permissible for multiple element mappers to be linked to the same virtual controller element. Xidi intelligently combines the multiple inputs into a single coherent output as follows.
- Axis output is determined by summation of contributions from element mappers.
- Button output is determined by the logical-or of contributions from element mappers. In other words, if any element mapper says the button is pressed, Xidi reports it as pressed.
- POV hat output is determined by proper direction combination.
- Opposing contributions (for example, simultaneous up and down) are cancelled out.
- Orthogonal contributions (for example, simultaneous left and up) are combined into a diagonal output.
Custom mappers theoretically can define virtual controllers of arbitrary capabilities (i.e. which axes are present, how many buttons are present, and whether or not a POV hat exists). Xidi imposes certain limits to simplify its own implementation and to accomodate expectations of both the DirectInput and WinMM APIs. Specifically, the following limits exist.
- Axes
- Minimum: X axis and Y axis must both be present.
- If no element mapper is linked to one of these axes then the application's view is that the corresponding axis is present but always held in a neutral position.
- Maximum: X, Y, Z, RotX, RotY, and RotZ axes are supported.
- Minimum: X axis and Y axis must both be present.
- Buttons
- The highest-numbered button determines the number of buttons Xidi reports to the application. Any buttons not linked to an element mapper are always held in an unpressed state.
- For example, if a custom mapper specifies buttons 5 and 10, then Xidi reports that a total 10 buttons exist on the virtual controller, but only buttons 5 and 10 could ever possibly be pressed.
- Minimum: 2 buttons must be present.
- If no element mappers contribute to a virtual controller button, then Xidi will report 2 buttons being present even though neither can ever be pressed.
- Maximum: 16 buttons are supported.
- The highest-numbered button determines the number of buttons Xidi reports to the application. Any buttons not linked to an element mapper are always held in an unpressed state.
- POV hats
- If any element mapper is linked to the POV hat, Xidi reports that the POV hat is present. Otherwise Xidi reports that it is not present.
- Minimum: 0 POV hats exist on the virtual controller.
- Maximum: 1 POV hat exists on the virtual controller.
Xidi provides several different types of element mappers, each of which implements a different way of translating input from an XInput controller element into virtual controller state. While some are designed with certain use cases in mind, there are no restrictions on the types of element mappers that can be linked to any specific XInput controller elements.
Both types of element mapper link an XInput controller element to a virtual controller axis. The difference between them is that Axis produces analog output whereas DigitalAxis maps all input to a digital output. In other words, any representable analog value can be produced by Axis, whereas DigitalAxis will produce either extreme negative, neutral, or extreme positive. This only manifests in different behavior if the element mapper is linked to an analog input source, such as a stick or a trigger.
Axis and DigitalAxis both require a parameter specifying the virtual controller axis to which to link. Supported axis names are X
, Y
, Z
, RotX
, RotY
, and RotZ
. A second optional parameter is additionally allowed to specify the axis direction, either +
or -
(alternative values Positive
and Negative
are also accepted).
By default all Axis and DigitalAxis element mappers are bidirectional, meaning they cover the entire range of possible axis values from extreme negative to extreme positive. Specifying a direction modifies this behavior and is primarily useful for Axis and DigitalAxis element mappers that accept input from XInput controller buttons. In bidirectional mode the axis is reported as extreme positive if the button is pressed and extreme negative if not pressed. In unidirectional mode the axis is reported as extreme in the configured direction if the button is pressed and neutral if the button is not pressed.
To see how this unidirectional configuration works in practice, below are two examples to highlight the difference.
[CustomMapper:BidirectionalAxisExample]
; Bidirectional axis example.
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; The A button is mapped to the X axis. Resulting behavior is likely undesirable.
; If the A button is pressed, X axis is extreme positive (i.e. all the way to the right).
; If the A button is not pressed, X axis is extreme negative (i.e. all the way to the left).
ButtonA = Axis(X)
[CustomMapper:UnidirectionalAxisExample]
; Unidirectional axis example.
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; The A button is mapped to the positive direction of the X axis.
; If the A button is pressed, X axis is extreme positive (i.e. all the way to the right).
; If the A button is not pressed, X axis is neutral (i.e. centered).
ButtonA = Axis(X, +)
XInputSharedTriggers, a built-in mapper, uses unidirectional Axis element mappers to implement sharing of the Z axis across both triggers. The example below shows how this would be represented in a configuration file.
[CustomMapper:XInputSharedTriggersExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; One trigger each is assigned to a different Z axis direction, equivalent to XInputSharedTriggers behavior.
TriggerLT = Axis(Z, +)
TriggerRT = Axis(Z, -)
A Button element mapper links an XInput controller element to a virtual controller button. It requires a single parameter specifying the button number, from 1 to 16.
A Compound element mapper forwards input to multiple element mappers, up to a maximum of 8. It requires one or more parameters each specifying an element mapper.
The example below shows how to use a Compound element mapper to link an XInput controller button to both a virtual controller button and a keyboard key. As a result, pressing the XInput controller button has the effect causing both the virtual controller button and the keyboard key to be pressed.
[CustomMapper:CompoundExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; Routes input from the Start button to both button 10 on the virtual controller the Enter key on the keyboard.
; Parameter order does not matter.
ButtonStart = Compound( Button(10), Keyboard(Enter) )
An Invert element mapper inverts whatever input it receives from its associated XInput controller element and then forwards the result to another element mapper. It requires a single parameter specifying an element mapper.
This type of element mapper is primarily useful for inverting axis values, which has the effect of swapping the positive and negative directions. The example below shows how this would be implemented in a configuration file.
[CustomMapper:InvertExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; Inverts analog input received from the left stick.
; Normally, right direction on the analog stick is positive and left direction is negative.
; As a result of the inversion, right direction on the analog stick is negative and left direction is positive.
StickLeftX = Invert( Axis(X) )
Inversion also works on triggers and buttons. Triggers follow the same basic inversion logic as axes, and buttons have their pressed and unpressed states swapped.
A keyboard element mapper links an XInput controller element to a key on the keyboard. As a result, it is not linked to any virtual controller element.
Element mappers of this type require a single parameter identifying the associated keyboard key. Keyboard keys can be identified in a few different ways, as listed below in order of precedence from top to bottom.
- Symbolic key name, which is case-insensitive and takes the form of one of the
DIK_
enumerator names from the DirectInput keyboard device enumeration, with or without the "DIK_" prefix.- This is the recommended way to identify a keyboard key.
- Raw numeric scan code expressed as a single byte number in decimal, octal (prefix "0" required), or hexadecimal (prefix "0x" required).
- Valid values are 0 to 255 (0x0 to 0xFF).
- Scan codes that identify keys other than extended keys fall into the range 0 to 127 (0x0 to 0x7F).
- Scan codes that identify extended keys typically use two bytes, the first of which is the prefix byte 0xE0. Instead of including a prefix byte, follow the DirectInput convention of setting the most significant bit to obtain a value from 128 to 255 (0x80 to 0xFF).
In general, the easiest way of identifying a keyboard key is by symbolic name. The complete list of supported symbolic names is contained in the MapperParser.cpp
source code file, but as a summary the following are recognized. Note that Xidi internally maps all keyboard key identifiers to hardware scan codes. Therefore, all symbolic names represent physical key positions on a US QWERTY keyboard.
-
Up
,Down
,Left
, andRight
to identify arrow keys.- Alternative names are
UpArrow
,DownArrow
,LeftArrow
, andRightArrow
respectively.
- Alternative names are
-
Insert
,Delete
,Home
,End
,PgUp
, andPgDown
to identify the cluster of special keys that sits atop the arrow keys. -
F1
toF15
to identify the function keys. -
Numpad0
toNumpad9
,NumpadEquals
,NumpadSlash
,NumpadStar
,NumpadMinus
,NumpadPlus
,NumpadPeriod
, andNumpadEnter
to identify keys on the number pad. -
LShift
,RShift
,LControl
,RControl
,LAlt
,RAlt
,LWin
,RWin
,Apps
,Esc
,Enter
,Space
,Backspace
,Tab
,NumLock
,CapsLock
, andScrollLock
to identify the corresponding special keyboard keys. -
Grave
,Minus
,Equals
,LBracket
,RBracket
,Backslash
,Semicolon
,Apostrophe
,Comma
,Period
, andSlash
to identify the corresponding symbol keys. - Single letters (
A
toZ
) or numbers (0
to9
) to identify the corresponding keys.
For example, the below configuration links the d-pad of an XInput controller to the arrow keys, the Start button to the Enter key, and the Back button to the Escape key.
[CustomMapper:KeyboardExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
DpadUp = Keyboard(UpArrow)
DpadDown = Keyboard(DownArrow)
DpadLeft = Keyboard(LeftArrow)
DpadRight = Keyboard(RightArrow)
ButtonStart = Keyboard(Enter)
ButtonBack = Keyboard(Esc)
A mouse axis element mapper links an XInput controller element to mouse movement along one of the possible mouse axes. It otherwise behaves very similarly to an axis mapper.
MouseAxis requires a parameter specifying the mouse motion axis to which to link. Supported axis names are X
, Y
, WheelHorizontal
, WheelVertical
; the first two correspond to physical mouse movement, and the second two correspond to rotation of the scroll wheel that is present on some mouse hardware. A second optional parameter is additionally allowed to specify the axis direction, either +
or -
(alternative values Positive
and Negative
are also accepted).
As an example, the below configuration links the right stick and the d-pad to mouse cursor movement.
[CustomMapper:MouseAxisExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; For the right stick one mouse axis maps entirely to an analog controller axis.
StickRightX = MouseAxis(X)
StickRightY = MouseAxis(Y)
; For the d-pad one button corresponds to a different direction of motion.
DpadUp = MouseAxis(Y, -)
DpadDown = MouseAxis(Y, +)
DpadLeft = MouseAxis(X, -)
DpadRight = MouseAxis(X, +)
A mouse button element mapper links an XInput controller element to a mouse button. It behaves very similarly to a keyboard element mapper except it acts on a mouse button rather than on a keyboard key.
Element mappers of this type require a single parameter identifying the associated mouse button. There are five possible mouse buttons for which standard identifiers exist: Left
, Middle
, Right
, X1
, and X2
. The X1 and X2 mouse buttons commonly appear on mouse hardware as "back" and "forward" buttons respectively and tend to be used for those navigation purposes in various places on Windows machines, including in internet browsers and in File Explorer.
For example, the below configuration links the A, B, X, LB, and RB buttons on an XInput controller to the left, right, middle, X1, and X2 mouse buttons respectively.
[CustomMapper:MouseButtonExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
ButtonA = MouseButton(Left)
ButtonB = MouseButton(Right)
ButtonX = MouseButton(Middle)
ButtonLB = MouseButton(X1)
ButtonRB = MouseButton(X2)
A POV element mapper links an XInput controller element to the POV hat on a virtual controller. A single parameter is required specifying the associated POV hat direction: Up
, Down
, Left
, or Right
.
A Null element mapper does nothing whatsoever and causes an XInput controller element to be ignored. No parameters are accepted.
This type of element mapper is primarily useful for removing element mappers from templates. For example, if the template is "StandardGamepad" and the goal is to cause the A button to be ignored, then the below will work.
[CustomMapper:NullExample]
Template = StandardGamepad
ButtonA = Null
A Split element mapper requires two parameters, each of which is another element mapper. The first parameter is its "positive" element mapper and the second is its "negative" element mapper. If the assigned XInput controller element reports positive input (i.e. stick position is positive, button is pressed, or trigger is greater than the mid-point value) then the positive element mapper is asked to process the input, otherwise the negative element mapper is asked to do so. It is valid to specify "Null" as a parameter, with the outcome being that the corresponding input (positive or negative) is simply ignored.
The primary use case for a Split element mapper is to separate an XInput controller's analog stick axis into a positive part and a negative part. For example, the below configuration splits both axes of the left stick into a positive part and a negative part, triggering a different keyboard key in each case.
[CustomMapper:SplitExampleArrowKeys]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; If the left stick's X axis is moved sufficiently to the right (positive), press the right arrow key.
; If the left stick's X axis is moved sufficiently to the left (negative), press the left arrow key.
; Of course, if the left stick's X axis is neutral, then neither key is pressed.
StickLeftX = Split( Keyboard(Right), Keyboard(Left) )
; If the left stick's Y axis is moved sufficiently down (positive), press the down arrow key.
; If the left stick's Y axis is moved sufficiently up (negative), press the up arrow key.
; Of course, if the left stick's Y axis is neutral, then neither key is pressed.
StickLeftY = Split( Keyboard(Down), Keyboard(Up) )
Another possible use case is filtering. Suppose the goal is to map from the left stick's X axis on an XInput controller to virtual controller button 2, but only if the left stick is pressed in the positive direction (i.e. to the right). The configuration below would not adequately capture this goal because the button would be pressed irrespective of axis direction.
[CustomMapper:ButtonFromAxisExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; If the left stick's X axis is pressed in either direction then button 2 is pressed.
StickLeftX = Button(2)
A Split element mapper can be used to filter out all of the negative input so that the button is only considered pressed in the positive direction.
[CustomMapper:SplitButtonFromAxisExample]
; This example is not complete.
; It only defines element mappers for a small subset of controller elements.
; If the left stick's X axis is pressed to the right (positive) direction then button 2 is pressed.
StickLeftX = Split( Button(2), Null )
Split element mappers behave somewhat differently depending if they are linked to an XInput axis, button, or trigger, as follows.
- If assigned to an axis...
- If the axis reports a neutral or positive value then the positive element mapper is forwarded the analog value.
- If the axis reports a negative value then the negative element mapper is forwarded the analog value.
- If assigned to a button...
- If the button is pressed, the positive element mapper is sent a "button pressed" input.
- If the button is not pressed, the negative element mapper is sent a "button pressed" input.
- This behavior may be counter-intuitive. Its supporting rationale is that sending a "button not pressed" input to an element mapper is functionally useless.
- If assigned to a trigger...
- If the trigger is pressed to at least at the midpoint position then the positive element mapper is forwarded the trigger value.
- If the trigger is either not pressed or pressed below the midpoint position then the negaive element mapper is forwarded the trigger value.
Customizing the force feedback actuators is an advanced feature.
A force feedback actuator is a physical device that produces a force feedback effect. For example, Xbox One controllers feature four such actuators:
- Left motor, located in the body of the controller
- Right motor, located in the body of the controller
- Left impulse trigger, located near the LT trigger
- Right impulse trigger, located near the RT trigger
Internally, the XInput API allows force feedback actuators to be used by specifying a rumble strength value, and these rumble strength values can vary with time to produce different vibration effects.
Force feedback in DirectInput is very different. While the concept does encompass vibration effects, it is much more general and also includes within its purview actual forces that a game controller device might apply to controller components. For example, a joystick might have an effect generator that is capable of exerting a force on the joystick such that it is pushed in a particular direction. Therefore, DirectInput exposes all force feedback effects as actual forces exerted along one or more axes. Following the joystick example, an application might request a force be exerted on the X axis, which would result in the joystick itself being pushed along the corresponding physical direction.
The idea of exerting a force along an axis does not make much sense in the context of vibration motors that accept a simple rumble strength value. DirectInput applications generally expect force feedback effects to be supported along both the X and Y axes, so Xidi provides that support. By default, Xidi computes the magnitude of the force vector along the X-Y plane and uses the resulting value as the rumble strength applied to both left and right motors. While this default behavior works in many situations, Xidi allows the mapping of axes to physical force feedback actuators to be customized.
In addition to controller components like DpadUp, TriggerLT, and ButtonA, there are a few specific force feedback actuators whose behaviors can be customized. The example below shows all supported force feedback actuators and the default values used for the built-in mappers.
[CustomMapper:DefaultForceFeedbackSettings]
; This example is not complete.
; It only defines force feedback actuators, nothing else.
; Left motor.
ForceFeedback.LeftMotor = MagnitudeProjection(X, Y)
; Right motor.
ForceFeedback.LeftMotor = MagnitudeProjection(X, Y)
Xidi internally supports all four actuators, but the documented XInput API only exposes the left and right motors. As a result, the impulse triggers are currently not available.
Force feedback actuator settings exist alongside the element mappers and are generally treated the same way when it comes to creating new custom mappers and using existing mappers as templates. However, there is one caveat: if a custom mapper does not use a template and also does not define any force feedback settings, then the default force feedback settings are applied, as shown in the preceding example. The rationale for this caveat is that it ensures users who want to build custom mappers from scratch but do not wish to concern themselves with force feedback settings are still able to use force feedback.
Various modes are supported for each force feedback actuator. These are described in the subsections that follow.
A Disabled force feedback actuator does not produce any vibration effects whatsoever. This is primarily useful for removing a force feedback actuator from templates. For example, if the template is "StandardGamepad" and the goal is to cause the left motor to be turned off, then the below will work.
[CustomMapper:DisabledForceFeedbackExample]
Template = StandardGamepad
ForceFeedback.LeftMotor = Disabled
A MagnitudeProjection force feedback actuator computes the magnitude of the force feedback effect along a two-axis plane and uses the result as the rumble strength. Two parameters are required, each identifying an axis. This is the default mode for the left and right motors, using the X and Y axes together to obtain the rumble strength, as shown in the default settings example.
A SingleAxis force feedback actuator directly obtains its rumble strength from a single force feedback axis. A direction can optionally be specified so that either positive or negative axis values are filtered out. Using a bidirectional SingleAxis force feedback actuator causes the absolute value of the effect strength along that axis to be mapped to the rumble strength.
Parameters are the same as for the Axis and DigitalAxis element mappers. The first parameter identifies the axis of interest, and the second may optionally specify a direction. Refer to the example below for a demonstration of how to use SingleAxis force feedback actuators.
[CustomMapper:ForceFeedbackSingleAxisExample]
; Left motor rumble strength is the absolute value of the force effect's X component.
ForceFeedback.LeftMotor = SingleAxis(X)
; Right motor rumble strength is 0 if the force effect's X component is positive, otherwise it is the absolute value of the force effect's X component.
ForceFeedback.RightMotor = SingleAxis(X, -)