Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Added

- **Xbox Elite Series 2 wired support.** The pad (`045e:0b00`) speaks the same 18-byte GIP input frame over USB as the already-supported Xbox One S, but its PID was unlisted, so it fell through to the `generic` driver and produced no input. Adding it to `XBOX_GIP_PIDS` is sufficient; no parser changes were needed.

## [1.4.0] - 2026-07-23

### Added
Expand Down
1 change: 1 addition & 0 deletions CONTROLLERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Every controller below has a committed `openmicro doctor` report. CI replays cap
| ------------------------------- | ------------------------------- | --------- | ---------- | --------- | -------------- | ------------- | ------- |
| GameSir Cyclone 2 (DS4 mode) | DUALSHOCK 4 Wireless Controller | 054c:05c4 | bluetooth | ds4 | 17/17 | none | ✅ full |
| GameSir G7 Pro | GameSir-G7 Pro | 3537:1022 | bluetooth | gamesir | 17/17 | none | ✅ full |
| Microsoft Xbox Elite Series 2 | Controller | 045e:0b00 | usb | xbox | 17/17 | none | ✅ full |
| Microsoft Xbox One S Controller | Controller | 045e:02ea | usb | xbox | 17/17 | none | ✅ full |
| Microsoft Xbox One S Controller | Xbox Wireless Controller | 045e:0b20 | bluetooth | xbox | 17/17 | none | ✅ full |
| Sony DualSense | DualSense Wireless Controller | 054c:0ce6 | usb | dualsense | 17/17 | lightbar+LEDs | ✅ full |
Expand Down
5 changes: 3 additions & 2 deletions src/controller/xbox-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import type { ButtonId, ControllerEvent } from '../types.js'
export const XBOX_VID = 0x045e
export const XBOX_PIDS = [0x0b12, 0x0b13, 0x02fd, 0x02e0]
// Wired pads that speak GIP over USB (macOS exposes them via HID with the raw
// GIP input frame). Verified against a live Xbox One S (0x02ea) capture.
export const XBOX_GIP_PIDS = [0x02ea]
// GIP input frame). Verified against live Xbox One S (0x02ea) and Xbox Elite
// Series 2 (0x0b00) captures.
export const XBOX_GIP_PIDS = [0x02ea, 0x0b00]
// Bluetooth pads using the standard Xbox BT HID report (report ID 0x01).
// Verified against a live Xbox Wireless Controller (0x0b20) capture.
export const XBOX_BT_PIDS = [0x0b20]
Expand Down
159 changes: 159 additions & 0 deletions test/fixtures/controllers/045e-0b00-usb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
"schemaVersion": 1,
"openmicroVersion": "1.4.0",
"platform": "darwin",
"osVersion": "Darwin Kernel Version 25.5.0: Mon Apr 27 20:41:15 PDT 2026; root:xnu-12377.121.6~2/RELEASE_ARM64_T6041",
"controller": {
"vid": "0x045e",
"pid": "0x0b00",
"product": "Controller",
"makeModel": "Microsoft Xbox Elite Series 2",
"transport": "usb",
"driver": "xbox"
},
"results": {
"south": {
"status": "pass"
},
"east": {
"status": "pass",
"capture": {
"pressed": "2000e62f20000000000036000e07d0041904",
"idle": "2000da2f1000000000004d040e07d0041904"
}
},
"west": {
"status": "pass",
"capture": {
"pressed": "2000eb2f40000000000096000e07d0041904",
"idle": "2000e62f20000000000036000e07d0041904"
}
},
"north": {
"status": "pass",
"capture": {
"pressed": "2000ed2f80000000000096000e07d0041904",
"idle": "2000eb2f40000000000096000e07d0041904"
}
},
"dpad_up": {
"status": "pass",
"capture": {
"pressed": "2000fc2f0001000000008dfc0e0778038e02",
"idle": "2000ed2f80000000000096000e07d0041904"
}
},
"dpad_down": {
"status": "pass",
"capture": {
"pressed": "2000fe2f0002000000008dfc0e0778038e02",
"idle": "2000fc2f0001000000008dfc0e0778038e02"
}
},
"dpad_left": {
"status": "pass",
"capture": {
"pressed": "2000012f0004000000008dfc0e0778038e02",
"idle": "2000fe2f0002000000008dfc0e0778038e02"
}
},
"dpad_right": {
"status": "pass",
"capture": {
"pressed": "2000032f0008000000008dfc0e0778038e02",
"idle": "2000012f0004000000008dfc0e0778038e02"
}
},
"l1": {
"status": "pass",
"capture": {
"pressed": "2000052f0010000000008dfc0e0778038e02",
"idle": "2000032f0008000000008dfc0e0778038e02"
}
},
"r1": {
"status": "pass",
"capture": {
"pressed": "2000092f0020000000008dfc0e0778038e02",
"idle": "2000052f0010000000008dfc0e0778038e02"
}
},
"l2": {
"status": "pass",
"capture": {
"pressed": "20000c2f0000100300008dfc0e0778038e02",
"idle": "2000092f0020000000008dfc0e0778038e02"
}
},
"r2": {
"status": "pass",
"capture": {
"pressed": "2000102f0000000017018dfc0e0778038e02",
"idle": "20000c2f0000100300008dfc0e0778038e02"
}
},
"l3": {
"status": "pass",
"capture": {
"pressed": "2000252f00400000000042fdbbf442047dfb",
"idle": "2000102f0000000017018dfc0e0778038e02"
}
},
"r3": {
"status": "pass",
"capture": {
"pressed": "20003d2f0080000000001d0676f6a504c702",
"idle": "2000252f00400000000042fdbbf442047dfb"
}
},
"menu": {
"status": "pass",
"capture": {
"pressed": "2000742f0400000000000f0584f796018608",
"idle": "20003d2f0080000000001d0676f6a504c702"
}
},
"view": {
"status": "pass",
"capture": {
"pressed": "2000852f0800000000000f05a1f71202e500",
"idle": "2000742f0400000000000f0584f796018608"
}
},
"touchpad": {
"status": "pass",
"capture": {
"pressed": "07304b02015b",
"idle": "2000852f0800000000000f05a1f71202e500"
}
}
},
"axes": {
"left_x": {
"min": -1,
"max": 1
},
"left_y": {
"min": -1,
"max": 1
},
"right_x": {
"min": -1,
"max": 1
},
"right_y": {
"min": -1,
"max": 1
},
"l2": {
"min": 0,
"max": 1
},
"r2": {
"min": 0,
"max": 1
}
},
"output": "unsupported",
"timestamp": "2026-07-27T19:49:41.053Z"
}