moonlight-chrome/static/js/messages.js
bob aaa1ca7079 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.
2022-11-06 19:58:35 -06:00

99 lines
3.7 KiB
JavaScript

var callbacks = {}
var callbacks_ids = 1;
/**
* var sendMessage - Sends a message with arguments to the NaCl module
*
* @param {String} method A named method
* @param {(String|Array)} params An array of options or a signle string
* @return {void} The NaCl module calls back trought the handleMessage method
*/
var sendMessage = function(method, params) {
return new Promise(function(resolve, reject) {
var id = callbacks_ids++;
callbacks[id] = {
'resolve': resolve,
'reject': reject
};
common.naclModule.postMessage({
'callbackId': id,
'method': method,
'params': params
});
});
}
/**
* handleMessage - Handles messages from the NaCl module
*
* @param {Object} msg An object given by the NaCl module
* @return {void}
*/
function handleMessage(msg) {
if (msg.data.callbackId && callbacks[msg.data.callbackId]) { // if it's a callback, treat it as such
callbacks[msg.data.callbackId][msg.data.type](msg.data.ret);
delete callbacks[msg.data.callbackId]
} else { // else, it's just info, or an event
console.log('%c[messages.js, handleMessage]', 'color:gray;', 'Message data: ', msg.data)
if (msg.data.indexOf('streamTerminated: ') === 0) { // if it's a recognized event, notify the appropriate function
// Release our keep awake request
chrome.power.releaseKeepAwake();
// Show a termination snackbar message if the termination was unexpected
var errorCode = parseInt(msg.data.replace('streamTerminated: ', ''));
switch (errorCode) {
case 0: // ML_ERROR_GRACEFUL_TERMINATION
break;
case -100: // ML_ERROR_NO_VIDEO_TRAFFIC
snackbarLogLong("No video received from host. Check the host PC's firewall and port forwarding rules.");
break;
case -101: // ML_ERROR_NO_VIDEO_FRAME
snackbarLogLong("Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.");
break;
default:
snackbarLogLong("Connection terminated");
break;
}
api.refreshServerInfo().then(function(ret) {
// Return to app list with new currentgame
showApps(api);
}, function() {
// Return to app list anyway
showApps(api);
});
} else if (msg.data === 'Connection Established') {
$('#loadingSpinner').css('display', 'none');
$('body').css('backgroundColor', 'black');
// Keep the display awake while streaming
chrome.power.requestKeepAwake("display");
} else if (msg.data.indexOf('ProgressMsg: ') === 0) {
$('#loadingMessage').text(msg.data.replace('ProgressMsg: ', ''));
} else if (msg.data.indexOf('TransientMsg: ') === 0) {
snackbarLog(msg.data.replace('TransientMsg: ', ''));
} else if (msg.data.indexOf('DialogMsg: ') === 0) {
// FIXME: Really use a dialog
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,
});
}
}
}