mirror of
https://github.com/redphx/better-xcloud.git
synced 2025-06-07 08:07:18 +02:00
Toggle touch controller visibility (#72)
* Double-tap anywhere at the bottom of the screen to show/hide touch controller * Update CSS * Update the size of the screenshot button * Update screenshot button's CSS * Update screenshot button's opacity
This commit is contained in:
parent
cd82c5a94c
commit
0b0f5add1b
@ -23,7 +23,6 @@ var $SCREENSHOT_CANVAS;
|
|||||||
var GAME_TITLE_ID;
|
var GAME_TITLE_ID;
|
||||||
|
|
||||||
const TOUCH_SUPPORTED_GAME_IDS = new Set();
|
const TOUCH_SUPPORTED_GAME_IDS = new Set();
|
||||||
var SHOW_GENERIC_TOUCH_CONTROLLER = false;
|
|
||||||
|
|
||||||
// Credit: https://phosphoricons.com
|
// Credit: https://phosphoricons.com
|
||||||
const ICON_VIDEO_SETTINGS = '<path d="M16 9.144A6.89 6.89 0 0 0 9.144 16 6.89 6.89 0 0 0 16 22.856 6.89 6.89 0 0 0 22.856 16 6.9 6.9 0 0 0 16 9.144zm0 11.427c-2.507 0-4.571-2.064-4.571-4.571s2.064-4.571 4.571-4.571 4.571 2.064 4.571 4.571-2.064 4.571-4.571 4.571zm15.704-7.541c-.065-.326-.267-.607-.556-.771l-4.26-2.428-.017-4.802c-.001-.335-.15-.652-.405-.868-1.546-1.307-3.325-2.309-5.245-2.953-.306-.103-.641-.073-.923.085L16 3.694l-4.302-2.407c-.282-.158-.618-.189-.924-.086a16.02 16.02 0 0 0-5.239 2.964 1.14 1.14 0 0 0-.403.867L5.109 9.84.848 12.268a1.14 1.14 0 0 0-.555.771 15.22 15.22 0 0 0 0 5.936c.064.326.267.607.555.771l4.261 2.428.017 4.802c.001.335.149.652.403.868 1.546 1.307 3.326 2.309 5.245 2.953.306.103.641.073.923-.085L16 28.306l4.302 2.407a1.13 1.13 0 0 0 .558.143 1.18 1.18 0 0 0 .367-.059c1.917-.648 3.695-1.652 5.239-2.962.255-.216.402-.532.405-.866l.021-4.807 4.261-2.428a1.14 1.14 0 0 0 .555-.771 15.21 15.21 0 0 0-.003-5.931zm-2.143 4.987l-4.082 2.321a1.15 1.15 0 0 0-.429.429l-.258.438a1.13 1.13 0 0 0-.174.601l-.022 4.606a13.71 13.71 0 0 1-3.623 2.043l-4.117-2.295a1.15 1.15 0 0 0-.559-.143h-.546c-.205-.005-.407.045-.586.143l-4.119 2.3a13.74 13.74 0 0 1-3.634-2.033l-.016-4.599a1.14 1.14 0 0 0-.174-.603l-.257-.437c-.102-.182-.249-.333-.429-.437l-4.085-2.328a12.92 12.92 0 0 1 0-4.036l4.074-2.325a1.15 1.15 0 0 0 .429-.429l.258-.438a1.14 1.14 0 0 0 .175-.601l.021-4.606a13.7 13.7 0 0 1 3.625-2.043l4.11 2.295a1.14 1.14 0 0 0 .585.143h.52c.205.005.407-.045.586-.143l4.119-2.3a13.74 13.74 0 0 1 3.634 2.033l.016 4.599a1.14 1.14 0 0 0 .174.603l.257.437c.102.182.249.333.429.438l4.085 2.327a12.88 12.88 0 0 1 .007 4.041h.007z" fill-rule="nonzero"/>';
|
const ICON_VIDEO_SETTINGS = '<path d="M16 9.144A6.89 6.89 0 0 0 9.144 16 6.89 6.89 0 0 0 16 22.856 6.89 6.89 0 0 0 22.856 16 6.9 6.9 0 0 0 16 9.144zm0 11.427c-2.507 0-4.571-2.064-4.571-4.571s2.064-4.571 4.571-4.571 4.571 2.064 4.571 4.571-2.064 4.571-4.571 4.571zm15.704-7.541c-.065-.326-.267-.607-.556-.771l-4.26-2.428-.017-4.802c-.001-.335-.15-.652-.405-.868-1.546-1.307-3.325-2.309-5.245-2.953-.306-.103-.641-.073-.923.085L16 3.694l-4.302-2.407c-.282-.158-.618-.189-.924-.086a16.02 16.02 0 0 0-5.239 2.964 1.14 1.14 0 0 0-.403.867L5.109 9.84.848 12.268a1.14 1.14 0 0 0-.555.771 15.22 15.22 0 0 0 0 5.936c.064.326.267.607.555.771l4.261 2.428.017 4.802c.001.335.149.652.403.868 1.546 1.307 3.326 2.309 5.245 2.953.306.103.641.073.923-.085L16 28.306l4.302 2.407a1.13 1.13 0 0 0 .558.143 1.18 1.18 0 0 0 .367-.059c1.917-.648 3.695-1.652 5.239-2.962.255-.216.402-.532.405-.866l.021-4.807 4.261-2.428a1.14 1.14 0 0 0 .555-.771 15.21 15.21 0 0 0-.003-5.931zm-2.143 4.987l-4.082 2.321a1.15 1.15 0 0 0-.429.429l-.258.438a1.13 1.13 0 0 0-.174.601l-.022 4.606a13.71 13.71 0 0 1-3.623 2.043l-4.117-2.295a1.15 1.15 0 0 0-.559-.143h-.546c-.205-.005-.407.045-.586.143l-4.119 2.3a13.74 13.74 0 0 1-3.634-2.033l-.016-4.599a1.14 1.14 0 0 0-.174-.603l-.257-.437c-.102-.182-.249-.333-.429-.437l-4.085-2.328a12.92 12.92 0 0 1 0-4.036l4.074-2.325a1.15 1.15 0 0 0 .429-.429l.258-.438a1.14 1.14 0 0 0 .175-.601l.021-4.606a13.7 13.7 0 0 1 3.625-2.043l4.11 2.295a1.14 1.14 0 0 0 .585.143h.52c.205.005.407-.045.586-.143l4.119-2.3a13.74 13.74 0 0 1 3.634 2.033l.016 4.599a1.14 1.14 0 0 0 .174.603l.257.437c.102.182.249.333.429.438l4.085 2.327a12.88 12.88 0 0 1 .007 4.041h.007z" fill-rule="nonzero"/>';
|
||||||
@ -31,6 +30,126 @@ const ICON_STREAM_STATS = '<path d="M27.295 9.31C24.303 6.313 20.234 4.631 16 4.
|
|||||||
const ICON_SCREENSHOT_B64 = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSIjZmZmIj48cGF0aCBkPSJNMjguMzA4IDUuMDM4aC00LjI2NWwtMi4wOTctMy4xNDVhMS4yMyAxLjIzIDAgMCAwLTEuMDIzLS41NDhoLTkuODQ2YTEuMjMgMS4yMyAwIDAgMC0xLjAyMy41NDhMNy45NTYgNS4wMzhIMy42OTJBMy43MSAzLjcxIDAgMCAwIDAgOC43MzF2MTcuMjMxYTMuNzEgMy43MSAwIDAgMCAzLjY5MiAzLjY5MmgyNC42MTVBMy43MSAzLjcxIDAgMCAwIDMyIDI1Ljk2MlY4LjczMWEzLjcxIDMuNzEgMCAwIDAtMy42OTItMy42OTJ6bS02Ljc2OSAxMS42OTJjMCAzLjAzOS0yLjUgNS41MzgtNS41MzggNS41MzhzLTUuNTM4LTIuNS01LjUzOC01LjUzOCAyLjUtNS41MzggNS41MzgtNS41MzggNS41MzggMi41IDUuNTM4IDUuNTM4eiIvPjwvc3ZnPgo=';
|
const ICON_SCREENSHOT_B64 = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSIjZmZmIj48cGF0aCBkPSJNMjguMzA4IDUuMDM4aC00LjI2NWwtMi4wOTctMy4xNDVhMS4yMyAxLjIzIDAgMCAwLTEuMDIzLS41NDhoLTkuODQ2YTEuMjMgMS4yMyAwIDAgMC0xLjAyMy41NDhMNy45NTYgNS4wMzhIMy42OTJBMy43MSAzLjcxIDAgMCAwIDAgOC43MzF2MTcuMjMxYTMuNzEgMy43MSAwIDAgMCAzLjY5MiAzLjY5MmgyNC42MTVBMy43MSAzLjcxIDAgMCAwIDMyIDI1Ljk2MlY4LjczMWEzLjcxIDMuNzEgMCAwIDAtMy42OTItMy42OTJ6bS02Ljc2OSAxMS42OTJjMCAzLjAzOS0yLjUgNS41MzgtNS41MzggNS41MzhzLTUuNTM4LTIuNS01LjUzOC01LjUzOCAyLjUtNS41MzggNS41MzgtNS41MzggNS41MzggMi41IDUuNTM4IDUuNTM4eiIvPjwvc3ZnPgo=';
|
||||||
|
|
||||||
|
|
||||||
|
class TouchController {
|
||||||
|
static get #EVENT_SHOW_CONTROLLER() {
|
||||||
|
return new MessageEvent('message', {
|
||||||
|
data: '{"content":"{\\"layoutId\\":\\"\\"}","target":"/streaming/touchcontrols/showlayoutv2","type":"Message"}',
|
||||||
|
origin: 'better-xcloud',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get #EVENT_HIDE_CONTROLLER() {
|
||||||
|
return new MessageEvent('message', {
|
||||||
|
data: '{"content":"","target":"/streaming/touchcontrols/hide","type":"Message"}',
|
||||||
|
origin: 'better-xcloud',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static #$bar;
|
||||||
|
static #enable = false;
|
||||||
|
static #showing = false;
|
||||||
|
static #dataChannel;
|
||||||
|
|
||||||
|
static enable() {
|
||||||
|
TouchController.#enable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static disable() {
|
||||||
|
TouchController.#enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static isEnabled() {
|
||||||
|
return TouchController.#enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static #show() {
|
||||||
|
TouchController.#dispatchMessage(TouchController.#EVENT_SHOW_CONTROLLER);
|
||||||
|
TouchController.#showing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static #hide() {
|
||||||
|
TouchController.#dispatchMessage(TouchController.#EVENT_HIDE_CONTROLLER);
|
||||||
|
TouchController.#showing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static #toggleVisibility() {
|
||||||
|
if (!TouchController.#dataChannel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchController.#showing ? TouchController.#hide() : TouchController.#show();
|
||||||
|
}
|
||||||
|
|
||||||
|
static enableBar() {
|
||||||
|
TouchController.#$bar && TouchController.#$bar.setAttribute('data-showing', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static reset() {
|
||||||
|
TouchController.#enable = false;
|
||||||
|
TouchController.#showing = false;
|
||||||
|
TouchController.#dataChannel = null;
|
||||||
|
|
||||||
|
TouchController.#$bar && TouchController.#$bar.removeAttribute('data-showing');
|
||||||
|
}
|
||||||
|
|
||||||
|
static #dispatchMessage(msg) {
|
||||||
|
TouchController.#dataChannel && setTimeout(() => {
|
||||||
|
TouchController.#dataChannel.dispatchEvent(msg);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setup() {
|
||||||
|
const $bar = createElement('div', {'id': 'better-xcloud-touch-controller-bar'});
|
||||||
|
document.documentElement.appendChild($bar);
|
||||||
|
|
||||||
|
// Setup double-tap event
|
||||||
|
let clickTimeout;
|
||||||
|
$bar.addEventListener('mousedown', e => {
|
||||||
|
clickTimeout && clearTimeout(clickTimeout);
|
||||||
|
if (clickTimeout) {
|
||||||
|
// Double-clicked
|
||||||
|
clickTimeout = null;
|
||||||
|
TouchController.#toggleVisibility();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clickTimeout = setTimeout(() => {
|
||||||
|
clickTimeout = null;
|
||||||
|
}, 400);
|
||||||
|
});
|
||||||
|
|
||||||
|
TouchController.#$bar = $bar;
|
||||||
|
|
||||||
|
RTCPeerConnection.prototype.orgCreateDataChannel = RTCPeerConnection.prototype.createDataChannel;
|
||||||
|
RTCPeerConnection.prototype.createDataChannel = function() {
|
||||||
|
const dataChannel = this.orgCreateDataChannel.apply(this, arguments);
|
||||||
|
if (!TouchController.#enable) {
|
||||||
|
return dataChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchController.#dataChannel = dataChannel;
|
||||||
|
|
||||||
|
// Fix sometimes the touch controller doesn't show at the beginning
|
||||||
|
dataChannel.addEventListener('open', e => {
|
||||||
|
TouchController.#show();
|
||||||
|
});
|
||||||
|
|
||||||
|
dataChannel.addEventListener('message', msg => {
|
||||||
|
if (msg.origin === 'better-xcloud' || typeof msg.data !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch a message to display generic touch controller
|
||||||
|
if (msg.data.includes('touchcontrols/showtitledefault')) {
|
||||||
|
TouchController.#show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dataChannel;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MouseCursorHider {
|
class MouseCursorHider {
|
||||||
static #timeout;
|
static #timeout;
|
||||||
static #cursorVisible = true;
|
static #cursorVisible = true;
|
||||||
@ -1157,9 +1276,13 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 60px;
|
box-sizing: border-box;
|
||||||
height: 60px;
|
width: 16vh;
|
||||||
padding: 12px;
|
height: 16vh;
|
||||||
|
max-width: 128px;
|
||||||
|
max-height: 128px;
|
||||||
|
padding: 2vh;
|
||||||
|
padding: 24px 24px 12px 12px;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-origin: content-box;
|
background-origin: content-box;
|
||||||
@ -1172,11 +1295,11 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-screenshot-button[data-showing=true] {
|
.better-xcloud-screenshot-button[data-showing=true] {
|
||||||
opacity: 1;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-screenshot-button[data-capturing=true] {
|
.better-xcloud-screenshot-button[data-capturing=true] {
|
||||||
padding: 6px;
|
padding: 1vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.better-xcloud-screenshot-canvas {
|
.better-xcloud-screenshot-canvas {
|
||||||
@ -1404,6 +1527,21 @@ div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module] {
|
|||||||
font-family: Consolas, "Courier New", Courier, monospace;
|
font-family: Consolas, "Courier New", Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#better-xcloud-touch-controller-bar {
|
||||||
|
display: none;
|
||||||
|
opacity: 0;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 6vh;
|
||||||
|
z-index: 5555;
|
||||||
|
}
|
||||||
|
|
||||||
|
#better-xcloud-touch-controller-bar[data-showing=true] {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hide UI elements */
|
/* Hide UI elements */
|
||||||
#headerArea, #uhfSkipToMain, .uhf-footer {
|
#headerArea, #uhfSkipToMain, .uhf-footer {
|
||||||
display: none;
|
display: none;
|
||||||
@ -1722,16 +1860,16 @@ function interceptHttpRequests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && url.endsWith('/configuration') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
if (PREF_STREAM_TOUCH_CONTROLLER === 'all' && url.endsWith('/configuration') && url.includes('/sessions/cloud/') && request.method === 'GET') {
|
||||||
SHOW_GENERIC_TOUCH_CONTROLLER = false;
|
TouchController.disable();
|
||||||
// Get game ID from window.location
|
// Get game ID from window.location
|
||||||
const match = window.location.pathname.match(/\/launch\/[^\/]+\/([\w\d]+)/);
|
const match = window.location.pathname.match(/\/launch\/[^\/]+\/([\w\d]+)/);
|
||||||
// Check touch support
|
// Check touch support
|
||||||
if (match && !TOUCH_SUPPORTED_GAME_IDS.has(match[1])) {
|
if (match && !TOUCH_SUPPORTED_GAME_IDS.has(match[1])) {
|
||||||
SHOW_GENERIC_TOUCH_CONTROLLER = true;
|
TouchController.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
const promise = orgFetch(...arg);
|
const promise = orgFetch(...arg);
|
||||||
if (!SHOW_GENERIC_TOUCH_CONTROLLER) {
|
if (!TouchController.isEnabled()) {
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2540,6 +2678,7 @@ function onHistoryChanged() {
|
|||||||
document.querySelector('.better-xcloud-screenshot-button').style = '';
|
document.querySelector('.better-xcloud-screenshot-button').style = '';
|
||||||
|
|
||||||
MouseCursorHider.stop();
|
MouseCursorHider.stop();
|
||||||
|
TouchController.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2547,6 +2686,10 @@ function onStreamStarted($video) {
|
|||||||
// Get title ID for screenshot's name
|
// Get title ID for screenshot's name
|
||||||
GAME_TITLE_ID = /\/launch\/([^/]+)/.exec(window.location.pathname)[1];
|
GAME_TITLE_ID = /\/launch\/([^/]+)/.exec(window.location.pathname)[1];
|
||||||
|
|
||||||
|
if (TouchController.isEnabled()) {
|
||||||
|
TouchController.enableBar();
|
||||||
|
}
|
||||||
|
|
||||||
const PREF_SCREENSHOT_BUTTON_POSITION = PREFS.get(Preferences.SCREENSHOT_BUTTON_POSITION);
|
const PREF_SCREENSHOT_BUTTON_POSITION = PREFS.get(Preferences.SCREENSHOT_BUTTON_POSITION);
|
||||||
const PREF_STATS_QUICK_GLANCE = PREFS.get(Preferences.STATS_QUICK_GLANCE);
|
const PREF_STATS_QUICK_GLANCE = PREFS.get(Preferences.STATS_QUICK_GLANCE);
|
||||||
|
|
||||||
@ -2673,36 +2816,7 @@ RTCPeerConnection.prototype.addIceCandidate = function(...args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PREFS.get(Preferences.STREAM_TOUCH_CONTROLLER) === 'all') {
|
if (PREFS.get(Preferences.STREAM_TOUCH_CONTROLLER) === 'all') {
|
||||||
RTCPeerConnection.prototype.orgCreateDataChannel = RTCPeerConnection.prototype.createDataChannel;
|
TouchController.setup();
|
||||||
RTCPeerConnection.prototype.createDataChannel = function() {
|
|
||||||
const dataChannel = this.orgCreateDataChannel.apply(this, arguments);
|
|
||||||
if (!SHOW_GENERIC_TOUCH_CONTROLLER) {
|
|
||||||
return dataChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatchLayout = () => {
|
|
||||||
// Dispatch a message to display generic touch controller
|
|
||||||
dataChannel.dispatchEvent(new MessageEvent('message', {
|
|
||||||
data: '{"content":"{\\"layoutId\\":\\"\\"}","target":"/streaming/touchcontrols/showlayoutv2","type":"Message"}',
|
|
||||||
origin: 'better-xcloud',
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix sometimes the touch controller doesn't show at the beginning
|
|
||||||
setTimeout(dispatchLayout, 100);
|
|
||||||
|
|
||||||
dataChannel.addEventListener('message', msg => {
|
|
||||||
if (msg.origin === 'better-xcloud' || typeof msg.data !== 'string') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.data.includes('touchcontrols/showtitledefault')) {
|
|
||||||
setTimeout(dispatchLayout, 10);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return dataChannel;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user