sc-controller
sc-controller copied to clipboard
[Feature Request] Steam Deck Support?
Any plans on adding a layout for the new Steam Deck inputs?
I'd like to, but it will take few months before I can even think about buying one from here.
Most likely I will receive my deck in May-June. I'm not as experienced as the other devs here so I can test some stuff plus maybe write some code.
Just glad to hear it's on the radar.
Would you also look into pushing support for the kernel driver? hid-steam was being worked on in 2018
Hello, Steam Deck owner here! Got mine last Friday.
The Steam Deck inputs are connected internally via USB, similar to how a wired Steam Controller works. Its vid:pid is 28de:1205
, and even reports itself as "Valve Software Steam Controller".

@Jack-Sibley was doing some reverse engineering of the HID reports that it sends and at least got the gyro to work. It seems pretty similar to how the Steam Controller sends reports, so hopefully only the modifications that need to be made are minor.
I am not familiar with how this project actually obtains a handle for the USB HID, but according to Jack, Steam gets upset when other apps try to access it. As a sort of workaround we were using usbmon
to get the raw HID events directly from the kernel (at /dev/usbmonX
).
Anyway, my point is that it's basically a necessity for this to work while Steam is open and actively using the controller, otherwise games launched from the Deck's UI wouldn't be able to utilize this. (There are cases where you would want to use SC Controller instead of the native Steam Input bindings, for e.g. cemuhook. I detailed it more here)
@kozec If there is anything I can do to help out, by providing USB pcaps or otherwise, let me know! Would love to see this work with Steam Deck.
@tjhorner does UINPUT do anything with it if Steam isn't running ? Does it show up as a DirectInput gamepad device when Windows is installed ?
@offalynne I'm afraid not, without steam it's just a raw hid device.
The official steam client now has support for Steam Deck trackpad typing. The keyboard works more similar to sc-controller where the input is stretched horizontally rather than completely square like with the SC via Steam
Here is my rendition of the input area and how it maps to the square trackpads on Steam with the Steam Deck.
This is the default keyboard in Steam with SC
Would a non-developer be able to supply any useful info from the deck to give the development for a driver a head start?
An unofficial mod for adding plugins to the steam deck menu. If devs do make it work alongside steam, may consider a tool which can modify config.py integrated with steam
https://github.com/SteamDeckHomebrew/PluginLoader
example, calculator app: https://github.com/SpyrexDE/SDH-Calculator
I got my Steam Deck yesterday, but it seemed that no one else had reverse engineered the HID data layout yet, so I decided to give it a try today. Here's what I have so far:
Digital inputs
A bit set in these locations indicates the following:
-
0x08, bit 0
: Right trigger (virtual) button pressed -
0x08, bit 1
: Left trigger (virtual) button pressed -
0x08, bit 2
: Right bumper pressed -
0x08, bit 3
: Left bumper pressed -
0x08, bit 4
: "Y" button pressed -
0x08, bit 5
: "B" button pressed -
0x08, bit 6
: "X" button pressed -
0x08, bit 7
: "A" button pressed -
0x09, bit 0
: D-pad UP pressed -
0x09, bit 1
: D-pad RIGHT pressed -
0x09, bit 2
: D-pad LEFT pressed -
0x09, bit 3
: D-pad DOWN pressed -
0x09, bit 4
: "View" button (two rectangles, above left thumbstick) pressed -
0x09, bit 5
: "STEAM" button pressed -
0x09, bit 6
: "Options" ("≡", above right thumbstick) button pressed -
0x09, bit 7
: L5 pressed -
0x0A, bit 0
: R5 pressed -
0x0A, bit 1
: Left trackpad pressed (not possible for a "press" to be detected without the pad being touched--i.e., bit 3 also being set) -
0x0A, bit 2
: Right trackpad pressed (not possible for a "press" to be detected without the pad being touched--i.e., bit 4 also being set) -
0x0A, bit 3
: Left trackpad touched -
0x0A, bit 4
: Right trackpad touched -
0x0A, bit 6
: Left thumbstick pressed -
0x0B, bit 2
: Right thumbstick pressed -
0x0D, bit 1
: L4 pressed -
0x0D, bit 2
: R4 pressed -
0x0D, bit 6
: Left thumbstick capacitive pad touched -
0x0D, bit 7
: Right thumbstick capacitive pad touched -
0x0E, bit 2
: "Quick access" ("...") button pressed
Analog inputs
Notes
- All fields are 16-bit, signed, little-endian integers unless otherwise noted.
- Accelerometer axes are treated as follows:
- With the screen as the "front" of the console, and the exhaust vent as the "top" of the console, and the screen facing the user:
- Moving the console ventward will result in a positive acceleration in the X-direction.
- Moving the console left will result in a positive acceleration in the Y-direction.
- Moving the console toward the user will result in a positive acceleration in the Z-direction.
- Basically, it's the right-hand rule. With the thumb pointing up and the index finger pointing forward:
- Thumb is positive-Z.
- Index finger is positive-X.
- Middle finger is positive-Y.
- With the screen as the "front" of the console, and the exhaust vent as the "top" of the console, and the screen facing the user:
- Gyroscope axes are treated as follows:
- Pitch axis points out the right side of the console.
- Yaw axis points out the exhaust vent side of the console.
- Roll axis points out the screen side of the console.
Fields
-
0x10
: Left trackpad X-axis, positive == East, negative == West -
0x12
: Left trackpad Y-axis, positive == North, negative == South -
0x14
: Right trackpad X-axis, positive == East, negative == West -
0x16
: Right trackpad Y-axis, positive == North, negative == South -
0x18
: Accelerometer X-axis -
0x1A
: Accelerometer Y-axis -
0x1C
: Accelerometer Z-axis -
0x1E
: Gyroscope pitch -
0x20
: Gyroscope yaw -
0x22
: Gyroscope roll -
0x24
: Q1? -
0x26
: Q2? -
0x28
: Q3? -
0x2A
: Q4? -
0x2C
: Left analog trigger pressure (never goes negative--bit 15 always zero), higher value == higher pressure -
0x2E
: Right analog trigger pressure (never goes negative--bit 15 always zero), higher value == higher pressure -
0x30
: Left thumbstick X-axis, positive == East, negative == West -
0x32
: Left thumbstick Y-axis, positive == North, negative == South -
0x34
: Right thumbstick X-axis, positive == East, negative == West -
0x36
: Right thumbstick Y-axis, positive == North, negative == South -
0x38
: Left trackpad pressure (never goes negative--bit 15 always zero), higher value == higher pressure -
0x3A
: Right trackpad pressure (never goes negative--bit 15 always zero), higher value == higher pressure -
0x3C
: ? -
0x3E
: ?
@kozec, does this help?
@cyrozap I believe 0x20
is yaw and 0x22
is roll
Here's the USB descriptor, in case anyone needs it:
Bus 003 Device 002: ID 28de:1205 Valve Software Steam Controller
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x28de Valve Software
idProduct 0x1205
bcdDevice 1.00
iManufacturer 1 Valve Software
iProduct 2 Steam Controller
iSerial 3 123456789ABCDEF
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x005b
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 2 Mouse
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 33 US
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 50
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 1 Boot Interface Subclass
bInterfaceProtocol 1 Keyboard
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 33 US
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 39
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.10
bCountryCode 33 US
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 53
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Device Status: 0x0000
(Bus Powered)
@tjhorner I did some more testing today, and you're correct--I didn't follow the right-hand rule when labeling the accelerometer and gyroscope axes, so I had X/Y and roll/yaw swapped. I've updated my earlier comment to reflect these changes, as well as to describe the gyroscope axes (since they're different from the accelerometer axes).
All this has really started to confuse me, so I'm tempted to mock up a diagram illustrating how the six axes are positioned relative to the controller and how they relate to the values in the HID report.
Behold--my extremely professional diagrams:
Axis names and positive directions correspond to the ones in my earlier post.
@cyrozap have you had any other progress so far? I might want to give implementing it a shot.
Just for the record, if it needs testing I also got a Steam Deck. I wonder if it would be easy to make a flatpak out of it, because that's the standard way to install stuff on the device.
Is it possible to buy the left and right daughterboards and plug in touchpads and plug that into a generic system?
https://www.ifixit.com/Guide/Steam+Deck+Left+Button+Board+Replacement/148931
I think they refer to the cord which plugs into the mobo as a ZIF connector. Having an isolated board could help for development
@Patola i think that should be possible, but first up is getting it to work ;) @pattontim could be, but i dont know how to get the data out of it.
Right now im looking at the raw data output of the device. Here is what i've got so far:
https://github.com/mKenfenheuer/sc-controller/blob/v0.4.9.12-steamdeck-raw-data/steam_deck_dump/raw_data.md
If you can provide some data, please feel free. Binaries for windows are available here
Someone published source which utilizes gyro data on GitHub, but I couldn't get it working https://github.com/kmicki/SteamDeckGyroDSU
@mKenfenheuer I haven't done any more reverse engineering work on this after I figured out the gyroscope stuff, and haven't started adding support to SC-Controller either, so feel free to start on a driver. You might want to use the field definitions I posted earlier so you don't have to reverse engineer the protocol/report format from scratch. I think the only reverse engineering work that remains to be done is to find the commands that enable the gyroscope, switch the device out of lizard mode, etc.
@pattontim Rather than physically connecting the Deck's controller to a PC, I've been using USB/IP to present the controller's USB device as a virtual USB device on my laptop over the network. That way, I can do any reverse engineering and development work from the comfort of my laptop instead of directly on the Deck.
@cyrozap i see, out of what ive got so far i think we are getting the same data format. Is your payload 64bytes too?
Yes, it's 64 bytes.
So, good news: i've got the sticks, triggers and most of the buttons working (although they are wrongly mapped). Bad news: the steam deck controller does not stop sending mouse and keyboard inputs.
Does anyone know using which HID Report we can disable that?
Got it, hid request with first byte set to 0x81 disables the mouse and keyboard input temporarily. Needs to be repeated about every 1-2 secs to keep it that way.
Once i got all sticks, trackpads etc mapped i will publish another build.
I couldnt get the mapping to work correctly here, so i decided to rewrite a separate driver specific for the steam deck. See https://github.com/mKenfenheuer/steam-deck-windows-usermode-driver - it's windows only for now.
My attempt at implementing it with c is pushed to https://github.com/mKenfenheuer/sc-controller.
Regarding Lizard mode here is a short snippet on how to enable/disable it:
bool sdc_set_lizard_mode(bool enabled)
{
if (!enabled)
{
//Disable mouse emulation
uint8_t data[64] = { 0x87, 0x03, 0x08, 0x07 };
if (hid_request(data, -64) == NULL) {
return false;
}
//Disable keyboard/mouse button emulation
uint8_t data2[64] = { 0x81, 0x00 };
if (hid_request(data2, -64) == NULL) {
return false;
}
}
else
{
//Enable keyboard/mouse button emulation
uint8_t data[64] = { 0x85, 0x00 };
if (hid_request(data, -64) == NULL) {
return false;
}
//Enable mouse emulation
data[0] = 0x8e;
if (hid_request(data, -64) == NULL) {
return false;
}
}
return true;
}
Progress. Using the above linked c project and a few edits I can type using both the trackpads. However non kb inputs are doubled
On the other hand, building the c branch GUI for windows is very hard because the python2 library is no longer offered. The py3 version doesn't build for windows AFAIK.
I'm going to reference steam-deck-windows-usermode-driver to add the correct SD timers and inputs and then perhaps try to backport the drivers to the py3 version
You will likely have to use the HID Hide driver, at some point, to hide the Steam Deck HID device from Steam. I have to use that driver when using my own mapper for the Steam Controller.
https://vigem.org/projects/HidHide/
To answer original question, I've just merged basic support for Steam Deck both to master and c branch.
There are two-and-half remaining issues with it:
- support for gyro is not yet implemented, althought it seems like it uses same fields / values as SC does
- it works on regular Linux booted on Deck. It should run on SteamOS as well, but I have yet to find way how to run anything with dependencies there. Plus, I'm not entirelly sure whether such use case is even relevant.
- support in 'c' version is not yet tested on Windows
Good work, I pushed some edits which allows it to partially build and run on windows, at least the OSD builds and runs and I can type. May simplify build process by removing GUI and its deps, just kbm to deal with gi not being distributed
https://github.com/pattontim/sc-controller-kbm/tree/origin/windows-osd-only