125 lines
3.7 KiB
C
125 lines
3.7 KiB
C
#include "stk/stk.h"
|
|
|
|
#include <windows.h>
|
|
#include <setupapi.h>
|
|
#include <hidsdi.h>
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
// GUID_DEVINTERFACE_HID from devguid.h
|
|
static const GUID GUID_DEVINTERFACE_HID = {
|
|
0x4d1e55b2, 0xf16f, 0x11cf,
|
|
{ 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 }
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Internal state
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static HANDLE g_handle = INVALID_HANDLE_VALUE;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Platform backend
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int stk_open(stk_config_t const* config) {
|
|
if (!config)
|
|
return -1;
|
|
|
|
HDEVINFO info = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_HID, NULL,
|
|
NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
if (info == INVALID_HANDLE_VALUE)
|
|
return -1;
|
|
|
|
for (DWORD i = 0; ; i++) {
|
|
SP_DEVICE_INTERFACE_DATA iface = { .cbSize = sizeof(iface) };
|
|
if (!SetupDiEnumDeviceInterfaces(info, NULL,
|
|
&GUID_DEVINTERFACE_HID, i, &iface))
|
|
break;
|
|
|
|
DWORD buflen = 0;
|
|
SetupDiGetDeviceInterfaceDetailW(info, &iface, NULL, 0, &buflen, NULL);
|
|
if (buflen == 0)
|
|
continue;
|
|
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail =
|
|
(PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
|
|
0, buflen);
|
|
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
|
|
|
if (!SetupDiGetDeviceInterfaceDetailW(info, &iface, detail, buflen,
|
|
&buflen, NULL)) {
|
|
HeapFree(GetProcessHeap(), 0, detail);
|
|
continue;
|
|
}
|
|
|
|
HANDLE handle = CreateFileW(detail->DevicePath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0,
|
|
NULL);
|
|
|
|
HeapFree(GetProcessHeap(), 0, detail);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
continue;
|
|
|
|
HIDD_ATTRIBUTES attrs = { .Size = sizeof(attrs) };
|
|
if (!HidD_GetAttributes(handle, &attrs)) {
|
|
CloseHandle(handle);
|
|
continue;
|
|
}
|
|
|
|
if (attrs.VendorID == config->vendor_id &&
|
|
attrs.ProductID == config->product_id) {
|
|
g_handle = handle;
|
|
SetupDiDestroyDeviceInfoList(info);
|
|
return 0;
|
|
}
|
|
|
|
CloseHandle(handle);
|
|
}
|
|
|
|
SetupDiDestroyDeviceInfoList(info);
|
|
fprintf(stderr, "stk: device 0x%04X:0x%04X not found\n",
|
|
config->vendor_id, config->product_id);
|
|
return -1;
|
|
}
|
|
|
|
int stk_read(stk_state_t* state) {
|
|
if (g_handle == INVALID_HANDLE_VALUE)
|
|
return -1;
|
|
|
|
uint8_t buf[64];
|
|
DWORD bytes = 0;
|
|
|
|
if (!ReadFile(g_handle, buf, sizeof(buf), &bytes, NULL))
|
|
return -1;
|
|
|
|
if (bytes < 20)
|
|
return -1;
|
|
|
|
// Parse axes (little-endian 16-bit values, offset by 2 bytes)
|
|
for (int i = 0; i < STK_NUM_AXES; i++) {
|
|
size_t off = 2 + (size_t)i * 2;
|
|
uint16_t val = (uint16_t)buf[off] |
|
|
((uint16_t)buf[off + 1] << 8);
|
|
state->axes[i] = (int16_t)val;
|
|
}
|
|
|
|
// Parse buttons (byte 1 + bytes 18-19 = 24 bits)
|
|
state->buttons = (uint32_t)buf[1] |
|
|
((uint32_t)buf[18] << 8) |
|
|
((uint32_t)buf[19] << 16);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void stk_close(void) {
|
|
if (g_handle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(g_handle);
|
|
g_handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|