Main GUI of sc-controller, illustrated as running on Ubuntu 20.04 as a snap package
sc-controller running on Ubuntu 20.04

sc-controller is a neat little utility which allows Linux users to use a Steam Controller to play non-Steam games. I’ve used it for a long time on Ubuntu to play games like Pillars of Eternity from the comfort of my armchair. Sadly, it is built with the now-deprecated python2 technology, and the upcoming 20.04 release of Ubuntu drops support for the application. Whilst the author is busy rewriting sc-controller in a supported language, for the time being we do not have an easy way to use the Steam Controller for our non-Steam games.

I decided to do something about this by building a snap package. Snaps are a fairly recent way of packaging and distributing applications for Linux. They are much simpler to create than traditional packaging formats like Debian .debs, and bring additional advantages such as application isolation, confinement, a choice of runtime environments and easy portability. I knew that if I could create a snap based on an Ubuntu 18.04 runtime, I could use it on 20.04.

The snap packages are created by the snapcraft tool, uploaded to the Snap Store and made available to download via the snap client from the command line or via a graphical storefront. Installation and configuration are handled by the snapd service. All of this is trivial to use on Ubuntu but some other Linux distributions require a bit more configuration.

snapcraft uses a simple configuration file to build the snap. There’s nothing too challenging in my sc-controller snap:

name: sc-controller
base: core18
version: '0.4.7'
summary: Driver, mapper and GUI for Steam Controller, DS4 and similar controllers.
description: |
  Allows setup, configuration and use of Steam Controller(s) without ever launching Steam. Supports switchable profiles, sticks, pads, gyroscope input, haptic feedback and in-game rumble support. OSD, menus and on-screen keyboard for desktop and in games. Automatic profile switching based on active window. Emulates Xbox360 controller, mouse, trackball and keyboard and much more.

grade: stable
confinement: strict

parts:
  main:
    source: https://github.com/kozec/sc-controller/archive/v0.4.7.tar.gz
    plugin: python
    python-version: python2
    organize:
      bin: /usr/bin
      share: /usr/share
    stage-packages:
      - python-gobject
      - python-gi
      - libgtk-3-0
      - gir1.2-gtk-3.0
      - python-gi-cairo
      - gir1.2-rsvg-2.0
      - xinput
      - python-pylibacl
      - python
      - python-evdev
      - libusb-1.0-0
      - linux-libc-dev

apps:
  sc-controller:
    extensions: [gnome-3-28]
    command: $SNAP/usr/bin/sc-controller
    plugs: [raw-usb]

layout:
  /usr/bin/python:
    symlink: $SNAP/usr/bin/python
  /usr/include/linux/input.h:
    symlink: $SNAP/usr/include/linux/input.h
  /usr/include/linux/input-event-codes.h:
    symlink: $SNAP/usr/include/linux/input-event-codes.h

Basically, this is a big recipe and shopping list for how to build and bundle the application, along with some descriptive metadata. The most interesting bits are the base: core18 line which tells snapcraft we’ll be using a runtime based on Ubuntu 18.04 (which fully supports sc-controller) and the confinement: strict line which means there will be limits on what this snap can do to a user’s system. By default, strictly confined apps can only access a very limited selection of files, services and hardware on a device. This adds safety and security, but can stop the application from carrying out its intended function. snapd allows us to poke holes in the confinement to let the application function properly. My app asks for plugs: [raw-usb] permissions, needed to let the app interact with the controller. Without it, sc-controller cannot “see” the Steam Controller at all.

Some of these so-called plugs will be connected by default if a user installs a snap from the Store. Other plugs require approval from a small committee of trusted reviewers on the Snapcraft Forums before an automatic connection will be made (although the user can connect them manually). Sadly, raw-usb is one of the cursed selection of interfaces which requires to go through this approval process; a frustrating experience for packagers and users as there aren’t many reviewers and they are always very busy. In the interim, the “out-of-the-box” experience of using the application can feel broken and unpleasant and can lead to snapped packages getting a bad reputation. At the time of writing, my own request for auto-connection of the raw-usb plug is over 3 weeks old and counting. I’m not sure how this process could be improved, but it seems clear the current approach is not scaling with demand.

Nevertheless, even if raw-usb is connected my snap is still not functional. sc-controller needs to be able to access /dev/uinput to create an emulated controller device and there currently isn’t any available plug which can access this. Support should be coming in a future version of snapd, so hopefully it will not be long before access to this new uinput interface will be granted to my snap. When that day comes, I’ll be able to offer this brilliant utility to the Linux community running modern distributions. I know there’s demand for this as there are already scores of people running the broken alpha-quality snap on multiple distributions in over 40 countries around the world.

Graph of active users of the sc-controller snap over time. There has been a steady upward curve across a variety of Linux distributions.
Graph showing the building demand for a working snap!

If you’re feeling brave you can install my snap right now. It will require a bit of tweaking to be functional (follow the threads linked on the Store) but I think it is the best way to run sc-controller on Ubuntu 20.04 at present. Have fun!