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
15 changes: 15 additions & 0 deletions docs/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ new metadata fields make backend selection easier for agents and host apps:
- `transport`: memory, callback, WebSocket, or native process
- `virtualDeviceKind`: none, native helper, or OS virtual gamepad

For `NativeBridgeAdapter` and `NativeProcessBridgeAdapter`, these formats and
feature booleans describe the configured SDK serializer. Their default options
advertise full controller state, touchpad/motion/status data, and profile HID
reports. Disabling `includeState`, `includeExtensions`, and
`includeProfileHidReport` removes those corresponding claims while retaining
the XInput and HID gamepad reports and the JSONL transport. Touchpad and gyro
remain advertised if any enabled state channel can carry them; device status
tracks the full state and extensions channels.
`supportedCommands` continues to describe runtime actions the adapter accepts;
it does not change when an output channel is suppressed.

This metadata does not establish support from the operating system, browser,
physical device, Steam, or a game. Those layers may omit or reinterpret data
even when the SDK serializer emits it.

```ts
const capabilities = controller.capabilities();

Expand Down
63 changes: 63 additions & 0 deletions packages/core/src/__tests__/native-bridge-capabilities.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { describe, expect, test } from "bun:test";
import { NativeBridgeAdapter, NativeProcessBridgeAdapter } from "../adapters";

describe("native bridge adapter capabilities", () => {
test("describe default serialized state and profile report outputs", () => {
const adapters = [
new NativeBridgeAdapter(),
new NativeProcessBridgeAdapter({ command: "/bin/cat" }),
];

for (const adapter of adapters) {
const capabilities = adapter.capabilities();
expect(capabilities.supportsTouchpad).toBe(true);
expect(capabilities.supportsGyro).toBe(true);
expect(capabilities.supportsDeviceStatus).toBe(true);
expect(capabilities.outputFormats).toEqual([
"controller-state",
"xinput-report",
"hid-gamepad-report",
"hid-playstation-extended-report",
"hid-switch-extended-report",
"native-bridge-jsonl",
]);
expect(capabilities.reportFormats).toEqual([
"xinput",
"hid-gamepad",
"hid-playstation-extended",
"hid-switch-extended",
]);
}
});

test("omit capability claims for fully suppressed payload channels", () => {
const adapters = [
new NativeBridgeAdapter({
includeState: false,
includeExtensions: false,
includeProfileHidReport: false,
}),
new NativeProcessBridgeAdapter({
command: "/bin/cat",
includeState: false,
includeExtensions: false,
includeProfileHidReport: false,
}),
];

for (const adapter of adapters) {
const capabilities = adapter.capabilities();
expect(capabilities.supportsTouchpad).toBe(false);
expect(capabilities.supportsGyro).toBe(false);
expect(capabilities.supportsDeviceStatus).toBe(false);
expect(capabilities.outputFormats).toEqual([
"xinput-report",
"hid-gamepad-report",
"native-bridge-jsonl",
]);
expect(capabilities.reportFormats).toEqual(["xinput", "hid-gamepad"]);
expect(capabilities.supportedCommands).toContain("touchpad");
expect(capabilities.supportedCommands).toContain("motion");
}
});
});
27 changes: 19 additions & 8 deletions packages/core/src/adapters/native-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,38 @@ export class NativeBridgeAdapter implements ControllerAdapter {
}

capabilities() {
const includeState = this.options.includeState !== false;
const includeExtensions = this.options.includeExtensions !== false;
const includeProfileHidReport =
this.options.includeProfileHidReport !== false;
return createAdapterCapabilities({
supportsStateSync: true,
supportsXInputReports: true,
supportsNativeBridge: true,
supportsTouchpad: true,
supportsGyro: true,
supportsDeviceStatus: true,
supportsTouchpad:
includeState || includeExtensions || includeProfileHidReport,
supportsGyro:
includeState || includeExtensions || includeProfileHidReport,
supportsDeviceStatus: includeState || includeExtensions,
supportedCommands: controllerCommandTypes,
outputFormats: [
"controller-state",
...(includeState ? (["controller-state"] as const) : []),
"xinput-report",
"hid-gamepad-report",
"hid-playstation-extended-report",
"hid-switch-extended-report",
...(includeProfileHidReport
? ([
"hid-playstation-extended-report",
"hid-switch-extended-report",
] as const)
: []),
"native-bridge-jsonl",
],
reportFormats: [
"xinput",
"hid-gamepad",
"hid-playstation-extended",
"hid-switch-extended",
...(includeProfileHidReport
? (["hid-playstation-extended", "hid-switch-extended"] as const)
: []),
],
transport: "callback",
});
Expand Down
27 changes: 19 additions & 8 deletions packages/core/src/adapters/native-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ export class NativeProcessBridgeAdapter implements ControllerAdapter {
}

capabilities() {
const includeState = this.options.includeState !== false;
const includeExtensions = this.options.includeExtensions !== false;
const includeProfileHidReport =
this.options.includeProfileHidReport !== false;
const supportsRumble = this.options.supportsRumble ?? false;
const supportsLights = this.options.supportsLights ?? false;
const supportsVirtualDevice = this.options.supportsVirtualDevice ?? true;
Expand All @@ -176,27 +180,34 @@ export class NativeProcessBridgeAdapter implements ControllerAdapter {
supportsNativeBridge: true,
supportsRumble,
supportsLights,
supportsTouchpad: true,
supportsGyro: true,
supportsDeviceStatus: true,
supportsTouchpad:
includeState || includeExtensions || includeProfileHidReport,
supportsGyro:
includeState || includeExtensions || includeProfileHidReport,
supportsDeviceStatus: includeState || includeExtensions,
supportsVirtualDevice,
supportedCommands: controllerCommandTypes,
requiresNativeInstall: this.options.requiresNativeInstall ?? true,
requiresElevatedPermissions:
this.options.requiresElevatedPermissions ?? false,
outputFormats: [
"controller-state",
...(includeState ? (["controller-state"] as const) : []),
"xinput-report",
"hid-gamepad-report",
"hid-playstation-extended-report",
"hid-switch-extended-report",
...(includeProfileHidReport
? ([
"hid-playstation-extended-report",
"hid-switch-extended-report",
] as const)
: []),
"native-bridge-jsonl",
],
reportFormats: [
"xinput",
"hid-gamepad",
"hid-playstation-extended",
"hid-switch-extended",
...(includeProfileHidReport
? (["hid-playstation-extended", "hid-switch-extended"] as const)
: []),
...feedbackReportFormats,
],
feedbackTypes: [
Expand Down
Loading