Skip to content

Commit a88ec2c

Browse files
committed
Bug 1465643 - Part 2: Remapping DualShock 4 buttons and axes on Windows. r=qdot
Differential Revision: https://phabricator.services.mozilla.com/D24217 --HG-- extra : moz-landing-system : lando
1 parent 0614a16 commit a88ec2c

File tree

4 files changed

+351
-45
lines changed

4 files changed

+351
-45
lines changed

dom/gamepad/GamepadRemapping.cpp

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
5+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
// Based on
8+
// https://cs.chromium.org/chromium/src/device/gamepad/gamepad_standard_mappings.h
9+
10+
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
11+
// Use of this source code is governed by a BSD-style license that can be
12+
// found in the LICENSE file.
13+
14+
#include "mozilla/dom/GamepadRemapping.h"
15+
16+
namespace mozilla {
17+
namespace dom {
18+
19+
// Follow the canonical ordering recommendation for the "Standard Gamepad"
20+
// from https://www.w3.org/TR/gamepad/#remapping.
21+
enum CanonicalButtonIndex {
22+
BUTTON_INDEX_PRIMARY,
23+
BUTTON_INDEX_SECONDARY,
24+
BUTTON_INDEX_TERTIARY,
25+
BUTTON_INDEX_QUATERNARY,
26+
BUTTON_INDEX_LEFT_SHOULDER,
27+
BUTTON_INDEX_RIGHT_SHOULDER,
28+
BUTTON_INDEX_LEFT_TRIGGER,
29+
BUTTON_INDEX_RIGHT_TRIGGER,
30+
BUTTON_INDEX_BACK_SELECT,
31+
BUTTON_INDEX_START,
32+
BUTTON_INDEX_LEFT_THUMBSTICK,
33+
BUTTON_INDEX_RIGHT_THUMBSTICK,
34+
BUTTON_INDEX_DPAD_UP,
35+
BUTTON_INDEX_DPAD_DOWN,
36+
BUTTON_INDEX_DPAD_LEFT,
37+
BUTTON_INDEX_DPAD_RIGHT,
38+
BUTTON_INDEX_META,
39+
BUTTON_INDEX_COUNT
40+
};
41+
42+
enum CanonicalAxisIndex {
43+
AXIS_INDEX_LEFT_STICK_X,
44+
AXIS_INDEX_LEFT_STICK_Y,
45+
AXIS_INDEX_RIGHT_STICK_X,
46+
AXIS_INDEX_RIGHT_STICK_Y,
47+
AXIS_INDEX_COUNT
48+
};
49+
50+
void FetchDpadFromAxis(uint32_t aIndex, double dir) {
51+
bool up = false;
52+
bool right = false;
53+
bool down = false;
54+
bool left = false;
55+
56+
// Dpad is mapped as a direction on one axis, where -1 is up and it
57+
// increases clockwise to 1, which is up + left. It's set to a large (> 1.f)
58+
// number when nothing is depressed, except on start up, sometimes it's 0.0
59+
// for no data, rather than the large number.
60+
if (dir != 0.0f) {
61+
up = (dir >= -1.f && dir < -0.7f) || (dir >= .95f && dir <= 1.f);
62+
right = dir >= -.75f && dir < -.1f;
63+
down = dir >= -.2f && dir < .45f;
64+
left = dir >= .4f && dir <= 1.f;
65+
}
66+
67+
RefPtr<GamepadPlatformService> service =
68+
GamepadPlatformService::GetParentService();
69+
if (!service) {
70+
return;
71+
}
72+
73+
service->NewButtonEvent(aIndex, BUTTON_INDEX_DPAD_UP, up);
74+
service->NewButtonEvent(aIndex, BUTTON_INDEX_DPAD_RIGHT, right);
75+
service->NewButtonEvent(aIndex, BUTTON_INDEX_DPAD_DOWN, down);
76+
service->NewButtonEvent(aIndex, BUTTON_INDEX_DPAD_LEFT, left);
77+
}
78+
79+
class DefaultRemapper final : public GamepadRemapper {
80+
public:
81+
virtual uint32_t GetAxisCount() const override {
82+
return numAxes;
83+
}
84+
85+
virtual uint32_t GetButtonCount() const override {
86+
return numButtons;
87+
}
88+
89+
virtual void SetAxisCount(uint32_t aAxisCount) override {
90+
numAxes = aAxisCount;
91+
}
92+
93+
virtual void SetButtonCount(uint32_t aButtonCount) override {
94+
numButtons = aButtonCount;
95+
}
96+
97+
virtual void RemapAxisMoveEvent(uint32_t aIndex, uint32_t aAxis,
98+
double aValue) const override {
99+
RefPtr<GamepadPlatformService> service =
100+
GamepadPlatformService::GetParentService();
101+
if (!service) {
102+
return;
103+
}
104+
service->NewAxisMoveEvent(aIndex, aAxis, aValue);
105+
}
106+
107+
virtual void RemapButtonEvent(uint32_t aIndex, uint32_t aButton,
108+
bool aPressed) const override {
109+
RefPtr<GamepadPlatformService> service =
110+
GamepadPlatformService::GetParentService();
111+
if (!service) {
112+
return;
113+
}
114+
service->NewButtonEvent(aIndex, aButton, aPressed);
115+
}
116+
117+
private:
118+
uint32_t numAxes;
119+
uint32_t numButtons;
120+
};
121+
122+
class Dualshock4Remapper final : public GamepadRemapper {
123+
public:
124+
virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
125+
126+
virtual uint32_t GetButtonCount() const override {
127+
return DUALSHOCK_BUTTON_COUNT;
128+
}
129+
130+
virtual GamepadMappingType GetMappingType() const override {
131+
return GamepadMappingType::_empty;
132+
}
133+
134+
virtual void RemapAxisMoveEvent(uint32_t aIndex, uint32_t aAxis,
135+
double aValue) const override {
136+
RefPtr<GamepadPlatformService> service =
137+
GamepadPlatformService::GetParentService();
138+
if (!service) {
139+
return;
140+
}
141+
142+
switch (aAxis) {
143+
case 0:
144+
service->NewAxisMoveEvent(aIndex, AXIS_INDEX_LEFT_STICK_X, aValue);
145+
break;
146+
case 1:
147+
service->NewAxisMoveEvent(aIndex, AXIS_INDEX_LEFT_STICK_Y, aValue);
148+
break;
149+
case 2:
150+
service->NewAxisMoveEvent(aIndex, AXIS_INDEX_RIGHT_STICK_X, aValue);
151+
break;
152+
case 3:
153+
service->NewButtonEvent(aIndex, BUTTON_INDEX_LEFT_TRIGGER,
154+
aValue > 0.1f);
155+
break;
156+
case 4:
157+
service->NewButtonEvent(aIndex, BUTTON_INDEX_RIGHT_TRIGGER,
158+
aValue > 0.1f);
159+
break;
160+
case 5:
161+
service->NewAxisMoveEvent(aIndex, AXIS_INDEX_RIGHT_STICK_Y, aValue);
162+
break;
163+
case 9:
164+
FetchDpadFromAxis(aIndex, aValue);
165+
break;
166+
default:
167+
NS_WARNING(
168+
nsPrintfCString(
169+
"Axis idx '%d' doesn't support in Dualshock4Remapper().", aAxis)
170+
.get());
171+
break;
172+
}
173+
}
174+
175+
virtual void RemapButtonEvent(uint32_t aIndex, uint32_t aButton,
176+
bool aPressed) const override {
177+
RefPtr<GamepadPlatformService> service =
178+
GamepadPlatformService::GetParentService();
179+
if (!service) {
180+
return;
181+
}
182+
183+
const std::vector<uint32_t> buttonMapping = {
184+
BUTTON_INDEX_TERTIARY,
185+
BUTTON_INDEX_PRIMARY,
186+
BUTTON_INDEX_SECONDARY,
187+
BUTTON_INDEX_QUATERNARY,
188+
BUTTON_INDEX_LEFT_SHOULDER,
189+
BUTTON_INDEX_RIGHT_SHOULDER,
190+
BUTTON_INDEX_LEFT_TRIGGER,
191+
BUTTON_INDEX_RIGHT_TRIGGER,
192+
BUTTON_INDEX_BACK_SELECT,
193+
BUTTON_INDEX_START,
194+
BUTTON_INDEX_LEFT_THUMBSTICK,
195+
BUTTON_INDEX_RIGHT_THUMBSTICK,
196+
BUTTON_INDEX_META,
197+
DUALSHOCK_BUTTON_TOUCHPAD
198+
};
199+
200+
if (buttonMapping.size() <= aIndex) {
201+
NS_WARNING(
202+
nsPrintfCString(
203+
"Button idx '%d' doesn't support in Dualshock4Remapper().",
204+
aButton)
205+
.get());
206+
return;
207+
}
208+
209+
service->NewButtonEvent(aIndex, buttonMapping[aButton], aPressed);
210+
}
211+
212+
private:
213+
enum Dualshock4Buttons {
214+
DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
215+
DUALSHOCK_BUTTON_COUNT
216+
};
217+
};
218+
219+
already_AddRefed<GamepadRemapper> GetGamepadRemapper(const uint16_t aVendorId,
220+
const uint16_t aProductId) {
221+
const std::vector<GamepadRemappingData> remappingRules = {
222+
{GamepadId::kSonyDualshock4, new Dualshock4Remapper()},
223+
{GamepadId::kSonyDualshock4Slim, new Dualshock4Remapper()},
224+
{GamepadId::kSonyDualshock4USBReceiver, new Dualshock4Remapper()}
225+
};
226+
const GamepadId id = static_cast<GamepadId>((aVendorId << 16) | aProductId);
227+
228+
for (uint32_t i = 0; i < remappingRules.size(); ++i) {
229+
if (id == remappingRules[i].id) {
230+
return do_AddRef(remappingRules[i].remapping.get());
231+
}
232+
}
233+
234+
static RefPtr<GamepadRemapper> defaultRemapper = new DefaultRemapper();
235+
return do_AddRef(defaultRemapper.get());
236+
}
237+
238+
} // namespace dom
239+
} // namespace mozilla

dom/gamepad/GamepadRemapping.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
5+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef mozilla_dom_GamepadRemapping_h_
8+
#define mozilla_dom_GamepadRemapping_h_
9+
10+
namespace mozilla {
11+
namespace dom {
12+
13+
// GamepadId is (vendorId << 16) | productId)
14+
enum class GamepadId : uint32_t {
15+
kSonyDualshock4 = 0x054c05c4,
16+
kSonyDualshock4Slim = 0x054c09cc,
17+
kSonyDualshock4USBReceiver = 0x054c0ba0,
18+
};
19+
20+
class GamepadRemapper {
21+
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GamepadRemapper)
22+
23+
public:
24+
virtual uint32_t GetAxisCount() const = 0;
25+
virtual uint32_t GetButtonCount() const = 0;
26+
virtual void SetAxisCount(uint32_t aButtonCount) {}
27+
virtual void SetButtonCount(uint32_t aButtonCount) {}
28+
virtual GamepadMappingType GetMappingType() const {
29+
return GamepadMappingType::Standard;
30+
}
31+
virtual void RemapAxisMoveEvent(uint32_t aIndex, uint32_t aAxis,
32+
double aValue) const = 0;
33+
virtual void RemapButtonEvent(uint32_t aIndex, uint32_t aButton,
34+
bool aPressed) const = 0;
35+
36+
protected:
37+
GamepadRemapper() = default;
38+
virtual ~GamepadRemapper() = default;
39+
};
40+
41+
struct GamepadRemappingData {
42+
GamepadId id;
43+
RefPtr<GamepadRemapper> remapping;
44+
};
45+
46+
already_AddRefed<GamepadRemapper> GetGamepadRemapper(const uint16_t aVendorId,
47+
const uint16_t aProductId);
48+
49+
} // namespace dom
50+
} // namespace mozilla
51+
52+
#endif

dom/gamepad/moz.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ EXPORTS.mozilla.dom += [
2222
'GamepadPlatformService.h',
2323
'GamepadPose.h',
2424
'GamepadPoseState.h',
25+
'GamepadRemapping.h',
2526
'GamepadServiceTest.h',
2627
'ipc/GamepadEventChannelChild.h',
2728
'ipc/GamepadEventChannelParent.h',
@@ -39,6 +40,7 @@ UNIFIED_SOURCES = [
3940
'GamepadMonitoring.cpp',
4041
'GamepadPlatformService.cpp',
4142
'GamepadPose.cpp',
43+
'GamepadRemapping.cpp',
4244
'GamepadServiceTest.cpp',
4345
'ipc/GamepadEventChannelChild.cpp',
4446
'ipc/GamepadEventChannelParent.cpp',

0 commit comments

Comments
 (0)