WebHID fixes

This commit is contained in:
Nintorch 2026-05-14 16:27:55 +05:00
parent 138683e645
commit 6577fc722e
4 changed files with 49 additions and 31 deletions

View file

@ -27,6 +27,10 @@
EM_JS_DEPS(hidapi, "$dynCall");
#if 0
#define HIDAPI_WEBHID_DEBUG
#endif
struct hid_device_ {
int device_id;
unsigned char *last_report;
@ -66,26 +70,8 @@ HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
return HID_API_VERSION_STR;
}
// static void test(hid_device *dev, unsigned char *data, size_t length)
// static void test(unsigned char *data)
// {
// // printf("Test function, device_id=%d\n", dev->device_id);
// printf("Test function\n");
// for (int i = 0; i < 3; i++) {
// printf("Test function, data[%d]=%d\n", i, data[i]);
// }
// free(data);
// }
int HID_API_EXPORT hid_init(void)
{
// MAIN_THREAD_EM_ASM({
// const typedArray = Uint8Array.from([1,2,3]);
// const heapPointer = _malloc(typedArray.length * typedArray.BYTES_PER_ELEMENT);
// HEAPU8.set(typedArray, heapPointer);
// dynCall('vi', $0, [heapPointer]);
// }, &test);
return MAIN_THREAD_EM_ASM_INT({
return "hid" in navigator ? 0 : -1;
});
@ -167,12 +153,14 @@ static struct hid_device_info * create_device_info_for_device(int device_id)
cur_dev->next = NULL;
#ifdef HIDAPI_WEBHID_DEBUG
printf("HIDAPI: New device found: %d %d\n", cur_dev->vendor_id, cur_dev->product_id);
#endif
end:
return root;
}
// TODO: remove all EM_ASYNC_JS
// TODO: remove all EM_ASYNC_JS for non-blocking operations
EM_ASYNC_JS(int, hid_js_get_device_count, (), {
window._hidDeviceList = await navigator.hid.getDevices();
return window._hidDeviceList.length;
@ -188,7 +176,9 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, u
device_count = hid_js_get_device_count();
#ifdef HIDAPI_WEBHID_DEBUG
printf("hid_enumerate, device_count=%d\n", device_count);
#endif
int device_id;
for (device_id = 0; device_id < device_count; device_id++) {
@ -277,7 +267,9 @@ static void set_byte(unsigned char *data, size_t length, int byte, size_t offset
if (offset >= length)
return;
data[offset] = (unsigned char)byte;
#ifdef HIDAPI_WEBHID_DEBUG
// printf("set_byte: offset=%d byte=%d\n", (int)offset, byte);
#endif
}
static void set_report(hid_device *dev, unsigned char *data, size_t length)
@ -292,16 +284,14 @@ static void set_report(hid_device *dev, unsigned char *data, size_t length)
EM_ASYNC_JS(void, hid_js_open, (int device_id, hid_device *dev, SetByteCallback callback, SetReportCallback set_report_callback), {
let device = window._hidDeviceList[device_id];
console.log("Opening device1 " + device_id);
if (device) {
console.log("Opening device2 " + device_id);
await device.open();
device.addEventListener("inputreport", function (event) {
const { data, device, reportId } = event;
let dataLength = data['byteLength']+1;
let pointer = _malloc(dataLength);
dynCall("viiii", callback, [pointer, dataLength, report_id, 0]);
dynCall("viiii", callback, [pointer, dataLength, reportId, 0]);
for (let i = 0; i < data['byteLength']; i++) {
dynCall("viiii", callback, [pointer, dataLength, data['getUint8'](i), i+1]);
}
@ -318,16 +308,22 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
hid_init();
/* register_global_error: global error is reset by hid_init */
#ifdef HIDAPI_WEBHID_DEBUG
printf("hid_open_path: %s\n", path);
#endif
dev = new_hid_device();
if (!dev) {
#ifdef HIDAPI_WEBHID_DEBUG
printf("hid_open_path: no memory\n");
#endif
return NULL;
}
if (sscanf(path, "hid%d", &device_id) != 1) {
free(dev);
#ifdef HIDAPI_WEBHID_DEBUG
printf("hid_open_path: invalid path\n");
#endif
return NULL;
}
@ -342,7 +338,6 @@ EM_ASYNC_JS(int, hid_js_write, (int device_id, int report_id, const unsigned cha
if (device) {
let dataArray = new Uint8Array(length);
for (let i = 0; i < length; i++) {
// console.log("hid_write: offset=" + i + " byte=" + HEAPU8[data+i]);
dataArray[i] = HEAPU8[data+i];
}
await device.sendReport(report_id, dataArray);
@ -362,8 +357,8 @@ EM_ASYNC_JS(int, hid_js_read_timeout, (int device_id, unsigned char *data, size_
if (device) {
let [report_id, dataView] = await new Promise(function(resolve, reject) {
device.addEventListener("inputreport", function (event) {
const { data, device, reportId } = event;
resolve([reportId, data]); // done
const { data, device, report_id } = event;
resolve([report_id, data]); // done
}, {once: true});
});
dynCall("viiii", callback, [data, length, report_id, 0]);

View file

@ -1034,7 +1034,6 @@ static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, touchpad_down, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_down ? 1.0f : 0.0f);
}
printf("PS4 Packet usb1 %d\n", packet->rgucButtonsHatAndCounter[0]);
if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
{
Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
@ -1296,9 +1295,7 @@ static bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_PS4_PROTOCOL
HIDAPI_DumpPacket("PS4 packet: size = %d", data, size);
#endif
printf("PS4 Packet start\n");
if (!HIDAPI_DriverPS4_IsPacketValid(ctx, data, size)) {
printf("PS4 Packet invalid\n");
continue;
}
@ -1306,13 +1303,11 @@ static bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
ctx->last_packet = now;
if (!joystick) {
printf("PS4 Packet no joystick\n");
continue;
}
switch (data[0]) {
case k_EPS4ReportIdUsbState:
printf("PS4 Packet usb, packet[1]=%d\n", +data[1]);
HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1], size - 1);
break;
case k_EPS4ReportIdBluetoothState1:

View file

@ -49,12 +49,15 @@ typedef struct SDL_HIDAPI_RumbleContext
SDL_HIDAPI_RumbleRequest *requests_tail;
} SDL_HIDAPI_RumbleContext;
#ifndef SDL_PLATFORM_EMSCRIPTEN
#ifndef SDL_THREAD_SAFETY_ANALYSIS
static
#endif
SDL_Mutex *SDL_HIDAPI_rumble_lock;
#endif
static SDL_HIDAPI_RumbleContext rumble_context SDL_GUARDED_BY(SDL_HIDAPI_rumble_lock);
#ifndef SDL_PLATFORM_EMSCRIPTEN // Threads are not used for the web
static int SDLCALL SDL_HIDAPI_RumbleThread(void *data)
{
SDL_HIDAPI_RumbleContext *ctx = (SDL_HIDAPI_RumbleContext *)data;
@ -161,9 +164,11 @@ static bool SDL_HIDAPI_StartRumbleThread(SDL_HIDAPI_RumbleContext *ctx)
}
return true;
}
#endif
bool SDL_HIDAPI_LockRumble(void)
{
#ifndef SDL_PLATFORM_EMSCRIPTEN
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
if (SDL_CompareAndSwapAtomicInt(&ctx->initialized, false, true)) {
@ -173,11 +178,13 @@ bool SDL_HIDAPI_LockRumble(void)
}
SDL_LockMutex(SDL_HIDAPI_rumble_lock);
#endif
return true;
}
bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size)
{
#ifndef SDL_PLATFORM_EMSCRIPTEN
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
SDL_HIDAPI_RumbleRequest *request, *found;
@ -193,6 +200,7 @@ bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data,
*maximum_size = sizeof(found->data);
return true;
}
#endif
return false;
}
@ -212,6 +220,7 @@ int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const
return -1;
}
#ifndef SDL_PLATFORM_EMSCRIPTEN
request = (SDL_HIDAPI_RumbleRequest *)SDL_calloc(1, sizeof(*request));
if (!request) {
SDL_HIDAPI_UnlockRumble();
@ -234,6 +243,9 @@ int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const
// Make sure we unlock before posting the semaphore so the rumble thread can run immediately
SDL_HIDAPI_UnlockRumble();
#else
SDL_hid_write(device->dev, data, size);
#endif
SDL_SignalSemaphore(ctx->request_sem);
@ -242,7 +254,9 @@ int SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(SDL_HIDAPI_Device *device, const
void SDL_HIDAPI_UnlockRumble(void)
{
#ifndef SDL_PLATFORM_EMSCRIPTEN
SDL_UnlockMutex(SDL_HIDAPI_rumble_lock);
#endif
}
int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size)
@ -273,11 +287,13 @@ int SDL_HIDAPI_SendRumble(SDL_HIDAPI_Device *device, const Uint8 *data, int size
void SDL_HIDAPI_QuitRumble(void)
{
#ifndef SDL_PLATFORM_EMSCRIPTEN
SDL_HIDAPI_RumbleContext *ctx = &rumble_context;
if (SDL_GetAtomicInt(&ctx->running)) {
SDL_HIDAPI_StopRumbleThread(ctx);
}
#endif
}
#endif // SDL_JOYSTICK_HIDAPI

View file

@ -642,6 +642,7 @@ void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 vendor_id, Uint16
device->guid = SDL_CreateJoystickGUID(device->guid.data[0], vendor_id, product_id, device->version, device->manufacturer_string, device->product_string, 'h', 0);
}
#ifndef SDL_PLATFORM_EMSCRIPTEN
static void HIDAPI_UpdateJoystickSerial(SDL_HIDAPI_Device *device)
{
int i;
@ -656,6 +657,7 @@ static void HIDAPI_UpdateJoystickSerial(SDL_HIDAPI_Device *device)
}
}
}
#endif
static bool HIDAPI_SerialIsEmpty(SDL_HIDAPI_Device *device)
{
@ -675,13 +677,18 @@ static bool HIDAPI_SerialIsEmpty(SDL_HIDAPI_Device *device)
void HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial)
{
#ifdef SDL_PLATFORM_EMSCRIPTEN
// Don't include the serial number for the web to decrease the fingerprinting surface
#else
if (serial && *serial && (!device->serial || SDL_strcmp(serial, device->serial) != 0)) {
SDL_free(device->serial);
device->serial = SDL_strdup(serial);
HIDAPI_UpdateJoystickSerial(device);
}
#endif
}
#ifndef SDL_PLATFORM_EMSCRIPTEN
static int wcstrcmp(const wchar_t *str1, const char *str2)
{
int result;
@ -696,14 +703,19 @@ static int wcstrcmp(const wchar_t *str1, const char *str2)
}
return result;
}
#endif
static void HIDAPI_SetDeviceSerialW(SDL_HIDAPI_Device *device, const wchar_t *serial)
{
#ifdef SDL_PLATFORM_EMSCRIPTEN
// Don't include the serial number for the web to decrease the fingerprinting surface
#else
if (serial && *serial && (!device->serial || wcstrcmp(serial, device->serial) != 0)) {
SDL_free(device->serial);
device->serial = HIDAPI_ConvertString(serial);
HIDAPI_UpdateJoystickSerial(device);
}
#endif
}
bool HIDAPI_HasConnectedUSBDevice(const char *serial)