/* -*- 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 {
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;
}
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;
}
constexpr std::array 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;
}
constexpr std::array<uint32_t, 14> 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;
}
static constexpr std::array 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;
}
--> --------------------
--> maximum size reached
--> --------------------