Gamepad
Many gamepads are working out-of-the-box nowadays, but there are still many potential problems and sources for errors since gamepad support in applications varies by a lot.
Linux has two different input systems for gamepads – the original Joystick interface and the newer evdev-based interface.
/dev/input/jsX
maps to the Joystick API interface and /dev/input/event*
maps to the evdev ones (this also includes other input devices such as mice and keyboards). Symbolic links to those devices are also available in /dev/input/by-id/
and /dev/input/by-path/
where the legacy Joystick API has names ending with -joystick
while the evdev have names ending with -event-joystick
.
Most new games will default to the evdev interface as it gives more detailed information about the buttons and axes available and also adds support for force feedback.
While SDL1 defaults to evdev interface you can force it to use the old Joystick API by setting the environment variable SDL_JOYSTICK_DEVICE=/dev/input/js0
. This can help many games such as X3. SDL2 supports only the new evdev interface.
Installation
Unless you are using very old joystick that uses Gameport or a proprietary USB protocol, you will need just the generic USB Human Interface Device (HID) modules.
For an extensive overview of all joystick related modules in Linux, you will need access to the Linux kernel sources — specifically the Documentation section. Unfortunately, official kernel packages do not include what we need. If you have the kernel sources downloaded, have a look at Documentation/input/joydev/
. You can browse the kernel source tree at kernel.org by clicking the "browse" (cgit - the git frontend) link for the kernel that you are using, then clicking the "tree" link near the top. Alternatively, see documentation from the latest kernel.
Some joysticks need specific modules, such as the Microsoft Sidewinder controllers (sidewinder
), or the Logitech digital controllers (adi
). Many older joysticks will work with the simple analog
module. If your joystick is plugging in to a gameport provided by your soundcard, you will need your soundcard drivers loaded — however, some cards, like the Soundblaster Live, have a specific gameport driver (emu10k1-gp
). Older ISA soundcards may need the ns558
module, which is a standard gameport module.
As you can see, there are many different modules related to getting your joystick working in Linux, so everything is not covered here. Please have a look at the documentation mentioned above for details.
Loading the modules for analogue devices
You need to load a module for your gameport (ns558
, emu10k1-gp
, cs461x
, etc...), a module for your joystick (analog
, sidewinder
, adi
, etc...), and finally the kernel joystick device driver (joydev
). You can load the module at boot, or simply modprobe it. The gameport
module should load automatically, as this is a dependency of the other modules.
USB gamepads
You need to get USB working, and then modprobe your gamepad driver, which is usbhid
, as well as joydev
.
If you use a usb mouse or keyboard, usbhid
will be loaded already and you just have to load the joydev
module.
lsusb
but it will not show up as an input device in /dev/input/js*
, see #Xbox 360 controller.Configuration
Testing
Once the modules are loaded, you should be able to find a new device: /dev/input/js0
and a file ending with -event-joystick
in /dev/input/by-id
directory. You can simply cat
those devices to see if the joystick works — move the stick around, press all the buttons - you should see mojibake printed when you move the sticks or press buttons.
If you get a permission error, see #Device permissions.
Both interfaces are also supported in Wine and reported as separate devices. You can test them (including vibration feedback) with wine control joy.cpl
.
Joystick API
There are a lot of applications that can test this old API, jstest
from the joyutils package is the simplest one. If the output is unreadable because the line printed is too long you can also use graphical tools. KDE Plasma has a built in one in System Settings > Input Devices > Game Controller. There is jstest-gtk-gitAUR as an alternative.
Use of jstest
is fairly simple, you just run jstest /dev/input/js0
and it will print a line with state of all the axes (normalised to {-32767,32767}
) and buttons.
After you start jstest-gtk
, it will just show you a list of joysticks available, you just need to select one and press Properties.
evdev API
The new 'evdev' API can be tested using the SDL2 joystick test application or using evtest
from evtest or evtest-qt
from evtest-qt-gitAUR. Install sdl-jstest-gitAUR and then run sdl2-jstest --test 0
. Use sdl2-jstest --list
to get IDs of other controllers if you have multiple ones connected.
To test force feedback on the device, use fftest
from linuxconsole:
$ fftest /dev/input/by-id/usb-*event-joystick
HTML5 Gamepad API
Go to https://gamepad-tester.com/. Currently, testing vibration and producing a visual of the gamepad is supported in Chromium but not Firefox. Additionally, as of version 107.0.5304.121-1, Chromium can read Joystick devices but not evdev.
Setting up deadzones and calibration
If you want to set up the deadzones (or remove them completely) of your analog input you have to do it separately for the xorg (for mouse and keyboard emulation), Joystick API and evdev API.
Wine deadzones
Add the following registry entry and set it to a string from 0
to 10000
(affects all axes):
HKEY_CURRENT_USER\Software\Wine\DirectInput\DefaultDeadZone
Source: Useful Registry Keys
Xorg deadzones
Add a similar line to /etc/X11/xorg.conf.d/51-joystick.conf
(create if it does not exist):
/etc/X11/xorg.conf.d/51-joystick.conf
Section "InputClass" Option "MapAxis1" "deadzone=1000" EndSection
1000
is the default value, but you can set anything between 0
and {{30000
. To get the axis number see the "Testing Your Configuration" section of this article.
If you already have an option with a specific axis just type in the deadzone=value
at the end of the parameter separated by a space.
Joystick API deadzones and calibration
The easiest way is using jstest-gtk from jstest-gtk-gitAUR. Select the joystick you want to edit, click the Properties button. On this new window, click the Calibration button (do not click Start Calibration after that). You can then set the CenterMin
and CenterMax
values, which control the center deadzone, and RangeMin
and RangeMax
, which control the end of throw deadzones. Note that the calibration settings are applied when the application opens the device, so you need to restart your game or test application to see updated calibration settings.
After you set the deadzones, you also can create an udev rule to make all changes permanent:
First, grab the vendor id of your joystick (replace X
with your joystick's number, it is usually 0
):
$ udevadm info -q property --property ID_VENDOR_ID --value /dev/input/jsX
Also grab the model id:
$ udevadm info -q property --property ID_MODEL_ID --value /dev/input/jsX
If the commands above give you an empty output, it could be because your controller is connected via Bluetooth, making these unique attributes only visible on the parent device(s). To mitigate this, you could try finding other unique attributes by running:
$ udevadm info -a /dev/input/jsX
This will list all available attributes from your device (and parent devices). So, for example, if the parent device of your joystick has the attribute ATTRS{uniq}=="a0:b1:c2:d3:e4:f5"
, or maybe both ATTRS{idVendor}=="054c"
and ATTRS{idProduct}=="09cc"
, then you can use these instead of ENV{ID_VENDOR_ID}
and ENV{ID_MODEL_ID}
in the udev rule below.
You can also have both rules at the same time, just separate them with a new line.
Anyway, now use jscal to dump the new calibration settings of your joystick:
$ jscal -p /dev/input/jsX
Now, modify this udev rule with the values you got:
/etc/udev/rules.d/85-jscal-custom-calibration.rules
ACTION=="add", KERNEL=="js[0-9]*", ENV{ID_VENDOR_ID}=="054c", ENV{ID_MODEL_ID}=="09cc", RUN+="/usr/bin/jscal -s 1,1,1,1 /dev/input/js%n"
This rule will automatically run /usr/bin/jscal -s 1,1,1,1 /dev/input/js%n
whenever you connect a joystick with vendor id 054c
and model id 09cc
. The /dev/input/js%n
part is required to automatically determine the correct joystick, so do not remove it.
Finally, load this new udev rule.
evdev API deadzones and calibration
The evdev-joystick tool from the linuxconsole package can be used to view and change deadzones and calibration for evdev
API devices.
To view your device configuration:
$ evdev-joystick --showcal /dev/input/by-id/usb-*-event-joystick
To change the deadzone for a particular axis, use a command like:
$ evdev-joystick --evdev /dev/input/by-id/usb-*-event-joystick --axis 0 --deadzone 0
To set the same deadzone for all axes at once, omit the --axis 0
option.
Use udev rules file to set them automatically when the controller is connected.
Note that inside the kernel, the value is called flatness
and is set using the EVIOCSABS
ioctl
.
Default configuration will look like similar to this:
$ evdev-joystick --showcal /dev/input/by-id/usb-Madcatz_Saitek_Pro_Flight_X-55_Rhino_Stick_G0000090-event-joystick
Supported Absolute axes: Absolute axis 0x00 (0) (X Axis) (min: 0, max: 65535, flatness: 4095 (=6.25%), fuzz: 255) Absolute axis 0x01 (1) (Y Axis) (min: 0, max: 65535, flatness: 4095 (=6.25%), fuzz: 255) Absolute axis 0x05 (5) (Z Rate Axis) (min: 0, max: 4095, flatness: 255 (=6.23%), fuzz: 15) Absolute axis 0x10 (16) (Hat zero, x axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0) Absolute axis 0x11 (17) (Hat zero, y axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0)
While a more reasonable setting would be achieved with something like this (repeat for other axes):
$ evdev-joystick --evdev /dev/input/by-id/usb-Madcatz_Saitek_Pro_Flight_X-55_Rhino_Stick_G0000090-event-joystick --axis 0 --deadzone 512
Event device file: /dev/input/by-id/usb-Madcatz_Saitek_Pro_Flight_X-55_Rhino_Stick_G0000090-event-joystick Axis index to deal with: 0 New dead zone value: 512 Trying to set axis 0 deadzone to: 512 Absolute axis 0x00 (0) (X Axis) Setting deadzone value to : 512 (min: 0, max: 65535, flatness: 512 (=0.78%), fuzz: 255)
Virtual xboxdrv gamepad deadzones and calibration
It is possible to use xboxdrv to present your gamepad as a virtual xbox360 gamepad, while handling the axis calibration and deadzones.
Imagine that you tested your gamepad with evtest-qt, and find out that your left joystick cannot reach the maximum read value when you direct it to top most position. The side effect of this is that in some games (for example, HITMAN 2) the character cannot run.
Run xboxdrv and determine how the problematic axis is called. In this case it is Y1
. Now try to direct it to top most position several times, and determine the lowest value that you saw. Imagine it is 29426
. Now to be on a safe side, we take the value that is lower than that, like 29000
. Run the command:
# xboxdrv --detach-kernel-driver --calibration Y1=-32767:128:29000
This will translate the values of your real gamepad from 128
(center) to 29000
(max readable value on top) of Y1
axis to the ideal values of virtual gamepad.
Nice thing about xboxdrv is that it exports resulting device as both old Joystick API and new style evdev API so it should be compatible with basically any application. You can now see in jstest that the values of axis 1
(corresponds to vertical axis of left joystick) is read from 0
to -32767
, and in evtest-qt that you can reach the maximum value. And your character in game can run.
Configuring curves and responsiveness
In case your game requires just limited amount of buttons or has good support for multiple controllers, you may have good results with using xboxdrv to change response curves of the joystick.
Below are example setups for Saitek X-55 HOTAS:
$ xboxdrv --evdev /dev/input/by-id/usb-Madcatz_Saitek_Pro_Flight_X-55_Rhino_Throttle_G0000021-event-joystick \ --evdev-no-grab --evdev-absmap 'ABS_#40=x1,ABS_#41=y1,ABS_X=x2,ABS_Y=y2' --device-name 'Hat and throttle' \ --ui-axismap 'x2^cal:-32000:0:32000=,y2^cal:-32000:0:32000=' --silent
this maps the EV_ABS
event with id of 40 and 41 (use xboxdrv with --evdev-debug
to see the events registered), which is the normally inaccessible "mouse pointer" on the throttle, to first gamepad joystick and throttles to second joystick, it also clamps the top and lower ranges as they not always register fully.
A bit more interesting is the setup for the stick:
$ xboxdrv --evdev /dev/input/by-id/usb-Madcatz_Saitek_Pro_Flight_X-55_Rhino_Stick_G0000090-event-joystick \ --evdev-no-grab --evdev-absmap 'ABS_X=x1' --evdev-absmap 'ABS_Y=y1' --device-name 'Joystick' \ --ui-axismap 'x1^cal:-32537:-455:32561=,x1^dead:-900:700:1=,x1^resp:-32768:-21845:-2000:0:2000:21485:32767=' \ --ui-axismap 'y1^cal:-32539:-177:32532=,y1^dead:-700:2500:1=,y1^resp:-32768:-21845:-2000:0:2000:21485:32767=' \ --evdev-absmap 'ABS_RZ=x2' --ui-axismap 'x2^cal:-32000:-100:32000,x2^dead:-1500:1000:1=,x2^resp:-32768:-21845:-2000:0:2000:21485:32767=' \ --silent
this maps the 3 joystick axes to gamepad axes and changes the calibration (min value, centre value, max value), dead zones (negative side, positive side, flag to turn smoothing) and finally change of response curve to a more flat one in the middle.
You can also modify the responsiveness by setting the sen
(sensitivity) parameter. Setting it to value of 0
will give you a linear sensitivity, value of -1
will give very insensitive axis while value of 1
will give very sensitive axis. You can use intermediate values to make it less or more sensitive. Internally xboxdrv uses a quadratic formula to calculate the resulting value, so this setting gives a more smooth result than resp
shown above.
Disable joystick from controlling mouse
If you want to play games with your gamepad, you might want to disable its joystick control over mouse cursor. To do this, edit /etc/X11/xorg.conf.d/51-joystick.conf
(create if it does not exists) so that it looks like this:
/etc/X11/xorg.conf.d/51-joystick.conf
Section "InputClass" Identifier "joystick catchall" MatchIsJoystick "on" MatchDevicePath "/dev/input/event*" Driver "joystick" Option "StartKeysEnabled" "False" Option "StartMouseEnabled" "False" EndSection
Using gamepad to send keystrokes
A couple of programs exist to map gamepad buttons to keyboard keys, including:
- qjoypadAUR
- antimicrox
- sc-controllerAUR
- steam - see Steam#Steam Input
All work well without the need for additional X.org configuration.
Xorg configuration example
This is a good solution for systems where restarting Xorg is a rare event because it is a static configuration loaded only on X startup. The example runs on a Kodi media PC, controlled with a Logitech Cordless RumblePad 2. Due to a problem with the d-pad (a.k.a. "hat") being recognized as another axis, Joy2key was used as a workaround. Since kodi version 11.0 and joy2keyAUR 1.6.3-1, this setup no longer worked and the following was created for letting Xorg handle joystick events.
First, install the xf86-input-joystickAUR package. Then, create an X configuration file:
/etc/X11/xorg.conf.d/51-joystick.conf
Section "InputClass" Identifier "Joystick hat mapping" Option "StartKeysEnabled" "True" #MatchIsJoystick "on" Option "MapAxis5" "keylow=113 keyhigh=114" Option "MapAxis6" "keylow=111 keyhigh=116" EndSection
MatchIsJoystick "on"
line does not seem to be required for the setup to work, but you may want to uncomment it.Remapping of gamepad buttons and more
With some programs you can also configure your gamepad further, including the following potential features:
- Remapping buttons and axes.
- Assigning mapping profiles to different games.
- Emulating a different type of gamepad. As noted in #Mimic Xbox 360 controller, software can often behave better when seemingly given an Xbox 360 Controller, as this is a very common controller that many games have been tested with.
- Additional functionality such as Macros, On-Screen-Displays etc.
List of software:
- SC Controller — Open-source software supporting button remapping and Xbox 360 Controller emulation.
- Steam — Proprietary storefront whose client supports rebinding gamepad inputs via Steam Input. When enabled, Steam exposes a Steam Controller to games that opt into the Steam Input API, as well as an emulated Xbox 360 Controller to games using traditional gamepad APIs. See Steam#Steam Input for further details.
- xboxdrv — Xbox 360 controller driver which supports emulating the controller from a different input controller. Even if you don't have or need (in the sense of #Mimic Xbox 360 controller) a 360 controller, this is still flexible option for performing remapping.
Remapping of gamepad on SDL2 applications
Gamepads can be remapped for SDL2 applications using the SDL_GAMECONTROLLERCONFIG
environment variable. For each line, it includes the gamepad's GUID, a name, button / axis mappings and a platform. The controller's GUID can be retrieved by installing sdl-jstest-gitAUR and then running sdl2-jstest --list
.
For example, to map Microsoft Xbox 360 controllers with different GUIDs:
~/.bashrc
export SDL_GAMECONTROLLERCONFIG=" 030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, "
Some apps extract mapping information from a gamecontrollerdb.txt
file. It can be edited graphically with controllermapAUR. An up to date database can be found on [1].
Specific devices
While most gamepads, especially USB based ones should just work, some may require (or give better results) if you use alternative drivers. If it does not work the first time, do not give up, and read the following sections thoroughly!
Dance pads
Most dance pads should work. However some pads, especially those used from a video game console via an adapter, have a tendency to map the directional buttons as axis buttons. This prevents hitting left-right or up-down simultaneously. This behavior can be fixed for devices recognized by xpad via a module option:
# modprobe -r xpad # modprobe xpad dpad_to_buttons=1
If that did not work, you can try axisfix-gitAUR or patching the joydev
kernel module (https://github.com/adiel-mittmann/dancepad).
Logitech Thunderpad Digital
Logitech Thunderpad Digital will not show all the buttons if you use the analog
module. Use the device specific adi
module for this controller.
Nintendo Gamecube Controller
Dolphin Emulator has a page on their wiki that explains how to use the official Nintendo USB adapter with a Gamecube controller. This configuration also works with the Mayflash Controller Adapter if the switch is set to "Wii U".
For use with steam there is a tool on github that sends the input to steam as a generic controller.
Nintendo Switch Pro Controller and Joy-Cons
Using the kernel Nintendo HID driver
The hid-nintendo kernel HID driver was mainlined in kernel 5.16. If you are using an earlier kernel, you will need to install the DKMS module named hid-nintendo-dkmsAUR[broken link: package not found]. The driver provides support for rumble, battery level, and control of the player and home LEDs. It supports the Nintendo Switch Pro Controller over both USB and Bluetooth in addition to the Joy-Cons.
An alternate DKMS module named hid-nintendo-nso-dkmsAUR patches in support for the Switch Online NES and SNES controllers.
Using joycond userspace daemon
The hid-nintendo kernel driver does not handle the combination of two Joy-Cons into one virtual input device. That functionality has been left up to userspace. joycond-gitAUR is a userspace daemon that combines two kernel Joy-Con evdev devices into one virtual input device using uinput. An application can use two Joy-Cons as if they are a single controller. When the daemon is active, Switch controllers will be placed in a pseudo pairing mode, and the LEDs will start flashing. Holding the triggers can be used to pair controllers and make them usable. To pair two Joy-Cons together, press one trigger on each Joy-Con.
Mimic Xbox 360 controller
Some games and emulators are hardcoded to work with an Xbox 360 controller, and will not work with other controllers. To get around this, you need to create a virtual Xbox 360 controller that emulates the expected interface, but is bound to your controller's inputs. This can be done with Steam Input or xboxdrv.
Use positional layout on SDL2 applications
By default, SDL2 maps buttons on Nintendo controllers according to the gamepad's label instead of the button's position. This is enabled by the SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS setting, which defaults to 1
for controllers known to use the Nintendo button layout,[2] and 0
for other controllers.[3] This behavior can be overridden for all controllers by setting the SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS
environment variable. For example, if Nintendo's conception of A/B and X/Y is undesirable, set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS=0
.
iPEGA-9017s and other Bluetooth gamepads
If you want to use one of the widely available Bluetooth gamepads, such as iPEGA-9017s designed mostly for Android and iOS devices you would need xboxdrvAUR, bluez and bluez-utils. You should connect it in gamepad mode (if there are different modes, choose the gamepad one). Technically it is ready to be used, but in most cases games would not recognize it, and you would have to map it individually for every application. The best way to simplify it and make it work with all applications is to mimic Microsoft X360 controller with xboxdrvAUR. Once connected you can create a udev rule to give it a persistent name, that would come in handy when setting it up.
/etc/udev/rules.d/99-btjoy.rules
#Create a symlink to appropriate /dev/input/eventX at /dev/btjoy ACTION=="add", SUBSYSTEM=="input", ATTRS{name}=="Bluetooth Gamepad", ATTRS{uniq}=="00:17:02:01:ae:2a", SYMLINK+="btjoy"
Replace "Bluetooth Gamepad" with your device name and "00:17:02:01:ae:2a" with your device's address.
Next, create a configuration for xboxdrvAUR somewhere, for example:
~/.config/xboxdrv/ipega.conf
#iPEGA PG-9017S Config [xboxdrv] evdev-debug = true evdev-grab = true rumble = false mimic-xpad = true [evdev-absmap] ABS_HAT0X = dpad_x ABS_HAT0Y = dpad_y ABS_X = X1 ABS_Y = Y1 ABS_Z = X2 ABS_RZ = Y2 [axismap] -Y1 = Y1 -Y2 = Y2 [evdev-keymap] BTN_EAST=a BTN_C=b BTN_NORTH=y BTN_SOUTH=x BTN_TR2=start BTN_TL2=back BTN_Z=rt BTN_WEST=lt BTN_MODE = guide
Refer to xboxdrv(1)[dead link 2023-11-25] to see all the options.
Now when you have the configuration and your device is connected you can start the xboxdrvAUR like so:
# xboxdrv --evdev /dev/btjoy --config .config/xboxdrv/ipega.conf
Your games will now work with bluetooth gamepad as long as xboxdrv is running.
iPEGA-9068 and 9087
For this model, use the same procedures as above, but with the configs:
~/.config/xboxdrv/ipega.conf
#iPEGA PG-9068 and PG-9087 Config [xboxdrv] evdev-debug = true evdev-grab = true rumble = false mimic-xpad = true [evdev-absmap] ABS_HAT0X = dpad_x ABS_HAT0Y = dpad_y ABS_X = X1 ABS_Y = Y1 ABS_Z = X2 ABS_RZ = Y2 [axismap] -Y1 = Y1 -Y2 = Y2 [evdev-keymap] BTN_A=a BTN_B=b BTN_Y=y BTN_X=x BTN_TR=rb BTN_TL=lb BTN_TR2=rt BTN_TL2=lt BTN_THUMBL=tl BTN_THUMBR=tr BTN_START=start BTN_SELECT=back BTN_MODE = guide
Defender X7
For this model, use the same procedures as above, but with the configs:
~/.config/xboxdrv/defender.conf
#Defender x7 xboxdrv config [xboxdrv] evdev-debug = true evdev-grab = true rumble = false mimic-xpad = true [evdev-absmap] ABS_HAT0X = dpad_x ABS_HAT0Y = dpad_y ABS_X = X1 ABS_Y = Y1 ABS_Z = X2 ABS_RZ = Y2 [axismap] -Y1 = Y1 -Y2 = Y2 [evdev-keymap] BTN_EAST=b BTN_NORTH=x BTN_SOUTH=a BTN_WEST=y BTN_TR2=rt BTN_TL2=lt BTN_TR=rb BTN_TL=lb BTN_THUMBL=tl BTN_THUMBR=tr BTN_START=start BTN_SELECT=back BTN_MODE = guide
Now when you have the configuration and your device is connected you can start the xboxdrvAUR like so:
# xboxdrv --evdev /dev/btjoy --config .config/xboxdrv/defender.conf
Stadia Controller
The Stadia controller can also be mapped with xboxdrv:
~/.config/xboxdrv/stadia.conf
# Stadia xboxdrv config [xboxdrv] mimic-xpad=true silent=true [evdev-absmap] ABS_X=x1 ABS_Y=y1 ABS_Z=x2 ABS_RZ=y2 ABS_GAS=rt ABS_BRAKE=lt ABS_HAT0X=dpad_x ABS_HAT0Y=dpad_y [axismap] -y1=y1 -y2=y2 [evdev-keymap] BTN_SOUTH=A BTN_EAST=B BTN_NORTH=X BTN_WEST=Y BTN_START=start BTN_SELECT=back BTN_MODE=guide BTN_THUMBL=tl BTN_THUMBR=tr BTN_TR=rb BTN_TL=lb
Steam Controller
The Steam client will recognize the controller and provide keyboard/mouse/gamepad emulation while Steam is running. The in-game Steam overlay needs to be enabled and working in order for gamepad emulation to work. You may need to run udevadm trigger
with root privileges or plug the dongle out and in again, if the controller does not work immediately after installing and running Steam. If all else fails, try restarting the computer while the dongle is plugged in.
If you are using the controller connected via Bluetooth LE, make sure the user is part of the input
group.
If you cannot get the Steam Controller to work, see #Steam Controller not pairing.
Alternatively you can install python-steamcontroller-gitAUR to have controller and mouse emulation without Steam or sc-controllerAUR for a versatile graphical configuration tool simillar to what is provided by the Steam client.
Wine
python-steamcontroller-gitAUR can also be used to make the Steam Controller work for games running under Wine. You need to find and download the application xbox360cemu.v.3.0
(e.g. from here). Then copy the files dinput8.dll
, xbox360cemu.ini
, xinput1_3.dll
and xinput_9_1_0.dll
to the directory that contains your game executable. Edit xbox360cemu.ini
and only change the following values under [PAD1]
to remap the Steam Controller correctly to a XBox controller.
xbox360cemu.ini
Right Analog X=4 Right Analog Y=-5 A=1 B=2 X=3 Y=4 Back=7 Start=8 Left Thumb=10 Right Thumb=11 Left Trigger=a3 Right Trigger=a6
Now start python-steamcontroller in Xbox360 mode (sc-xbox.py start
). You might also want to copy XInputTest.exe
from xbox360cemu.v.3.0
to the same directory and run it with Wine in order to test if the mappings work correctly. However neither mouse nor keyboard emulation work with this method.
Alternatively you can use sc-controllerAUR for a similar graphical setup as Steam's own configurator. As of writing, it is a bit buggy here and there but offers an easy click and go way of configuring the controller.
Xbox 360 controller
Both the wired and wireless (with the Xbox 360 Wireless Receiver for Windows) controllers are supported by the xpad
kernel module and should work without additional packages. Note that using a wireless Xbox360 controller with the Play&Charge USB cable will not work. The cable is for recharging only and does not transmit any input data over the wire.
It has been reported that the default xpad driver has some issues with a few newer wired and wireless controllers, such as:
- incorrect button mapping. (discussion in Steam bugtracker)
- not-working sync. (discussion in Arch Forum)
- all four LEDs keep blinking, but controller works. TLP's USB autosuspend is one sure cause of this issue with wireless controllers. See below for fix.
If you use the TLP power management tool, you may experience connection issues with your Microsoft wireless adapter (e.g. the indicator LED will go out after the adapter has been connected for a few seconds, and controller connection attempts fail, four LEDs keep blinking but controller works). This is due to TLP's USB autosuspend functionality, and the solution is to add the Microsoft wireless adapter's device ID to TLP blacklist
(to check device ID to blacklist, run tlp-stat -u
; for original MS wireless dongle just add USB_DENYLIST="045e:0719"
to /etc/tlp.conf
),
check TLP configuration for more details.
If you experience such issues, you can use #xboxdrv as the default xpad
driver instead.
If you wish to use the controller for controlling the mouse, or mapping buttons to keys, etc. you should use the xf86-input-joystickAUR package (configuration help can be found using joystick(4)). If the mouse locks itself in a corner, it might help changing the MatchDevicePath
in /etc/X11/xorg.conf.d/50-joystick.conf
from /dev/input/event*
to /dev/input/js*
.
In order to connect via Bluetooth using KDE, add the following kernel parameter bluetooth.disable_ertm=1
.
If you experience problems with the rumble feature not working in games, it may be necessary to set the environment variable SDL_JOYSTICK_HIDAPI=0
xboxdrv
xboxdrv is an alternative to xpad
which provides more functionality and might work better with certain controllers. It works in userspace and can be launched as system service.
Install it with the xboxdrvAUR package. Then start/enable xboxdrv.service
.
If you have issues with the controller being recognized but not working in steam games or working but with incorrect mappings, it may be required to modify you configuration as such:
/etc/default/xboxdrv
[xboxdrv] silent = true device-name = "Xbox 360 Wireless Receiver" mimic-xpad = true deadzone = 4000 [xboxdrv-daemon] dbus = disabled
Then restart xboxdrv.service
.
Multiple controllers
xboxdrv supports a multitude of controllers, but they need to be set up in /etc/default/xboxdrv
. For each extra controller, add an next-controller = true
line. For example, when using 4 controllers, add it 3 times:
[xboxdrv] silent = true next-controller = true next-controller = true next-controller = true [xboxdrv-daemon] dbus = disabled
Then restart xboxdrv.service
.
Mimic Xbox 360 controller with other controllers
xboxdrv can be used to make any controller register as an Xbox 360 controller with the --mimic-xpad
switch. This may be desirable for games that support Xbox 360 controllers out of the box, but have trouble detecting or working with other gamepads.
First, you need to find out what each button and axis on the controller is called. You can use evtest for this. Run evtest
and select the device event ID number (/dev/input/event*
) that corresponds to your controller. Press the buttons on the controller and move the axes to read the names of each button and axis.
Here is an example of the output:
Event: time 1380985017.964843, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003 Event: time 1380985017.964843, type 1 (EV_KEY), code 290 (BTN_THUMB2), value 1 Event: time 1380985017.964843, -------------- SYN_REPORT ------------ Event: time 1380985018.076843, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90003 Event: time 1380985018.076843, type 1 (EV_KEY), code 290 (BTN_THUMB2), value 0 Event: time 1380985018.076843, -------------- SYN_REPORT ------------ Event: time 1380985018.460841, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90002 Event: time 1380985018.460841, type 1 (EV_KEY), code 289 (BTN_THUMB), value 1 Event: time 1380985018.460841, -------------- SYN_REPORT ------------ Event: time 1380985018.572835, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90002 Event: time 1380985018.572835, type 1 (EV_KEY), code 289 (BTN_THUMB), value 0 Event: time 1380985018.572835, -------------- SYN_REPORT ------------ Event: time 1380985019.980824, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90006 Event: time 1380985019.980824, type 1 (EV_KEY), code 293 (BTN_PINKIE), value 1 Event: time 1380985019.980824, -------------- SYN_REPORT ------------ Event: time 1380985020.092835, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90006 Event: time 1380985020.092835, type 1 (EV_KEY), code 293 (BTN_PINKIE), value 0 Event: time 1380985020.092835, -------------- SYN_REPORT ------------ Event: time 1380985023.596806, type 3 (EV_ABS), code 3 (ABS_RX), value 18 Event: time 1380985023.596806, -------------- SYN_REPORT ------------ Event: time 1380985023.612811, type 3 (EV_ABS), code 3 (ABS_RX), value 0 Event: time 1380985023.612811, -------------- SYN_REPORT ------------ Event: time 1380985023.708768, type 3 (EV_ABS), code 3 (ABS_RX), value 14 Event: time 1380985023.708768, -------------- SYN_REPORT ------------ Event: time 1380985023.724772, type 3 (EV_ABS), code 3 (ABS_RX), value 128 Event: time 1380985023.724772, -------------- SYN_REPORT ------------
In this case, BTN_THUMB
, BTN_THUMB2
and BTN_PINKIE
are buttons and ABS_RX
is the X axis of the right analogue stick.
You can now mimic an Xbox 360 controller with the following command:
$ xboxdrv --evdev /dev/input/event* --evdev-absmap ABS_RX=X2 --evdev-keymap BTN_THUMB2=a,BTN_THUMB=b,BTN_PINKIE=rt --mimic-xpad
The above example is incomplete. It only maps one axis and 3 buttons for demonstration purposes. Use xboxdrv --help-button
to see the names of the Xbox controller buttons and axes and bind them accordingly by expanding the command above. Axes mappings should go after --evdev-absmap
and button mappings follow --evdev-keymap
(comma separated list; no spaces).
By default, xboxdrv outputs all events to the terminal. You can use this to test that the mappings are correct. Append the --silent
option to keep it quiet.
Using generic/clone controllers
Some clone gamepads might require a specific initialization sequence in order to work (Super User answer). For that you should run the following python script as the root user:
#!/usr/bin/env python3 import usb.core dev = usb.core.find(idVendor=0x045e, idProduct=0x028e) if dev is None: raise ValueError('Device not found') else: dev.ctrl_transfer(0xc1, 0x01, 0x0100, 0x00, 0x14)
Xbox Wireless Controller / Xbox One Wireless Controller
Connect Xbox Wireless Controller with USB cable
This is supported by the kernel and works without any additional packages.
Connect Xbox Wireless Controller with Bluetooth
Update controller firmware via Windows 10
The firmware of the Xbox Wireless Controller used to cause loops of connecting/disconnecting with Bluez. The best workaround is to plug the controller (via a USB cord) to a Windows 10 computer, download the Xbox Accessories application through the Microsoft Store, and update the firmware of the controller.
xpadneo
A relatively new driver which does support the Xbox One S and Xbox Series X|S controller via Bluetooth is called xpadneo. In addition to these two models, it has also basic support for the Xbox Elite Series 2 Wireless controller. In exchange for fully supporting just two controllers so far, it enables one to read out the correct battery level, supports rumble (even the one on the trigger buttons - L2/R2), corrects the (sometimes wrong) button mapping and more.
Installation is done using DKMS: xpadneo-dkmsAUR.
Connect Xbox Wireless Controller with Microsoft Xbox Wireless Adapter
xone
xone is a Linux kernel driver for Xbox One and Xbox Series X|S accessories. It serves as a modern replacement for xpad, supersedes xow. Currently working via wired or with the wireless dongle. This driver is still in active development.
Install xone-dkms-gitAUR and, if using the wireless dongle, xone-dongle-firmwareAUR. Reboot your system.
If the controller performs poorly (low polling rate) after being paired, you will need to update the controller's firmware in Windows using the "Xbox Accessories" app from the Microsoft Store. Theoretically this should be possible with USB passthrough to a Windows virtual machine, but you may need to dual boot to an actual (baremetal) Windows installation for the Xbox Accessories application to see the controller and do the firmware update.
Also, if you dual boot Windows, pairing the controller & adapter in Windows may cause the pairing to be lost in Linux. You will need to re-pair the controller & dongle when you reboot into Linux. This also happens in the other direction — when the controller & dongle are paired in Linux, they will need to be re-paired the next time you want to use them in Windows.
Logitech Dual Action
The Logitech Dual Action gamepad has a very similar mapping to the PS2 pad, but some buttons and triggers need to be swapped to mimic the Xbox controller.
# xboxdrv --evdev /dev/input/event* \ --evdev-absmap ABS_X=x1,ABS_Y=y1,ABS_RZ=x2,ABS_Z=y2,ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y \ --axismap -Y1=Y1,-Y2=Y2 \ --evdev-keymap BTN_TRIGGER=x,BTN_TOP=y,BTN_THUMB=a,BTN_THUMB2=b,BTN_BASE3=back,BTN_BASE4=start,BTN_BASE=lt,BTN_BASE2=rt,BTN_TOP2=lb,BTN_PINKIE=rb,BTN_BASE5=tl,BTN_BASE6=tr \ --mimic-xpad --silent
PlayStation 2 controller via USB adapter
To fix the button mapping of PS2 dual adapters and mimic the Xbox controller you can run the following command:
# xboxdrv --evdev /dev/input/event* \ --evdev-absmap ABS_X=x1,ABS_Y=y1,ABS_RZ=x2,ABS_Z=y2,ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y \ --axismap -Y1=Y1,-Y2=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 \ --mimic-xpad --silent
PlayStation 3 controller
Pairing via USB
If you own a PS3 controller and can connect with USB, plug it to your computer and press the PS button. The controller will power up and one of the four LEDs should light up indicating the controller's number.
Pairing via Bluetooth
Install bluez and bluez-utils. Make sure bluetooth is working by following the first five steps of Bluetooth#Pairing and leave the bluetoothctl command running, then turn on the controller by pressing the middle 'PS' button(all 4 leds should be blinking quickly ~4 hz) and connect to your computer using usb. Lastly, type yes in the bluetoothctl prompt when asked 'Authorize service 00001124-0000-1000-8000-00805f9b34fb (yes/no)
'.
Alternative instructions: To connect your PS3 controller to your computer using Bluetooth, you first need to install bluez and then connect your controller via USB. A pop-up should appear asking for pairing. Click on Trust & Authorize. You can now unplug your controller and press the PS button. The controller will connect and a LED will remain solid. You can now use it to play games. Connecting using the USB cable is only needed after the controller has been connected to another system.
In the latest version of bluez (as of 2024/01/03), the default value for ClassicBondedOnly
was changed from false
to true
for security reasons [4]. This change makes it impossible to pair a Dual Shock 3 controller, as bluetoothctl
asks for a PIN and cannot proceed. To work around this, set ClassicBondedOnly
to false
by adding the following lines in the newly created file at /etc/bluetooth/input.conf
.
As of 2024-03-09, the default value for UserspaceHID
has also changed to true
. While the connection succeeds, controllers can no longer be set into operational mode unless this value is changed to false
. See issue #771 on Github for more information.
[General] ClassicBondedOnly=false UserspaceHID=false
Note this solution regress on security. For the details, please refer to GitHub
PlayStation 3/4 controller
The DualShock 3, DualShock 4 and Sixaxis controllers work out of the box when plugged in via USB (the PS button will need to be pushed to begin). They can also be used wirelessly via Bluetooth.
Steam properly recognizes it as a PS3 pad and Big Picture can be launched with the PS button. Big Picture and some games may act as if it was a 360 controller. Gamepad control over mouse is on by default. You may want to turn it off before playing games, see #Joystick moving mouse.
Pairing via Bluetooth
Install the bluez and bluez-utils packages, which includes the sixaxis plugin. Then start the bluetooth service and ensure bluetooth is powered on. If using bluetoothctl start it in a terminal and then plug the controller in via USB. You should be prompted to trust the controller in bluetoothctl. A graphical bluetooth front-end may program your PC's bluetooth address into the controller automatically. Hit the PlayStation button and check that the controller works while plugged in.
You can now disconnect your controller. The next time you hit the PlayStation button it will connect without asking anything else.
Alternatively, on a PS4 controller you can hold the share button and the PlayStation button simultaneously (for a few seconds) to put the gamepad in pairing mode, and pair as you would normally.
GNOME's Settings also provides a graphical interface to pair sixaxis controllers when connected by wire.
Remember to disconnect the controller when you are done as the controller will stay on when connected and drain the battery.
Using generic/clone controllers
Using generic/clone Dualshock controllers is possible, however there is an issue that may require to install a patched package. The default Bluetooth protocol stack does not detect some of the clone controllers. The bluez-ps3AUR package is a version patched to be able to detect them. bluez-plugins-ps3AUR is another package that only patch the bluez-plugins may work for some controllers.
PlayStation 4 controller
Pairing via USB
Connect your controller via USB and press the PS
button.
Pairing via Bluetooth
If you want to use bluetooth mode, hold down the PS
button and Share
button together. The white LED of the controller should blink very quickly, and the wireless controller can be paired with your bluetooth manager (bluez, gnome-bluetooth).
Disable touchpad acting as mouse
The libinput and Xorg fixes conflict with games that actually use touchpad as part of the gamepad, such as Rise of the Tomb Raider. This will work with both DualShock4 and DualSense controllers.
KDE
if using KDE Plasma with a mouse you can simply disable the touchpad through System Settings > Mouse & Touchpad > General > Device Enabled.
libinput
If using libinput with Xorg, or if using Wayland, then you can follow Libinput#Using environment variable to disable the touchpad device.
Note that, since the touchpad is just one part of the controller, selecting the input device by vendor and product IDs will not suffice. Instead, consider selecting the device by name.
For a full set of attributes you can use, consult udevadm info --attribute-walk --name=device_path
, where device_path
is the path to the device, such as /dev/input/eventn
or /dev/input/by-id/identifier
.
To find the device path, you can use a tool such as evtest by just running evtest
. This command should also print out the name of the device.
Example snippet:
/etc/udev/rules.d/72-ds4tm.rules
# Disable DS4 touchpad acting as mouse # USB ATTRS{name}=="Sony Interactive Entertainment Wireless Controller Touchpad", ENV{LIBINPUT_IGNORE_DEVICE}="1" # Bluetooth ATTRS{name}=="Wireless Controller Touchpad", ENV{LIBINPUT_IGNORE_DEVICE}="1"
With DualSense controllers, you need to replace the names with Sony Interactive Entertainment DualSense Wireless Controller Touchpad
and DualSense Wireless Controller Touchpad
.
Then, reload udev rules. Reconnect the gamepad to apply changes.
Xorg
If using Xorg, you can follow Xorg#Persistently disable input source with MatchProduct "Wireless Controller Touchpad"
to disable the DualShock4/DualSense touchpad. See xinput list
for detected product names.
Control Mapping (Xbox)
Proton-GE and xboxdrv
Proton-GE does not support mapping DualShock 4 to an Xbox gamepad like Wine or Wine-GE does, because Proton is supposed to run on Steam which has its own software for mapping (emulating) one controller type to another. However, Proton-GE does not need Steam any more with UMU (UWLGL) support which provides full support (patches for any game) for Proton without Steam.
This is the configuration file xboxdrvAUR, it requires the new DualShock driver from Sony from kernel 6.2, not the DS4DRV one. Enable/start xboxdrv.service
.
/etc/default/xboxdrv
[xboxdrv] silent = true mimic-xpad = true [evdev-absmap] ABS_X = x1 ABS_Y = y1 ABS_Z = lt ABS_RZ = rt ABS_RX = x2 ABS_RY = y2 ABS_HAT0X = dpad_x ABS_HAT0Y = dpad_y [evdev-keymap] BTN_SOUTH = a BTN_EAST = b BTN_NORTH = y BTN_WEST = x BTN_TL = lb BTN_TR = rb BTN_THUMBL = tl BTN_THUMBR = tr BTN_SELECT = back BTN_START = start [axismap] -y1 = y1 -y2 = y2
If you want to verify that the mapping is working (DualShock gamepad emulating a Xbox 360 Gamepad), use:
$ evtest
/dev/input/event15: Microsoft X-Box 360 pad /dev/input/event16: Wireless Controller /dev/input/event17: Wireless Controller Motion Sensors /dev/input/event18: Wireless Controller Touchpad
For alternative direct use on terminal, with Bluetooth, we can make a rule for always access to the gamepad with the same path (because with Bluetooth, there is no access by-id for gamepads):
/etc/udev/rules.d/99-bluetooth.rules
SUBSYSTEM=="input", ATTRS{name}=="Wireless Controller", MODE="0666", SYMLINK+="dualshock4-bt"
Now, the DualShock path with Bluetooth will always be /dev/dualshock4-bt
After a reboot, it is now possible to run without changing the path in /dev/input
:
$ xboxdrv --evdev "/dev/dualshock4-bt" --evdev-keymap "BTN_SOUTH=a,BTN_EAST=b,BTN_TL=lb,BTN_THUMBR=tr,BTN_SELECT=back,BTN_START=start,BTN_THUMBL=tl,BTN_TR=rb,BTN_NORTH=y,BTN_WEST=x" --evdev-absmap "ABS_RZ=rt,ABS_RY=y2,ABS_RX=x2,ABS_Z=lt,ABS_Y=y1,ABS_X=x1,ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y" --axismap "-y2=y2,-y1=y1" --mimic-xpad --silent
PlayStation 5 (Dualsense) controller
Bluetooth connection of Dualsense requires enabling userspace HID support, otherwise Dualsense refuses Bluetooth connection after pairing. If userspace HID is not already enabled, this can be done by editing or creating new file /etc/bluetooth/input.conf
with line UserspaceHID=true
and restarting the bluetooth.service
.
GNOME currently doesn't need to modify this.
Control Mapping (Xbox)
Steam Input
Thanks to Steam Input, a feature that's baked in Steam Client, games w/o DualSense support can use it to translate buttons to Xbox ones.
From the Steam tray icon, select Big Picture. Then, press the PS Button on your DualSense, select Settings -> Controller, ensure that PlayStation Controller Support is set to Enabled in Games w/o Support.
xboxdrv
Thanks to yoyossef:
# xboxdrv \ --evdev /dev/input/by-id/usb-Sony_Interactive_Entertainment_DualSense_Wireless_Controller-if03-event-joystick \ --evdev-absmap ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y,ABS_X=X1,ABS_Y=Y1,ABS_RX=X2,ABS_RY=Y2,ABS_Z=LT,ABS_RZ=RT \ --evdev-keymap BTN_SOUTH=A,BTN_EAST=B,BTN_NORTH=Y,BTN_WEST=X,BTN_START=start,BTN_MODE=guide,BTN_SELECT=back \ --evdev-keymap BTN_TL=LB,BTN_TR=RB,BTN_TL2=LT,BTN_TR2=RT,BTN_THUMBL=TL,BTN_THUMBR=TR \ --axismap -y1=y1,-y2=y2 \ --mimic-xpad \ --silent
Some applications, for example, Steam inside Geforce NOW inside web browser, may be confused with original joystick events, which shadow the newly created event source.
Simply deleting /dev/input/js0
works this around.
The PlayStation and mode buttons still do not work, however.
dualsensectl
dualsensectl is a tool that can toggle the lightbar and microphone (and its LED), monitor the battery status, and power off the controller. To use it, install dualsensectl-gitAUR.
Multi-mode wired gamepads
Some gamepads have 3 modes when wired: Switch, Xbox 360/Windows, Android.
And they also don't have hotkeys to switch between them when connected wired.
When you connect such gamepad to Windows, it is in Xbox 360 Controller mode.
But when you connect such gamepad to Linux, it enters the fallback mode (which happens to be the Android mode), which has a worse polling rate (100 Hz), the Home button acting as XF86Home
; doesn't expose vibration, gyroscope, and accelerometer; doesn't support xboxdrvAUR without --evdev
; and identifies itself as e.g. "SHANWAN Android Gamepad" which is not liked by some games (though for SDL2 apps you can set a name in SDL_GAMECONTROLLERCONFIG
).
When you connect the gamepad, it first tries to be a "Switch Pro Controller", but for some reason the Linux kernel considers the descriptors (sent by the gamepad) invalid, and therefore disconnects the gamepad. This causes the gamepad to reconnect in the aforementioned fallback mode.
In dmesg
this looks like:
usb 1-5.3: new full-speed USB device number 37 using xhci_hcd usb 1-5.3: unable to read config index 0 descriptor/start: -32 usb 1-5.3: chopping to 0 config(s) usb 1-5.3: can't read configurations, error -32 usb 1-5.3: new full-speed USB device number 38 using xhci_hcd usb 1-5.3: New USB device found, idVendor=0079, idProduct=181c, bcdDevice= 1.00 usb 1-5.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 1-5.3: Product: Android Gamepad usb 1-5.3: Manufacturer: SHANWAN
Notice that the "USB Device number" gets increased after the failure. For some USB hubs the error code is -32
(EPIPE: broken pipe), for others it is -71
(EPROTO: protocol error).
This error can be fixed by setting a quirk in usbcore
module (not usbhid
) for Switch controller's USB ID:
# If you have already *manually* set quirks for other devices, # then don't forget to include them in the two commands below ↓ echo -n "057e:2009:ik" | sudo tee /sys/module/usbcore/parameters/quirks
# Optionally constant polling mode: sudo modprobe -r usbhid ; sleep 4 ; sudo modprobe -v usbhid "quirks=0x057e:0x2009:0x400"
ik
are 2 flags (List of all flags).
The flag i
means "allow bad descriptors".
And the flag k
means "disable LPM" (link power management). It is specified in the command because it often helps devices of other types. This flag might do nothing because not all USB controllers even have LPM. You can try without k
aftewards.
You could also try the flag g
("200 ms pause after reading the descriptors") because it often helps devices of other types, but at least in the case of iPEGA PG-SW038C (a $10 gamepad) flag g
causes it infinitely reconnect.
Note that once the gamepad downgrades to the fallback mode, it will never change its mode until you reconnect it. Even echo 0 then 1 > %sysfsGamepadDir%/authorized
doesn't work. And that's why passing the gamepad to a Windows VM would not help; usbcore
inits USB devices before passing them to a VM.
Now reconnect the gamepad, it should be finally listed now as ID 057e:2009 Nintendo Co., Ltd Switch Pro Controller
when you run lsusb
. If that's true, then you can make this quirk permanent by add this option to GRUB:
usbcore.quirks="057e:2009:ik"
along with (optionally) usbhid.quirks="0x057e:0x2009:0x400"
which stops the pointless blinking of LEDs when the gamepad is unused.
Now that your gamepad is in Switch mode, you'll run into a problem of SDL2 deciding to become a user-space driver (for this it uses libusb, just like xboxdrvAUR), which causes any SDL2 game to claim the whole gamepad (that is: /dev/input/*
and /dev/hidraw*
disappear, yet it's still possible to play this launched game with the gamepad), so you can't use the gamepad in multiple apps anymore.
This can be fixed by adding
SDL_HIDAPI_DISABLE_LIBUSB=1
into /etc/environment
, and rebooting.
If you have joycond-gitAUR, then delete it, because it is useless for such Switch-like gamepads, moreover joycond
has a udev
rule that disallows Steam to provide its own user-space driver.
Unlike SDL2 (when it uses /dev/hidraw*
which is its preferred way in 2023), xboxdrv
and /dev/input/*
provide incorrect values for the right stick's X axis (it's always ≤0). Probably a bug in hid-nintendo
or something. For this reason xboxdrv
is unusable in most games when in Switch mode.
You can test your gyroscope and accelerometer by launching antimicrox. They are not available in other gamepad modes when connected wired because their values are sent mixed with other event data (RX/RY/etc) in a special format that is not fully compatible with xpad
and hid-generic
.
If you see in dmesg
that hid-generic
is used by your gamepad, then it's probably because you have built Linux kernel with your own config without hid-nintendo
. Unfortuately, Switch mode + hid-generic
is as useless as the fallback mode (even no vibration).
Xbox 360 Controller mode
After having completed everything above (i.e. 1-2 quirks, 1 envvar),
add
blacklist hid_nintendo
into /etc/modprobe.d/blacklist.conf
then run sudo mkinitcpio -P
to rebuild /boot/initramfs*
(kernel reads /etc/modprobe.d/
only from its own initramfs, not your rootfs)
Now create the following file:
/etc/udev/rules.d/10-disallow-generic-driver-for-switch.rules
# If # 1. a gamepad is multi-mode (Switch, X360, PC) and defaults to USB ID 057e:2009 # AND at the same time # 2. `hid-nintendo` module can't be loaded (blacklisted or not compiled) # AND at the same time # 3. there's already a launched game that immediately grabs a gamepad, # # Then when you connect such gamepad, it will stay in "Switch Pro" mode, # but using the fallback `hid-generic` module # which would result in no vibration/etc # despite still being listed as a "Switch Pro Controller". # But by notifying the gamepad that we abandon to use it as an HID, # it automatically downgrades to "Xbox 360 Controller" mode, # which causes vibration and `xboxdrv` to work. SUBSYSTEM=="hid", DRIVER=="hid-generic", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="2009", RUN="/bin/sh -c 'echo $id:1.0 > /sys/bus/usb/drivers/usbhid/unbind'"
then run sudo udevadm control --reload-rules && sudo udevadm trigger
Since you probably don't want to reboot, run sudo modprobe -r hid_nintendo
From now on, to switch ("downgrade") from Switch mode to Xbox 360 mode, just run sudo modprobe -r hid_nintendo
(you don't even need to reconnect it). Within 2 seconds you'll have 045e:028e Microsoft Corp. Xbox360 Controller
in lsusb
And if you want to switch vice versa:
sudo modprobe hid_nintendo
(even though it is blacklisted, this command still works because blacklisting just means "don't load this module automatically").- Reconnect.
Alternative rootless solution
If you don't have root access, then:
- Power off your PC (not just suspend)
- Reconnect your gamepad.
- Power the PC on.
- UEFI (just like non-virtualized Windows) automatically and successfully initializes the gamepad (even if it's connected through a USB hub in your monitor) despite the invalid descriptors.
- The gamepad receives info from UEFI (or maybe GRUB) that it's no longer needed as an HID, which causes it to switch ("downgrade") to Xbox 360 Controller mode. Switching between modes is done this way: the gamepad disconnects, then connects under a different USB ID.
- You can even suspend (without turning off the monitor if that's what it's connected to) and then wake-up the PC, and it will still be in Xbox 360 Controller mode. But if you reconnect the gamepad, it will be in the fallback mode, so you'll have to follow the instruction again.
USB debugging
You'll probably not need to know this, but this USB ID (057e:2009) was discovered by USB debugging:
# Allow debugging of the kernel: sudo ls /sys/kernel/debug/usb >/dev/null 2>&1 || sudo mount -t debugfs none_debugfs /sys/kernel/debug # Load the module that allows sniffing of the traffic of USB buses: sudo modprobe usbmon # We need only connection events, and in these events # we need only a USB ID which is in the pre-pre-last column: sudo /bin/grep --line-buffered -Po '(?<=0 0 18 = .{18}).{8}' /sys/kernel/debug/usb/usbmon/99999u | /bin/sed -E 's/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/\2\1:\4\3/'
where 99999
must be replaced with the USB Bus number that your gamepad uses, e.g. 1
(without leading zeroes). It can be found by running lsusb
.
If nothing helped and your gamepad still works in full capacity only in Windows, you can catch USB messages while in Windows, and then replay them while in Linux. See usbrply. For this, Windows must not be in VM because Linux kernel's usbcore
initializes a USB device before passing it to a VM. This could be avoided by buying a PCI-E USB controller and passing it through (External USB hubs can't be passed through). Or you can pass-through your motherboard's own USB controller if it is in a IOMMU group without devices important for you:
Script which lists IOMMU groups |
list-iommu-groups.sh #!/bin/bash shopt -s nullglob for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do echo "IOMMU Group ${g##*/}:" for d in $g/devices/*; do echo -e "\t$(lspci -nns ${d##*/})" done; done; |
Tips and Tricks
Gamepad over network
If you want to use your gamepad with another computer over a network, you can use USB/IP or netstick-gitAUR to do this.
Troubleshooting
Device permissions
Gamepad devices are affected by udev rules: unless they grant access to the device, it simply will not be readable by users. This section investigates the possibility of you already having a configuration file handling this.
Any gamepad device, regardless of whether it is over USB or Bluetooth, is handled by the "input" subsystem of the kernel, corresponding with /dev/input
. It's also common for udev rules to target the "hidraw" kernel module. Combining these, we can understand udev's handling of these devices by inspecting the configuration shipped by packages:
$ grep --extended-regexp 'SUBSYSTEM=="input"|KERNEL=="hidraw' --recursive /usr/lib/udev/rules.d
Some examples of applications which ship noteworthy rules:
- systemd's default rules set the group of all
input
devices toinput
, and the mode of joystick devices to664
[5]. - Steam ships udev rules allowing access to a variety of controllers. See this Steam discussion for further info about the contents of the rules.
- Dolphin emulator ships udev rules allowing access to controllers it supports.
If your system does not already happen to have a udev rule for the device you want to use, you can either write one yourself or install the game-devices-udevAUR package and restart your computer.
input
group in order to give them access to all devices. However, this is not recommended [6].Joystick moving mouse
Sometimes USB gamepad can be recognized as HID mouse (only in X, it is still being installed as /dev/input/js0
as well). Known issue is cursor being moved by the joystick, or escaping to en edge of a screen right after plugin. If your application can detect gamepad by itself, you can remove the xf86-input-joystickAUR package.
A more gentle solution is described in #Disable joystick from controlling mouse.
Gamepad is not working in FNA/SDL based games
If you are using a generic non-widely used gamepad you may encounter issues getting the gamepad recognized in games based on SDL. Since 14 May 2015, FNA supports dropping a gamecontrollerdb.txt
into the executable folder of the game, for example the SDL_GameControllerDB.
As an alternative and for older versions of FNA or for SDL you can generate a mapping yourself by downloading the SDL source code via https://libsdl.org/, navigating to /test/
, compile the controllermap.c
program (alternatively install controllermapAUR) and run the test. After completing the controllermap test, a GUID will be generated that you can put in the SDL_GAMECONTROLLERCONFIG
environment variable which will then be picked up by SDL/FNA games. For example:
$ export SDL_GAMECONTROLLERCONFIG="030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,"
Gamepad is not recognized by all programs
Some software, Steam for example, will only recognize the first gamepad it encounters. Due to a bug in the driver for Microsoft wireless periphery devices this can in fact be the bluetooth dongle. If you find you have a /dev/input/js*
and /dev/input/event*
belonging to you keyboard's bluetooth transceiver you can get automatically get rid of it by creating according udev rules:
/etc/udev/rules.d/99-btcleanup.rules
ACTION=="add", KERNEL=="js[0-9]*", SUBSYSTEM=="input", KERNELS=="...", ATTRS{bInterfaceSubClass}=="00", ATTRS{bInterfaceProtocol}=="00", ATTRS{bInterfaceNumber}=="02", RUN+="/usr/bin/rm /dev/input/js%n" ACTION=="add", KERNEL=="event*", SUBSYSTEM=="input", KERNELS=="...", ATTRS{bInterfaceSubClass}=="00", ATTRS{bInterfaceProtocol}=="00", ATTRS{bInterfaceNumber}=="02", RUN+="/usr/bin/rm /dev/input/event%n"
Correct the KERNELS=="..."
to match your device. The correct value can be found by running
# udevadm info -an /dev/input/js0
Assuming the device in question is /dev/input/js0
. After you placed the rule reload the rules with
# udevadm control --reload
Then replug the device making you trouble. The joystick and event devices should be gone, although their number will still be reserved. But the files are out of the way.
Vibration does not work in certain Windows games
Some Windows games look for an Xbox 360 controller in particular, causing vibration to not work even with otherwise functional XInput gamepads. One example of such game is Inside.
As a work-around for these games:
- Unload the
xpad
kernel module. - Launch
xboxdrv
, including Xbox 360 mimicking gamepad and with vibration support:
# xboxdrv --mimic-xpad --force-feedback
Steam Controller
Steam Controller not pairing
There are some unknown cases where the packaged udev rule for the Steam controller does not work (FS#47330). The most reliable workaround is to make the controller world readable. Copy the rule /usr/lib/udev/rules.d/70-steam-controller.rules
to /etc/udev/rules.d
with a later prioritiy and change anything that says MODE="0660"
to MODE="0666"
e.g.
/etc/udev/rules.d/99-steam-controller-perms.rules
... SUBSYSTEM=="usb", ATTRS{idVendor}=="28de", MODE="0666" ...
You may have to reboot in order for the change to take effect.
Steam Controller makes a game crash or not recognized
If your Steam Controller is working well in Steam Big Picture mode, but not recognized by a game or the game starts crashing when you plug in the controller, this may be because of the native driver that has been added to the Linux kernel 4.18. Try to unload it, restart Steam and replug the controller.
The module name of the driver is hid_steam
, so to unload it you may perform:
# rmmod hid_steam
Xbox One Wireless Gamepad detected but no inputs recognized
This can occur when using a third party Xbox One controller with the xpad
or #xboxdrv drivers. Try switching to #xpadneo.
Playstation 4 controllers
Controller not recognized when using Bluetooth
Install the ds4drvAUR package and run it with the hidraw (ds4drv --hidraw
) backend parameter.
Button mapping
To fix the button mapping of PS4 controller you can use the following command with xboxdrv (or try with the ds4drv program, ds4drvAUR):
# xboxdrv \ --evdev /dev/input/by-id/usb-Sony_Computer_Entertainment_Wireless_Controller-event-joystick\ --evdev-absmap ABS_X=x1,ABS_Y=y1 \ --evdev-absmap ABS_Z=x2,ABS_RZ=y2 \ --evdev-absmap ABS_HAT0X=dpad_x,ABS_HAT0Y=dpad_y \ --evdev-keymap BTN_A=x,BTN_B=a \ --evdev-keymap BTN_C=b,BTN_X=y \ --evdev-keymap BTN_Y=lb,BTN_Z=rb \ --evdev-keymap BTN_TL=lt,BTN_TR=rt \ --evdev-keymap BTN_SELECT=tl,BTN_START=tr \ --evdev-keymap BTN_TL2=back,BTN_TR2=start \ --evdev-keymap BTN_MODE=guide \ --axismap -y1=y1,-y2=y2 \ --mimic-xpad \ --silent
Motion controls taking over joypad controls and/or causing unintended input with joypad controls
With certain cloud gaming applications such as Parsec and Shadow, the Dualshock 4 V1 and V2 motion controls can conflict with the joypad controls resulting in the joypad not working, and with certain input sensitive games, especially racing games, the motion controls can cause unintentional drift during joypad control gameplay.
This can be worked around by disabling the motion controls and the touchpad by adding the following udev rules:
/etc/udev/rules.d/51-disable-DS3-and-DS4-motion-controls.rules
SUBSYSTEM=="input", ATTRS{name}=="*Controller Motion Sensors", RUN+="/bin/rm %E{DEVNAME}", ENV{ID_INPUT_JOYSTICK}="" SUBSYSTEM=="input", ATTRS{name}=="*Controller Touchpad", RUN+="/bin/rm %E{DEVNAME}", ENV{ID_INPUT_JOYSTICK}=""
Then reload the rules or reboot: these rules should work in both USB and Bluetooth mode.
Epic games
Some games bought from Epicgames do not recognize the controller. (In fact this is not specific to Linux at all.) [7] [8] [9] In this case running them from the Steam client may solve the problem.