You can sign up to get a daily email of our articles, see the Mailing List page.

Setting up a Bluetooth Controller for Linux Gaming

By - | Views: 41,539

Recently I solved an issue for setting up my Wireless (via Bluetooth) controller on Steam for Linux, and decided to elaborate a little better about my experience, and share my results and observations with you all.

The controller I have used as a reference for the procedures here below is the ASUS Gamepad TV500BG, whose specs are detailed here. Alternatively, I have verified that the same procedures apply with any other Bluetooth device.

The important thing I would like to highlight is that my approach was to find a procedure that could work in several scenarios, such as for both native games (with or without Steam) and games running via Wine or Proton/Steam Play.

According to the approach mentioned above, I discarded immediately the use of the x360ce driver, which it is largely used for games running on Wine but it represents a limited solution from an architectural point of view.

Using the Userspace driver xboxdrv

The xboxdrv driver is the Xbox/360 gamepad driver for Linux running on userspace. It is widely considered as a replacement of the linux kernel module xpad, and shows significant advantages on handling several types of devices, other than the Xbox-like gamepads.

The additional capability provided by the xboxdrv driver is to remap any of your controller button or axis, and tweak the default configuration for adding new functionalities to it. By using xboxdrv, the device will be recognised then by Steam as an Xbox controller.

The only inconvenience I noticed when using xboxdrv was that the driver was able to lock and consume the hardware resource just exactly 60 seconds after launching the xboxdrv executable from the command line. This is a very well known issue tracked in this bug. You'll also see that there's a workaround noted.

I started with a udev rule for linking the input/event* device of the hardware controller in an arbitrarily named symlink (so that it would be easier to identify). The device has few attributes that make easy to recognise it. They can be read by typing the following statement in a terminal emulator:

$ udevadm info -a /sys/class/input/event*

where you have to replace the * above with the device ID (the highest number you find as soon as you turn the device on might be the right one). The output might look similar to the following:

  looking at device '/devices/pci0000:40/0000:40:07.1/0000:42:00.3/usb7/7-1/7-1:1.0/bluetooth/hci0/hci0:11/0005:0B05:4500.000B/input/input30/event26':

  looking at parent device '/devices/pci0000:40/0000:40:07.1/0000:42:00.3/usb7/7-1/7-1:1.0/bluetooth/hci0/hci0:11/0005:0B05:4500.000B/input/input30':
    ATTRS{name}=="ASUS Gamepad"

The lines above are telling that the device currently identified as "event26" has an attribute name ("ASUS Gamepad") which we can use to easily identify it in the udev rules. We can then open the user-defined rules file, as shown here below:

$ sudo nano /etc/udev/rules.d/75-input-events.rules

and add the following line to it:

KERNEL=="event*" , SUBSYSTEM=="input", MODE="0666"
KERNEL=="event*", ATTRS{name}=="ASUS Gamepad", SYMLINK+="input/event-asus-gamepad"

By specifying the last keyword in the rule, the system will automatically create the symlink /dev/input/event-asus-gamepad (named like that in a totally arbitrary way) pointing to the controller device any time it is turned on, regardless of the device current ID in the current session.

Now that we have a way for identifying the controller event device, we can restart the udev rules with the following command:

$ sudo udevadm control --reload-rules && sudo udevadm trigger

and then call the xboxdrv driver with this command:

$ xboxdrv --evdev "/dev/input/event-asus-gamepad" --config xboxdrv.config --debug

The --evdev option enables xboxdrv to read any input coming from the event-asus-gamepad device and convert it into an Xbox controller input. The Xbox-converted input signals are sent by a different char device, which is specified in the command output:

Your Xbox/Xbox360 controller should now be available as:

The new devices js1 and event27 above replace the old one, and will be automatically recognised by Steam.

The --config option defines a configuration file where I've specified all the mapping between the Asus Gamepad controller axes and buttons into the conventional Xbox ones:


-Y1 = Y1
-Y2 = Y2



The content of the configuration above above might vary according to your local controller.

I can then launch Steam with the following script:


if [ -h /dev/input/event-asus-gamepad ]
# remove any previous instance:
        killall -KILL xboxdrv

# start the new driver in userspace mode:
        xboxdrv --evdev "/dev/input/event-asus-gamepad" \
        --config xboxdrv.config &

/usr/bin/steam %U

In the same way, we could define the additional logic for giving an arbitrary event symlink to the xboxdrv controller device as soon as the system loads the driver. We can maintain again the user-defined rules file, as shown here below:

$ sudo nano /etc/udev/rules.d/75-input-events.rules

and add the following new line at the bottom:

KERNEL=="event*", ATTRS{name}=="Xbox Gamepad (userspace driver)", SYMLINK+="input/event-xboxdrv-gamepad"

With the definition above, the system will automatically create the symlink /dev/input/event-xboxdrv-gamepad regardless of the device current ID in the current user session.

Some people might try to run the xboxdrv driver as a daemon (with the options: --daemon --detach). Unfortunately I didn't get a working controller when I tried to do it.

Alternatively, you could try to start xboxdrv as soon as you turn on (or plug) your controller. You can implement it by adding a RUN keyword on the udev rule above (please refer to the udev documentation for further information on it).

Although this approach looks more direct, I prefer to follow the recommendation to run the driver at the same moment you run your game. This can be particularly useful if you need a different keys mapping for each game.

Some additional consideration would apply according to the specific game category.

Games running natively on Linux

Some best examples of very well-known games belonging to this category are Bioshock Infinite, Tomb Raider (2013) and Borderlands 2 (but this is just a personal opinion).

You have nothing to do in this case. Some specific games might require a value for the SDL environment variable SDL_JOYSTICK_DEVICE as shown in the example here below:


Although Steam will automatically identify the virtual Xbox Controller for most of the games.

Additionally, you can configure Steam itself with the Xbox Controller support (configuration is available under the menu: Steam --> Settings --> Controller --> General Controller Settings) as shown in the picture here below. This will enable you to use the controller as a replacement for the mouse pointer in Steam:

Hopefully some of you find this useful.

Article taken from
Tags: HOWTO, Steam, Ubuntu
We do often include affiliate links to earn us some pennies. We are currently affiliated with GOG and Humble Store. See more here.
The comments on this article are closed.
Page: «2/2
  Go to:

TurtleShark 25 Jan, 2019
Slightly off-topic, but has ANYONE been able to get force-feedback/rumble working on their controllers? I can get it working via Jtest, but I am starting to think that most games don't support it.
cprn 25 Jan, 2019
Quoting: bird_or_cageMaybe this will work?

Nah, they need to be separate devices in OS first.

Quoting: LordDaveTheKindHave you already tried with the following udev rule?

KERNEL=="event*", ATTRS{name}=="Your Gamepad Name", SYMLINK+="input/event-gamepad-%n"

This looks promising! :) Will check when I get home on Monday. I saw %k, %p and %n in the man pages but I didn't understand you can use those when writing rules :D Thank you!
Cyba.Cowboy 28 Jan, 2019
Seriously, why all the code? You're just making things harder to be than they need to be!

Whilst I can't speak for other controllers (though my understanding is that it is generally the same)(in my experience, wired USB gamepads of various types "just work"), all you need to do is put a Sony DUALSHOCK 4 into "pairing" mode and "pair" it with your computer over bluetooth using the usual process... As you can see from my Ask Ubuntu post ( ), everything works pretty seamlessly, with most games.

I'm sure your heart is in the right place, but it's articles like this which keep people thinking that Linux-based operating systems are harder to use than they are... If you're going to post an article like this, you post the KISS solution first, then post the Terminal-based solution for those of us that prefer that method (I prefer Terminal for a lot of - but not all - things).

Last edited by Cyba.Cowboy on 28 January 2019 at 3:18 am UTC
LordDaveTheKind 28 Jan, 2019
View PC info
  • Supporter Plus
Quoting: Cyba.CowboyI'm sure your heart is in the right place, but it's articles like this which keep people thinking that Linux-based operating systems are harder to use than they are... If you're going to post an article like this, you post the KISS solution first, then post the Terminal-based solution for those of us that prefer that method (I prefer Terminal for a lot of - but not all - things).

The KISS approach has been the first one I tried, but (as I have already mentioned above) it wasn't working: the controller mapping was completely wrong, with axes mapped on triggers and buttons on the wrong positions. The mapping/configuration tool provided by Steam was easily working with the keys, but not that easily with either the axes or the triggers (and you could tell that having the camera controls on a trigger can give some motion sickness).

Speaking about the article purpose, the main reason was for sharing experiences on how to make things work. Are there easier way to achieve the same results? Of course they are. That's why I ask everyone to share their observations.
I totally understand that a KISS solution would be better (and that would be appealing also to a less-skilled user), but if that solution does not exist, a workaround can be an alternative. Does this workaround require some basic skills with either the terminal or the recompiling of source code? So be it.
While you're here, please consider supporting GamingOnLinux on:

Reward Tiers: Patreon. Plain Donations: Liberapay or PayPal.

This ensures all of our main content remains totally free for everyone with no article paywalls. We also don't have tons of adverts, there's also no tracking and we respect your privacy. Just good, fresh content. Without your continued support, we simply could not continue!

You can find even more ways to support us on this dedicated page any time. If you already are, thank you!
The comments on this article are closed.