1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 // Based on
8 // https://cs.chromium.org/chromium/src/device/gamepad/gamepad_standard_mappings.h
9
10 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
11 // Use of this source code is governed by a BSD-style license that can be
12 // found in the LICENSE file.
13
14 #include "mozilla/dom/GamepadRemapping.h"
15 #include "mozilla/dom/GamepadPlatformService.h"
16
17 #include <vector>
18 #include <unordered_map>
19
20 namespace mozilla::dom {
21
22 // Follow the canonical ordering recommendation for the "Standard Gamepad"
23 // from https://www.w3.org/TR/gamepad/#remapping.
24 enum CanonicalButtonIndex {
25 BUTTON_INDEX_PRIMARY,
26 BUTTON_INDEX_SECONDARY,
27 BUTTON_INDEX_TERTIARY,
28 BUTTON_INDEX_QUATERNARY,
29 BUTTON_INDEX_LEFT_SHOULDER,
30 BUTTON_INDEX_RIGHT_SHOULDER,
31 BUTTON_INDEX_LEFT_TRIGGER,
32 BUTTON_INDEX_RIGHT_TRIGGER,
33 BUTTON_INDEX_BACK_SELECT,
34 BUTTON_INDEX_START,
35 BUTTON_INDEX_LEFT_THUMBSTICK,
36 BUTTON_INDEX_RIGHT_THUMBSTICK,
37 BUTTON_INDEX_DPAD_UP,
38 BUTTON_INDEX_DPAD_DOWN,
39 BUTTON_INDEX_DPAD_LEFT,
40 BUTTON_INDEX_DPAD_RIGHT,
41 BUTTON_INDEX_META,
42 BUTTON_INDEX_COUNT
43 };
44
45 enum CanonicalAxisIndex {
46 AXIS_INDEX_LEFT_STICK_X,
47 AXIS_INDEX_LEFT_STICK_Y,
48 AXIS_INDEX_RIGHT_STICK_X,
49 AXIS_INDEX_RIGHT_STICK_Y,
50 AXIS_INDEX_COUNT
51 };
52
53 const float BUTTON_THRESHOLD_VALUE = 0.1f;
54
NormalizeTouch(long aValue,long aMin,long aMax)55 float NormalizeTouch(long aValue, long aMin, long aMax) {
56 return (2.f * (aValue - aMin) / static_cast<float>(aMax - aMin)) - 1.f;
57 }
58
AxisNegativeAsButton(float input)59 bool AxisNegativeAsButton(float input) {
60 const float value = (input < -0.5f) ? 1.f : 0.f;
61 return value > BUTTON_THRESHOLD_VALUE;
62 }
63
AxisPositiveAsButton(float input)64 bool AxisPositiveAsButton(float input) {
65 const float value = (input > 0.5f) ? 1.f : 0.f;
66 return value > BUTTON_THRESHOLD_VALUE;
67 }
68
AxisToButtonValue(double aValue)69 double AxisToButtonValue(double aValue) {
70 // Mapping axis value range from (-1, +1) to (0, +1).
71 return (aValue + 1.0f) * 0.5f;
72 }
73
FetchDpadFromAxis(GamepadHandle aHandle,double dir)74 void FetchDpadFromAxis(GamepadHandle aHandle, double dir) {
75 bool up = false;
76 bool right = false;
77 bool down = false;
78 bool left = false;
79
80 // Dpad is mapped as a direction on one axis, where -1 is up and it
81 // increases clockwise to 1, which is up + left. It's set to a large (> 1.f)
82 // number when nothing is depressed, except on start up, sometimes it's 0.0
83 // for no data, rather than the large number.
84 if (dir != 0.0f) {
85 up = (dir >= -1.f && dir < -0.7f) || (dir >= .95f && dir <= 1.f);
86 right = dir >= -.75f && dir < -.1f;
87 down = dir >= -.2f && dir < .45f;
88 left = dir >= .4f && dir <= 1.f;
89 }
90
91 RefPtr<GamepadPlatformService> service =
92 GamepadPlatformService::GetParentService();
93 if (!service) {
94 return;
95 }
96
97 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP, up);
98 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT, right);
99 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN, down);
100 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT, left);
101 }
102
103 class DefaultRemapper final : public GamepadRemapper {
104 public:
GetAxisCount() const105 virtual uint32_t GetAxisCount() const override { return numAxes; }
106
GetButtonCount() const107 virtual uint32_t GetButtonCount() const override { return numButtons; }
108
SetAxisCount(uint32_t aAxisCount)109 virtual void SetAxisCount(uint32_t aAxisCount) override {
110 numAxes = aAxisCount;
111 }
112
SetButtonCount(uint32_t aButtonCount)113 virtual void SetButtonCount(uint32_t aButtonCount) override {
114 numButtons = aButtonCount;
115 }
116
GetMappingType() const117 virtual GamepadMappingType GetMappingType() const override {
118 return GamepadMappingType::_empty;
119 }
120
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const121 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
122 double aValue) const override {
123 if (GetAxisCount() <= aAxis) {
124 NS_WARNING(
125 nsPrintfCString("Axis idx '%d' doesn't support in DefaultRemapper().",
126 aAxis)
127 .get());
128 return;
129 }
130 RefPtr<GamepadPlatformService> service =
131 GamepadPlatformService::GetParentService();
132 if (!service) {
133 return;
134 }
135 service->NewAxisMoveEvent(aHandle, aAxis, aValue);
136 }
137
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const138 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
139 bool aPressed) const override {
140 if (GetButtonCount() <= aButton) {
141 NS_WARNING(
142 nsPrintfCString(
143 "Button idx '%d' doesn't support in DefaultRemapper().", aButton)
144 .get());
145 return;
146 }
147 RefPtr<GamepadPlatformService> service =
148 GamepadPlatformService::GetParentService();
149 if (!service) {
150 return;
151 }
152 service->NewButtonEvent(aHandle, aButton, aPressed);
153 }
154
155 private:
156 uint32_t numAxes;
157 uint32_t numButtons;
158 };
159
160 class ADT1Remapper final : public GamepadRemapper {
161 public:
GetAxisCount() const162 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
163
GetButtonCount() const164 virtual uint32_t GetButtonCount() const override {
165 return BUTTON_INDEX_COUNT;
166 }
167
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const168 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
169 double aValue) const override {
170 RefPtr<GamepadPlatformService> service =
171 GamepadPlatformService::GetParentService();
172 if (!service) {
173 return;
174 }
175
176 switch (aAxis) {
177 case 0:
178 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
179 break;
180 case 1:
181 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
182 break;
183 case 2:
184 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
185 break;
186 case 3: {
187 const double value = AxisToButtonValue(aValue);
188 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
189 value > BUTTON_THRESHOLD_VALUE, value);
190 break;
191 }
192 case 4: {
193 const double value = AxisToButtonValue(aValue);
194 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
195 value > BUTTON_THRESHOLD_VALUE, value);
196 break;
197 }
198 case 5:
199 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
200 break;
201 case 9:
202 FetchDpadFromAxis(aHandle, aValue);
203 break;
204 default:
205 NS_WARNING(
206 nsPrintfCString("Axis idx '%d' doesn't support in ADT1Remapper().",
207 aAxis)
208 .get());
209 break;
210 }
211 }
212
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const213 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
214 bool aPressed) const override {
215 RefPtr<GamepadPlatformService> service =
216 GamepadPlatformService::GetParentService();
217 if (!service) {
218 return;
219 }
220
221 if (GetButtonCount() <= aButton) {
222 NS_WARNING(
223 nsPrintfCString("Button idx '%d' doesn't support in ADT1Remapper().",
224 aButton)
225 .get());
226 return;
227 }
228
229 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
230 {3, BUTTON_INDEX_TERTIARY},
231 {4, BUTTON_INDEX_QUATERNARY},
232 {6, BUTTON_INDEX_LEFT_SHOULDER},
233 {7, BUTTON_INDEX_RIGHT_SHOULDER},
234 {12, BUTTON_INDEX_META},
235 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
236 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
237
238 auto find = buttonMapping.find(aButton);
239 if (find != buttonMapping.end()) {
240 service->NewButtonEvent(aHandle, find->second, aPressed);
241 } else {
242 service->NewButtonEvent(aHandle, aButton, aPressed);
243 }
244 }
245 };
246
247 class TwoAxesEightKeysRemapper final : public GamepadRemapper {
248 public:
GetAxisCount() const249 virtual uint32_t GetAxisCount() const override { return 0; }
250
GetButtonCount() const251 virtual uint32_t GetButtonCount() const override {
252 return BUTTON_INDEX_COUNT - 1;
253 }
254
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const255 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
256 double aValue) const override {
257 RefPtr<GamepadPlatformService> service =
258 GamepadPlatformService::GetParentService();
259 if (!service) {
260 return;
261 }
262
263 switch (aAxis) {
264 case 0:
265 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT,
266 AxisNegativeAsButton(aValue));
267 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT,
268 AxisPositiveAsButton(aValue));
269 break;
270 case 1:
271 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP,
272 AxisNegativeAsButton(aValue));
273 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN,
274 AxisPositiveAsButton(aValue));
275 break;
276 default:
277 NS_WARNING(
278 nsPrintfCString(
279 "Axis idx '%d' doesn't support in TwoAxesEightKeysRemapper().",
280 aAxis)
281 .get());
282 break;
283 }
284 }
285
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const286 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
287 bool aPressed) const override {
288 RefPtr<GamepadPlatformService> service =
289 GamepadPlatformService::GetParentService();
290 if (!service) {
291 return;
292 }
293
294 if (GetButtonCount() <= aButton) {
295 NS_WARNING(
296 nsPrintfCString(
297 "Button idx '%d' doesn't support in TwoAxesEightKeysRemapper().",
298 aButton)
299 .get());
300 return;
301 }
302
303 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
304 {0, BUTTON_INDEX_QUATERNARY},
305 {2, BUTTON_INDEX_PRIMARY},
306 {3, BUTTON_INDEX_TERTIARY}};
307
308 auto find = buttonMapping.find(aButton);
309 if (find != buttonMapping.end()) {
310 service->NewButtonEvent(aHandle, find->second, aPressed);
311 } else {
312 service->NewButtonEvent(aHandle, aButton, aPressed);
313 }
314 }
315 };
316
317 class StadiaControllerRemapper final : public GamepadRemapper {
318 public:
GetAxisCount() const319 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
320
GetButtonCount() const321 virtual uint32_t GetButtonCount() const override {
322 return STADIA_BUTTON_COUNT;
323 }
324
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const325 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
326 double aValue) const override {
327 RefPtr<GamepadPlatformService> service =
328 GamepadPlatformService::GetParentService();
329 if (!service) {
330 return;
331 }
332
333 switch (aAxis) {
334 case 0:
335 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
336 break;
337 case 1:
338 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
339 break;
340 case 2:
341 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
342 break;
343 case 3:
344 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
345 break;
346 case 4: {
347 const double value = AxisToButtonValue(aValue);
348 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
349 value > BUTTON_THRESHOLD_VALUE, value);
350 break;
351 }
352 case 5: {
353 const double value = AxisToButtonValue(aValue);
354 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
355 value > BUTTON_THRESHOLD_VALUE, value);
356 break;
357 }
358 default:
359 NS_WARNING(
360 nsPrintfCString(
361 "Axis idx '%d' doesn't support in StadiaControllerRemapper().",
362 aAxis)
363 .get());
364 break;
365 }
366 }
367
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const368 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
369 bool aPressed) const override {
370 RefPtr<GamepadPlatformService> service =
371 GamepadPlatformService::GetParentService();
372 if (!service) {
373 return;
374 }
375
376 if (STADIA_BUTTON_COUNT <= aButton) {
377 NS_WARNING(
378 nsPrintfCString(
379 "Button idx '%d' doesn't support in StadiaControllerRemapper().",
380 aButton)
381 .get());
382 return;
383 }
384
385 service->NewButtonEvent(aHandle, aButton, aPressed);
386 }
387
388 private:
389 enum STADIAButtons {
390 STADIA_BUTTON_EXTRA1 = BUTTON_INDEX_COUNT,
391 STADIA_BUTTON_EXTRA2,
392 STADIA_BUTTON_COUNT
393 };
394 };
395
396 class Playstation3Remapper final : public GamepadRemapper {
397 public:
398 Playstation3Remapper() = default;
399
GetAxisCount() const400 uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
401
GetButtonCount() const402 uint32_t GetButtonCount() const override { return BUTTON_INDEX_COUNT; }
403
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const404 void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
405 double aValue) const override {
406 RefPtr<GamepadPlatformService> service =
407 GamepadPlatformService::GetParentService();
408 if (!service) {
409 return;
410 }
411
412 switch (aAxis) {
413 case 0:
414 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
415 break;
416 case 1:
417 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
418 break;
419 case 2:
420 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
421 break;
422 case 5:
423 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
424 break;
425 default:
426 NS_WARNING(
427 nsPrintfCString(
428 "Axis idx '%d' doesn't support in Playstation3Remapper().",
429 aAxis)
430 .get());
431 break;
432 }
433 }
434
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const435 void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
436 bool aPressed) const override {
437 RefPtr<GamepadPlatformService> service =
438 GamepadPlatformService::GetParentService();
439 if (!service) {
440 return;
441 }
442
443 const std::vector<uint32_t> buttonMapping = {BUTTON_INDEX_BACK_SELECT,
444 BUTTON_INDEX_LEFT_THUMBSTICK,
445 BUTTON_INDEX_RIGHT_THUMBSTICK,
446 BUTTON_INDEX_START,
447 BUTTON_INDEX_DPAD_UP,
448 BUTTON_INDEX_DPAD_RIGHT,
449 BUTTON_INDEX_DPAD_DOWN,
450 BUTTON_INDEX_DPAD_LEFT,
451 BUTTON_INDEX_LEFT_TRIGGER,
452 BUTTON_INDEX_RIGHT_TRIGGER,
453 BUTTON_INDEX_LEFT_SHOULDER,
454 BUTTON_INDEX_RIGHT_SHOULDER,
455 BUTTON_INDEX_QUATERNARY,
456 BUTTON_INDEX_SECONDARY,
457 BUTTON_INDEX_PRIMARY,
458 BUTTON_INDEX_TERTIARY,
459 BUTTON_INDEX_META};
460
461 if (buttonMapping.size() <= aButton) {
462 NS_WARNING(
463 nsPrintfCString(
464 "Button idx '%d' doesn't support in Playstation3Remapper().",
465 aButton)
466 .get());
467 return;
468 }
469 service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
470 }
471 };
472
473 class Dualshock4Remapper final : public GamepadRemapper {
474 public:
Dualshock4Remapper()475 Dualshock4Remapper() {
476 mLastTouches.SetLength(TOUCH_EVENT_COUNT);
477 mLastTouchId.SetLength(TOUCH_EVENT_COUNT);
478 }
479
GetAxisCount() const480 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
481
GetButtonCount() const482 virtual uint32_t GetButtonCount() const override {
483 return DUALSHOCK_BUTTON_COUNT;
484 }
485
GetLightIndicatorCount() const486 virtual uint32_t GetLightIndicatorCount() const override {
487 return LIGHT_INDICATOR_COUNT;
488 }
489
GetLightIndicators(nsTArray<GamepadLightIndicatorType> & aTypes) const490 virtual void GetLightIndicators(
491 nsTArray<GamepadLightIndicatorType>& aTypes) const override {
492 const uint32_t len = GetLightIndicatorCount();
493 aTypes.SetLength(len);
494 for (uint32_t i = 0; i < len; ++i) {
495 aTypes[i] = GamepadLightIndicatorType::Rgb;
496 }
497 }
498
GetTouchEventCount() const499 virtual uint32_t GetTouchEventCount() const override {
500 return TOUCH_EVENT_COUNT;
501 }
502
GetLightColorReport(uint8_t aRed,uint8_t aGreen,uint8_t aBlue,std::vector<uint8_t> & aReport) const503 virtual void GetLightColorReport(
504 uint8_t aRed, uint8_t aGreen, uint8_t aBlue,
505 std::vector<uint8_t>& aReport) const override {
506 const size_t report_length = 32;
507 aReport.resize(report_length);
508 aReport.assign(report_length, 0);
509
510 aReport[0] = 0x05; // report ID USB only
511 aReport[1] = 0x02; // LED only
512 aReport[6] = aRed;
513 aReport[7] = aGreen;
514 aReport[8] = aBlue;
515 }
516
GetMaxInputReportLength() const517 virtual uint32_t GetMaxInputReportLength() const override {
518 return MAX_INPUT_LEN;
519 }
520
ProcessTouchData(GamepadHandle aHandle,void * aInput)521 virtual void ProcessTouchData(GamepadHandle aHandle, void* aInput) override {
522 nsTArray<GamepadTouchState> touches(TOUCH_EVENT_COUNT);
523 touches.SetLength(TOUCH_EVENT_COUNT);
524 uint8_t* rawData = (uint8_t*)aInput;
525
526 const uint32_t kTouchDimensionX = 1920;
527 const uint32_t kTouchDimensionY = 942;
528 bool touch0Pressed = (((rawData[35] & 0xff) >> 7) == 0);
529 bool touch1Pressed = (((rawData[39] & 0xff) >> 7) == 0);
530
531 if ((touch0Pressed && (rawData[35] & 0xff) < mLastTouchId[0]) ||
532 (touch1Pressed && (rawData[39] & 0xff) < mLastTouchId[1])) {
533 mTouchIdBase += 128;
534 }
535
536 if (touch0Pressed) {
537 touches[0].touchId = mTouchIdBase + (rawData[35] & 0x7f);
538 touches[0].surfaceId = 0;
539 touches[0].position[0] = NormalizeTouch(
540 ((rawData[37] & 0xf) << 8) | rawData[36], 0, (kTouchDimensionX - 1));
541 touches[0].position[1] =
542 NormalizeTouch(rawData[38] << 4 | ((rawData[37] & 0xf0) >> 4), 0,
543 (kTouchDimensionY - 1));
544 touches[0].surfaceDimensions[0] = kTouchDimensionX;
545 touches[0].surfaceDimensions[1] = kTouchDimensionY;
546 touches[0].isSurfaceDimensionsValid = true;
547 mLastTouchId[0] = rawData[35] & 0x7f;
548 }
549 if (touch1Pressed) {
550 touches[1].touchId = mTouchIdBase + (rawData[39] & 0x7f);
551 touches[1].surfaceId = 0;
552 touches[1].position[0] =
553 NormalizeTouch((((rawData[41] & 0xf) << 8) | rawData[40]) + 1, 0,
554 (kTouchDimensionX - 1));
555 touches[1].position[1] =
556 NormalizeTouch(rawData[42] << 4 | ((rawData[41] & 0xf0) >> 4), 0,
557 (kTouchDimensionY - 1));
558 touches[1].surfaceDimensions[0] = kTouchDimensionX;
559 touches[1].surfaceDimensions[1] = kTouchDimensionY;
560 touches[1].isSurfaceDimensionsValid = true;
561 mLastTouchId[1] = rawData[39] & 0x7f;
562 }
563
564 RefPtr<GamepadPlatformService> service =
565 GamepadPlatformService::GetParentService();
566 if (!service) {
567 return;
568 }
569
570 // Avoid to send duplicate untouched events to the gamepad service.
571 if ((mLastTouches[0] != touch0Pressed) || touch0Pressed) {
572 service->NewMultiTouchEvent(aHandle, 0, touches[0]);
573 }
574 if ((mLastTouches[1] != touch1Pressed) || touch1Pressed) {
575 service->NewMultiTouchEvent(aHandle, 1, touches[1]);
576 }
577 mLastTouches[0] = touch0Pressed;
578 mLastTouches[1] = touch1Pressed;
579 }
580
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const581 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
582 double aValue) const override {
583 RefPtr<GamepadPlatformService> service =
584 GamepadPlatformService::GetParentService();
585 if (!service) {
586 return;
587 }
588
589 switch (aAxis) {
590 case 0:
591 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
592 break;
593 case 1:
594 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
595 break;
596 case 2:
597 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
598 break;
599 case 3: {
600 const double value = AxisToButtonValue(aValue);
601 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
602 value > BUTTON_THRESHOLD_VALUE, value);
603 break;
604 }
605 case 4: {
606 const double value = AxisToButtonValue(aValue);
607 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
608 value > BUTTON_THRESHOLD_VALUE, value);
609 break;
610 }
611 case 5:
612 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
613 break;
614 case 9:
615 FetchDpadFromAxis(aHandle, aValue);
616 break;
617 default:
618 NS_WARNING(
619 nsPrintfCString(
620 "Axis idx '%d' doesn't support in Dualshock4Remapper().", aAxis)
621 .get());
622 break;
623 }
624 }
625
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const626 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
627 bool aPressed) const override {
628 RefPtr<GamepadPlatformService> service =
629 GamepadPlatformService::GetParentService();
630 if (!service) {
631 return;
632 }
633
634 const std::vector<uint32_t> buttonMapping = {BUTTON_INDEX_TERTIARY,
635 BUTTON_INDEX_PRIMARY,
636 BUTTON_INDEX_SECONDARY,
637 BUTTON_INDEX_QUATERNARY,
638 BUTTON_INDEX_LEFT_SHOULDER,
639 BUTTON_INDEX_RIGHT_SHOULDER,
640 BUTTON_INDEX_LEFT_TRIGGER,
641 BUTTON_INDEX_RIGHT_TRIGGER,
642 BUTTON_INDEX_BACK_SELECT,
643 BUTTON_INDEX_START,
644 BUTTON_INDEX_LEFT_THUMBSTICK,
645 BUTTON_INDEX_RIGHT_THUMBSTICK,
646 BUTTON_INDEX_META,
647 DUALSHOCK_BUTTON_TOUCHPAD};
648
649 if (buttonMapping.size() <= aButton) {
650 NS_WARNING(nsPrintfCString(
651 "Button idx '%d' doesn't support in Dualshock4Remapper().",
652 aButton)
653 .get());
654 return;
655 }
656
657 service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
658 }
659
660 private:
661 enum Dualshock4Buttons {
662 DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
663 DUALSHOCK_BUTTON_COUNT
664 };
665
666 static const uint32_t LIGHT_INDICATOR_COUNT = 1;
667 static const uint32_t TOUCH_EVENT_COUNT = 2;
668 static const uint32_t MAX_INPUT_LEN = 68;
669
670 nsTArray<unsigned long> mLastTouchId;
671 nsTArray<bool> mLastTouches;
672 unsigned long mTouchIdBase = 0;
673 };
674
675 class Xbox360Remapper final : public GamepadRemapper {
676 public:
GetAxisCount() const677 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
678
GetButtonCount() const679 virtual uint32_t GetButtonCount() const override {
680 return BUTTON_INDEX_COUNT;
681 }
682
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const683 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
684 double aValue) const override {
685 RefPtr<GamepadPlatformService> service =
686 GamepadPlatformService::GetParentService();
687 if (!service) {
688 return;
689 }
690
691 switch (aAxis) {
692 case 0:
693 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
694 break;
695 case 1:
696 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
697 break;
698 case 2: {
699 const double value = AxisToButtonValue(aValue);
700 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
701 value > BUTTON_THRESHOLD_VALUE, value);
702 break;
703 }
704 case 3:
705 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
706 break;
707 case 4:
708 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
709 break;
710 case 5: {
711 const double value = AxisToButtonValue(aValue);
712 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
713 value > BUTTON_THRESHOLD_VALUE, value);
714 break;
715 }
716 default:
717 NS_WARNING(
718 nsPrintfCString(
719 "Axis idx '%d' doesn't support in Xbox360Remapper().", aAxis)
720 .get());
721 break;
722 }
723 }
724
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const725 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
726 bool aPressed) const override {
727 RefPtr<GamepadPlatformService> service =
728 GamepadPlatformService::GetParentService();
729 if (!service) {
730 return;
731 }
732
733 if (GetButtonCount() <= aButton) {
734 NS_WARNING(
735 nsPrintfCString(
736 "Button idx '%d' doesn't support in Xbox360Remapper().", aButton)
737 .get());
738 return;
739 }
740
741 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
742 {6, BUTTON_INDEX_LEFT_THUMBSTICK}, {7, BUTTON_INDEX_RIGHT_THUMBSTICK},
743 {8, BUTTON_INDEX_START}, {9, BUTTON_INDEX_BACK_SELECT},
744 {10, BUTTON_INDEX_META}, {11, BUTTON_INDEX_DPAD_UP},
745 {12, BUTTON_INDEX_DPAD_DOWN}, {13, BUTTON_INDEX_DPAD_LEFT},
746 {14, BUTTON_INDEX_DPAD_RIGHT}};
747
748 auto find = buttonMapping.find(aButton);
749 if (find != buttonMapping.end()) {
750 service->NewButtonEvent(aHandle, find->second, aPressed);
751 } else {
752 service->NewButtonEvent(aHandle, aButton, aPressed);
753 }
754 }
755 };
756
757 class XboxOneSRemapper final : public GamepadRemapper {
758 public:
GetAxisCount() const759 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
760
GetButtonCount() const761 virtual uint32_t GetButtonCount() const override {
762 return BUTTON_INDEX_COUNT;
763 }
764
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const765 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
766 double aValue) const override {
767 RefPtr<GamepadPlatformService> service =
768 GamepadPlatformService::GetParentService();
769 if (!service) {
770 return;
771 }
772
773 switch (aAxis) {
774 case 0:
775 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
776 break;
777 case 1:
778 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
779 break;
780 case 2: {
781 const double value = AxisToButtonValue(aValue);
782 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
783 value > BUTTON_THRESHOLD_VALUE, value);
784 break;
785 }
786 case 3:
787 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
788 break;
789 case 4:
790 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
791 break;
792 case 5: {
793 const double value = AxisToButtonValue(aValue);
794 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
795 value > BUTTON_THRESHOLD_VALUE, value);
796 break;
797 }
798 case 9:
799 FetchDpadFromAxis(aHandle, aValue);
800 break;
801 default:
802 NS_WARNING(
803 nsPrintfCString(
804 "Axis idx '%d' doesn't support in XboxOneSRemapper().", aAxis)
805 .get());
806 break;
807 }
808 }
809
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const810 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
811 bool aPressed) const override {
812 RefPtr<GamepadPlatformService> service =
813 GamepadPlatformService::GetParentService();
814 if (!service) {
815 return;
816 }
817
818 if (GetButtonCount() <= aButton) {
819 NS_WARNING(
820 nsPrintfCString(
821 "Button idx '%d' doesn't support in XboxOneSRemapper().", aButton)
822 .get());
823 return;
824 }
825
826 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
827 {6, BUTTON_INDEX_BACK_SELECT},
828 {7, BUTTON_INDEX_START},
829 {8, BUTTON_INDEX_LEFT_THUMBSTICK},
830 {9, BUTTON_INDEX_RIGHT_THUMBSTICK},
831 {10, BUTTON_INDEX_META}};
832
833 auto find = buttonMapping.find(aButton);
834 if (find != buttonMapping.end()) {
835 service->NewButtonEvent(aHandle, find->second, aPressed);
836 } else {
837 service->NewButtonEvent(aHandle, aButton, aPressed);
838 }
839 }
840 };
841
842 class XboxOneS2016FirmwareRemapper final : public GamepadRemapper {
843 public:
GetAxisCount() const844 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
845
GetButtonCount() const846 virtual uint32_t GetButtonCount() const override {
847 return BUTTON_INDEX_COUNT;
848 }
849
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const850 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
851 double aValue) const override {
852 RefPtr<GamepadPlatformService> service =
853 GamepadPlatformService::GetParentService();
854 if (!service) {
855 return;
856 }
857
858 switch (aAxis) {
859 case 0:
860 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
861 break;
862 case 1:
863 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
864 break;
865 case 2:
866 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
867 break;
868 case 3: {
869 const double value = AxisToButtonValue(aValue);
870 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
871 value > BUTTON_THRESHOLD_VALUE, value);
872 break;
873 }
874 case 4: {
875 const double value = AxisToButtonValue(aValue);
876 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
877 value > BUTTON_THRESHOLD_VALUE, value);
878 break;
879 }
880 case 5:
881 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
882 break;
883 case 9:
884 FetchDpadFromAxis(aHandle, aValue);
885 break;
886 default:
887 NS_WARNING(nsPrintfCString("Axis idx '%d' doesn't support in "
888 "XboxOneS2016FirmwareRemapper().",
889 aAxis)
890 .get());
891 break;
892 }
893 }
894
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const895 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
896 bool aPressed) const override {
897 RefPtr<GamepadPlatformService> service =
898 GamepadPlatformService::GetParentService();
899 if (!service) {
900 return;
901 }
902
903 if (GetButtonCount() <= aButton) {
904 NS_WARNING(nsPrintfCString("Button idx '%d' doesn't support in "
905 "XboxOneS2016FirmwareRemapper().",
906 aButton)
907 .get());
908 return;
909 }
910
911 // kMicrosoftProductXboxOneSWireless2016 controller received a firmware
912 // update in 2019 that changed which field is populated with the meta button
913 // state. In order to cover the old and new cases, we have to check both
914 // fields of {12, 15} buttons.
915 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
916 {0, BUTTON_INDEX_PRIMARY},
917 {1, BUTTON_INDEX_SECONDARY},
918 {3, BUTTON_INDEX_TERTIARY},
919 {4, BUTTON_INDEX_QUATERNARY},
920 {6, BUTTON_INDEX_LEFT_SHOULDER},
921 {7, BUTTON_INDEX_RIGHT_SHOULDER},
922 {11, BUTTON_INDEX_START},
923 {12, BUTTON_INDEX_META},
924 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
925 {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
926 {15, BUTTON_INDEX_META},
927 {16, BUTTON_INDEX_BACK_SELECT}};
928
929 auto find = buttonMapping.find(aButton);
930 if (find != buttonMapping.end()) {
931 service->NewButtonEvent(aHandle, find->second, aPressed);
932 } else {
933 service->NewButtonEvent(aHandle, aButton, aPressed);
934 }
935 }
936 };
937
938 class XboxOneRemapper final : public GamepadRemapper {
939 public:
GetAxisCount() const940 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
941
GetButtonCount() const942 virtual uint32_t GetButtonCount() const override {
943 return BUTTON_INDEX_COUNT;
944 }
945
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const946 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
947 double aValue) const override {
948 RefPtr<GamepadPlatformService> service =
949 GamepadPlatformService::GetParentService();
950 if (!service) {
951 return;
952 }
953
954 switch (aAxis) {
955 case 0:
956 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
957 break;
958 case 1:
959 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
960 break;
961 case 2:
962 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
963 break;
964 case 3:
965 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
966 break;
967 case 9:
968 FetchDpadFromAxis(aHandle, aValue);
969 break;
970 case 10: {
971 const double value = AxisToButtonValue(aValue);
972 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
973 value > BUTTON_THRESHOLD_VALUE, value);
974 break;
975 }
976 case 11: {
977 const double value = AxisToButtonValue(aValue);
978 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
979 value > BUTTON_THRESHOLD_VALUE, value);
980 break;
981 }
982 default:
983 NS_WARNING(
984 nsPrintfCString(
985 "Axis idx '%d' doesn't support in XboxOneRemapper().", aAxis)
986 .get());
987 break;
988 }
989 }
990
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const991 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
992 bool aPressed) const override {
993 RefPtr<GamepadPlatformService> service =
994 GamepadPlatformService::GetParentService();
995 if (!service) {
996 return;
997 }
998
999 if (GetButtonCount() <= aButton) {
1000 NS_WARNING(
1001 nsPrintfCString(
1002 "Button idx '%d' doesn't support in XboxOneRemapper().", aButton)
1003 .get());
1004 return;
1005 }
1006
1007 // Accessing {30, 31} buttons looks strange to me
1008 // and without an avilable device to help verify it.
1009 // It is according to `MapperXboxOneBluetooth()` in
1010 // https://cs.chromium.org/chromium/src/device/gamepad/gamepad_standard_mappings_mac.mm
1011 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1012 {0, BUTTON_INDEX_PRIMARY},
1013 {1, BUTTON_INDEX_SECONDARY},
1014 {3, BUTTON_INDEX_TERTIARY},
1015 {4, BUTTON_INDEX_QUATERNARY},
1016 {6, BUTTON_INDEX_LEFT_SHOULDER},
1017 {7, BUTTON_INDEX_RIGHT_SHOULDER},
1018 {11, BUTTON_INDEX_START},
1019 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1020 {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
1021 {30, BUTTON_INDEX_META},
1022 {31, BUTTON_INDEX_BACK_SELECT}};
1023
1024 auto find = buttonMapping.find(aButton);
1025 if (find != buttonMapping.end()) {
1026 service->NewButtonEvent(aHandle, find->second, aPressed);
1027 } else {
1028 service->NewButtonEvent(aHandle, aButton, aPressed);
1029 }
1030 }
1031 };
1032
1033 class LogitechDInputRemapper final : public GamepadRemapper {
1034 public:
GetAxisCount() const1035 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1036
GetButtonCount() const1037 virtual uint32_t GetButtonCount() const override {
1038 // The Logitech button (BUTTON_INDEX_META) is not accessible through the
1039 // device's D-mode.
1040 return BUTTON_INDEX_COUNT - 1;
1041 }
1042
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1043 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1044 double aValue) const override {
1045 RefPtr<GamepadPlatformService> service =
1046 GamepadPlatformService::GetParentService();
1047 if (!service) {
1048 return;
1049 }
1050
1051 switch (aAxis) {
1052 case 0:
1053 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1054 break;
1055 case 1:
1056 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1057 break;
1058 case 2:
1059 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1060 break;
1061 case 5:
1062 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1063 break;
1064 case 9:
1065 FetchDpadFromAxis(aHandle, aValue);
1066 break;
1067 default:
1068 NS_WARNING(
1069 nsPrintfCString(
1070 "Axis idx '%d' doesn't support in LogitechDInputRemapper().",
1071 aAxis)
1072 .get());
1073 break;
1074 }
1075 }
1076
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1077 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1078 bool aPressed) const override {
1079 RefPtr<GamepadPlatformService> service =
1080 GamepadPlatformService::GetParentService();
1081 if (!service) {
1082 return;
1083 }
1084
1085 if (GetButtonCount() <= aButton) {
1086 NS_WARNING(
1087 nsPrintfCString(
1088 "Button idx '%d' doesn't support in LogitechDInputRemapper().",
1089 aButton)
1090 .get());
1091 return;
1092 }
1093
1094 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1095 {0, BUTTON_INDEX_TERTIARY},
1096 {1, BUTTON_INDEX_PRIMARY},
1097 {2, BUTTON_INDEX_SECONDARY}};
1098
1099 auto find = buttonMapping.find(aButton);
1100 if (find != buttonMapping.end()) {
1101 service->NewButtonEvent(aHandle, find->second, aPressed);
1102 } else {
1103 service->NewButtonEvent(aHandle, aButton, aPressed);
1104 }
1105 }
1106 };
1107
1108 class SwitchJoyConRemapper final : public GamepadRemapper {
1109 public:
GetAxisCount() const1110 virtual uint32_t GetAxisCount() const override { return 2; }
1111
GetButtonCount() const1112 virtual uint32_t GetButtonCount() const override {
1113 return BUTTON_INDEX_COUNT;
1114 }
1115
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1116 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1117 double aValue) const override {
1118 if (GetAxisCount() <= aAxis) {
1119 NS_WARNING(
1120 nsPrintfCString(
1121 "Axis idx '%d' doesn't support in SwitchJoyConRemapper().", aAxis)
1122 .get());
1123 return;
1124 }
1125 RefPtr<GamepadPlatformService> service =
1126 GamepadPlatformService::GetParentService();
1127 if (!service) {
1128 return;
1129 }
1130
1131 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1132 }
1133
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1134 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1135 bool aPressed) const override {
1136 RefPtr<GamepadPlatformService> service =
1137 GamepadPlatformService::GetParentService();
1138 if (!service) {
1139 return;
1140 }
1141
1142 service->NewButtonEvent(aHandle, aButton, aPressed);
1143 }
1144 };
1145
1146 class SwitchProRemapper final : public GamepadRemapper {
1147 public:
GetAxisCount() const1148 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1149
GetButtonCount() const1150 virtual uint32_t GetButtonCount() const override {
1151 // The Switch Pro controller has a Capture button that has no equivalent in
1152 // the Standard Gamepad.
1153 return SWITCHPRO_BUTTON_COUNT;
1154 }
1155
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1156 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1157 double aValue) const override {
1158 if (GetAxisCount() <= aAxis) {
1159 NS_WARNING(
1160 nsPrintfCString(
1161 "Axis idx '%d' doesn't support in SwitchProRemapper().", aAxis)
1162 .get());
1163 return;
1164 }
1165 RefPtr<GamepadPlatformService> service =
1166 GamepadPlatformService::GetParentService();
1167 if (!service) {
1168 return;
1169 }
1170
1171 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1172 }
1173
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1174 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1175 bool aPressed) const override {
1176 RefPtr<GamepadPlatformService> service =
1177 GamepadPlatformService::GetParentService();
1178 if (!service) {
1179 return;
1180 }
1181
1182 service->NewButtonEvent(aHandle, aButton, aPressed);
1183 }
1184
1185 private:
1186 enum SwitchProButtons {
1187 SWITCHPRO_BUTTON_EXTRA = BUTTON_INDEX_COUNT,
1188 SWITCHPRO_BUTTON_COUNT
1189 };
1190 };
1191
1192 class NvShieldRemapper final : public GamepadRemapper {
1193 public:
GetAxisCount() const1194 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1195
GetButtonCount() const1196 virtual uint32_t GetButtonCount() const override {
1197 return SHIELD_BUTTON_COUNT;
1198 }
1199
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1200 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1201 double aValue) const override {
1202 RefPtr<GamepadPlatformService> service =
1203 GamepadPlatformService::GetParentService();
1204 if (!service) {
1205 return;
1206 }
1207
1208 switch (aAxis) {
1209 case 0:
1210 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1211 break;
1212 case 1:
1213 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1214 break;
1215 case 2:
1216 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1217 break;
1218 case 3: {
1219 const double value = AxisToButtonValue(aValue);
1220 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1221 value > BUTTON_THRESHOLD_VALUE, value);
1222 break;
1223 }
1224 case 4: {
1225 const double value = AxisToButtonValue(aValue);
1226 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1227 value > BUTTON_THRESHOLD_VALUE, value);
1228 break;
1229 }
1230 case 5:
1231 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1232 break;
1233 case 9:
1234 FetchDpadFromAxis(aHandle, aValue);
1235 break;
1236 default:
1237 NS_WARNING(
1238 nsPrintfCString(
1239 "Axis idx '%d' doesn't support in NvShieldRemapper().", aAxis)
1240 .get());
1241 break;
1242 }
1243 }
1244
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1245 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1246 bool aPressed) const override {
1247 RefPtr<GamepadPlatformService> service =
1248 GamepadPlatformService::GetParentService();
1249 if (!service) {
1250 return;
1251 }
1252
1253 if (GetButtonCount() <= aButton) {
1254 NS_WARNING(
1255 nsPrintfCString(
1256 "Button idx '%d' doesn't support in NvShieldRemapper().", aButton)
1257 .get());
1258 return;
1259 }
1260
1261 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1262 {2, BUTTON_INDEX_META},
1263 {3, BUTTON_INDEX_TERTIARY},
1264 {4, BUTTON_INDEX_QUATERNARY},
1265 {5, SHIELD_BUTTON_CIRCLE},
1266 {6, BUTTON_INDEX_LEFT_SHOULDER},
1267 {7, BUTTON_INDEX_RIGHT_SHOULDER},
1268 {9, BUTTON_INDEX_BACK_SELECT},
1269 {11, BUTTON_INDEX_START},
1270 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1271 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
1272
1273 auto find = buttonMapping.find(aButton);
1274 if (find != buttonMapping.end()) {
1275 service->NewButtonEvent(aHandle, find->second, aPressed);
1276 } else {
1277 service->NewButtonEvent(aHandle, aButton, aPressed);
1278 }
1279 }
1280
1281 private:
1282 enum ShieldButtons {
1283 SHIELD_BUTTON_CIRCLE = BUTTON_INDEX_COUNT,
1284 SHIELD_BUTTON_COUNT
1285 };
1286 };
1287
1288 class NvShield2017Remapper final : public GamepadRemapper {
1289 public:
GetAxisCount() const1290 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1291
GetButtonCount() const1292 virtual uint32_t GetButtonCount() const override {
1293 return SHIELD2017_BUTTON_COUNT;
1294 }
1295
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1296 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1297 double aValue) const override {
1298 RefPtr<GamepadPlatformService> service =
1299 GamepadPlatformService::GetParentService();
1300 if (!service) {
1301 return;
1302 }
1303
1304 switch (aAxis) {
1305 case 0:
1306 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1307 break;
1308 case 1:
1309 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1310 break;
1311 case 2:
1312 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1313 break;
1314 case 3: {
1315 const double value = AxisToButtonValue(aValue);
1316 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1317 value > BUTTON_THRESHOLD_VALUE, value);
1318 break;
1319 }
1320 case 4: {
1321 const double value = AxisToButtonValue(aValue);
1322 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1323 value > BUTTON_THRESHOLD_VALUE, value);
1324 break;
1325 }
1326 case 5:
1327 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1328 break;
1329 case 9:
1330 FetchDpadFromAxis(aHandle, aValue);
1331 break;
1332 default:
1333 NS_WARNING(
1334 nsPrintfCString(
1335 "Axis idx '%d' doesn't support in NvShield2017Remapper().",
1336 aAxis)
1337 .get());
1338 break;
1339 }
1340 }
1341
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1342 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1343 bool aPressed) const override {
1344 RefPtr<GamepadPlatformService> service =
1345 GamepadPlatformService::GetParentService();
1346 if (!service) {
1347 return;
1348 }
1349
1350 if (GetButtonCount() <= aButton) {
1351 NS_WARNING(
1352 nsPrintfCString(
1353 "Button idx '%d' doesn't support in NvShield2017Remapper().",
1354 aButton)
1355 .get());
1356 return;
1357 }
1358
1359 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1360 {2, BUTTON_INDEX_META},
1361 {3, BUTTON_INDEX_TERTIARY},
1362 {4, BUTTON_INDEX_QUATERNARY},
1363 {5, BUTTON_INDEX_START},
1364 {6, BUTTON_INDEX_LEFT_SHOULDER},
1365 {7, BUTTON_INDEX_RIGHT_SHOULDER},
1366 {8, BUTTON_INDEX_BACK_SELECT},
1367 {11, SHIELD2017_BUTTON_PLAYPAUSE},
1368 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1369 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
1370
1371 auto find = buttonMapping.find(aButton);
1372 if (find != buttonMapping.end()) {
1373 service->NewButtonEvent(aHandle, find->second, aPressed);
1374 } else {
1375 service->NewButtonEvent(aHandle, aButton, aPressed);
1376 }
1377 }
1378
1379 private:
1380 enum Shield2017Buttons {
1381 SHIELD2017_BUTTON_PLAYPAUSE = BUTTON_INDEX_COUNT,
1382 SHIELD2017_BUTTON_COUNT
1383 };
1384 };
1385
1386 class IBuffaloRemapper final : public GamepadRemapper {
1387 public:
GetAxisCount() const1388 virtual uint32_t GetAxisCount() const override { return 2; }
1389
GetButtonCount() const1390 virtual uint32_t GetButtonCount() const override {
1391 return BUTTON_INDEX_COUNT - 1; /* no meta */
1392 }
1393
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1394 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1395 double aValue) const override {
1396 RefPtr<GamepadPlatformService> service =
1397 GamepadPlatformService::GetParentService();
1398 if (!service) {
1399 return;
1400 }
1401
1402 switch (aAxis) {
1403 case 0:
1404 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1405 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT,
1406 AxisNegativeAsButton(aValue));
1407 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT,
1408 AxisPositiveAsButton(aValue));
1409 break;
1410 case 1:
1411 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1412 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP,
1413 AxisNegativeAsButton(aValue));
1414 service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN,
1415 AxisPositiveAsButton(aValue));
1416 break;
1417 default:
1418 NS_WARNING(
1419 nsPrintfCString(
1420 "Axis idx '%d' doesn't support in IBuffaloRemapper().", aAxis)
1421 .get());
1422 break;
1423 }
1424 }
1425
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1426 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1427 bool aPressed) const override {
1428 RefPtr<GamepadPlatformService> service =
1429 GamepadPlatformService::GetParentService();
1430 if (!service) {
1431 return;
1432 }
1433
1434 if (GetButtonCount() <= aButton) {
1435 NS_WARNING(
1436 nsPrintfCString(
1437 "Button idx '%d' doesn't support in IBuffaloRemapper().", aButton)
1438 .get());
1439 return;
1440 }
1441
1442 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1443 {0, BUTTON_INDEX_SECONDARY}, {1, BUTTON_INDEX_PRIMARY},
1444 {2, BUTTON_INDEX_QUATERNARY}, {3, BUTTON_INDEX_TERTIARY},
1445 {5, BUTTON_INDEX_RIGHT_TRIGGER}, {6, BUTTON_INDEX_BACK_SELECT},
1446 {7, BUTTON_INDEX_START}};
1447
1448 auto find = buttonMapping.find(aButton);
1449 if (find != buttonMapping.end()) {
1450 service->NewButtonEvent(aHandle, find->second, aPressed);
1451 } else {
1452 service->NewButtonEvent(aHandle, aButton, aPressed);
1453 }
1454 }
1455 };
1456
1457 class XSkillsRemapper final : public GamepadRemapper {
1458 public:
GetAxisCount() const1459 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1460
GetButtonCount() const1461 virtual uint32_t GetButtonCount() const override {
1462 return GAMECUBE_BUTTON_COUNT;
1463 }
1464
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1465 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1466 double aValue) const override {
1467 RefPtr<GamepadPlatformService> service =
1468 GamepadPlatformService::GetParentService();
1469 if (!service) {
1470 return;
1471 }
1472
1473 switch (aAxis) {
1474 case 0:
1475 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1476 break;
1477 case 1:
1478 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1479 break;
1480 case 2:
1481 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1482 break;
1483 case 3: {
1484 const double value = AxisToButtonValue(aValue);
1485 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1486 value > BUTTON_THRESHOLD_VALUE, value);
1487 break;
1488 }
1489 case 4: {
1490 const double value = AxisToButtonValue(aValue);
1491 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1492 value > BUTTON_THRESHOLD_VALUE, value);
1493 break;
1494 }
1495 case 5:
1496 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1497 break;
1498 default:
1499 NS_WARNING(
1500 nsPrintfCString(
1501 "Axis idx '%d' doesn't support in XSkillsRemapper().", aAxis)
1502 .get());
1503 break;
1504 }
1505 }
1506
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1507 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1508 bool aPressed) const override {
1509 RefPtr<GamepadPlatformService> service =
1510 GamepadPlatformService::GetParentService();
1511 if (!service) {
1512 return;
1513 }
1514
1515 if (GetButtonCount() <= aButton) {
1516 NS_WARNING(
1517 nsPrintfCString(
1518 "Button idx '%d' doesn't support in XSkillsRemapper().", aButton)
1519 .get());
1520 return;
1521 }
1522
1523 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1524 {0, BUTTON_INDEX_PRIMARY}, // A
1525 {1, BUTTON_INDEX_TERTIARY}, // B
1526 {2, BUTTON_INDEX_SECONDARY}, // X
1527 {3, BUTTON_INDEX_QUATERNARY}, // Y
1528 {4, GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK},
1529 {5, GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK},
1530 {6, BUTTON_INDEX_RIGHT_SHOULDER},
1531 {7, BUTTON_INDEX_START},
1532 {8, BUTTON_INDEX_DPAD_LEFT},
1533 {9, BUTTON_INDEX_DPAD_RIGHT},
1534 {10, BUTTON_INDEX_DPAD_DOWN},
1535 {11, BUTTON_INDEX_DPAD_UP}};
1536
1537 auto find = buttonMapping.find(aButton);
1538 if (find != buttonMapping.end()) {
1539 service->NewButtonEvent(aHandle, find->second, aPressed);
1540 } else {
1541 service->NewButtonEvent(aHandle, aButton, aPressed);
1542 }
1543 }
1544
1545 private:
1546 enum GamecubeButtons {
1547 GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK = BUTTON_INDEX_COUNT,
1548 GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK,
1549 GAMECUBE_BUTTON_COUNT
1550 };
1551 };
1552
1553 class BoomN64PsxRemapper final : public GamepadRemapper {
1554 public:
GetAxisCount() const1555 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1556
GetButtonCount() const1557 virtual uint32_t GetButtonCount() const override {
1558 return BUTTON_INDEX_COUNT - 1; // no meta
1559 }
1560
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1561 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1562 double aValue) const override {
1563 RefPtr<GamepadPlatformService> service =
1564 GamepadPlatformService::GetParentService();
1565 if (!service) {
1566 return;
1567 }
1568
1569 switch (aAxis) {
1570 case 0:
1571 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1572 break;
1573 case 1:
1574 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1575 break;
1576 case 2:
1577 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1578 break;
1579 case 5:
1580 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1581 break;
1582 default:
1583 NS_WARNING(
1584 nsPrintfCString(
1585 "Axis idx '%d' doesn't support in BoomN64PsxRemapper().", aAxis)
1586 .get());
1587 break;
1588 }
1589 }
1590
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1591 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1592 bool aPressed) const override {
1593 RefPtr<GamepadPlatformService> service =
1594 GamepadPlatformService::GetParentService();
1595 if (!service) {
1596 return;
1597 }
1598
1599 const std::vector<uint32_t> buttonMapping = {
1600 BUTTON_INDEX_QUATERNARY, BUTTON_INDEX_SECONDARY,
1601 BUTTON_INDEX_PRIMARY, BUTTON_INDEX_TERTIARY,
1602 BUTTON_INDEX_LEFT_TRIGGER, BUTTON_INDEX_RIGHT_TRIGGER,
1603 BUTTON_INDEX_LEFT_SHOULDER, BUTTON_INDEX_RIGHT_SHOULDER,
1604 BUTTON_INDEX_BACK_SELECT, BUTTON_INDEX_LEFT_THUMBSTICK,
1605 BUTTON_INDEX_RIGHT_THUMBSTICK, BUTTON_INDEX_START,
1606 BUTTON_INDEX_DPAD_UP, BUTTON_INDEX_DPAD_RIGHT,
1607 BUTTON_INDEX_DPAD_DOWN, BUTTON_INDEX_DPAD_LEFT};
1608
1609 if (buttonMapping.size() <= aButton) {
1610 NS_WARNING(nsPrintfCString(
1611 "Button idx '%d' doesn't support in BoomN64PsxRemapper().",
1612 aButton)
1613 .get());
1614 return;
1615 }
1616
1617 service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
1618 }
1619
1620 private:
1621 enum GamecubeButtons {
1622 GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK = BUTTON_INDEX_COUNT,
1623 GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK,
1624 GAMECUBE_BUTTON_COUNT
1625 };
1626 };
1627
1628 class StadiaControllerOldFirmwareRemapper final : public GamepadRemapper {
1629 public:
GetAxisCount() const1630 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1631
GetButtonCount() const1632 virtual uint32_t GetButtonCount() const override {
1633 return ANALOG_GAMEPAD_BUTTON_COUNT;
1634 }
1635
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1636 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1637 double aValue) const override {
1638 RefPtr<GamepadPlatformService> service =
1639 GamepadPlatformService::GetParentService();
1640 if (!service) {
1641 return;
1642 }
1643
1644 switch (aAxis) {
1645 case 0:
1646 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1647 break;
1648 case 1:
1649 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1650 break;
1651 case 2:
1652 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1653 break;
1654 case 3: {
1655 const double value = AxisToButtonValue(aValue);
1656 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1657 value > BUTTON_THRESHOLD_VALUE, value);
1658 break;
1659 }
1660 case 4: {
1661 const double value = AxisToButtonValue(aValue);
1662 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1663 value > BUTTON_THRESHOLD_VALUE, value);
1664 break;
1665 }
1666 case 5:
1667 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1668 break;
1669 case 9:
1670 FetchDpadFromAxis(aHandle, aValue);
1671 break;
1672 default:
1673 NS_WARNING(
1674 nsPrintfCString(
1675 "Axis idx '%d' doesn't support in AnalogGamepadRemapper().",
1676 aAxis)
1677 .get());
1678 break;
1679 }
1680 }
1681
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1682 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1683 bool aPressed) const override {
1684 RefPtr<GamepadPlatformService> service =
1685 GamepadPlatformService::GetParentService();
1686 if (!service) {
1687 return;
1688 }
1689
1690 if (GetButtonCount() <= aButton) {
1691 NS_WARNING(
1692 nsPrintfCString(
1693 "Button idx '%d' doesn't support in AnalogGamepadRemapper().",
1694 aButton)
1695 .get());
1696 return;
1697 }
1698
1699 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1700 {3, BUTTON_INDEX_TERTIARY},
1701 {4, BUTTON_INDEX_QUATERNARY},
1702 {6, BUTTON_INDEX_LEFT_SHOULDER},
1703 {7, BUTTON_INDEX_RIGHT_SHOULDER},
1704 {10, BUTTON_INDEX_BACK_SELECT},
1705 {11, BUTTON_INDEX_META},
1706 {12, BUTTON_INDEX_START},
1707 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1708 {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
1709 {16, ANALOG_GAMEPAD_BUTTON_EXTRA},
1710 {17, ANALOG_GAMEPAD_BUTTON_EXTRA2}};
1711
1712 auto find = buttonMapping.find(aButton);
1713 if (find != buttonMapping.end()) {
1714 service->NewButtonEvent(aHandle, find->second, aPressed);
1715 } else {
1716 service->NewButtonEvent(aHandle, aButton, aPressed);
1717 }
1718 }
1719
1720 private:
1721 enum AnalogGamepadButtons {
1722 ANALOG_GAMEPAD_BUTTON_EXTRA = BUTTON_INDEX_COUNT,
1723 ANALOG_GAMEPAD_BUTTON_EXTRA2,
1724 ANALOG_GAMEPAD_BUTTON_COUNT
1725 };
1726 };
1727
1728 class RazerServalRemapper final : public GamepadRemapper {
1729 public:
GetAxisCount() const1730 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1731
GetButtonCount() const1732 virtual uint32_t GetButtonCount() const override {
1733 return BUTTON_INDEX_COUNT - 1; /* no meta */
1734 }
1735
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1736 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1737 double aValue) const override {
1738 RefPtr<GamepadPlatformService> service =
1739 GamepadPlatformService::GetParentService();
1740 if (!service) {
1741 return;
1742 }
1743
1744 switch (aAxis) {
1745 case 0:
1746 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1747 break;
1748 case 1:
1749 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1750 break;
1751 case 2:
1752 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1753 break;
1754 case 3: {
1755 const double value = AxisToButtonValue(aValue);
1756 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1757 value > BUTTON_THRESHOLD_VALUE, value);
1758 break;
1759 }
1760 case 4: {
1761 const double value = AxisToButtonValue(aValue);
1762 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1763 value > BUTTON_THRESHOLD_VALUE, value);
1764 break;
1765 }
1766 case 5:
1767 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1768 break;
1769 case 9:
1770 FetchDpadFromAxis(aHandle, aValue);
1771 break;
1772 default:
1773 NS_WARNING(
1774 nsPrintfCString(
1775 "Axis idx '%d' doesn't support in RazerServalRemapper().",
1776 aAxis)
1777 .get());
1778 break;
1779 }
1780 }
1781
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1782 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1783 bool aPressed) const override {
1784 RefPtr<GamepadPlatformService> service =
1785 GamepadPlatformService::GetParentService();
1786 if (!service) {
1787 return;
1788 }
1789
1790 if (GetButtonCount() <= aButton) {
1791 NS_WARNING(
1792 nsPrintfCString(
1793 "Button idx '%d' doesn't support in RazerServalRemapper().",
1794 aButton)
1795 .get());
1796 return;
1797 }
1798
1799 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1800 {3, BUTTON_INDEX_TERTIARY}, {4, BUTTON_INDEX_QUATERNARY},
1801 {6, BUTTON_INDEX_LEFT_SHOULDER}, {7, BUTTON_INDEX_RIGHT_SHOULDER},
1802 {10, BUTTON_INDEX_BACK_SELECT}, {11, BUTTON_INDEX_START},
1803 {12, BUTTON_INDEX_START}, {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1804 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
1805
1806 auto find = buttonMapping.find(aButton);
1807 if (find != buttonMapping.end()) {
1808 service->NewButtonEvent(aHandle, find->second, aPressed);
1809 } else {
1810 service->NewButtonEvent(aHandle, aButton, aPressed);
1811 }
1812 }
1813 };
1814
1815 class MogaProRemapper final : public GamepadRemapper {
1816 public:
GetAxisCount() const1817 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1818
GetButtonCount() const1819 virtual uint32_t GetButtonCount() const override {
1820 return BUTTON_INDEX_COUNT - 1; /* no meta */
1821 }
1822
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1823 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1824 double aValue) const override {
1825 RefPtr<GamepadPlatformService> service =
1826 GamepadPlatformService::GetParentService();
1827 if (!service) {
1828 return;
1829 }
1830
1831 switch (aAxis) {
1832 case 0:
1833 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1834 break;
1835 case 1:
1836 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1837 break;
1838 case 2:
1839 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1840 break;
1841 case 3: {
1842 const double value = AxisToButtonValue(aValue);
1843 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1844 value > BUTTON_THRESHOLD_VALUE, value);
1845 break;
1846 }
1847 case 4: {
1848 const double value = AxisToButtonValue(aValue);
1849 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1850 value > BUTTON_THRESHOLD_VALUE, value);
1851 break;
1852 }
1853 case 5:
1854 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1855 break;
1856 case 9:
1857 FetchDpadFromAxis(aHandle, aValue);
1858 break;
1859 default:
1860 NS_WARNING(
1861 nsPrintfCString(
1862 "Axis idx '%d' doesn't support in MogaProRemapper().", aAxis)
1863 .get());
1864 break;
1865 }
1866 }
1867
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1868 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1869 bool aPressed) const override {
1870 RefPtr<GamepadPlatformService> service =
1871 GamepadPlatformService::GetParentService();
1872 if (!service) {
1873 return;
1874 }
1875
1876 if (GetButtonCount() <= aButton) {
1877 NS_WARNING(
1878 nsPrintfCString(
1879 "Button idx '%d' doesn't support in MogaProRemapper().", aButton)
1880 .get());
1881 return;
1882 }
1883
1884 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1885 {3, BUTTON_INDEX_TERTIARY}, {4, BUTTON_INDEX_QUATERNARY},
1886 {6, BUTTON_INDEX_LEFT_SHOULDER}, {7, BUTTON_INDEX_RIGHT_SHOULDER},
1887 {11, BUTTON_INDEX_START}, {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1888 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
1889
1890 auto find = buttonMapping.find(aButton);
1891 if (find != buttonMapping.end()) {
1892 service->NewButtonEvent(aHandle, find->second, aPressed);
1893 } else {
1894 service->NewButtonEvent(aHandle, aButton, aPressed);
1895 }
1896 }
1897 };
1898
1899 class OnLiveWirelessRemapper final : public GamepadRemapper {
1900 public:
GetAxisCount() const1901 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1902
GetButtonCount() const1903 virtual uint32_t GetButtonCount() const override {
1904 return BUTTON_INDEX_COUNT;
1905 }
1906
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1907 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1908 double aValue) const override {
1909 RefPtr<GamepadPlatformService> service =
1910 GamepadPlatformService::GetParentService();
1911 if (!service) {
1912 return;
1913 }
1914
1915 switch (aAxis) {
1916 case 0:
1917 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
1918 break;
1919 case 1:
1920 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
1921 break;
1922 case 2: {
1923 const double value = AxisToButtonValue(aValue);
1924 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
1925 value > BUTTON_THRESHOLD_VALUE, value);
1926 break;
1927 }
1928 case 3:
1929 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
1930 break;
1931 case 4:
1932 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
1933 break;
1934 case 5: {
1935 const double value = AxisToButtonValue(aValue);
1936 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
1937 value > BUTTON_THRESHOLD_VALUE, value);
1938 break;
1939 }
1940 case 9:
1941 FetchDpadFromAxis(aHandle, aValue);
1942 break;
1943 default:
1944 NS_WARNING(
1945 nsPrintfCString(
1946 "Axis idx '%d' doesn't support in OnLiveWirelessRemapper().",
1947 aAxis)
1948 .get());
1949 break;
1950 }
1951 }
1952
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const1953 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
1954 bool aPressed) const override {
1955 RefPtr<GamepadPlatformService> service =
1956 GamepadPlatformService::GetParentService();
1957 if (!service) {
1958 return;
1959 }
1960
1961 if (GetButtonCount() <= aButton) {
1962 NS_WARNING(
1963 nsPrintfCString(
1964 "Button idx '%d' doesn't support in OnLiveWirelessRemapper().",
1965 aButton)
1966 .get());
1967 return;
1968 }
1969
1970 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
1971 {3, BUTTON_INDEX_TERTIARY},
1972 {4, BUTTON_INDEX_QUATERNARY},
1973 {6, BUTTON_INDEX_LEFT_SHOULDER},
1974 {7, BUTTON_INDEX_RIGHT_SHOULDER},
1975 {12, BUTTON_INDEX_META},
1976 {13, BUTTON_INDEX_LEFT_THUMBSTICK},
1977 {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
1978
1979 auto find = buttonMapping.find(aButton);
1980 if (find != buttonMapping.end()) {
1981 service->NewButtonEvent(aHandle, find->second, aPressed);
1982 } else {
1983 service->NewButtonEvent(aHandle, aButton, aPressed);
1984 }
1985 }
1986 };
1987
1988 class OUYARemapper final : public GamepadRemapper {
1989 public:
GetAxisCount() const1990 virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
1991
GetButtonCount() const1992 virtual uint32_t GetButtonCount() const override {
1993 return BUTTON_INDEX_COUNT;
1994 }
1995
RemapAxisMoveEvent(GamepadHandle aHandle,uint32_t aAxis,double aValue) const1996 virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
1997 double aValue) const override {
1998 RefPtr<GamepadPlatformService> service =
1999 GamepadPlatformService::GetParentService();
2000 if (!service) {
2001 return;
2002 }
2003
2004 switch (aAxis) {
2005 case 0:
2006 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
2007 break;
2008 case 1:
2009 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
2010 break;
2011 case 2: {
2012 const double value = AxisToButtonValue(aValue);
2013 service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
2014 value > BUTTON_THRESHOLD_VALUE, value);
2015 break;
2016 }
2017 case 3:
2018 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
2019 break;
2020 case 4:
2021 service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
2022 break;
2023 case 5: {
2024 const double value = AxisToButtonValue(aValue);
2025 service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
2026 value > BUTTON_THRESHOLD_VALUE, value);
2027 break;
2028 }
2029 default:
2030 NS_WARNING(
2031 nsPrintfCString("Axis idx '%d' doesn't support in OUYARemapper().",
2032 aAxis)
2033 .get());
2034 break;
2035 }
2036 }
2037
RemapButtonEvent(GamepadHandle aHandle,uint32_t aButton,bool aPressed) const2038 virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
2039 bool aPressed) const override {
2040 RefPtr<GamepadPlatformService> service =
2041 GamepadPlatformService::GetParentService();
2042 if (!service) {
2043 return;
2044 }
2045
2046 if (GetButtonCount() <= aButton) {
2047 NS_WARNING(
2048 nsPrintfCString("Button idx '%d' doesn't support in OUYARemapper().",
2049 aButton)
2050 .get());
2051 return;
2052 }
2053
2054 const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
2055 {1, BUTTON_INDEX_TERTIARY}, {2, BUTTON_INDEX_QUATERNARY},
2056 {3, BUTTON_INDEX_SECONDARY}, {6, BUTTON_INDEX_LEFT_THUMBSTICK},
2057 {7, BUTTON_INDEX_RIGHT_THUMBSTICK}, {8, BUTTON_INDEX_DPAD_UP},
2058 {9, BUTTON_INDEX_DPAD_DOWN}, {10, BUTTON_INDEX_DPAD_LEFT},
2059 {11, BUTTON_INDEX_DPAD_RIGHT}, {15, BUTTON_INDEX_META}};
2060
2061 auto find = buttonMapping.find(aButton);
2062 if (find != buttonMapping.end()) {
2063 service->NewButtonEvent(aHandle, find->second, aPressed);
2064 } else {
2065 service->NewButtonEvent(aHandle, aButton, aPressed);
2066 }
2067 }
2068 };
2069
GetGamepadRemapper(const uint16_t aVendorId,const uint16_t aProductId,bool & aUsingDefault)2070 already_AddRefed<GamepadRemapper> GetGamepadRemapper(const uint16_t aVendorId,
2071 const uint16_t aProductId,
2072 bool& aUsingDefault) {
2073 const std::vector<GamepadRemappingData> remappingRules = {
2074 {GamepadId::kAsusTekProduct4500, new ADT1Remapper()},
2075 {GamepadId::kDragonRiseProduct0011, new TwoAxesEightKeysRemapper()},
2076 {GamepadId::kGoogleProduct2c40, new ADT1Remapper()},
2077 {GamepadId::kGoogleProduct9400, new StadiaControllerRemapper()},
2078 {GamepadId::kLogitechProductc216, new LogitechDInputRemapper()},
2079 {GamepadId::kLogitechProductc218, new LogitechDInputRemapper()},
2080 {GamepadId::kLogitechProductc219, new LogitechDInputRemapper()},
2081 {GamepadId::kMicrosoftProductXbox360Wireless, new Xbox360Remapper()},
2082 {GamepadId::kMicrosoftProductXbox360Wireless2, new Xbox360Remapper()},
2083 {GamepadId::kMicrosoftProductXboxOneElite2Wireless,
2084 new XboxOneRemapper()},
2085 {GamepadId::kMicrosoftProductXboxOneSWireless, new XboxOneSRemapper()},
2086 {GamepadId::kMicrosoftProductXboxOneSWireless2016,
2087 new XboxOneS2016FirmwareRemapper()},
2088 {GamepadId::kMicrosoftProductXboxAdaptiveWireless, new XboxOneRemapper()},
2089 {GamepadId::kNintendoProduct2006, new SwitchJoyConRemapper()},
2090 {GamepadId::kNintendoProduct2007, new SwitchJoyConRemapper()},
2091 {GamepadId::kNintendoProduct2009, new SwitchProRemapper()},
2092 {GamepadId::kNintendoProduct200e, new SwitchProRemapper()},
2093 {GamepadId::kNvidiaProduct7210, new NvShieldRemapper()},
2094 {GamepadId::kNvidiaProduct7214, new NvShield2017Remapper()},
2095 {GamepadId::kPadixProduct2060, new IBuffaloRemapper()},
2096 {GamepadId::kPlayComProduct0005, new XSkillsRemapper()},
2097 {GamepadId::kPrototypeVendorProduct0667, new BoomN64PsxRemapper()},
2098 {GamepadId::kPrototypeVendorProduct9401,
2099 new StadiaControllerOldFirmwareRemapper()},
2100 {GamepadId::kRazer1532Product0900, new RazerServalRemapper()},
2101 {GamepadId::kSonyProduct0268, new Playstation3Remapper()},
2102 {GamepadId::kSonyProduct05c4, new Dualshock4Remapper()},
2103 {GamepadId::kSonyProduct09cc, new Dualshock4Remapper()},
2104 {GamepadId::kSonyProduct0ba0, new Dualshock4Remapper()},
2105 {GamepadId::kVendor20d6Product6271, new MogaProRemapper()},
2106 {GamepadId::kVendor2378Product1008, new OnLiveWirelessRemapper()},
2107 {GamepadId::kVendor2378Product100a, new OnLiveWirelessRemapper()},
2108 {GamepadId::kVendor2836Product0001, new OUYARemapper()}};
2109 const GamepadId id = static_cast<GamepadId>((aVendorId << 16) | aProductId);
2110
2111 for (uint32_t i = 0; i < remappingRules.size(); ++i) {
2112 if (id == remappingRules[i].id) {
2113 aUsingDefault = false;
2114 return do_AddRef(remappingRules[i].remapping.get());
2115 }
2116 }
2117
2118 RefPtr<GamepadRemapper> defaultRemapper = new DefaultRemapper();
2119 aUsingDefault = true;
2120 return do_AddRef(defaultRemapper.get());
2121 }
2122
2123 } // namespace mozilla::dom
2124