From fdcd3d4747b70ca6e1c906956c62b44d7778c5da Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 20 Jan 2018 15:08:36 -0800 Subject: [PATCH] Send attached gamepads at launch to fix L4D2 --- gamepad.cpp | 5 ++++- static/js/index.js | 8 ++++++-- static/js/utils.js | 43 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/gamepad.cpp b/gamepad.cpp index c70eb23..93df0fc 100644 --- a/gamepad.cpp +++ b/gamepad.cpp @@ -24,7 +24,10 @@ static short GetActiveGamepadMask(PP_GamepadsSampleData& gamepadData) { 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; diff --git a/static/js/index.js b/static/js/index.js index 52b1a02..720d64f 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -598,12 +598,15 @@ function startGame(host, appID) { var rikey = generateRemoteInputKey(); var rikeyid = generateRemoteInputKeyId(); + var gamepadMask = getConnectedGamepadMask(); $('#loadingMessage').text('Starting ' + appToStart.title + '...'); playGameMode(); if(host.currentGame == appID) { // if user wants to launch the already-running app, then we resume it. - return host.resumeApp(rikey, rikeyid).then(function (ret) { + return host.resumeApp( + rikey, rikeyid, 0x030002 // Surround channel mask << 16 | Surround channel count + ).then(function (ret) { sendMessage('startRequest', [host.address, streamWidth, streamHeight, frameRate, bitrate.toString(), rikey, rikeyid.toString(), host.appVersion]); }, function (failedResumeApp) { @@ -619,7 +622,8 @@ function startGame(host, appID) { optimize, // DON'T Allow GFE (0) to optimize game settings, or ALLOW (1) to optimize game settings rikey, rikeyid, remote_audio_enabled, // Play audio locally too? - 0x030002 // Surround channel mask << 16 | Surround channel count + 0x030002, // Surround channel mask << 16 | Surround channel count + gamepadMask ).then(function (ret) { sendMessage('startRequest', [host.address, streamWidth, streamHeight, frameRate, bitrate.toString(), rikey, rikeyid.toString(), host.appVersion]); diff --git a/static/js/utils.js b/static/js/utils.js index 006cfbd..566f6ac 100644 --- a/static/js/utils.js +++ b/static/js/utils.js @@ -23,6 +23,38 @@ function generateRemoteInputKeyId() { return ((Math.random()-0.5) * 0x7FFFFFFF)|0; } +function getConnectedGamepadMask() { + var count = 0; + var mask = 0; + var gamepads = navigator.getGamepads ? navigator.getGamepads() : []; + + for (var i = 0; i < gamepads.length; i++) { + var gamepad = gamepads[i]; + if (gamepad) { + // See logic in gamepad.cpp + // These must stay in sync! + + if (!gamepad.connected) { + // Not connected + continue; + } + + if (gamepad.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; + } + + mask |= 1 << count++; + } + } + + console.log('%c[utils.js, getConnectedGamepadMask]', 'color:gray;', 'Detected '+count+' gamepads'); + return mask; +} + String.prototype.toHex = function() { var hex = ''; for(var i = 0; i < this.length; i++) { @@ -440,7 +472,7 @@ NvHTTP.prototype = { } }, - launchApp: function (appId, mode, sops, rikey, rikeyid, localAudio, surroundAudioInfo) { + launchApp: function (appId, mode, sops, rikey, rikeyid, localAudio, surroundAudioInfo, gamepadMask) { return sendMessage('openUrl', [ this._baseUrlHttps + '/launch?' + this._buildUidStr() + @@ -450,19 +482,22 @@ NvHTTP.prototype = { '&rikey=' + rikey + '&rikeyid=' + rikeyid + '&localAudioPlayMode=' + localAudio + - '&surroundAudioInfo=' + surroundAudioInfo, + '&surroundAudioInfo=' + surroundAudioInfo + + '&remoteControllersBitmap=' + gamepadMask + + '&gcmap=' + gamepadMask, false ]).then(function (ret) { return true; }); }, - resumeApp: function (rikey, rikeyid) { + resumeApp: function (rikey, rikeyid, surroundAudioInfo) { return sendMessage('openUrl', [ this._baseUrlHttps + '/resume?' + this._buildUidStr() + '&rikey=' + rikey + - '&rikeyid=' + rikeyid, + '&rikeyid=' + rikeyid + + '&surroundAudioInfo=' + surroundAudioInfo, false ]).then(function (ret) { return true;