The Xbox 360 controller has become the defacto standard controller in PC gaming in recent years, likely due to both the popularity of the Xbox and the fact that the controller can easily be used with a computer. One downside of this is that some games assume you have one. If the game supports it and is running through Steam, then Steam's controller settings will let you use any controller, but that doesn't work for all games, and you might not be using Steam. The game that prompted this blog post actually does have Steam controller support promised in the future, but it's in early access and they are busy developing other parts of the game.1
The solution is
xboxdrv, the userspace
Xbox controller driver. In addition to supporting actual Xbox
controllers, it can also simulate Xbox controllers based on inputs from
other devices like a PlayStation controller or some less
Just do something like
#!/bin/sh echo -n "Press a button on the PSOne controller... " evdev="$($(dirname "$0")/identify_evdev.py)" echo using device "$evdev". xboxdrv --evdev "$evdev" \ --evdev-absmap ABS_X=x1,ABS_Y=y1,ABS_RZ=x2,ABS_Z=y2 \ --axismap -Y1=Y1,Y2=X2,-X2=Y2 \ --evdev-keymap BTN_TOP=x,BTN_TRIGGER=y,BTN_THUMB2=a,BTN_THUMB=b,BTN_BASE3=back,BTN_BASE4=start,BTN_BASE=lb,BTN_BASE2=rb,BTN_TOP2=lt,BTN_PINKIE=rt,BTN_BASE5=tl,BTN_BASE6=tr,BTN_DEAD=dl,KEY_#300=du,KEY_#301=dr,KEY_#302=dd \ --mimic-xpad --silent --quiet
and you're done. Easy, right?
Well, no. The first few lines are a pretty straightforward use of identify_evdev.py to discover the right device to use. But the big lists of axis and button mappings are not at all obvious and depend on your actual controller setup. So I made a script for generating them.
Generating button maps
create_xboxdrv_evdev_map.py generates that
command by listing the Xbox buttons and axes and asking the user to
touch the corresponding button or axis on their controller, just
like you would expect in any input configuration screen. The code is
implemented in Python using the
evdev library and is well
To use it, just run the command and follow the directions. When done,
the final line output will be an invocation of
xboxdrv that you
can save and run any time you want to use that controller:
$ git clone https://github.com/dperelman/gamepad-util.git $ gamepad-util/create_xboxdrv_evdev_map.py Press any button on only the joystick you are setting up. Selected event device: /dev/input/event22 Stop pressing any buttons. Press the corresponding button on your controller. If the button doesn't exist, press the start button again to ignore it. Press start: BTN_START Press back (or select): BTN_SELECT Press guide (large center button): (none) ... Press trigger lt (left analog trigger (L or L2 button)) all the way: ABS_Z Press trigger rt (right analog trigger (R or R2 button)) all the way: ABS_RZ xboxdrv --evdev "/dev/input/event22" --evdev-keymap "BTN_A=a,BTN_B=b,BTN_TL=lb,BTN_THUMBR=tr,BTN_SELECT=back,BTN_START=start,BTN_THUMBL=tl,BTN_TR=rb,BTN_WEST=y,BTN_NORTH=x" --evdev-absmap "ABS_RZ=rt,ABS_RY=y2,ABS_RX=x2,ABS_Z=lt,ABS_Y=y1,ABS_X=x1" --axismap "-y2=y2,-y1=y1" --mimic-xpad --silent
One of the most confusing parts of figuring out how to generate these
mappings was the y-axis.
jstest was showing one thing
and the debug output from
xboxdrv was showing a different value,
which made no sense:
$ sudo xboxdrv --detach-kernel-driver --mimic-xpad ... X1: -2288 Y1:-32768 X2: -2879 Y2: 887 du:0 dd:0 dl:0 dr:0 back:0 guide:0 start:0 TL:0 TR:0 A:0 B:0 X:0 Y:0 LB:0 RB:0 LT: 0 RT: 0 $ jstest /dev ... Axes: 0: -2178 1: 32767 2:-32767 3: 0 4: 0 5:-32767 6: 0 7: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off
The differences between the
xboxdrv and axis
jstest can be explained by them simply printing at different times
as the joystick was still moving. On the other hand,
Y1 as -32768 while
jstest shows axis
1 as 32767. Even though
the two clearly change together, they are always opposite.
Eventually I solved the mystery by delving into the source code of
xboxdrv: it inverts the y-axis just before emitting
it to uinput, but after it prints the value to the screen. Which is why
create_xboxdrv_evdev_map.py asks for the y-axis in reverse order: as a
simple way of inverting it back.
Non-standard key names
Some of the buttons mapped have names, albeit weird ones like
while others just have numbers like
KEY_#300. The names are listed in
input.h in the Linux kernel, and there are some numbers
that lack corresponding names like 300 which is
0x12c in hexadecimal.
xboxdrv works around that by supporting the
format so it can reference unnamed buttons.
There is a kernel driver for Xbox controllers called
which has different default mappings. All of the
invocations in this blog post use
--mimic-xpad to make
xpad which some games expect. When using
with an actual Xbox controller, the command to run is
$ sudo xboxdrv --silent --detach-kernel-driver --mimic-xpad
--silent disables debugging output and
xpad isn't also handling the controller.