Added controller rumble support.

Pepper SDK and NaCl in general is EOL for Chrome, although still supported for Chrome Apps.
This means that the Pepper Gamepad API was never updated with rumble support so in order
to add rumble support, rumble messages from Gamestream have to be forwarded to JavaScript
and handled with gamepad.vibrationActuator.playEffect().

Side note, Chrome limits the duration of playEffect to 5 seconds and requesting more than
that causes the vibration request to be rejected.
This commit is contained in:
bob 2022-10-20 06:52:28 +00:00 committed by Cameron Gutman
parent ab3aac8d05
commit aaa1ca7079
5 changed files with 28 additions and 1 deletions

View File

@ -61,4 +61,5 @@ CONNECTION_LISTENER_CALLBACKS MoonlightInstance::s_ClCallbacks = {
.connectionStarted = MoonlightInstance::ClConnectionStarted,
.connectionTerminated = MoonlightInstance::ClConnectionTerminated,
.logMessage = MoonlightInstance::ClLogMessage,
.rumble = MoonlightInstance::ClControllerRumble,
};

View File

@ -4,6 +4,8 @@
#include <Limelight.h>
#include <sstream>
static const unsigned short k_StandardGamepadButtonMapping[] = {
A_FLAG, B_FLAG, X_FLAG, Y_FLAG,
LB_FLAG, RB_FLAG,
@ -127,3 +129,14 @@ void MoonlightInstance::PollGamepads() {
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);
}

View File

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Moonlight Game Streaming",
"short_name": "Moonlight",
"version": "0.10.21",
"version": "0.10.22",
"description": "Open-source client for NVIDIA GameStream",
"icons": {
"128": "icons/icon128.png",

View File

@ -137,6 +137,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
static void ClDisplayMessage(const char* message);
static void ClDisplayTransientMessage(const char* message);
static void ClLogMessage(const char* format, ...);
static void ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor);
static Shader CreateProgram(const char* vertexShader, const char* fragmentShader);
static void CreateShader(GLuint program, GLenum type, const char* source, int size);

View File

@ -81,6 +81,18 @@ function handleMessage(msg) {
snackbarLogLong(msg.data.replace('DialogMsg: ', ''));
} else if (msg.data === 'displayVideo') {
$("#listener").addClass("fullscreen");
} else if (msg.data.indexOf('controllerRumble: ' ) === 0) {
const eventData = msg.data.split( ' ' )[1].split(',');
const gamepadIdx = parseInt(eventData[0]);
const weakMagnitude = parseFloat(eventData[1]);
const strongMagnitude = parseFloat(eventData[2]);
console.log("Playing rumble on gamepad " + gamepadIdx + " with weakMagnitude " + weakMagnitude + " and strongMagnitude " + strongMagnitude);
navigator.getGamepads()[gamepadIdx].vibrationActuator.playEffect('dual-rumble', {
startDelay: 0,
duration: 5000, // Moonlight should be sending another rumble event when stopping.
weakMagnitude: weakMagnitude,
strongMagnitude: strongMagnitude,
});
}
}
}