summaryrefslogtreecommitdiffstats
path: root/dom/gamepad/GamepadRemapping.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/gamepad/GamepadRemapping.cpp')
-rw-r--r--dom/gamepad/GamepadRemapping.cpp2123
1 files changed, 2123 insertions, 0 deletions
diff --git a/dom/gamepad/GamepadRemapping.cpp b/dom/gamepad/GamepadRemapping.cpp
new file mode 100644
index 0000000000..227d5fbf38
--- /dev/null
+++ b/dom/gamepad/GamepadRemapping.cpp
@@ -0,0 +1,2123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Based on
+// https://cs.chromium.org/chromium/src/device/gamepad/gamepad_standard_mappings.h
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mozilla/dom/GamepadRemapping.h"
+#include "mozilla/dom/GamepadPlatformService.h"
+
+#include <vector>
+#include <unordered_map>
+
+namespace mozilla::dom {
+
+// Follow the canonical ordering recommendation for the "Standard Gamepad"
+// from https://www.w3.org/TR/gamepad/#remapping.
+enum CanonicalButtonIndex {
+ BUTTON_INDEX_PRIMARY,
+ BUTTON_INDEX_SECONDARY,
+ BUTTON_INDEX_TERTIARY,
+ BUTTON_INDEX_QUATERNARY,
+ BUTTON_INDEX_LEFT_SHOULDER,
+ BUTTON_INDEX_RIGHT_SHOULDER,
+ BUTTON_INDEX_LEFT_TRIGGER,
+ BUTTON_INDEX_RIGHT_TRIGGER,
+ BUTTON_INDEX_BACK_SELECT,
+ BUTTON_INDEX_START,
+ BUTTON_INDEX_LEFT_THUMBSTICK,
+ BUTTON_INDEX_RIGHT_THUMBSTICK,
+ BUTTON_INDEX_DPAD_UP,
+ BUTTON_INDEX_DPAD_DOWN,
+ BUTTON_INDEX_DPAD_LEFT,
+ BUTTON_INDEX_DPAD_RIGHT,
+ BUTTON_INDEX_META,
+ BUTTON_INDEX_COUNT
+};
+
+enum CanonicalAxisIndex {
+ AXIS_INDEX_LEFT_STICK_X,
+ AXIS_INDEX_LEFT_STICK_Y,
+ AXIS_INDEX_RIGHT_STICK_X,
+ AXIS_INDEX_RIGHT_STICK_Y,
+ AXIS_INDEX_COUNT
+};
+
+const float BUTTON_THRESHOLD_VALUE = 0.1f;
+
+float NormalizeTouch(long aValue, long aMin, long aMax) {
+ return (2.f * (aValue - aMin) / static_cast<float>(aMax - aMin)) - 1.f;
+}
+
+bool AxisNegativeAsButton(float input) {
+ const float value = (input < -0.5f) ? 1.f : 0.f;
+ return value > BUTTON_THRESHOLD_VALUE;
+}
+
+bool AxisPositiveAsButton(float input) {
+ const float value = (input > 0.5f) ? 1.f : 0.f;
+ return value > BUTTON_THRESHOLD_VALUE;
+}
+
+double AxisToButtonValue(double aValue) {
+ // Mapping axis value range from (-1, +1) to (0, +1).
+ return (aValue + 1.0f) * 0.5f;
+}
+
+void FetchDpadFromAxis(GamepadHandle aHandle, double dir) {
+ bool up = false;
+ bool right = false;
+ bool down = false;
+ bool left = false;
+
+ // Dpad is mapped as a direction on one axis, where -1 is up and it
+ // increases clockwise to 1, which is up + left. It's set to a large (> 1.f)
+ // number when nothing is depressed, except on start up, sometimes it's 0.0
+ // for no data, rather than the large number.
+ if (dir != 0.0f) {
+ up = (dir >= -1.f && dir < -0.7f) || (dir >= .95f && dir <= 1.f);
+ right = dir >= -.75f && dir < -.1f;
+ down = dir >= -.2f && dir < .45f;
+ left = dir >= .4f && dir <= 1.f;
+ }
+
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP, up);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT, right);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN, down);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT, left);
+}
+
+class DefaultRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return numAxes; }
+
+ virtual uint32_t GetButtonCount() const override { return numButtons; }
+
+ virtual void SetAxisCount(uint32_t aAxisCount) override {
+ numAxes = aAxisCount;
+ }
+
+ virtual void SetButtonCount(uint32_t aButtonCount) override {
+ numButtons = aButtonCount;
+ }
+
+ virtual GamepadMappingType GetMappingType() const override {
+ return GamepadMappingType::_empty;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ if (GetAxisCount() <= aAxis) {
+ NS_WARNING(
+ nsPrintfCString("Axis idx '%d' doesn't support in DefaultRemapper().",
+ aAxis)
+ .get());
+ return;
+ }
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+ service->NewAxisMoveEvent(aHandle, aAxis, aValue);
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in DefaultRemapper().", aButton)
+ .get());
+ return;
+ }
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+
+ private:
+ uint32_t numAxes;
+ uint32_t numButtons;
+};
+
+class ADT1Remapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString("Axis idx '%d' doesn't support in ADT1Remapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString("Button idx '%d' doesn't support in ADT1Remapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {12, BUTTON_INDEX_META},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class TwoAxesEightKeysRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return 0; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT - 1;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT,
+ AxisNegativeAsButton(aValue));
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT,
+ AxisPositiveAsButton(aValue));
+ break;
+ case 1:
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP,
+ AxisNegativeAsButton(aValue));
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN,
+ AxisPositiveAsButton(aValue));
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in TwoAxesEightKeysRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in TwoAxesEightKeysRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_QUATERNARY},
+ {2, BUTTON_INDEX_PRIMARY},
+ {3, BUTTON_INDEX_TERTIARY}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class StadiaControllerRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return STADIA_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in StadiaControllerRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (STADIA_BUTTON_COUNT <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in StadiaControllerRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+
+ private:
+ enum STADIAButtons {
+ STADIA_BUTTON_EXTRA1 = BUTTON_INDEX_COUNT,
+ STADIA_BUTTON_EXTRA2,
+ STADIA_BUTTON_COUNT
+ };
+};
+
+class Playstation3Remapper final : public GamepadRemapper {
+ public:
+ Playstation3Remapper() = default;
+
+ uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ uint32_t GetButtonCount() const override { return BUTTON_INDEX_COUNT; }
+
+ void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in Playstation3Remapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ const std::vector<uint32_t> buttonMapping = {BUTTON_INDEX_BACK_SELECT,
+ BUTTON_INDEX_LEFT_THUMBSTICK,
+ BUTTON_INDEX_RIGHT_THUMBSTICK,
+ BUTTON_INDEX_START,
+ BUTTON_INDEX_DPAD_UP,
+ BUTTON_INDEX_DPAD_RIGHT,
+ BUTTON_INDEX_DPAD_DOWN,
+ BUTTON_INDEX_DPAD_LEFT,
+ BUTTON_INDEX_LEFT_TRIGGER,
+ BUTTON_INDEX_RIGHT_TRIGGER,
+ BUTTON_INDEX_LEFT_SHOULDER,
+ BUTTON_INDEX_RIGHT_SHOULDER,
+ BUTTON_INDEX_QUATERNARY,
+ BUTTON_INDEX_SECONDARY,
+ BUTTON_INDEX_PRIMARY,
+ BUTTON_INDEX_TERTIARY,
+ BUTTON_INDEX_META};
+
+ if (buttonMapping.size() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in Playstation3Remapper().",
+ aButton)
+ .get());
+ return;
+ }
+ service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
+ }
+};
+
+class Dualshock4Remapper final : public GamepadRemapper {
+ public:
+ Dualshock4Remapper() {
+ mLastTouches.SetLength(TOUCH_EVENT_COUNT);
+ mLastTouchId.SetLength(TOUCH_EVENT_COUNT);
+ }
+
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return DUALSHOCK_BUTTON_COUNT;
+ }
+
+ virtual uint32_t GetLightIndicatorCount() const override {
+ return LIGHT_INDICATOR_COUNT;
+ }
+
+ virtual void GetLightIndicators(
+ nsTArray<GamepadLightIndicatorType>& aTypes) const override {
+ const uint32_t len = GetLightIndicatorCount();
+ aTypes.SetLength(len);
+ for (uint32_t i = 0; i < len; ++i) {
+ aTypes[i] = GamepadLightIndicatorType::Rgb;
+ }
+ }
+
+ virtual uint32_t GetTouchEventCount() const override {
+ return TOUCH_EVENT_COUNT;
+ }
+
+ virtual void GetLightColorReport(
+ uint8_t aRed, uint8_t aGreen, uint8_t aBlue,
+ std::vector<uint8_t>& aReport) const override {
+ const size_t report_length = 32;
+ aReport.resize(report_length);
+ aReport.assign(report_length, 0);
+
+ aReport[0] = 0x05; // report ID USB only
+ aReport[1] = 0x02; // LED only
+ aReport[6] = aRed;
+ aReport[7] = aGreen;
+ aReport[8] = aBlue;
+ }
+
+ virtual uint32_t GetMaxInputReportLength() const override {
+ return MAX_INPUT_LEN;
+ }
+
+ virtual void ProcessTouchData(GamepadHandle aHandle, void* aInput) override {
+ nsTArray<GamepadTouchState> touches(TOUCH_EVENT_COUNT);
+ touches.SetLength(TOUCH_EVENT_COUNT);
+ uint8_t* rawData = (uint8_t*)aInput;
+
+ const uint32_t kTouchDimensionX = 1920;
+ const uint32_t kTouchDimensionY = 942;
+ bool touch0Pressed = (((rawData[35] & 0xff) >> 7) == 0);
+ bool touch1Pressed = (((rawData[39] & 0xff) >> 7) == 0);
+
+ if ((touch0Pressed && (rawData[35] & 0xff) < mLastTouchId[0]) ||
+ (touch1Pressed && (rawData[39] & 0xff) < mLastTouchId[1])) {
+ mTouchIdBase += 128;
+ }
+
+ if (touch0Pressed) {
+ touches[0].touchId = mTouchIdBase + (rawData[35] & 0x7f);
+ touches[0].surfaceId = 0;
+ touches[0].position[0] = NormalizeTouch(
+ ((rawData[37] & 0xf) << 8) | rawData[36], 0, (kTouchDimensionX - 1));
+ touches[0].position[1] =
+ NormalizeTouch(rawData[38] << 4 | ((rawData[37] & 0xf0) >> 4), 0,
+ (kTouchDimensionY - 1));
+ touches[0].surfaceDimensions[0] = kTouchDimensionX;
+ touches[0].surfaceDimensions[1] = kTouchDimensionY;
+ touches[0].isSurfaceDimensionsValid = true;
+ mLastTouchId[0] = rawData[35] & 0x7f;
+ }
+ if (touch1Pressed) {
+ touches[1].touchId = mTouchIdBase + (rawData[39] & 0x7f);
+ touches[1].surfaceId = 0;
+ touches[1].position[0] =
+ NormalizeTouch((((rawData[41] & 0xf) << 8) | rawData[40]) + 1, 0,
+ (kTouchDimensionX - 1));
+ touches[1].position[1] =
+ NormalizeTouch(rawData[42] << 4 | ((rawData[41] & 0xf0) >> 4), 0,
+ (kTouchDimensionY - 1));
+ touches[1].surfaceDimensions[0] = kTouchDimensionX;
+ touches[1].surfaceDimensions[1] = kTouchDimensionY;
+ touches[1].isSurfaceDimensionsValid = true;
+ mLastTouchId[1] = rawData[39] & 0x7f;
+ }
+
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ // Avoid to send duplicate untouched events to the gamepad service.
+ if ((mLastTouches[0] != touch0Pressed) || touch0Pressed) {
+ service->NewMultiTouchEvent(aHandle, 0, touches[0]);
+ }
+ if ((mLastTouches[1] != touch1Pressed) || touch1Pressed) {
+ service->NewMultiTouchEvent(aHandle, 1, touches[1]);
+ }
+ mLastTouches[0] = touch0Pressed;
+ mLastTouches[1] = touch1Pressed;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in Dualshock4Remapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ const std::vector<uint32_t> buttonMapping = {BUTTON_INDEX_TERTIARY,
+ BUTTON_INDEX_PRIMARY,
+ BUTTON_INDEX_SECONDARY,
+ BUTTON_INDEX_QUATERNARY,
+ BUTTON_INDEX_LEFT_SHOULDER,
+ BUTTON_INDEX_RIGHT_SHOULDER,
+ BUTTON_INDEX_LEFT_TRIGGER,
+ BUTTON_INDEX_RIGHT_TRIGGER,
+ BUTTON_INDEX_BACK_SELECT,
+ BUTTON_INDEX_START,
+ BUTTON_INDEX_LEFT_THUMBSTICK,
+ BUTTON_INDEX_RIGHT_THUMBSTICK,
+ BUTTON_INDEX_META,
+ DUALSHOCK_BUTTON_TOUCHPAD};
+
+ if (buttonMapping.size() <= aButton) {
+ NS_WARNING(nsPrintfCString(
+ "Button idx '%d' doesn't support in Dualshock4Remapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
+ }
+
+ private:
+ enum Dualshock4Buttons {
+ DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
+ DUALSHOCK_BUTTON_COUNT
+ };
+
+ static const uint32_t LIGHT_INDICATOR_COUNT = 1;
+ static const uint32_t TOUCH_EVENT_COUNT = 2;
+ static const uint32_t MAX_INPUT_LEN = 68;
+
+ nsTArray<unsigned long> mLastTouchId;
+ nsTArray<bool> mLastTouches;
+ unsigned long mTouchIdBase = 0;
+};
+
+class Xbox360Remapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 4:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 5: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in Xbox360Remapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in Xbox360Remapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {6, BUTTON_INDEX_LEFT_THUMBSTICK}, {7, BUTTON_INDEX_RIGHT_THUMBSTICK},
+ {8, BUTTON_INDEX_START}, {9, BUTTON_INDEX_BACK_SELECT},
+ {10, BUTTON_INDEX_META}, {11, BUTTON_INDEX_DPAD_UP},
+ {12, BUTTON_INDEX_DPAD_DOWN}, {13, BUTTON_INDEX_DPAD_LEFT},
+ {14, BUTTON_INDEX_DPAD_RIGHT}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class XboxOneSRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 4:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 5: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in XboxOneSRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in XboxOneSRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {6, BUTTON_INDEX_BACK_SELECT},
+ {7, BUTTON_INDEX_START},
+ {8, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {9, BUTTON_INDEX_RIGHT_THUMBSTICK},
+ {10, BUTTON_INDEX_META}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class XboxOneS2016FirmwareRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(nsPrintfCString("Axis idx '%d' doesn't support in "
+ "XboxOneS2016FirmwareRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(nsPrintfCString("Button idx '%d' doesn't support in "
+ "XboxOneS2016FirmwareRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ // kMicrosoftProductXboxOneSWireless2016 controller received a firmware
+ // update in 2019 that changed which field is populated with the meta button
+ // state. In order to cover the old and new cases, we have to check both
+ // fields of {12, 15} buttons.
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_PRIMARY},
+ {1, BUTTON_INDEX_SECONDARY},
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {11, BUTTON_INDEX_START},
+ {12, BUTTON_INDEX_META},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
+ {15, BUTTON_INDEX_META},
+ {16, BUTTON_INDEX_BACK_SELECT}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class XboxOneRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ case 10: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 11: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in XboxOneRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in XboxOneRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ // Accessing {30, 31} buttons looks strange to me
+ // and without an avilable device to help verify it.
+ // It is according to `MapperXboxOneBluetooth()` in
+ // https://cs.chromium.org/chromium/src/device/gamepad/gamepad_standard_mappings_mac.mm
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_PRIMARY},
+ {1, BUTTON_INDEX_SECONDARY},
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {11, BUTTON_INDEX_START},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
+ {30, BUTTON_INDEX_META},
+ {31, BUTTON_INDEX_BACK_SELECT}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class LogitechDInputRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ // The Logitech button (BUTTON_INDEX_META) is not accessible through the
+ // device's D-mode.
+ return BUTTON_INDEX_COUNT - 1;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in LogitechDInputRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in LogitechDInputRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_TERTIARY},
+ {1, BUTTON_INDEX_PRIMARY},
+ {2, BUTTON_INDEX_SECONDARY}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class SwitchJoyConRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return 2; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ if (GetAxisCount() <= aAxis) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in SwitchJoyConRemapper().", aAxis)
+ .get());
+ return;
+ }
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+};
+
+class SwitchProRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ // The Switch Pro controller has a Capture button that has no equivalent in
+ // the Standard Gamepad.
+ return SWITCHPRO_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ if (GetAxisCount() <= aAxis) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in SwitchProRemapper().", aAxis)
+ .get());
+ return;
+ }
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+
+ private:
+ enum SwitchProButtons {
+ SWITCHPRO_BUTTON_EXTRA = BUTTON_INDEX_COUNT,
+ SWITCHPRO_BUTTON_COUNT
+ };
+};
+
+class NvShieldRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return SHIELD_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in NvShieldRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in NvShieldRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {2, BUTTON_INDEX_META},
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {5, SHIELD_BUTTON_CIRCLE},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {9, BUTTON_INDEX_BACK_SELECT},
+ {11, BUTTON_INDEX_START},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+
+ private:
+ enum ShieldButtons {
+ SHIELD_BUTTON_CIRCLE = BUTTON_INDEX_COUNT,
+ SHIELD_BUTTON_COUNT
+ };
+};
+
+class NvShield2017Remapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return SHIELD2017_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in NvShield2017Remapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in NvShield2017Remapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {2, BUTTON_INDEX_META},
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {5, BUTTON_INDEX_START},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {8, BUTTON_INDEX_BACK_SELECT},
+ {11, SHIELD2017_BUTTON_PLAYPAUSE},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+
+ private:
+ enum Shield2017Buttons {
+ SHIELD2017_BUTTON_PLAYPAUSE = BUTTON_INDEX_COUNT,
+ SHIELD2017_BUTTON_COUNT
+ };
+};
+
+class IBuffaloRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return 2; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT - 1; /* no meta */
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_LEFT,
+ AxisNegativeAsButton(aValue));
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_RIGHT,
+ AxisPositiveAsButton(aValue));
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_UP,
+ AxisNegativeAsButton(aValue));
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_DPAD_DOWN,
+ AxisPositiveAsButton(aValue));
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in IBuffaloRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in IBuffaloRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_SECONDARY}, {1, BUTTON_INDEX_PRIMARY},
+ {2, BUTTON_INDEX_QUATERNARY}, {3, BUTTON_INDEX_TERTIARY},
+ {5, BUTTON_INDEX_RIGHT_TRIGGER}, {6, BUTTON_INDEX_BACK_SELECT},
+ {7, BUTTON_INDEX_START}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class XSkillsRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return GAMECUBE_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in XSkillsRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in XSkillsRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {0, BUTTON_INDEX_PRIMARY}, // A
+ {1, BUTTON_INDEX_TERTIARY}, // B
+ {2, BUTTON_INDEX_SECONDARY}, // X
+ {3, BUTTON_INDEX_QUATERNARY}, // Y
+ {4, GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK},
+ {5, GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK},
+ {6, BUTTON_INDEX_RIGHT_SHOULDER},
+ {7, BUTTON_INDEX_START},
+ {8, BUTTON_INDEX_DPAD_LEFT},
+ {9, BUTTON_INDEX_DPAD_RIGHT},
+ {10, BUTTON_INDEX_DPAD_DOWN},
+ {11, BUTTON_INDEX_DPAD_UP}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+
+ private:
+ enum GamecubeButtons {
+ GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK = BUTTON_INDEX_COUNT,
+ GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK,
+ GAMECUBE_BUTTON_COUNT
+ };
+};
+
+class BoomN64PsxRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT - 1; // no meta
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in BoomN64PsxRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ const std::vector<uint32_t> buttonMapping = {
+ BUTTON_INDEX_QUATERNARY, BUTTON_INDEX_SECONDARY,
+ BUTTON_INDEX_PRIMARY, BUTTON_INDEX_TERTIARY,
+ BUTTON_INDEX_LEFT_TRIGGER, BUTTON_INDEX_RIGHT_TRIGGER,
+ BUTTON_INDEX_LEFT_SHOULDER, BUTTON_INDEX_RIGHT_SHOULDER,
+ BUTTON_INDEX_BACK_SELECT, BUTTON_INDEX_LEFT_THUMBSTICK,
+ BUTTON_INDEX_RIGHT_THUMBSTICK, BUTTON_INDEX_START,
+ BUTTON_INDEX_DPAD_UP, BUTTON_INDEX_DPAD_RIGHT,
+ BUTTON_INDEX_DPAD_DOWN, BUTTON_INDEX_DPAD_LEFT};
+
+ if (buttonMapping.size() <= aButton) {
+ NS_WARNING(nsPrintfCString(
+ "Button idx '%d' doesn't support in BoomN64PsxRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ service->NewButtonEvent(aHandle, buttonMapping[aButton], aPressed);
+ }
+
+ private:
+ enum GamecubeButtons {
+ GAMECUBE_BUTTON_LEFT_TRIGGER_CLICK = BUTTON_INDEX_COUNT,
+ GAMECUBE_BUTTON_RIGHT_TRIGGER_CLICK,
+ GAMECUBE_BUTTON_COUNT
+ };
+};
+
+class StadiaControllerOldFirmwareRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return ANALOG_GAMEPAD_BUTTON_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in AnalogGamepadRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in AnalogGamepadRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {10, BUTTON_INDEX_BACK_SELECT},
+ {11, BUTTON_INDEX_META},
+ {12, BUTTON_INDEX_START},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK},
+ {16, ANALOG_GAMEPAD_BUTTON_EXTRA},
+ {17, ANALOG_GAMEPAD_BUTTON_EXTRA2}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+
+ private:
+ enum AnalogGamepadButtons {
+ ANALOG_GAMEPAD_BUTTON_EXTRA = BUTTON_INDEX_COUNT,
+ ANALOG_GAMEPAD_BUTTON_EXTRA2,
+ ANALOG_GAMEPAD_BUTTON_COUNT
+ };
+};
+
+class RazerServalRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT - 1; /* no meta */
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in RazerServalRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in RazerServalRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {3, BUTTON_INDEX_TERTIARY}, {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER}, {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {10, BUTTON_INDEX_BACK_SELECT}, {11, BUTTON_INDEX_START},
+ {12, BUTTON_INDEX_START}, {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class MogaProRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT - 1; /* no meta */
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 3: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 4: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 5:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in MogaProRemapper().", aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in MogaProRemapper().", aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {3, BUTTON_INDEX_TERTIARY}, {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER}, {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {11, BUTTON_INDEX_START}, {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class OnLiveWirelessRemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 4:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 5: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 9:
+ FetchDpadFromAxis(aHandle, aValue);
+ break;
+ default:
+ NS_WARNING(
+ nsPrintfCString(
+ "Axis idx '%d' doesn't support in OnLiveWirelessRemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString(
+ "Button idx '%d' doesn't support in OnLiveWirelessRemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {3, BUTTON_INDEX_TERTIARY},
+ {4, BUTTON_INDEX_QUATERNARY},
+ {6, BUTTON_INDEX_LEFT_SHOULDER},
+ {7, BUTTON_INDEX_RIGHT_SHOULDER},
+ {12, BUTTON_INDEX_META},
+ {13, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {14, BUTTON_INDEX_RIGHT_THUMBSTICK}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+class OUYARemapper final : public GamepadRemapper {
+ public:
+ virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
+
+ virtual uint32_t GetButtonCount() const override {
+ return BUTTON_INDEX_COUNT;
+ }
+
+ virtual void RemapAxisMoveEvent(GamepadHandle aHandle, uint32_t aAxis,
+ double aValue) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ switch (aAxis) {
+ case 0:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_X, aValue);
+ break;
+ case 1:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_LEFT_STICK_Y, aValue);
+ break;
+ case 2: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ case 3:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_X, aValue);
+ break;
+ case 4:
+ service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue);
+ break;
+ case 5: {
+ const double value = AxisToButtonValue(aValue);
+ service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER,
+ value > BUTTON_THRESHOLD_VALUE, value);
+ break;
+ }
+ default:
+ NS_WARNING(
+ nsPrintfCString("Axis idx '%d' doesn't support in OUYARemapper().",
+ aAxis)
+ .get());
+ break;
+ }
+ }
+
+ virtual void RemapButtonEvent(GamepadHandle aHandle, uint32_t aButton,
+ bool aPressed) const override {
+ RefPtr<GamepadPlatformService> service =
+ GamepadPlatformService::GetParentService();
+ if (!service) {
+ return;
+ }
+
+ if (GetButtonCount() <= aButton) {
+ NS_WARNING(
+ nsPrintfCString("Button idx '%d' doesn't support in OUYARemapper().",
+ aButton)
+ .get());
+ return;
+ }
+
+ const std::unordered_map<uint32_t, uint32_t> buttonMapping = {
+ {1, BUTTON_INDEX_TERTIARY}, {2, BUTTON_INDEX_QUATERNARY},
+ {3, BUTTON_INDEX_SECONDARY}, {6, BUTTON_INDEX_LEFT_THUMBSTICK},
+ {7, BUTTON_INDEX_RIGHT_THUMBSTICK}, {8, BUTTON_INDEX_DPAD_UP},
+ {9, BUTTON_INDEX_DPAD_DOWN}, {10, BUTTON_INDEX_DPAD_LEFT},
+ {11, BUTTON_INDEX_DPAD_RIGHT}, {15, BUTTON_INDEX_META}};
+
+ auto find = buttonMapping.find(aButton);
+ if (find != buttonMapping.end()) {
+ service->NewButtonEvent(aHandle, find->second, aPressed);
+ } else {
+ service->NewButtonEvent(aHandle, aButton, aPressed);
+ }
+ }
+};
+
+already_AddRefed<GamepadRemapper> GetGamepadRemapper(const uint16_t aVendorId,
+ const uint16_t aProductId,
+ bool& aUsingDefault) {
+ const std::vector<GamepadRemappingData> remappingRules = {
+ {GamepadId::kAsusTekProduct4500, new ADT1Remapper()},
+ {GamepadId::kDragonRiseProduct0011, new TwoAxesEightKeysRemapper()},
+ {GamepadId::kGoogleProduct2c40, new ADT1Remapper()},
+ {GamepadId::kGoogleProduct9400, new StadiaControllerRemapper()},
+ {GamepadId::kLogitechProductc216, new LogitechDInputRemapper()},
+ {GamepadId::kLogitechProductc218, new LogitechDInputRemapper()},
+ {GamepadId::kLogitechProductc219, new LogitechDInputRemapper()},
+ {GamepadId::kMicrosoftProductXbox360Wireless, new Xbox360Remapper()},
+ {GamepadId::kMicrosoftProductXbox360Wireless2, new Xbox360Remapper()},
+ {GamepadId::kMicrosoftProductXboxOneElite2Wireless,
+ new XboxOneRemapper()},
+ {GamepadId::kMicrosoftProductXboxOneSWireless, new XboxOneSRemapper()},
+ {GamepadId::kMicrosoftProductXboxOneSWireless2016,
+ new XboxOneS2016FirmwareRemapper()},
+ {GamepadId::kMicrosoftProductXboxAdaptiveWireless, new XboxOneRemapper()},
+ {GamepadId::kNintendoProduct2006, new SwitchJoyConRemapper()},
+ {GamepadId::kNintendoProduct2007, new SwitchJoyConRemapper()},
+ {GamepadId::kNintendoProduct2009, new SwitchProRemapper()},
+ {GamepadId::kNintendoProduct200e, new SwitchProRemapper()},
+ {GamepadId::kNvidiaProduct7210, new NvShieldRemapper()},
+ {GamepadId::kNvidiaProduct7214, new NvShield2017Remapper()},
+ {GamepadId::kPadixProduct2060, new IBuffaloRemapper()},
+ {GamepadId::kPlayComProduct0005, new XSkillsRemapper()},
+ {GamepadId::kPrototypeVendorProduct0667, new BoomN64PsxRemapper()},
+ {GamepadId::kPrototypeVendorProduct9401,
+ new StadiaControllerOldFirmwareRemapper()},
+ {GamepadId::kRazer1532Product0900, new RazerServalRemapper()},
+ {GamepadId::kSonyProduct0268, new Playstation3Remapper()},
+ {GamepadId::kSonyProduct05c4, new Dualshock4Remapper()},
+ {GamepadId::kSonyProduct09cc, new Dualshock4Remapper()},
+ {GamepadId::kSonyProduct0ba0, new Dualshock4Remapper()},
+ {GamepadId::kVendor20d6Product6271, new MogaProRemapper()},
+ {GamepadId::kVendor2378Product1008, new OnLiveWirelessRemapper()},
+ {GamepadId::kVendor2378Product100a, new OnLiveWirelessRemapper()},
+ {GamepadId::kVendor2836Product0001, new OUYARemapper()}};
+ const GamepadId id = static_cast<GamepadId>((aVendorId << 16) | aProductId);
+
+ for (uint32_t i = 0; i < remappingRules.size(); ++i) {
+ if (id == remappingRules[i].id) {
+ aUsingDefault = false;
+ return do_AddRef(remappingRules[i].remapping.get());
+ }
+ }
+
+ RefPtr<GamepadRemapper> defaultRemapper = new DefaultRemapper();
+ aUsingDefault = true;
+ return do_AddRef(defaultRemapper.get());
+}
+
+} // namespace mozilla::dom