Xbox 360 Controller

April 28, 2026 ยท View on GitHub

The Xbox 360 virtual gamepad emulates an XInput-compatible controller that most operating systems and games understand out of the box.

=== "TCP API"

Use `xbox360` as the device type when adding a device via the API or client libraries.

## Client Library Support

The wire protocol is abstracted by client libraries.  
The **Go client** includes built-in types (`/device/xbox360`),
and **generated client libraries** provide equivalent structures
with proper packing.

You don't need to manually construct packets, just use the provided types
and send/receive them via the device control and feedback stream.

You can optionally specify a sub type if you wish to emulate a different type of controller.
This is done by specifying it as part of the device options.

For example:

- `{"type":"xbox360", "deviceSpecific": {"subType": 7}}`

### Subtypes

| Subtype                                   | Value |
| ----------------------------------------- | ----- |
| Gamepad                                   | 1     |
| Wheel                                     | 2     |
| Arcade Stick                              | 3     |
| Flight Stick                              | 4     |
| Dance Pad                                 | 5     |
| Guitar                                    | 6     |
| Guitar Alternate                          | 7     |
| Drums                                     | 8     |
| Rock Band Stage Kit                       | 9     |
| Guitar Bass                               | 11    |
| Rock Band Pro Keys                        | 15    |
| Arcade Pad                                | 19    |
| Turntable                                 | 23    |
| Rock Band Pro Guitar                      | 25    |
| Disney Infinity or Lego Dimensions Portal | 33    |
| Skylanders Portal                         | 36    |

See: [API Reference](../api/overview.md)

## (RAW) Streaming protocol

The device stream is a bidirectional, raw TCP connection with fixed-size packets.

### Input State

- 20-byte packets, little-endian layout:
    - Buttons: uint32 (4 bytes, bitfield)
    - Triggers: LT, RT: uint8, uint8 (2 bytes)  
      0-255 (0=not pressed, 255=fully pressed)
    - Sticks: LX, LY, RX, RY: int16 each (8 bytes)  
      0 is center, -32768 is min, 32767 is max
    - Reserved: there are 6 reserved bytes at the end of the report. For most subtypes, these will be zeroed, but a few subtypes do put data here.

### Rumble Feedback

- 2-byte packets:
    - LeftMotor: uint8, RightMotor: uint8  
      0-255 intensity values

See `/device/xbox360/inputstate.go` for details.

### Button constants

| Button             | Hex Value |
| ------------------ | --------- |
| D-Pad Up           | 0x0001    |
| D-Pad Down         | 0x0002    |
| D-Pad Left         | 0x0004    |
| D-Pad Right        | 0x0008    |
| Start button       | 0x0010    |
| Back button        | 0x0020    |
| Left stick button  | 0x0040    |
| Right stick button | 0x0080    |
| Left bumper        | 0x0100    |
| Right bumper       | 0x0200    |
| Xbox/Guide button  | 0x0400    |
| A button           | 0x1000    |
| B button           | 0x2000    |
| X button           | 0x4000    |
| Y button           | 0x8000    |

=== "libVIIPER"

## API

| Function | Description |
| --- | --- |
| `CreateXbox360Device(serverHandle, &handle, busID, autoAttach, vid, pid, subType)` | Create a virtual Xbox 360 controller |
| `SetXbox360DeviceState(handle, state)` | Push an input state to the device |
| `SetXbox360RumbleCallback(handle, cb)` | Register a callback for rumble output |
| `RemoveXbox360Device(handle)` | Remove the device |

## Input state

```c
typedef struct {
    uint32_t Buttons;
    uint8_t  LT;
    uint8_t  RT;
    int16_t  LX;
    int16_t  LY;
    int16_t  RX;
    int16_t  RY;
    uint8_t  Reserved[6];
} Xbox360DeviceState;
```

### Button flags

| Constant | Value |
| --- | --- |
| `XBOX360_BUTTON_DPAD_UP` | `0x0001` |
| `XBOX360_BUTTON_DPAD_DOWN` | `0x0002` |
| `XBOX360_BUTTON_DPAD_LEFT` | `0x0004` |
| `XBOX360_BUTTON_DPAD_RIGHT` | `0x0008` |
| `XBOX360_BUTTON_START` | `0x0010` |
| `XBOX360_BUTTON_BACK` | `0x0020` |
| `XBOX360_BUTTON_LEFT_THUMB` | `0x0040` |
| `XBOX360_BUTTON_RIGHT_THUMB` | `0x0080` |
| `XBOX360_BUTTON_LEFT_SHOULDER` | `0x0100` |
| `XBOX360_BUTTON_RIGHT_SHOULDER` | `0x0200` |
| `XBOX360_BUTTON_GUIDE` | `0x0400` |
| `XBOX360_BUTTON_A` | `0x1000` |
| `XBOX360_BUTTON_B` | `0x2000` |
| `XBOX360_BUTTON_X` | `0x4000` |
| `XBOX360_BUTTON_Y` | `0x8000` |

## Rumble callback

```c
typedef void (*Xbox360RumbleCallback)(Xbox360DeviceHandle handle, uint8_t leftMotor, uint8_t rightMotor);
```

Pass `NULL` to `SetXbox360RumbleCallback` to clear a previously registered callback.