sc-controller icon indicating copy to clipboard operation
sc-controller copied to clipboard

[Feature Request] Steam Deck Support?

Open ChrisRevocateur opened this issue 2 years ago • 45 comments

Any plans on adding a layout for the new Steam Deck inputs?

ChrisRevocateur avatar Mar 02 '22 00:03 ChrisRevocateur

I'd like to, but it will take few months before I can even think about buying one from here.

kozec avatar Mar 03 '22 16:03 kozec

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.

pattontim avatar Mar 05 '22 03:03 pattontim

Just glad to hear it's on the radar.

ChrisRevocateur avatar Mar 09 '22 22:03 ChrisRevocateur

Would you also look into pushing support for the kernel driver? hid-steam was being worked on in 2018

yoshimo avatar Mar 17 '22 12:03 yoshimo

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".

image

@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 avatar Mar 23 '22 22:03 tjhorner

@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 avatar Mar 24 '22 21:03 offalynne

@offalynne I'm afraid not, without steam it's just a raw hid device.

Jack-Sibley avatar Mar 25 '22 10:03 Jack-Sibley

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. sc-deck sc-deck2

This is the default keyboard in Steam with SC XDNKX

pattontim avatar Apr 04 '22 20:04 pattontim

Would a non-developer be able to supply any useful info from the deck to give the development for a driver a head start?

yoshimo avatar Apr 05 '22 19:04 yoshimo

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

pattontim avatar Apr 05 '22 20:04 pattontim

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.
  • 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 avatar Apr 24 '22 21:04 cyrozap

@cyrozap I believe 0x20 is yaw and 0x22 is roll

tjhorner avatar Apr 24 '22 23:04 tjhorner

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)

cyrozap avatar Apr 30 '22 20:04 cyrozap

@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.

cyrozap avatar Apr 30 '22 23:04 cyrozap

Behold--my extremely professional diagrams:

deck-accel-labeled deck-gyro-labeled

Axis names and positive directions correspond to the ones in my earlier post.

cyrozap avatar May 01 '22 00:05 cyrozap

@cyrozap have you had any other progress so far? I might want to give implementing it a shot.

mKenfenheuer avatar May 24 '22 18:05 mKenfenheuer

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.

Patola avatar May 24 '22 19:05 Patola

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

pattontim avatar May 24 '22 20:05 pattontim

@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

mKenfenheuer avatar May 24 '22 21:05 mKenfenheuer

Someone published source which utilizes gyro data on GitHub, but I couldn't get it working https://github.com/kmicki/SteamDeckGyroDSU

tjhorner avatar May 24 '22 21:05 tjhorner

@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 avatar May 25 '22 06:05 cyrozap

@cyrozap i see, out of what ive got so far i think we are getting the same data format. Is your payload 64bytes too?

mKenfenheuer avatar May 25 '22 06:05 mKenfenheuer

Yes, it's 64 bytes.

cyrozap avatar May 25 '22 07:05 cyrozap

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?

mKenfenheuer avatar May 25 '22 13:05 mKenfenheuer

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.

mKenfenheuer avatar May 25 '22 16:05 mKenfenheuer

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;
}

mKenfenheuer avatar May 31 '22 08:05 mKenfenheuer

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

pattontim avatar Jun 21 '22 00:06 pattontim

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/

Ryochan7 avatar Jun 21 '22 02:06 Ryochan7

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

kozec avatar Jun 21 '22 06:06 kozec

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

pattontim avatar Jun 22 '22 03:06 pattontim