Added some prerequisites for dual display support

This commit is contained in:
Jeff Parsons 2015-05-23 12:25:34 -07:00 committed by jeffpar
commit f3b254ebcd
4 changed files with 102 additions and 46 deletions

View file

@ -1214,7 +1214,7 @@ Computer.prototype.onReset = function()
* *
* @this {Computer} * @this {Computer}
* @param {string} sType * @param {string} sType
* @param {Component} [componentPrev] of previously returned component, if any * @param {Component|null} [componentPrev] of previously returned component, if any
* @return {Component|null} * @return {Component|null}
*/ */
Computer.prototype.getComponentByType = function(sType, componentPrev) Computer.prototype.getComponentByType = function(sType, componentPrev)

View file

@ -133,6 +133,11 @@ function CPU(parmsCPU, nCyclesDefault)
this.aCounts.nCyclesChecksumInterval = parmsCPU["csInterval"]; this.aCounts.nCyclesChecksumInterval = parmsCPU["csInterval"];
this.aCounts.nCyclesChecksumStop = parmsCPU["csStop"]; this.aCounts.nCyclesChecksumStop = parmsCPU["csStop"];
/*
* Initially, no video devices are attached that require CPU-driven updates. initBus() will update this.
*/
this.aVideo = [];
var cpu = this; var cpu = this;
this.onRunTimeout = function() { cpu.runCPU(); }; this.onRunTimeout = function() { cpu.runCPU(); };
@ -181,7 +186,9 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
* Attach the Video component to the CPU, so that the CPU can periodically update * Attach the Video component to the CPU, so that the CPU can periodically update
* the video display via updateVideo(), as cycles permit. * the video display via updateVideo(), as cycles permit.
*/ */
this.video = cmp.getComponentByType("Video"); for (var video = null; (video = cmp.getComponentByType("Video", video));) {
this.aVideo.push(video);
}
/* /*
* Attach the ChipSet component to the CPU, so that it can obtain the IDT vector number of * Attach the ChipSet component to the CPU, so that it can obtain the IDT vector number of
* pending hardware interrupts, in response to ChipSet's updateINTR() notifications. * pending hardware interrupts, in response to ChipSet's updateINTR() notifications.
@ -482,7 +489,9 @@ CPU.prototype.updateStatus = function(fForce)
*/ */
CPU.prototype.updateVideo = function() CPU.prototype.updateVideo = function()
{ {
if (this.video) this.video.updateScreen(); for (var i = 0; i < this.aVideo.length; i++) {
this.aVideo[i].updateScreen();
}
if (this.cmp && this.cmp.panel) this.cmp.panel.updateAnimation(); if (this.cmp && this.cmp.panel) this.cmp.panel.updateAnimation();
}; };
@ -493,7 +502,7 @@ CPU.prototype.updateVideo = function()
*/ */
CPU.prototype.setFocus = function() CPU.prototype.setFocus = function()
{ {
if (this.video) this.video.setFocus(); if (this.aVideo.length) this.aVideo[0].setFocus();
}; };
/** /**

View file

@ -78,7 +78,14 @@ function Mouse(parmsMouse)
this.sAdapterType = "SerialPort"; this.sAdapterType = "SerialPort";
} }
this.setActive(false); this.setActive(false);
this.fLocked = false; this.fCaptured = this.fLocked = false;
/*
* Initially, no video devices, and therefore no input devices, are attached. initBus() will update aVideo,
* and powerUp() will update aInput.
*/
this.aVideo = [];
this.aInput = [];
this.setReady(); this.setReady();
} }
@ -177,7 +184,13 @@ Mouse.prototype.initBus = function(cmp, bus, cpu, dbg)
this.bus = bus; this.bus = bus;
this.cpu = cpu; this.cpu = cpu;
this.dbg = dbg; this.dbg = dbg;
this.video = this.cmp.getComponentByType("Video"); /*
* Attach the Video component to the CPU, so that the CPU can periodically update
* the video display via updateVideo(), as cycles permit.
*/
for (var video = null; (video = cmp.getComponentByType("Video", video));) {
this.aVideo.push(video);
}
}; };
/** /**
@ -204,7 +217,7 @@ Mouse.prototype.setActive = function(fActive)
* It's currently not possible to automatically lock the pointer outside the context of a user action * It's currently not possible to automatically lock the pointer outside the context of a user action
* (eg, a button or screen click), so this code is for naught. * (eg, a button or screen click), so this code is for naught.
* *
* if (this.video) this.video.notifyPointerActive(fActive); * if (this.aVideo.length) this.aVideo[0].notifyPointerActive(fActive);
* *
* We now rely on similar code in clickMouse(). * We now rely on similar code in clickMouse().
*/ */
@ -234,13 +247,13 @@ Mouse.prototype.powerUp = function(data, fRepower)
if (this.componentAdapter) { if (this.componentAdapter) {
/* /*
* It's possible that the SerialPort we've just attached to might want to bring us "up to speed" * It's possible that the SerialPort we've just attached to might want to bring us "up to speed"
* on the adapter's state, which is why I envisioned a subsequent syncMouse() call. And you would want * on the adapter's state, which is why I envisioned a subsequent syncMouse() call. And you would
* to do that as a separate call, not as part of attachMouse(), because componentAdapter isn't * want to do that as a separate call, not as part of attachMouse(), because componentAdapter
* set until attachMouse() returns. * isn't set until attachMouse() returns.
* *
* However, syncMouse() seems unnecessary, given that SerialPort initializes its MCR to an "inactive" * However, syncMouse() seems unnecessary, given that SerialPort initializes its MCR to an "inactive"
* state, and even when restoring a previous state, if we've done our job properly, both SerialPort and Mouse * state, and even when restoring a previous state, if we've done our job properly, both SerialPort
* should be restored in sync, making any explicit attempt at sync'ing unnecessary (or so I hope). * and Mouse should be restored in sync, making any explicit attempt at sync'ing unnecessary (or so I hope).
*/ */
// this.componentAdapter.syncMouse(); // this.componentAdapter.syncMouse();
break; break;
@ -248,15 +261,19 @@ Mouse.prototype.powerUp = function(data, fRepower)
} }
} }
if (this.componentAdapter) { if (this.componentAdapter) {
if (this.video) this.inputScreen = this.video.getInput(this); this.aInput = []; // ensure the input device array is empty before (re)filling it
for (var i = 0; i < this.aVideo.length; i++) {
var input = this.aVideo[i].getInput(this);
if (input) this.aInput.push(input);
}
} else { } else {
Component.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable"); Component.warning(this.id + ": " + this.sAdapterType + " " + this.idAdapter + " unavailable");
} }
} }
if (this.fActive) { if (this.fActive) {
this.captureMouse(this.inputScreen); this.captureAll();
} else { } else {
this.releaseMouse(this.inputScreen); this.releaseAll();
} }
} }
return true; return true;
@ -368,6 +385,34 @@ Mouse.prototype.notifyPointerLocked = function(fLocked)
this.fLocked = fLocked; this.fLocked = fLocked;
}; };
/**
* captureAll()
*
* @this {Mouse}
*/
Mouse.prototype.captureAll = function()
{
if (!this.fCaptured) {
for (var i = 0; i < this.aInput.length; i++) {
if (this.captureMouse(this.aInput[i])) this.fCaptured = true;
}
}
};
/**
* releaseAll()
*
* @this {Mouse}
*/
Mouse.prototype.releaseAll = function()
{
if (this.fCaptured) {
for (var i = 0; i < this.aInput.length; i++) {
if (this.releaseMouse(this.aInput[i])) this.fCaptured = false;
}
}
};
/** /**
* captureMouse(control) * captureMouse(control)
* *
@ -376,35 +421,33 @@ Mouse.prototype.notifyPointerLocked = function(fLocked)
* *
* @this {Mouse} * @this {Mouse}
* @param {Object} control from the HTML DOM (eg, the control for the simulated screen) * @param {Object} control from the HTML DOM (eg, the control for the simulated screen)
* @return {boolean} true if event handlers were actually added, false if not
*/ */
Mouse.prototype.captureMouse = function(control) Mouse.prototype.captureMouse = function(control)
{ {
if (control) { if (control) {
var mouse = this; var mouse = this;
if (!this.fCaptured) { control.addEventListener(
control.addEventListener( 'mousemove',
'mousemove', function onMouseMove(event) {
function onMouseMove(event) { mouse.moveMouse(event);
mouse.moveMouse(event); },
}, false // we'll specify false for the 'useCapture' parameter for now...
false // we'll specify false for the 'useCapture' parameter for now... );
); control.addEventListener(
control.addEventListener( 'mousedown',
'mousedown', function onMouseDown(event) {
function onMouseDown(event) { mouse.clickMouse(event.button, true);
mouse.clickMouse(event.button, true); },
}, false // we'll specify false for the 'useCapture' parameter for now...
false // we'll specify false for the 'useCapture' parameter for now... );
); control.addEventListener(
control.addEventListener( 'mouseup',
'mouseup', function onMouseUp(event) {
function onMouseUp(event) { mouse.clickMouse(event.button, false);
mouse.clickMouse(event.button, false); },
}, false // we'll specify false for the 'useCapture' parameter for now...
false // we'll specify false for the 'useCapture' parameter for now... );
);
this.fCaptured = true;
}
/* /*
* None of these tricks seemed to work for IE10, so I'm giving up hiding the browser's mouse pointer in IE for now. * None of these tricks seemed to work for IE10, so I'm giving up hiding the browser's mouse pointer in IE for now.
* *
@ -417,24 +460,28 @@ Mouse.prototype.captureMouse = function(control)
* to run this app from a different server, so think about that as well. * to run this app from a different server, so think about that as well.
*/ */
control['style']['cursor'] = "none"; control['style']['cursor'] = "none";
return true;
} }
return false;
}; };
/** /**
* releaseMouse(control) * releaseMouse(control)
* *
* TODO: Use removeEventListener() if fCaptured, to clean up our handlers; since I'm currently using * TODO: Use removeEventListener() to clean up our handlers; since I'm currently using anonymous functions,
* anonymous functions, and since I'm not seeing any compelling reason to remove the handlers once they've * and since I'm not seeing any compelling reason to remove the handlers once they've been established, it's
* been established, it's less code to leave them in place. * less code to leave them in place.
* *
* @this {Mouse} * @this {Mouse}
* @param {Object} control from the HTML DOM * @param {Object} control from the HTML DOM
* @return {boolean} true if event handlers were actually released, false if not
*/ */
Mouse.prototype.releaseMouse = function(control) Mouse.prototype.releaseMouse = function(control)
{ {
if (control) { if (control) {
control['style']['cursor'] = "auto"; control['style']['cursor'] = "auto";
} }
return false;
}; };
/** /**
@ -496,7 +543,7 @@ Mouse.prototype.clickMouse = function(iButton, fDown)
* If there's no support for automatic pointer locking in the Video component, then notifyPointerActive() * If there's no support for automatic pointer locking in the Video component, then notifyPointerActive()
* will return false, and we will set fLocked to null, ensuring that we never attempt this again. * will return false, and we will set fLocked to null, ensuring that we never attempt this again.
*/ */
if (!this.video || !this.video.notifyPointerActive(true)) { if (!this.aVideo.length || !this.aVideo[0].notifyPointerActive(true)) {
this.fLocked = null; this.fLocked = null;
} }
} }
@ -606,7 +653,7 @@ Mouse.prototype.notifyMCR = function(bMCR)
this.componentAdapter.sendRBR([Mouse.ID_SERIAL, Mouse.ID_SERIAL]); this.componentAdapter.sendRBR([Mouse.ID_SERIAL, Mouse.ID_SERIAL]);
this.printMessage("serial mouse ID sent"); this.printMessage("serial mouse ID sent");
} }
this.captureMouse(this.inputScreen); this.captureAll();
this.setActive(fActive); this.setActive(fActive);
} }
} else { } else {
@ -624,7 +671,7 @@ Mouse.prototype.notifyMCR = function(bMCR)
* polling the serial port, it might expect to see that data. Unlikely, but not impossible. * polling the serial port, it might expect to see that data. Unlikely, but not impossible.
*/ */
this.printMessage("serial mouse inactive"); this.printMessage("serial mouse inactive");
this.releaseMouse(this.inputScreen); this.releaseAll();
this.setActive(fActive); this.setActive(fActive);
} }
} }

View file

@ -412,7 +412,7 @@ Component.getComponentByID = function(id, idRelated)
* *
* @param {string} sType of the desired component * @param {string} sType of the desired component
* @param {string} [idRelated] of related component * @param {string} [idRelated] of related component
* @param {Component} [componentPrev] of previously returned component, if any * @param {Component|null} [componentPrev] of previously returned component, if any
* @return {Component|null} * @return {Component|null}
*/ */
Component.getComponentByType = function(sType, idRelated, componentPrev) Component.getComponentByType = function(sType, idRelated, componentPrev)