Disable desktop exit in browsers

This commit is contained in:
MeatSlicer Developer committed 2026-07-30 23:48:49 +10:00
1 parent 92491dd06e
commit b8b5c360f2
3 files changed
+20 -18

No files matched your search

+2 -2
View File
@@ -84,9 +84,9 @@ Your best score is saved in `localStorage` as `meatslicer_best` and shown on the
|---|---|
| **Enter / Space / Click** | Start run (title), restart after death |
The title screen has **[X] Exit to Desktop**. Pause has **[Q] Main Menu** and **[X] Exit**.
The desktop app title screen has **[X] Exit to Desktop**. Pause has **[Q] Main Menu** and **[X] Exit**.
The first matching press arms a 3-second confirmation; press it again to confirm. `P` or
`Escape` resumes. Electron quits directly; the browser fallback asks you to close the tab.
`Escape` resumes. In a web browser, desktop-exit controls are greyed out and non-interactive.
Right-click is disabled (context menu suppressed). There is **no dash, no interact key** — pickups are collected by walking over them.
+17 -16
View File
@@ -121,13 +121,12 @@ function returnToMenu() {
Music.playMenu();
}
function canQuitDesktop() {
return !!(window.MSDesktop && typeof window.MSDesktop.quit === 'function');
}
function quitToDesktop() {
if (window.MSDesktop && typeof window.MSDesktop.quit === 'function') {
window.MSDesktop.quit();
return;
}
window.close();
addToast('EXIT BLOCKED', 'close this browser tab to exit.');
if (canQuitDesktop()) window.MSDesktop.quit();
}
function confirmAction(name, action) {
@@ -181,7 +180,7 @@ function update(dt) {
case 'menu': {
const sl = PRESSURE_SLIDER_RECT;
const exitClick = Input.mpressed && inRect(Input.mx, Input.my, MENU_EXIT_BUTTON);
if (keyPressed('x') || exitClick) {
if (canQuitDesktop() && (keyPressed('x') || exitClick)) {
confirmAction('desktop', quitToDesktop);
break;
}
@@ -221,7 +220,7 @@ function update(dt) {
const menuClick = Input.mpressed && inRect(Input.mx, Input.my, PAUSE_MENU_BUTTON);
const exitClick = Input.mpressed && inRect(Input.mx, Input.my, PAUSE_EXIT_BUTTON);
if (keyPressed('q') || menuClick) { confirmAction('menu', returnToMenu); break; }
if (keyPressed('x') || exitClick) { confirmAction('desktop', quitToDesktop); break; }
if (canQuitDesktop() && (keyPressed('x') || exitClick)) { confirmAction('desktop', quitToDesktop); break; }
if (keyPressed('p', 'escape')) { G.mode = 'play'; G.confirmAction = null; G.confirmT = 0; Sfx.menu(); break; }
if (keyPressed('h') || (Input.mpressed && inRect(Input.mx, Input.my, HELP_BUTTON))) {
G.pauseHelp = true; G.helpPage = 0; G.confirmAction = null; G.confirmT = 0; Sfx.menu(); break;
@@ -388,11 +387,12 @@ function drawMenu(ctx) {
});
}
const exitHover = inRect(Input.mx, Input.my, MENU_EXIT_BUTTON);
const exitConfirm = G.confirmAction === 'desktop';
drawPixelTag(ctx, exitConfirm ? '[X] CONFIRM EXIT' : '[X] EXIT TO DESKTOP', MENU_EXIT_BUTTON.x, MENU_EXIT_BUTTON.y, {
const desktopExit = canQuitDesktop();
const exitConfirm = desktopExit && G.confirmAction === 'desktop';
drawPixelTag(ctx, !desktopExit ? '[X] DESKTOP APP ONLY' : (exitConfirm ? '[X] CONFIRM EXIT' : '[X] EXIT TO DESKTOP'), MENU_EXIT_BUTTON.x, MENU_EXIT_BUTTON.y, {
width: MENU_EXIT_BUTTON.w, height: MENU_EXIT_BUTTON.h,
color: exitConfirm ? '#ffd36a' : (exitHover ? '#f5e9d6' : '#ad8f8c'),
accent: exitConfirm ? '#d69a22' : (exitHover ? '#e22b46' : '#6e3843'),
color: !desktopExit ? '#65595b' : (exitConfirm ? '#ffd36a' : (exitHover ? '#f5e9d6' : '#ad8f8c')),
accent: !desktopExit ? '#3a2d31' : (exitConfirm ? '#d69a22' : (exitHover ? '#e22b46' : '#6e3843')),
});
}
@@ -488,17 +488,18 @@ function drawPause(ctx) {
const menuHover = inRect(Input.mx, Input.my, PAUSE_MENU_BUTTON);
const exitHover = inRect(Input.mx, Input.my, PAUSE_EXIT_BUTTON);
const menuConfirm = G.confirmAction === 'menu';
const exitConfirm = G.confirmAction === 'desktop';
const desktopExit = canQuitDesktop();
const exitConfirm = desktopExit && G.confirmAction === 'desktop';
drawPixelTag(ctx, '[M] MUTE AUDIO', gridX[0], 526, { width: 150, height: 28, color: '#bba9a1', accent: '#6e3843' });
drawPixelTag(ctx, menuConfirm ? '[Q] CONFIRM MENU' : '[Q] MAIN MENU', PAUSE_MENU_BUTTON.x, PAUSE_MENU_BUTTON.y, {
width: PAUSE_MENU_BUTTON.w, height: PAUSE_MENU_BUTTON.h,
color: menuConfirm ? '#ffd36a' : (menuHover ? '#f5e9d6' : '#bba9a1'),
accent: menuConfirm ? '#d69a22' : (menuHover ? '#b5243a' : '#6e3843'),
});
drawPixelTag(ctx, exitConfirm ? '[X] CONFIRM EXIT' : '[X] EXIT', PAUSE_EXIT_BUTTON.x, PAUSE_EXIT_BUTTON.y, {
drawPixelTag(ctx, !desktopExit ? '[X] DESKTOP ONLY' : (exitConfirm ? '[X] CONFIRM EXIT' : '[X] EXIT'), PAUSE_EXIT_BUTTON.x, PAUSE_EXIT_BUTTON.y, {
width: PAUSE_EXIT_BUTTON.w, height: PAUSE_EXIT_BUTTON.h,
color: exitConfirm ? '#ffd36a' : (exitHover ? '#f5e9d6' : '#bba9a1'),
accent: exitConfirm ? '#d69a22' : (exitHover ? '#b5243a' : '#6e3843'),
color: !desktopExit ? '#65595b' : (exitConfirm ? '#ffd36a' : (exitHover ? '#f5e9d6' : '#bba9a1')),
accent: !desktopExit ? '#3a2d31' : (exitConfirm ? '#d69a22' : (exitHover ? '#b5243a' : '#6e3843')),
});
const hb = HELP_BUTTON;
+1
View File
@@ -1582,6 +1582,7 @@ check('restart works', ctx.G.mode === 'play' && ctx.G.floor === 1);
console.log('== confirmed destructive actions ==');
{
check('web renderer disables desktop-only exit', ctx.canQuitDesktop() === false);
let fired = 0;
ctx.confirmAction('probe', () => fired++);
check('first destructive action arms confirmation without firing', ctx.G.confirmAction === 'probe' && ctx.G.confirmT > 2.9 && fired === 0);