diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/gamepad/GamepadRemapping.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/gamepad/GamepadRemapping.cpp')
-rw-r--r-- | dom/gamepad/GamepadRemapping.cpp | 2218 |
1 files changed, 2218 insertions, 0 deletions
diff --git a/dom/gamepad/GamepadRemapping.cpp b/dom/gamepad/GamepadRemapping.cpp new file mode 100644 index 0000000000..7c5a858bcc --- /dev/null +++ b/dom/gamepad/GamepadRemapping.cpp @@ -0,0 +1,2218 @@ +/* -*- 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 XboxSeriesXRemapper 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 5: + service->NewAxisMoveEvent(aHandle, AXIS_INDEX_RIGHT_STICK_Y, aValue); + break; + case 9: + FetchDpadFromAxis(aHandle, aValue); + break; + case 148: { + const double value = AxisToButtonValue(aValue); + service->NewButtonEvent(aHandle, BUTTON_INDEX_RIGHT_TRIGGER, + value > BUTTON_THRESHOLD_VALUE, value); + break; + } + case 149: { + const double value = AxisToButtonValue(aValue); + service->NewButtonEvent(aHandle, BUTTON_INDEX_LEFT_TRIGGER, + value > BUTTON_THRESHOLD_VALUE, value); + break; + } + default: + NS_WARNING( + nsPrintfCString( + "Axis idx '%d' doesn't support in XboxSeriesXRemapper().", + 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 XboxSeriesXRemapper().", + aButton) + .get()); + return; + } + + 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}, + {10, BUTTON_INDEX_BACK_SELECT}, + {11, BUTTON_INDEX_START}, + {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 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::kMicrosoftProductXboxSeriesXWireless, + new XboxSeriesXRemapper()}, + {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 |