Skip to content

5.d Controller | Adding new devices

Maschell edited this page Aug 6, 2018 · 16 revisions

Overview

Notes:

  • First line of the config, need the be the information about the vid/pid
  • Each controller needs a seperate config file
  • The config files are case-insensitive.
  • Comments can be added after a "//"

Where do I get the necessary data?

To get the data you can you HID-TEST. Simply start it from the homebrew launcher and you see your vid,pid and input data.

VID/PID

You'll need the vid and pid for your controller. Each HID device has his unique vid/pid combination, that can be used to identify them. Provide them in the first line of your config file.

Example:

When create a config file for a controller with the following data:

  • vid: 0x0D41
  • pid: 0xE124
    The config line would look like this:
[vid=0x0D41,pid=0xE124]

Buttons

To set the buttons, you need the the following information:

  • the position of the byte holding the information in the inputdata (counting starts a 0x00)
  • the value when the button is pressed (More precisely: the value that BIT OR'd)

Which buttons can be mapped

Here a list of the buttons that can be mapped. On the right side you see the name you need for the config file.

Buttons:
A                   =   VPAD_BUTTON_A
B                   =   VPAD_BUTTON_B
X                   =   VPAD_BUTTON_X
Y                   =   VPAD_BUTTON_Y
Plus                =   VPAD_BUTTON_PLUS
Minus               =   VPAD_BUTTON_MINUS
Home                =   VPAD_BUTTON_HOME (Won't trigger the home menu)
Sync                =   VPAD_BUTTON_SYNC
TV                  =   VPAD_BUTTON_TV

DPAD:
DPAD left           =   VPAD_BUTTON_LEFT
DPAD left           =   VPAD_BUTTON_RIGHT
DPAD left           =   VPAD_BUTTON_UP
DPAD left           =   VPAD_BUTTON_DOWN

Trigger:
ZR                  =   VPAD_BUTTON_ZR
ZL                  =   VPAD_BUTTON_ZL
L                   =   VPAD_BUTTON_L
R                   =   VPAD_BUTTON_R

Sticks:
Stick press left    =   VPAD_BUTTON_STICK_L
Stick press right   =   VPAD_BUTTON_STICK_R

Setting a button

To set a button, you'll need to set the byte postion and value

VPAD_BUTTON_A       = [position],[value]

Examples:

The connected USB controller set the 3 byte (0x02) to 0x08 when a button is pressed.
Using the following line in the config file, the button will be mapped to the X button.

VPAD_BUTTON_X       = 0x02,0x08

Do this for every button you want to map

DPAD

Different devices have different method to provivde the DPAD data. The controller patcher engine currently supports 3 of them. If you found an other method, that's currently not supported, please open an issue with further information.

Setting the DPAD mode

In order to use the DPAD, you'll need to set right DPAD mode. To set the DPAD mode, use the following config line:

DPAD_MODE              =   [DPAD_NORMAL/DPAD_HAT/DPAD_ABSOLUTE_2VALUES]

Example for setting it to the "hat" mode.

DPAD_MODE              =   DPAD_HAT

Note: When no mode is set, the normal mode will be used.

The value depends on the data the device is sending. Detailed information on how to identify and set up the invidual mode can be found in the following sections.

DPAD normal mode

In the "normal"-mode, the DPAD data is stored in one byte.
The directions north, south, west and east get their own values. To represent the direction, the pressed directions will be bitwise OR'd.


Example:
NOTE: Example values.
Values that will be OR'd when one the direction is pressed.

(UP) North             =   0x01 (bitwise: 0b0000 0001)
(RIGHT) East           =   0x02 (bitwise: 0b0000 0010)
(DOWN) South           =   0x04 (bitwise: 0b0000 0100)
(LEFT) West            =   0x08 (bitwise: 0b0000 1000)

The combined directions can result in other directions:

(UP+RIGHT) North-East  =   0x03 (bitwise: 0b0000 0011. Result of 0x01|0x02)
(DOWN+LEFT) South-West =   0x0C (bitwise: 0b0000 1100. Result of 0x04|0x08)

When the device uses this method for the DPAD data, you'll need to set the following data:

VPAD_BUTTON_LEFT       =   [position],[value]
VPAD_BUTTON_RIGHT      =   [position],[value]
VPAD_BUTTON_UP         =   [position],[value]
VPAD_BUTTON_DOWN       =   [position],[value]

Example:
DPAD data is provided in "normal" mode, the values are stored in the 3rd byte (aka 0x02, we're counting from 0) of the incoming data.
Values:

  • N = 0x01, E = 0x02, S = 0x04, W = 0x08.
DPAD_MODE              =   DPAD_NORMAL
VPAD_BUTTON_LEFT       =   0x02,0x08 //W
VPAD_BUTTON_RIGHT      =   0x02,0x02 //E
VPAD_BUTTON_UP         =   0x02,0x01 //N
VPAD_BUTTON_DOWN       =   0x02,0x04 //S

DPAD hat mode

In the "normal"-mode, the DPAD data is stored in one byte.
The directions north, north-east, east, south-east, south, south-west, west, north-west and the neutral position get their own values.


Example:
NOTE: Example values.
Each direction has his own, unique value.

(UP)           North       =   0x01
(UP+RIGHT)     North-East  =   0x02
(RIGHT)        East        =   0x03 
(DOWN + RIGHT) South-East  =   0x04
(DOWN)         South       =   0x05
(DOWN + LEFT)  South-West  =   0x06
(LEFT)         West        =   0x07
(UP + LEFT)    North-West  =   0x08
(NOTHING)      Neutral     =   0x0F

In addition to the values, you need a bit-mask for the values. Sometimes buttons and the dpad are stored in the same byte. The first 8 bit are used for the buttons, the last 8 bits for the DPAD (the other way round). The work with the data, we need to isolate the DPAD data from it.

  • When to data is in the last part of the byte (e.g. 0x05, 0x07), we need a 0x0F mask.
  • When to data is in the first part of the byte (e.g. 0x50, 0x70), we need a 0xF0 mask.

Example:
DPAD data is provided in "Hat" mode, the values are stored in the 6th byte (aka 0x05, we're counting from 0) of the incoming data.
Values:

  • N = 0x01, NE = 0x02, E = 0x03, SE = 0x04, S = 0x05, SW = 0x06, W = 0x07, NW = 0x08
  • neutral = 0x0F
  • bit-mask = 0x0F
DPAD_MODE                   =   DPAD_HAT  // normal mode
DPad_MASK                   =   0x0F      // mask: 0x0F

VPAD_BUTTON_DPAD_N          =   0x05,0x00 // postion: 0x05, value: 0x00
VPAD_BUTTON_DPAD_NE         =   0x05,0x01 // postion: 0x05, value: 0x01
VPAD_BUTTON_DPAD_E          =   0x05,0x02 // postion: 0x05, value: 0x02
VPAD_BUTTON_DPAD_SE         =   0x05,0x03 // postion: 0x05, value: 0x03
VPAD_BUTTON_DPAD_S          =   0x05,0x04 // postion: 0x05, value: 0x04
VPAD_BUTTON_DPAD_SW         =   0x05,0x05 // postion: 0x05, value: 0x05
VPAD_BUTTON_DPAD_W          =   0x05,0x06 // postion: 0x05, value: 0x06
VPAD_BUTTON_DPAD_NW         =   0x05,0x07 // postion: 0x05, value: 0x07
VPAD_BUTTON_DPAD_Neutral    =   0x05,0x0F // postion: 0x05, value: 0x0F

DPAD 2 bytes with 2 values (Using a Stick as DPAD)

Sometimes the DPAD info is stored like a stick: two bytes, one byte for each axis. When its a digital DPAD, the bytes will mostly have three states: the direction of the axis (up/down or left/right) and a value for the neutral position. Currently its not possible to map a "real" stick with analog values to the DPAD.

(NEUTRAL)              =   X: 0x80 Y: 0x80
(UP) North             =   X: 0x00 Y: 0x80
(RIGHT) East           =   X: 0x80 Y: 0xFF
(DOWN) South           =   X: 0xFF Y: 0x80
(LEFT) West            =   X: 0x80 Y: 0x00

Example 1:
Here is a sample configuration.

  • The data is coming from a digital DPAD, each byte only has three possible value (neutral and the 2 directions)
  • The X Axis (left/right) is on the first byte (0x00). Left = 0x00, Right = 0xFF
  • The Y Axis (up/down) is on the second byte (0x01). Up = 0x00, Down = 0xFF
DPAD_MODE                  =   DPAD_Absolute_2Values

VPAD_BUTTON_DPAD_ABS_UP    =   0x01, 0x00 // byte at postion 0x01 needs to be 0x00
VPAD_BUTTON_DPAD_ABS_DOWN  =   0x01, 0xFF // byte at postion 0x01 needs to be 0xFF
VPAD_BUTTON_DPAD_ABS_LEFT  =   0x00, 0x00 // byte at postion 0x00 needs to be 0x00
VPAD_BUTTON_DPAD_ABS_RIGHT =   0x00, 0xFF // byte at postion 0x00 needs to be 0xFF

Sticks

The WiiU Gamepad has 2 sticks with 2 axis. To map the stick from a hid device to them, you need the following information for each axis of each stick:

  • the position of the byte (counting from 0)
  • the byte value when its in neutral position.
  • the minimum and maxmimum value of the byte
  • (optional) the size of the deadzone. (Whats the minimum the values has to change to be recognized as an actual input)
  • (optional) is the axis inverted.

When you have these values, you can fill the config file. You need to set the values for each axis seperatly.

Left Stick X-Axis       =   VPad_L_Stick_X
Left Stick Y-Axis       =   VPad_L_Stick_Y
Right Stick X-Axis      =   VPad_R_Stick_X
Right Stick Y-Axis      =   VPad_R_Stick_Y

Setting the postion, and neutral value

The lines for setting the byte postion + neutral value is this:

VPad_L_Stick_X          =   [position],[neutral value] //left stick x Axis
VPad_L_Stick_Y          =   [position],[neutral value] //left stick y Axis
VPad_R_Stick_X          =   [position],[neutral value] //right stick x Axis
VPad_R_Stick_Y          =   [position],[neutral value] //right stick y Axis

Example:

VPad_L_Stick_X          =   0x03,0x80 //leftstick x Axis

Setting the min/max value

The lines for setting the min/max value is this:

VPad_L_Stick_X_MinMax   =   [min value],[max value] //left stick X Axis
VPad_L_Stick_Y_MinMax   =   [min value],[max value] //left stick Y Axis
VPad_R_Stick_X_MinMax   =   [min value],[max value] //right stick x Axis
VPad_R_Stick_Y_MinMax   =   [min value],[max value] //right stick x Axis

Example:

VPad_R_Stick_Y_MinMax   =   0x00,0xFF //right stick x Axis

Setting the deadzone (optional)

The lines for setting the deadzone is this:

VPad_L_Stick_X_Deadzone =   [deazone size] //left stick X Axis
VPad_L_Stick_Y_Deadzone =   [deazone size] //left stick Y Axis
VPad_R_Stick_X_Deadzone =   [deazone size] //right stick X Axis
VPad_R_Stick_Y_Deadzone =   [deazone size] //right stick Y Axis

Example:

VPad_L_Stick_Y_Deadzone =   0x09 //left stick Y Axis

When you need to know what value you should use: Thats depends on your actual gamepad. The deadzone is the value how much the stick can move before its getting recognized as a real movement.
Example: you have a stick that has this values:

Value in neutral position: 0x80, Min: 0x00, Max 0xFF

By the time the stick gets older and the stick produces other values than 0x80 in neutral position (probably 0x82, 0x89 or 0x74).
This leads to "random" movements even when the stick is not touched.
To ignore this, you can set the deadzone. When the deadzone is set to 0x0F and the neutral postion is 0x80, everything between 0x70 and 0x90 will be handled as no movement (ignored).
You can use HID-TEST to see the values of you gamepad. Move the sticks arround and try to get different values for the neutral position in both directions. Then calculate the deadzone.

Invert a Axis of a Stick (optional)

The lines for inverting a Axis is this:

VPad_L_Stick_X_Invert   =   [true/false] //left stick X Axis
VPad_L_Stick_Y_Invert   =   [true/false] //left stick Y Axis
VPad_R_Stick_X_Invert   =   [true/false] //right stick X Axis
VPad_R_Stick_Y_Invert   =   [true/false] //right stick Y Axis

Example:

VPad_R_Stick_Y_Invert   =   true         //invert right stick Y Axis
VPad_R_Stick_X_Invert   =   false        //don't invert right stick Y Axis

Complete Stick example:

//Thumbsticks
VPad_L_Stick_X          =   0x03,0x80 // postion: 0x03, neutral value: 0x80
VPad_L_Stick_X_MinMax   =   0x00,0xFF // min value: 0x00, max value: 0xFF
VPad_L_Stick_X_Deadzone =   0x0A      // deadzone: 0x0A

VPad_L_Stick_Y          =   0x04,0x80 // postion: 0x04, neutral value: 0x80
VPad_L_Stick_Y_MinMax   =   0x00,0xFF // min value: 0x00, max value: 0xFF
VPad_L_Stick_Y_Deadzone =   0x0A      // deadzone: 0x0A
VPad_L_Stick_Y_Invert   =   True      //invert Y-Axis

VPad_R_Stick_X          =   0x02,0x80 // postion: 0x02, neutral value: 0x80
VPad_R_Stick_X_MinMax   =   0x00,0xFF // min value: 0x00, max value: 0xFF
VPad_R_Stick_X_Deadzone =   0x0A      // deadzone: 0x0A

VPad_R_Stick_Y          =   0x01,0x80 // postion: 0x01, neutral value: 0x80
VPad_R_Stick_Y_MinMax   =   0x00,0xFF // min value: 0x00, max value: 0xFF
VPad_R_Stick_Y_Deadzone =   0x0A      // deadzone: 0x0A
VPad_R_Stick_Y_Invert   =   True      //invert Y-Axis

Using buttons to emulate the sticks

It's also possible to map buttons (for example the DPAD) to a stick

VPAD_L_STICK_UP =       0x01,           0x01
VPAD_L_STICK_DOWN =     0x01,           0x02
VPAD_L_STICK_LEFT =     0x01,           0x04
VPAD_L_STICK_RIGHT =    0x01,           0x08

VPAD_R_STICK_UP =       0x02,           0x01
VPAD_R_STICK_DOWN =     0x02,           0x02
VPAD_R_STICK_LEFT =     0x02,           0x04
VPAD_R_STICK_RIGHT =    0x02,           0x08

The device is sending informations for 2 or more pads

Some adapters has 2 ports and support mutiple controllers at the same time (the DualShock 1&2 Adapter, official GC-Adpater and maybe more). The dualshock 1/2 adapter is sending the information for each port alternating, with information about the port in the first byte.

HID 01 80 80 64 80 0F 00 00 // inputdata from port 1
HID 02 7F 7F 7F 7F 0F 00 00 // inputdata from port 2
HID 01 80 80 64 80 0F 00 00 // inputdata from port 1
HID 02 7F 7F 7F 7F 0F 00 00 // inputdata from port 2

Now we have two options:

  • Using only the information from one slot (old method)
  • Use each slot as a new controller

Use each slot as a new controller

At first, we need to tell the system, that this device could have (for example) two controllers.

PAD_COUNT=2 //This device has the information for 2 controllers.

Of course also other values are possible, if the device has slot for 3 or more controllers. Currently the maximum is 5.
For each controller we want to use, we need to write one rule, which acts like a filter.

PAD1_FILTER=0x00,0x01
PAD2_FILTER=0x00,0x02

The first value is the postion of the byte we're looking at, the second value is value we want.
After applying the filter, we get this input data for pad 1

HID 01 80 80 64 80 0F 00 00 // input data from port 1
HID 01 80 80 64 80 0F 00 00 // input data from port 1

And get this input data for pad 2

HID 02 7F 7F 7F 7F 0F 00 00 // inputdata from port 2
HID 02 7F 7F 7F 7F 0F 00 00 // inputdata from port 2

Filter to use only one slot (old method)

In this case we only want the data from one of the ports. To do this, a filter can be applied.
We only want to look at the inputdata, when the first byte is "0x01". This way to only read the data from one port.
This can be accomplished through the "INPUT_FILTER=x,x" line. In this example the following line would do the job.

INPUT_FILTER=0x00,0x01

The first value is the postion of the byte we're looking at, the second value is value we want.
After applying the filter, we only get this inputdata

HID 01 80 80 64 80 0F 00 00 // inputdata from port 1
HID 01 80 80 64 80 0F 00 00 // inputdata from port 1

Examples

You can find examples in the controller_patcher_configs repository. Most of the files should have helpful comments