Skip to main content

TDU2 Input Device Profiles

Source: TDU2 modding workspace notes.

TDU2 input profiles are JSON keymaps compiled to binary .xmb device profiles. The game reads the XMB; the JSON is the editable source. Profiles exist here for Xbox 360, Fanatec, Razer, and keyboard/mouse.

JSON structure​

Every value is wrapped in a typed object. Do not flatten or remove the wrappers, the game parser requires them.

{
"_PrimitiveType": "UINT8",
"Value": 0
}

Types in use: UINT8, UINT16, UINT32, BOOL, STRING.

Top-level keys​

KeyMeaning
FileVersionProfile format version.
FFBForce feedback.
VibrationsLevelVibration strength.
SteeringLinearitySteering response curve.
SpeedFactorSpeed influence.
SteeringDampingSteering damping.
DeadZoneCentre deadzone applied by the game.
ThrottleLinearityThrottle response curve.
BrakeLinearityBrake response curve.
ClutchLinearityClutch response curve.
KeyMap[]Array of action-to-channel bindings.

KeyMap entry fields​

FieldMeaning
ActionNameThe action being bound (for example CAR_ACCEL).
ChannelNameThe device channel, for example BUTTON_4.
ChannelNameANDSecondary channel for combined bindings.
ChannelLocNameFrench display string (the game's original locale). Changing it has no functional effect.
DevInstanceHIDDevice instance HID data (see below).
DevTypeDevice type.
DevSubTypeDevice subtype.
DevIndiceDevice index.
InvertedInvert the axis.
CombinedCombined binding flag.

Device identification​

A device is identified by DevType / DevSubType plus the DevInstanceHID values.

DeviceDevTypeDevSubTypeDevInstanceHID Data1HID4 (bytes 2-7)
Xbox 360 pad23274183038750 49 44 56 49 44 00 00 ("PIDVID")
Generic joystick (Fanatec)222667691950 49 44 56 49 44 00 00
Keyboard/mouse001864182625BF C7 44 45 53 54 00 00 ("DEST")

The HID4 bytes decode to ASCII: 50 49 44 56 49 44 is "PIDVID" and 44 45 53 54 is "DEST".

The Fanatec GT DD Pro exposes two HID variants for native versus compatibility mode (Data1: 2100919 versus 4198071). Match the HID to the exact device mode.

Channel names​

GroupChannels
ButtonsBUTTON_0 through BUTTON_18 (0-indexed)
D-PadUP, DOWN, LEFT, RIGHT
POV hatPOV_0_LEFT, POV_0_RIGHT, and so on
SticksSTICK_0_UP, STICK_0_DOWN, STICK_0_LEFT, STICK_0_RIGHT, STICK_1_*
SlidersSLIDER_1_BACKWARD
UnboundChannelName = "" with all HID and DevType fields zeroed

Common actions​

CAR_ACCEL, CAR_BRAKE, CAR_CLUTCH, CAR_LEFT, CAR_RIGHT, CAR_HBRAKE, CAR_GUP/CAR_GDOWN (gear up/down), CAR_G1ST–CAR_G7TH (individual gears), CAR_GREV (reverse), CAR_CAMERA, CAR_BACKVIEW, CAR_LIGHT, CAR_HORN, CAR_WINDOWS, MAP, MAP_CURSOR_ZOOMIN/ZOOMOUT, BACK_ON_TRACK, RADIO_VOL_MORE/LESS, CAR_LEFT_BLINKER, CAR_RIGHT_BLINKER.

Workflow: XMB → JSON → edit → XMB​

  1. Original .xmb files are binary device profiles shipped with the game.
  2. Export to JSON via TDU2Emploder.
  3. Edit the JSON profile.
  4. Re-import the edited JSON via TDU2Emploder and export as .xmb.
  5. Place the .xmb in the game's Input Devices directory.

JSON files in the workspace are the editable exports of the XMB originals. DeviceX360Pad.xmb is the binary that corresponds to xbox360_fixed.json.

DevicesPC mapping​

The game maps USB hardware IDs to XMB profiles through DevicesPC.ini. The line format is:

HIDDefaultConfig = "ProductIDVendorID-0-0-00-504944564944" "Device Name" "DeviceName.xmb"
  • Data1 in the XMB is the hex ProductIDVendorID (for example 0x1970EB7 = 26,676,919 for the generic Fanatec joystick).
  • Data4 is the ASCII \0\0PIDVID = [0, 0, 80, 73, 68, 86, 73, 68].

Unsupported wheels fall through to default_kb, which has deadzone=5. This is the root cause of centre-deadzone complaints.

Adding a new wheel​

  1. Find the wheel's USB PID/VID (Windows Device Manager → Properties → Hardware IDs).
  2. Add a HIDDefaultConfig entry to DevicesPC.ini.
  3. Re-encrypt it:
./tdudec e DevicesPC.ini DevicesPC.cpr 1
  1. Export the XMB via TDU2Emploder, edit the JSON profile, and re-import as XMB.
  2. Place the XMB in the game's Input Devices directory.

tdudec versus TDU2Emploder​

Different tools, different jobs:

  • TDU2Emploder: XMB ↔ JSON conversion for control profiles.
  • tdudec: decrypt/encrypt .cpr config files such as DevicesPC and Physics. Uses XTEA type 1 encryption for .cpr files.

Case study: Fanatec GT DD Pro​

USB IDs: native mode 0EB7:0020 (Data1 = 2100919), compatibility mode 0EB7:0040 (Data1 = 4198071). DevType = 2, DevSubType = 2.

Button mapping (from hid-fanatecff ftec_keymap[], custom_button_mapping=true):

HID ButtonPhysical ButtonTDU2 channel
0x01SquareBUTTON_0
0x02CrossBUTTON_1
0x03CircleBUTTON_2
0x04TriangleBUTTON_3
0x05Right paddle (gear up)BUTTON_4
0x06Left paddle (gear down)BUTTON_5
0x07R2BUTTON_6
0x08L2BUTTON_7
0x09Share/OptionsBUTTON_8
0x0aCreate/TouchpadBUTTON_9
0x0bR3BUTTON_10
0x0cL3BUTTON_11

The D-Pad is reported as a POV/hat switch (POV_0_*), not as button indices.

Profile mapping (sensible defaults, subject to revision):

ActionBinding
Gear upBUTTON_4 (right paddle)
Gear downBUTTON_5 (left paddle)
HandbrakeBUTTON_1 (Cross)
CameraBUTTON_3 (Triangle)
Back viewBUTTON_2 (Circle)
LightsBUTTON_0 (Square)
HornBUTTON_8 (Share)
MapBUTTON_9 (Options)
Back on trackBUTTON_10 (R3)
ReverseBUTTON_11 (L3)
WindowsPOV_0_LEFT
Radio channelPOV_0_RIGHT
Radio volume ±POV_0_UP / POV_0_DOWN

Blinkers stay on the keyboard, because the D-Pad is fully allocated. Individual gears (CAR_G1ST–CAR_G6TH) are unbound; the DD Pro uses sequential paddles.

Autodetect crash: a known TDU2 bug. "Detect Device" only works for wheels supported at launch (G25, G27, Porsche 911 Turbo S, and others). The DD Pro was not supported. Fanatec wheels expose multiple HID interfaces (native + compat + Col02), and TDU2 crashes while enumerating them. Workaround: build the profile manually via DevicesPC.ini and skip autodetect entirely. If the game freezes on startup with the wheel plugged in, disable the secondary HID device in Windows Device Manager (HID\VID_0EB7&PID_0004&REV_0474&Col02).

Sources for this case study: hid-fanatecff (gotzl/hid-fanatecff), Steam discussions, GameFAQs, and TurboDuck.net.

Case study: Razer Wolverine V2​

USB ID: 1532:0a29 (XInput, DevType = 2, DevSubType = 3). Same bindings as the Xbox 360 profile, with tuned settings.

Firmware deadzone bug: the Wolverine V2 hard-codes a roughly 15-20% deadzone in firmware that cannot be disabled on Linux, because the Razer Controller Setup app is Windows-only. The profile uses DeadZone=0 so the game deadzone does not stack on top. A companion userspace evdev daemon that rescales the stick axes to compensate is used alongside the profile.

DevicesPC.ini entry: 0A291532-0-0-00-504944564944 maps to DeviceRazerWolverineV2Pad.xmb.

Gotchas​

  • ChannelLocName is the French display string from the game's original locale. Changing it has no functional effect.
  • remap_360.py has a hardcoded input path that points at the author's own machine; update it before running.
  • xbox360_fixed.json and RazerWolverineV2.json share button bindings but differ in tuning settings (DeadZone, BrakeLinearity, SteeringLinearity, SteeringDamping, ThrottleLinearity).
  • Unbound actions use zeroed HID fields (all 0) with an empty ChannelName.
  • remap_360.py only adds missing D-Pad bindings; it does not touch existing button assignments (idempotent check via has_controller()).