@@ -66,8 +66,17 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
66
66
goto done ;
67
67
}
68
68
69
+ int first_hat_button = -1 ;
70
+ int num_buttons = gamepadEvent -> numButtons ;
71
+ if ((SDL_strcmp (gamepadEvent -> mapping , "standard" ) == 0 ) && (num_buttons >= 16 )) { // maps to a game console gamepad layout, turn the d-pad into a hat.
72
+ num_buttons -= 4 ;
73
+ first_hat_button = 12 ;
74
+ }
75
+
76
+ item -> first_hat_button = first_hat_button ;
77
+ item -> nhats = (first_hat_button >= 0 ) ? 1 : 0 ;
69
78
item -> naxes = gamepadEvent -> numAxes ;
70
- item -> nbuttons = gamepadEvent -> numButtons ;
79
+ item -> nbuttons = num_buttons ;
71
80
item -> device_instance = SDL_GetNextObjectID ();
72
81
73
82
item -> timestamp = gamepadEvent -> timestamp ;
@@ -76,9 +85,30 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
76
85
item -> axis [i ] = gamepadEvent -> axis [i ];
77
86
}
78
87
79
- for (i = 0 ; i < item -> nbuttons ; i ++ ) {
80
- item -> analogButton [i ] = gamepadEvent -> analogButton [i ];
81
- item -> digitalButton [i ] = gamepadEvent -> digitalButton [i ];
88
+ int buttonidx = 0 ;
89
+ for (i = 0 ; i < item -> nbuttons ; i ++ , buttonidx ++ ) {
90
+ if (buttonidx == first_hat_button ) {
91
+ buttonidx += 3 ; // skip these buttons, we're treating them as hat input.
92
+ }
93
+ item -> analogButton [i ] = gamepadEvent -> analogButton [buttonidx ];
94
+ item -> digitalButton [i ] = gamepadEvent -> digitalButton [buttonidx ];
95
+ }
96
+
97
+ SDL_assert (item -> nhats <= 1 ); // there is (currently) only ever one of these, faked from the d-pad buttons.
98
+ if (item -> nhats ) {
99
+ Uint8 value = SDL_HAT_CENTERED ;
100
+ // this currently expects the first button to be up, then down, then left, then right.
101
+ if (gamepadEvent -> digitalButton [first_hat_button + 0 ]) {
102
+ value |= SDL_HAT_UP ;
103
+ } else if (gamepadEvent -> digitalButton [first_hat_button + 1 ]) {
104
+ value |= SDL_HAT_DOWN ;
105
+ }
106
+ if (gamepadEvent -> digitalButton [first_hat_button + 2 ]) {
107
+ value |= SDL_HAT_LEFT ;
108
+ } else if (gamepadEvent -> digitalButton [first_hat_button + 3 ]) {
109
+ value |= SDL_HAT_RIGHT ;
110
+ }
111
+ item -> hat = value ;
82
112
}
83
113
84
114
if (!SDL_joylist_tail ) {
@@ -318,9 +348,8 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
318
348
joystick -> hwdata = (struct joystick_hwdata * )item ;
319
349
item -> joystick = joystick ;
320
350
321
- // HTML5 Gamepad API doesn't say anything about these
322
- joystick -> nhats = 0 ;
323
-
351
+ // HTML5 Gamepad API doesn't offer hats, but we can fake it from the d-pad buttons on the "standard" mapping.
352
+ joystick -> nhats = item -> nhats ;
324
353
joystick -> nbuttons = item -> nbuttons ;
325
354
joystick -> naxes = item -> naxes ;
326
355
@@ -361,15 +390,21 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
361
390
result = emscripten_get_gamepad_status (item -> index , & gamepadState );
362
391
if (result == EMSCRIPTEN_RESULT_SUCCESS ) {
363
392
if (gamepadState .timestamp == 0 || gamepadState .timestamp != item -> timestamp ) {
364
- for (i = 0 ; i < item -> nbuttons ; i ++ ) {
365
- if (item -> digitalButton [i ] != gamepadState .digitalButton [i ]) {
366
- bool down = (gamepadState .digitalButton [i ] != 0 );
393
+ const int first_hat_button = item -> first_hat_button ;
394
+
395
+ int buttonidx = 0 ;
396
+ for (i = 0 ; i < item -> nbuttons ; i ++ , buttonidx ++ ) {
397
+ if (buttonidx == first_hat_button ) {
398
+ buttonidx += 4 ; // skip these buttons, we're treating them as hat input.
399
+ }
400
+ if (item -> digitalButton [i ] != gamepadState .digitalButton [buttonidx ]) {
401
+ bool down = (gamepadState .digitalButton [buttonidx ] != 0 );
367
402
SDL_SendJoystickButton (timestamp , item -> joystick , i , down );
368
403
}
369
404
370
405
// store values to compare them in the next update
371
- item -> analogButton [i ] = gamepadState .analogButton [i ];
372
- item -> digitalButton [i ] = gamepadState .digitalButton [i ];
406
+ item -> analogButton [i ] = gamepadState .analogButton [buttonidx ];
407
+ item -> digitalButton [i ] = gamepadState .digitalButton [buttonidx ];
373
408
}
374
409
375
410
for (i = 0 ; i < item -> naxes ; i ++ ) {
@@ -383,6 +418,27 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
383
418
item -> axis [i ] = gamepadState .axis [i ];
384
419
}
385
420
421
+ SDL_assert (item -> nhats <= 1 ); // there is (currently) only ever one of these, faked from the d-pad buttons.
422
+ if (item -> nhats ) {
423
+ Uint8 value = SDL_HAT_CENTERED ;
424
+ // this currently expects the first button to be up, then down, then left, then right.
425
+ if (gamepadState .digitalButton [first_hat_button + 0 ]) {
426
+ value |= SDL_HAT_UP ;
427
+ } else if (gamepadState .digitalButton [first_hat_button + 1 ]) {
428
+ value |= SDL_HAT_DOWN ;
429
+ }
430
+ if (gamepadState .digitalButton [first_hat_button + 2 ]) {
431
+ value |= SDL_HAT_LEFT ;
432
+ } else if (gamepadState .digitalButton [first_hat_button + 3 ]) {
433
+ value |= SDL_HAT_RIGHT ;
434
+ }
435
+ if (item -> hat != value ) {
436
+ item -> hat = value ;
437
+ SDL_SendJoystickHat (timestamp , item -> joystick , 0 , value );
438
+ }
439
+ }
440
+
441
+
386
442
item -> timestamp = gamepadState .timestamp ;
387
443
}
388
444
}
0 commit comments