-
Notifications
You must be signed in to change notification settings - Fork 164
/
gamepad.cpp
142 lines (114 loc) · 4.7 KB
/
gamepad.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "moonlight.hpp"
#include "ppapi/c/ppb_gamepad.h"
#include <Limelight.h>
#include <sstream>
static const unsigned short k_StandardGamepadButtonMapping[] = {
A_FLAG, B_FLAG, X_FLAG, Y_FLAG,
LB_FLAG, RB_FLAG,
0, 0, // Triggers
BACK_FLAG, PLAY_FLAG,
LS_CLK_FLAG, RS_CLK_FLAG,
UP_FLAG, DOWN_FLAG, LEFT_FLAG, RIGHT_FLAG,
SPECIAL_FLAG
};
static const unsigned int k_StandardGamepadTriggerButtonIndexes[] = {
6, 7
};
static short GetActiveGamepadMask(PP_GamepadsSampleData& gamepadData) {
short controllerIndex = 0;
short activeGamepadMask = 0;
for (unsigned int p = 0; p < gamepadData.length; p++) {
PP_GamepadSampleData& padData = gamepadData.items[p];
// See logic in getConnectedGamepadMask() (utils.js)
// These must stay in sync!
if (!padData.connected) {
// Not connected
continue;
}
if (padData.timestamp == 0) {
// On some platforms, Chrome returns "connected" pads that
// really aren't, so timestamp stays at zero. To work around this,
// we'll only count gamepads that have a non-zero timestamp in our
// controller index.
continue;
}
activeGamepadMask |= (1 << controllerIndex);
controllerIndex++;
}
return activeGamepadMask;
}
void MoonlightInstance::PollGamepads() {
PP_GamepadsSampleData gamepadData;
short controllerIndex = 0;
short activeGamepadMask;
m_GamepadApi->Sample(pp_instance(), &gamepadData);
// We must determine which gamepads are connected before reporting
// any events.
activeGamepadMask = GetActiveGamepadMask(gamepadData);
for (unsigned int p = 0; p < gamepadData.length; p++) {
PP_GamepadSampleData& padData = gamepadData.items[p];
if (!padData.connected) {
// Not connected
continue;
}
if (padData.timestamp == 0) {
// On some platforms, Chrome returns "connected" pads that
// really aren't, so timestamp stays at zero. To work around this,
// we'll only count gamepads that have a non-zero timestamp in our
// controller index.
continue;
}
if (padData.timestamp == m_LastPadTimestamps[p]) {
// No change from last poll, but this controller is still valid
// so we skip this index.
controllerIndex++;
continue;
}
m_LastPadTimestamps[p] = padData.timestamp;
int buttonFlags = 0;
unsigned char leftTrigger = 0, rightTrigger = 0;
short leftStickX = 0, leftStickY = 0;
short rightStickX = 0, rightStickY = 0;
// Handle buttons and triggers
for (unsigned int i = 0; i < padData.buttons_length; i++) {
if (i >= sizeof(k_StandardGamepadButtonMapping) / sizeof(k_StandardGamepadButtonMapping[0])) {
// Ignore unmapped buttons
break;
}
// Handle triggers first
if (i == k_StandardGamepadTriggerButtonIndexes[0]) {
leftTrigger = padData.buttons[i] * 0xFF;
}
else if (i == k_StandardGamepadTriggerButtonIndexes[1]) {
rightTrigger = padData.buttons[i] * 0xFF;
}
// Now normal buttons
else if (padData.buttons[i] > 0.5f) {
buttonFlags |= k_StandardGamepadButtonMapping[i];
}
}
// Get left stick values
if (padData.axes_length >= 2) {
leftStickX = padData.axes[0] * 0x7FFF;
leftStickY = -padData.axes[1] * 0x7FFF;
}
// Get right stick values
if (padData.axes_length >= 4) {
rightStickX = padData.axes[2] * 0x7FFF;
rightStickY = -padData.axes[3] * 0x7FFF;
}
LiSendMultiControllerEvent(controllerIndex, activeGamepadMask,
buttonFlags, leftTrigger, rightTrigger,
leftStickX, leftStickY, rightStickX, rightStickY);
controllerIndex++;
}
}
void MoonlightInstance::ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor)
{
const float weakMagnitude = static_cast<float>(highFreqMotor) / static_cast<float>(UINT16_MAX);
const float strongMagnitude = static_cast<float>(lowFreqMotor) / static_cast<float>(UINT16_MAX);
std::ostringstream ss;
ss << controllerNumber << "," << weakMagnitude << "," << strongMagnitude;
pp::Var response(std::string("controllerRumble: ") + ss.str());
g_Instance->PostMessage(response);
}