Skip to content

[Bug] Fullscreen emulation broken on iOS — requestFullscreen not triggered #3430

@FindlayHi

Description

@FindlayHi

RomM version: 4.9.0-alpha.5

Describe the bug
Fullscreen doesn't work on iOS. Pressing the fullscreen button in EmulatorJS does nothing. The header and footer stay visible and the game doesn't expand.

To Reproduce

  1. Open RomM on an iPhone (Safari or Chrome)
  2. Launch any game via EmulatorJS
  3. Tap the fullscreen button
  4. Nothing happens, header/footer remain

Expected behavior
Game fills the screen, header and footer hide. Same as desktop.

Server (please complete the following information):

  • OS: Linux
  • Version: 4.9.0-alpha.5 (Docker Compose)

Client (please complete the following information):

  • Device: iPhone
  • OS: iOS 19
  • Browser: Chrome (latest)

Additional context
Working fix tested via nginx script injection. The approach is a CSS pseudo-fullscreen shim for iOS:

  1. Spoof document.fullscreenEnabled so EmulatorJS doesn't skip the call
  2. Override requestFullscreen() to apply position:fixed + full viewport sizing on the player element
  3. Hide .v-app-bar, .v-bottom-navigation, .v-navigation-drawer
  4. Dispatch a synthetic fullscreenchange event so RomM's store stays in sync
  5. Patch document.exitFullscreen() to reverse everything

Working implementation:

(function () {
  'use strict';

  var isIOS =
    /iP(ad|hone|od)/.test(navigator.userAgent) ||
    (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);

  if (!isIOS) return;

  var pseudoEl = null, origStyles = '';

  function hideNav() {
    document.querySelectorAll('.v-app-bar, .v-bottom-navigation, .v-navigation-drawer')
      .forEach(function(el) { el.style.setProperty('display','none','important'); });
  }

  function showNav() {
    document.querySelectorAll('.v-app-bar, .v-bottom-navigation, .v-navigation-drawer')
      .forEach(function(el) { el.style.removeProperty('display'); });
  }

  function enter(el) {
    pseudoEl = el;
    origStyles = el.getAttribute('style') || '';
    el.style.cssText =
      'position:fixed!important;top:0!important;left:0!important;' +
      'width:100vw!important;height:100svh!important;z-index:99999!important;background:#000!important;';
    hideNav();
    try {
      Object.defineProperty(document, 'fullscreenElement', {
        get: function() { return pseudoEl; }, configurable: true
      });
    } catch(e) {}
    document.dispatchEvent(new Event('fullscreenchange'));
    el.dispatchEvent(new Event('fullscreenchange'));
  }

  function exit() {
    if (!pseudoEl) return;
    pseudoEl.setAttribute('style', origStyles);
    showNav();
    try {
      Object.defineProperty(document, 'fullscreenElement', {
        get: function() { return null; }, configurable: true
      });
    } catch(e) {}
    document.dispatchEvent(new Event('fullscreenchange'));
    pseudoEl.dispatchEvent(new Event('fullscreenchange'));
    pseudoEl = null;
  }

  try {
    Object.defineProperty(document, 'fullscreenEnabled', {
      get: function() { return true; }, configurable: true
    });
  } catch(e) {}

  HTMLElement.prototype.requestFullscreen = function() {
    enter(this); return Promise.resolve();
  };

  if (typeof HTMLElement.prototype.webkitRequestFullscreen === 'function')
    HTMLElement.prototype.webkitRequestFullscreen = function() { enter(this); };

  document.exitFullscreen = function() {
    exit(); return Promise.resolve();
  };
})();

Metadata

Metadata

Labels

emulationEmulator.js bugs or feature requests

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions