From 8dadbb2da9fed7faceea6a68f8ee7fe990efc806 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Thu, 22 Jan 2015 11:19:38 -0800 Subject: [PATCH] Support "full-screen" mode to the extent that supported browsers support it (and thanks for your support!) --- devices/pc/video/video-ega-128kb-lock.xml | 1 + modules/pcjs/lib/keyboard.js | 28 ++++---- modules/pcjs/lib/state.js | 2 +- modules/pcjs/lib/video.js | 85 +++++++++++++++++++++-- 4 files changed, 95 insertions(+), 21 deletions(-) diff --git a/devices/pc/video/video-ega-128kb-lock.xml b/devices/pc/video/video-ega-128kb-lock.xml index 90c8e4d4d..bab466590 100644 --- a/devices/pc/video/video-ega-128kb-lock.xml +++ b/devices/pc/video/video-ega-128kb-lock.xml @@ -7,6 +7,7 @@ Lock Pointer + Full Screen diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js index 169960751..4831cabb6 100644 --- a/modules/pcjs/lib/keyboard.js +++ b/modules/pcjs/lib/keyboard.js @@ -134,20 +134,20 @@ function Keyboard(parmsKbd) this.msAutoRelease = 50; this.msInjectDelay = 300; // number of milliseconds between injected keystrokes + /* + * HACK: We set fAllDown to false to ignore all down/up events for keys not explicitly marked as ONDOWN; + * even though that prevents those keys from being repeated properly (ie, at the simulation's repeat rate + * rather than the browser's repeat rate), it's the safest thing to do when dealing with international keyboards, + * because our mapping tables are designed for US keyboards, and testing all the permutations of international + * keyboards and web browsers is more work than I can take on right now. TODO: Dig into this some day. + */ + this.fAllDown = false; + this.setReady(); } Component.subclass(Component, Keyboard); -/* - * HACK: We set ALL_ONDOWN to false to ignore all down/up events for keys not explicitly marked as ONDOWN; - * even though that prevents those keys from being repeated properly (ie, at the simulation's repeat rate - * rather than the browser's repeat rate), it's the safest thing to do when dealing with international keyboards, - * because our mapping tables are designed for US keyboards, and testing all the permutations of international - * keyboards and web browsers is more work than I can take on right now. TODO: Dig into this some day. - */ -Keyboard.ALL_ONDOWN = false; - /** * Alphanumeric and other common (printable) ASCII codes. * @@ -1128,16 +1128,18 @@ Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg) }; /** - * notifyEscape(fDisabled) + * notifyEscape(fDisabled, fAllDown) * * When ESC is used by the browser to disable pointer lock, this gives us the option of mapping a different key to ESC. * * @this {Keyboard} * @param {boolean} fDisabled + * @param {boolean} [fAllDown] (an experimental option to re-enable processing of all onkeydown/onkeyup events) */ -Keyboard.prototype.notifyEscape = function(fDisabled) +Keyboard.prototype.notifyEscape = function(fDisabled, fAllDown) { this.fEscapeDisabled = fDisabled; + if (fAllDown !== undefined) this.fAllDown = fAllDown; }; /** @@ -2050,7 +2052,7 @@ Keyboard.prototype.onKeyDown = function(event, fDown) /* * Don't simulate any key not explicitly marked ONDOWN, as well as any key sequence with the CMD key held. */ - if (!Keyboard.ALL_ONDOWN && fPass && fDown || !!(this.bitsState & Keyboard.STATE.CMDS)) fIgnore = true; + if (!this.fAllDown && fPass && fDown || !!(this.bitsState & Keyboard.STATE.CMDS)) fIgnore = true; } if (!fPass) { @@ -2093,7 +2095,7 @@ Keyboard.prototype.onKeyPress = function(event) event = event || window.event; var keyCode = event.which || event.keyCode; - if (Keyboard.ALL_ONDOWN) { + if (this.fAllDown) { var simCode = this.checkActiveKey(); if (simCode && this.isAlphaKey(simCode) && this.isAlphaKey(keyCode) && simCode != keyCode) { if (!COMPILED && this.messageEnabled(Messages.KEYS)) { diff --git a/modules/pcjs/lib/state.js b/modules/pcjs/lib/state.js index ccbfbf76d..9514c32a5 100644 --- a/modules/pcjs/lib/state.js +++ b/modules/pcjs/lib/state.js @@ -35,7 +35,7 @@ if (typeof module !== 'undefined') { var web = require("./../../shared/lib/weblib"); var Component = require("./../../shared/lib/component"); - var Messages = require("./messages"); + var Messages = require("./messages"); } /** diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 12b6160d0..2d031f6e6 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -44,7 +44,7 @@ if (typeof module !== 'undefined') { } /** - * Video(parmsVideo, canvas, context, textarea) + * Video(parmsVideo, canvas, context, textarea, container) * * The Video component can be configured with the following (parmsVideo) properties: * @@ -93,8 +93,9 @@ if (typeof module !== 'undefined') { * @param {Object} [canvas] * @param {Object} [context] * @param {Object} [textarea] + * @param {Object} [container] */ -function Video(parmsVideo, canvas, context, textarea) +function Video(parmsVideo, canvas, context, textarea, container) { Component.call(this, "Video", parmsVideo, Video, Messages.VIDEO); @@ -192,6 +193,31 @@ function Video(parmsVideo, canvas, context, textarea) this.fHasFocus = false; var video = this; + + /* + * All the gross code to handle full-screen support across all supported browsers (standards? hello?) + */ + this.container = container; + if (this.container) { + this.container.doFullScreen = container['requestFullscreen'] || container['msRequestFullscreen'] || container['mozRequestFullScreen'] || container['webkitRequestFullscreen']; + var onFullScreenChange = function() { + var fFullScreen = (document['fullscreenElement'] || document['mozFullScreenElement'] || document['webkitFullscreenElement'] || document['msFullscreenElement']); + video.notifyFullScreen(fFullScreen? true : false); + }; + if ('onfullscreenchange' in document) { + document.addEventListener('fullscreenchange', onFullScreenChange, false); + } else if ('onmozfullscreenchange' in document) { + document.addEventListener('mozfullscreenchange', onFullScreenChange, false); + } else if ('onwebkitfullscreenchange' in document) { + document.addEventListener('webkitfullscreenchange', onFullScreenChange, false); + } else if ('onmsfullscreenchange' in document) { + document.addEventListener('msfullscreenchange', onFullScreenChange, false); + } + } + + /* + * All the gross code to handle pointer-locking support across all supported browsers (standards? hello?) + */ if (this.inputScreen) { this.inputScreen.onfocus = function onFocusScreen() { return video.onFocusChange(true); @@ -2010,6 +2036,18 @@ Video.prototype.setBinding = function(sHTMLType, sBinding, control) switch (sBinding) { + case "fullScreen": + if (this.container && this.container.doFullScreen) { + control.onclick = function onClickFullScreen() { + if (DEBUG) video.printMessage("fullScreen()"); + video.doFullScreen(); + }; + } else { + if (DEBUG) this.log("FullScreen API not available"); + control.parentNode.removeChild(control); + } + return true; + case "lockPointer": this.sLockMessage = control.textContent; if (this.inputScreen && this.inputScreen.lockPointer) { @@ -2062,6 +2100,39 @@ Video.prototype.getInput = function(mouse) return this.inputScreen; }; +/** + * doFullScreen() + * + * @this {Video} + * @return {boolean} true if request successful, false if not (eg, failed OR not supported) + */ +Video.prototype.doFullScreen = function() +{ + var fSuccess = false; + if (this.container) { + if (this.container.doFullScreen) { + this.container.style.width = this.container.style.height = "100%"; + this.container.style.backgroundColor = "black"; + this.container.doFullScreen(); + fSuccess = true; + } + this.setFocus(); + } + return fSuccess; +}; + +/** + * notifyFullScreen(fFullScreen) + * + * @this {Video} + * @param {boolean} fFullScreen + */ +Video.prototype.notifyFullScreen = function(fFullScreen) +{ + this.printMessage("notifyFullScreen(" + fFullScreen + ")", true); + if (this.kbd) this.kbd.notifyEscape(fFullScreen); +}; + /** * lockPointer() * @@ -3753,10 +3824,10 @@ Video.prototype.setMode = function(nMode, fForce) Video.prototype.setPixel = function(imageData, x, y, rgb) { var index = (x + y * imageData.width) * rgb.length; - imageData.data[index + 0] = rgb[0]; - imageData.data[index + 1] = rgb[1]; - imageData.data[index + 2] = rgb[2]; - imageData.data[index + 3] = rgb[3]; + imageData.data[index] = rgb[0]; + imageData.data[index+1] = rgb[1]; + imageData.data[index+2] = rgb[2]; + imageData.data[index+3] = rgb[3]; }; /** @@ -5235,7 +5306,7 @@ Video.init = function() * Now we can create the Video object, record it, and wire it up to the associated document elements. */ var eContext = eCanvas.getContext("2d"); - var video = new Video(parmsVideo, eCanvas, eContext, eTextArea /* || eInput */); + var video = new Video(parmsVideo, eCanvas, eContext, eTextArea /* || eInput */, eVideo); /* * Bind any video-specific controls (eg, the Refresh button). There are no essential controls, however;