diff --git a/_config.yml b/_config.yml
index b0b3a7f1f..e20d5469e 100644
--- a/_config.yml
+++ b/_config.yml
@@ -6,7 +6,8 @@ description: >
PCjs: The Original IBM PC in a Browser.
Classic computer simulations in JavaScript.
Includes an archive of historical PC software and publications.
- Additional computer simulations in JavaScript include the 6502-based Ohio Scientific Challenger 1P.
+ Additional computer simulations in JavaScript include the 6502-based Ohio Scientific Challenger 1P and 8080-based
+ machines, including arcade machines such as Space Invaders.
baseurl: "" # "/pcjs" when using http://jeffpar.github.io or "" when using http://www.pcjs.org
url: "http://www.pcjs.org" # "http://jeffpar.github.io" or "http://www.pcjs.org"
twitter_username: jeffpar
diff --git a/devices/pc8080/machine/invaders/machine.xml b/devices/pc8080/machine/invaders/machine.xml
index 246adab95..1cdd8a49b 100644
--- a/devices/pc8080/machine/invaders/machine.xml
+++ b/devices/pc8080/machine/invaders/machine.xml
@@ -18,6 +18,7 @@
+
diff --git a/docs/pcjs/examples/pc-dbg.js b/docs/pcjs/examples/pc-dbg.js
index ee3b4194e..a4564278d 100644
--- a/docs/pcjs/examples/pc-dbg.js
+++ b/docs/pcjs/examples/pc-dbg.js
@@ -94,7 +94,7 @@ function kd(a,b,c){var d=a.F,e=a.Lb,f=d.Sa.Z,g=d.Sa.Aa;if(!c){if(!(d.Sa.type&512
d.oa(h+g)));c&&d.jb(h+0,f);d.Za|=8;return!0}m.save=function(){return[this.Z,this.Aa,this.Ta,this.wb,this.id,this.lc,this.Lb,this.Gc,this.Xb,this.Oc,this.Ba,this.ba,this.R,this.type,this.Zb]};m.restore=function(a){"number"==typeof a?this.load(a):(this.Z=a[0],this.Aa=a[1],this.Ta=a[2],this.wb=a[3],this.id=a[4],this.lc=a[5],this.Lb=a[6],this.Gc=a[7],this.Xb=a[8],this.Oc=a[9]||2,this.Ba=a[10]||65535,this.ba=a[11]||2,this.R=a[12]||65535,this.type=a[13]||this.wb&7936,this.Zb=a[14]||(this.Ta>>>0)+1)};
function ed(a,b,c,d){void 0===c&&(c=!!(a.F.Za&1));a.cd=!1;if(c)if(a.load=a.tg,a.Wi=a.fm,a.nc=a.Ci,a.oc=a.Ei,void 0===d&&(d=!!(a.F.ca&131072)),d)a.load=a.V,a.nc=a.ea,a.oc=a.qa,a.Lb=a.Gc=3,a.ba=a.Oc=2,a.R=a.Ba=65535,a.Ta=65535,a.Zb=a.Ta+1,a.Oc=a.ba,a.Xb=-1,a.cf=!1;else{if(!(a.Z&-4))a.nc=a.og,a.oc=a.pg;else if(a.type&4096){6144==(a.type&6656)&&(a.nc=a.og);if(a.type&2048||!(a.type&512))a.oc=a.pg;1024==(a.type&3072)&&(a.nc==a.Ci&&(a.nc=a.Ik),a.oc==a.Ei&&(a.oc=a.Jk),a.cd=!0);b&&6>a.id&&a.Z&-4&&-1!==a.Xb&&
(c=a.Xb+5,d=a.F.Qa(c),d&1||a.F.qc(c,d|1))}b&&(a.Lb=a.Z&3,a.Gc=(a.wb&24576)>>13,80386>a.F.ja||!(a.ext&64)?(a.ba=2,a.R=65535):(a.ba=4,a.R=-1),a.Oc=a.ba,a.Ba=a.R)}else a.load=a.lh,a.Wi=a.gm,a.nc=a.Di,a.oc=a.Fi,a.Lb=a.Gc=0,a.Xb=-1,a.cf=!1}
-function Ad(a){this.ja=a.model||8088;var b=a.stepping;this.Uc=this.ja+(b?ca(b,16):0);b=0;switch(this.ja){default:b=4772727;break;case 80286:b=6E6;break;case 80386:b=16E6}Lc.call(this,a,b);this.Yf=61442;this.Cc=1792;this.Wf=28672;this.Dd=4;this.ra=255;this.B=80286<=this.ja?xb:wb;this.X=Bd;this.bg=Cd;this.gg=Dd;this.hg=Ed;if(80186<=this.ja&&(this.X=Bd.slice(),this.bg=Cd.slice(),this.gg=Dd.slice(),this.ra=31,this.X[15]=Fd,this.X[96]=Gd,this.X[97]=Hd,this.X[98]=Id,this.X[99]=Fd,this.X[100]=Fd,this.X[101]=
+function Ad(a){this.ja=+a.model||8088;var b=a.stepping;this.Uc=this.ja+(b?ca(b,16):0);b=0;switch(this.ja){default:b=4772727;break;case 80286:b=6E6;break;case 80386:b=16E6}Lc.call(this,a,b);this.Yf=61442;this.Cc=1792;this.Wf=28672;this.Dd=4;this.ra=255;this.B=80286<=this.ja?xb:wb;this.X=Bd;this.bg=Cd;this.gg=Dd;this.hg=Ed;if(80186<=this.ja&&(this.X=Bd.slice(),this.bg=Cd.slice(),this.gg=Dd.slice(),this.ra=31,this.X[15]=Fd,this.X[96]=Gd,this.X[97]=Hd,this.X[98]=Id,this.X[99]=Fd,this.X[100]=Fd,this.X[101]=
Fd,this.X[102]=Fd,this.X[103]=Fd,this.X[104]=Jd,this.X[105]=Kd,this.X[106]=Ld,this.X[107]=Md,this.X[108]=Nd,this.X[109]=Od,this.X[110]=Pd,this.X[111]=Qd,this.X[192]=Rd,this.X[193]=Sd,this.X[200]=Td,this.X[201]=Ud,this.X[241]=Yd,this.bg[7]=Zd,this.gg[7]=Zd,80286<=this.ja)){this.Yf=2;this.Cc|=28672;this.Dd=0;this.X[15]=$d;this.tc=ae.slice();for(a=0;a=this.Uc&&(this.tc[166]=ne,this.tc[167]=oe)}}this.Id=[];this.le=[];this.ne=0;Oc(this);this.la.Wd=this.la.Mi=!1;this.Pg=0;this.ld=this.sa=[];this.La=this.Sb=this.Fa=this.Gd=this.jd=this.Hb=this.Db=0;pe(this)}db(Ad,Lc);function qe(a,b,c,d){Gc((d?a.ld:a.sa)[b>>>a.La],c);d&&Ub(a)}
function re(a){var b;if(a.sa===a.ld){a.sa=Array(a.Gd);a.me=new B(null,0,0,5,null,a);Mb(a.me,a.ha);for(b=0;ba.oe&&(a.ag[a.oe++]=d);a.sa[b]=a.me}a.Hd=[]}function Ub(a){a.Za&-2147483648&&re(a)}
@@ -461,7 +461,7 @@ function vm(a,b,c){var d=!0,e=!1,f=!1,g=b.keyCode,h=Em(a,g,!0);a.bh&&h==X["`"]&&
function Dm(a,b,c){var d=!1;xm(a,b,!0,c);var e=Y[b]||Y[b+1E3];if(void 0!==e){14==e&&40==(a.xc&40)&&(e=83);var d=[],f=e&255;if(83=b||97<=b&&122>=b;e>>>=8;){var g=0,h=e&255;224==f||225==f?d.push(f|(c?0:128)):(42==h?a.C&3||a.C&512&&b||(g=h):29==h?a.C&12||(g=h):56==h?a.C&48||(g=h):d.push(f|(c?0:128)),g&&(c?d.unshift(g):d.push(g|128)))}for(c=0;ce.A.length?(A(e)&&y(e,"scan code "+t(f)+" buffered"),e.A.push(f),1==
e.A.length&&e.N&&Wl(e.N,f)):(20==e.A.length&&e.A.push(255),y(e,"scan code buffer overflow")));d=!0}return d}Qa(function(){for(var a=nb(document,"pcjs","keyboard"),b=0;b>>0)+1)};
function zc(a,b,c,d){void 0===c&&(c=!!(a.A.Pa&1));a.zd=!1;if(c)if(a.load=a.Cf,a.Wh=a.Tk,a.Qb=a.Ih,a.Rb=a.Kh,void 0===d&&(d=!!(a.A.X&131072)),d)a.load=a.L,a.Qb=a.I,a.Rb=a.K,a.sb=a.nc=3,a.U=a.Nc=2,a.N=a.sa=65535,a.Za=65535,a.C=a.Za+1,a.Nc=a.U,a.hc=-1,a.pe=!1;else{if(!(a.ja&-4))a.Qb=a.wf,a.Rb=a.xf;else if(a.type&4096){6144==(a.type&6656)&&(a.Qb=a.wf);if(a.type&2048||!(a.type&512))a.Rb=a.xf;1024==(a.type&3072)&&(a.Qb==a.Ih&&(a.Qb=a.zj),a.Rb==a.Kh&&(a.Rb=a.Aj),a.zd=!0);b&&6>a.id&&a.ja&-4&&-1!==a.hc&&(c=
a.hc+5,d=a.A.Kb(c),d&1||a.A.Mc(c,d|1))}b&&(a.sb=a.ja&3,a.nc=(a.lb&24576)>>13,80386>a.A.ca||!(a.ext&64)?(a.U=2,a.N=65535):(a.U=4,a.N=-1),a.Nc=a.U,a.sa=a.N)}else a.load=a.Xh,a.Wh=a.Uk,a.Qb=a.Jh,a.Rb=a.Lh,a.sb=a.nc=0,a.hc=-1,a.pe=!1}
-function Qc(a){this.ca=a.model||8088;var b=a.stepping;this.pd=this.ca+(b?ca(b,16):0);b=0;switch(this.ca){default:b=4772727;break;case 80286:b=6E6;break;case 80386:b=16E6}hc.call(this,a,b);this.rh=61442;this.od=1792;this.qh=28672;this.ae=4;this.Da=255;this.B=80286<=this.ca?fb:eb;this.ma=Rc;this.uh=Sc;this.vh=Tc;this.wh=Uc;if(80186<=this.ca&&(this.ma=Rc.slice(),this.uh=Sc.slice(),this.vh=Tc.slice(),this.Da=31,this.ma[15]=Vc,this.ma[96]=Wc,this.ma[97]=Xc,this.ma[98]=Yc,this.ma[99]=Vc,this.ma[100]=Vc,
+function Qc(a){this.ca=+a.model||8088;var b=a.stepping;this.pd=this.ca+(b?ca(b,16):0);b=0;switch(this.ca){default:b=4772727;break;case 80286:b=6E6;break;case 80386:b=16E6}hc.call(this,a,b);this.rh=61442;this.od=1792;this.qh=28672;this.ae=4;this.Da=255;this.B=80286<=this.ca?fb:eb;this.ma=Rc;this.uh=Sc;this.vh=Tc;this.wh=Uc;if(80186<=this.ca&&(this.ma=Rc.slice(),this.uh=Sc.slice(),this.vh=Tc.slice(),this.Da=31,this.ma[15]=Vc,this.ma[96]=Wc,this.ma[97]=Xc,this.ma[98]=Yc,this.ma[99]=Vc,this.ma[100]=Vc,
this.ma[101]=Vc,this.ma[102]=Vc,this.ma[103]=Vc,this.ma[104]=Zc,this.ma[105]=$c,this.ma[106]=ad,this.ma[107]=bd,this.ma[108]=cd,this.ma[109]=dd,this.ma[110]=ed,this.ma[111]=fd,this.ma[192]=gd,this.ma[193]=hd,this.ma[200]=id,this.ma[201]=jd,this.ma[241]=kd,this.uh[7]=ld,this.vh[7]=ld,80286<=this.ca)){this.rh=2;this.od|=28672;this.ae=0;this.ma[15]=md;this.Zc=nd.slice();for(a=0;a=this.pd&&(this.Zc[166]=wd,this.Zc[167]=xd)}}this.of=[];this.th=[];this.Vf=0;kc(this);this.da.Le=this.da.Hj=!1;this.yh=0;this.vc=this.S=[];this.ea=this.xb=this.pb=this.mf=this.Yd=this.Fa=this.oc=0;yd(this)}Qa(Qc,hc);
function Bb(a){var b;if(a.S===a.vc){a.S=Array(a.mf);a.pf=new q(null,0,0,5,null,a);sb(a.pf,a.Ia);for(b=0;ba.qf&&(a.sh[a.qf++]=d);a.S[b]=a.pf}a.nf=[]}
@@ -433,10 +433,10 @@ function vk(a,b,c){var d=!0,e=!1,f=!1,g=b.keyCode,h=Ek(a,g,!0);a.ig&&h==U["`"]&&
function Dk(a,b,c){var d=!1;xk(a,b,!0,c);var e=X[b]||X[b+1E3];if(void 0!==e){14==e&&40==(a.bc&40)&&(e=83);var d=[],f=e&255;if(83=b||97<=b&&122>=b;e>>>=8;){var g=0,h=e&255;224==f||225==f?d.push(f|(c?0:128)):(42==h?a.C&3||a.C&512&&b||(g=h):29==h?a.C&12||(g=h):56==h?a.C&48||(g=h):d.push(f|(c?0:128)),g&&(c?d.unshift(g):d.push(g|128)))}for(c=0;ce.Pb.length?(e.Pb.push(f),1==e.Pb.length&&e.R&&Yj(e.R,f)):20==e.Pb.length&&
e.Pb.push(255));d=!0}return d}Ea(function(){for(var a=Za(document,"pcjs","keyboard"),b=0;b 39
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.FF_DASH] = Keyboard.ASCII['-'];
+/**
+ * Maps SOFTCODE (string) to KEYCODE (number).
+ *
+ * @enum {number}
+ */
+Keyboard.SOFTCODES = {
+ '1p': Keyboard.KEYCODE.ONE,
+ '2p': Keyboard.KEYCODE.TWO,
+ 'coin': Keyboard.KEYCODE.FIVE,
+ 'left': Keyboard.KEYCODE.LEFT,
+ 'right': Keyboard.KEYCODE.RIGHT,
+ 'fire': Keyboard.KEYCODE.SPACE
+};
+
+/**
+ * Alternate keyCode mappings (to support the popular WASD directional mappings)
+ *
+ * TODO: ES6 computed property name support may now be in all mainstream browsers, allowing us to use
+ * a simple object literal for this and all other object initializations.
+ */
+Keyboard.ALTCODES = {};
+Keyboard.ALTCODES[Keyboard.ASCII.A] = Keyboard.KEYCODE.LEFT;
+Keyboard.ALTCODES[Keyboard.ASCII.D] = Keyboard.KEYCODE.RIGHT;
+Keyboard.ALTCODES[Keyboard.ASCII.L] = Keyboard.KEYCODE.SPACE;
+
+/**
+ * getSoftCode(keyCode)
+ *
+ * @this {Keyboard}
+ * @return {string|null}
+ */
+Keyboard.prototype.getSoftCode = function(keyCode)
+{
+ keyCode = Keyboard.ALTCODES[keyCode] || keyCode;
+ for (var sSoftCode in Keyboard.SOFTCODES) {
+ if (Keyboard.SOFTCODES[sSoftCode] === keyCode) {
+ return sSoftCode;
+ }
+ }
+ return null;
+};
+
+/**
+ * reset()
+ *
+ * @this {Keyboard}
+ */
+Keyboard.prototype.reset = function()
+{
+ /*
+ * As SOFTCODE keyDown events are encountered, a corresponding property is set to true in
+ * keysPressed, and as SOFTCODE keyUp events are encountered, the property is set to false.
+ */
+ this.keysPressed = {};
+};
+
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
@@ -257,68 +324,24 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
control.onkeydown = function onKeyDown(event) {
return kbd.onKeyDown(event, true);
};
- control.onkeypress = function onKeyPressKbd(event) {
- return kbd.onKeyPress(event);
- };
control.onkeyup = function onKeyUp(event) {
return kbd.onKeyDown(event, false);
};
return true;
- case "caps-lock":
- this.bindings[id] = control;
- control.onclick = function onClickCapsLock(event) {
- if (kbd.cmp) kbd.cmp.updateFocus();
- return kbd.toggleCapsLock();
- };
- return true;
-
- case "num-lock":
- this.bindings[id] = control;
- control.onclick = function onClickNumLock(event) {
- if (kbd.cmp) kbd.cmp.updateFocus();
- return kbd.toggleNumLock();
- };
- return true;
-
- case "scroll-lock":
- this.bindings[id] = control;
- control.onclick = function onClickScrollLock(event) {
- if (kbd.cmp) kbd.cmp.updateFocus();
- return kbd.toggleScrollLock();
- };
- return true;
-
default:
- /*
- * Maintain support for older button codes; eg, map button code "ctrl-c" to CLICKCODE "CTRL_C"
- */
- var sCode = sBinding.toUpperCase().replace(/-/g, '_');
- if (Keyboard.CLICKCODES[sCode] !== undefined && sHTMLType == "button") {
+ if (Keyboard.SOFTCODES[sBinding] !== undefined) {
this.bindings[id] = control;
- control.onclick = function(kbd, sKey, simCode) {
- return function onClickKeyboard(event) {
- if (!COMPILED && kbd.messageEnabled()) kbd.printMessage(sKey + " clicked", Messages.KEYS);
- if (kbd.cmp) kbd.cmp.updateFocus();
- kbd.updateShiftState(simCode, true); // future-proofing if/when any LOCK keys are added to CLICKCODES
- kbd.addActiveKey(simCode, true);
- };
- }(this, sCode, Keyboard.CLICKCODES[sCode]);
- return true;
- }
- else if (Keyboard.SOFTCODES[sBinding] !== undefined) {
- this.cSoftCodes++;
- this.bindings[id] = control;
- var fnDown = function(kbd, sKey, simCode) {
+ var fnDown = function(kbd, sSoftCode) {
return function onMouseOrTouchDownKeyboard(event) {
- kbd.addActiveKey(simCode);
+ kbd.onSoftKeyDown(sSoftCode, true);
};
- }(this, sBinding, Keyboard.SOFTCODES[sBinding]);
- var fnUp = function (kbd, sKey, simCode) {
+ }(this, sBinding);
+ var fnUp = function (kbd, sSoftCode) {
return function onMouseOrTouchUpKeyboard(event) {
- kbd.removeActiveKey(simCode);
+ kbd.onSoftKeyDown(sSoftCode, false);
};
- }(this, sBinding, Keyboard.SOFTCODES[sBinding]);
+ }(this, sBinding);
if ('ontouchstart' in window) {
control.ontouchstart = fnDown;
control.ontouchend = fnUp;
@@ -328,19 +351,92 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
}
return true;
}
- else if (sValue) {
- /*
- * Instead of just having a dedicated "test" control, we now treat any unrecognized control with
- * a data value as a test control. The only caveat is that such controls must have binding IDs that
- * do not conflict with predefined controls (which, of course, is the only way you can get here).
- */
- this.bindings[id] = control;
- control.onclick = function onClickTest(event) {
- if (kbd.cmp) kbd.cmp.updateFocus();
- return kbd.injectKeys(sValue);
- };
- return true;
- }
+ break;
+ }
+ }
+ return false;
+};
+
+/**
+ * initBus(cmp, bus, cpu, dbg)
+ *
+ * @this {Keyboard}
+ * @param {Computer} cmp
+ * @param {Bus} bus
+ * @param {CPUState} cpu
+ * @param {Debugger} dbg
+ */
+Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
+{
+ this.dbg = dbg; // NOTE: The "dbg" property must be set for the message functions to work
+ this.chipset = cmp.getMachineComponent("ChipSet");
+};
+
+/**
+ * onKeyDown(event, fDown)
+ *
+ * @this {Keyboard}
+ * @param {Object} event
+ * @param {boolean} fDown is true for a keyDown event, false for a keyUp event
+ * @return {boolean} true to pass the event along, false to consume it
+ */
+Keyboard.prototype.onKeyDown = function(event, fDown)
+{
+ var fPass = true;
+ var keyCode = event.keyCode;
+ var sSoftCode = this.getSoftCode(keyCode);
+
+ if (sSoftCode) {
+ fPass = this.onSoftKeyDown(sSoftCode, fDown);
+ }
+
+ if (!fPass) {
+ event.preventDefault();
+ }
+
+ if (!COMPILED && this.messageEnabled(Messages.KEYS)) {
+ this.printMessage("onKey" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "true" : "false"), true);
+ }
+
+ return fPass;
+};
+
+/**
+ * onSoftKeyDown(sSoftCode, fDown)
+ *
+ * @this {Keyboard}
+ * @param {string} sSoftCode
+ * @param {boolean} fDown is true for a down event, false for an up event
+ * @return {boolean} true to pass the event along, false to consume it
+ */
+Keyboard.prototype.onSoftKeyDown = function(sSoftCode, fDown)
+{
+ this.keysPressed[sSoftCode] = fDown;
+
+ if (this.chipset) {
+ switch(sSoftCode) {
+ case '1p':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1, fDown);
+ break;
+
+ case '2p':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P2, fDown);
+ break;
+
+ case 'coin':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.CREDIT, fDown);
+ break;
+
+ case 'left':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_LEFT, fDown);
+ break;
+
+ case 'right':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_RIGHT, fDown);
+ break;
+
+ case 'fire':
+ this.chipset.updateStatus1(ChipSet.SI_1978.STATUS1.P1_FIRE, fDown);
break;
}
}
diff --git a/modules/pc8080/lib/video.js b/modules/pc8080/lib/video.js
index 621c9fb13..84c700b75 100644
--- a/modules/pc8080/lib/video.js
+++ b/modules/pc8080/lib/video.js
@@ -245,6 +245,16 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
this.initCache();
}
+
+ /*
+ * If we have an associated keyboard, then ensure that the keyboard will be notified whenever the canvas
+ * gets focus and receives input.
+ */
+ this.kbd = cmp.getMachineComponent("Keyboard");
+ if (this.kbd && this.canvasScreen) {
+ this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "kbd", this.inputScreen);
+ }
+
this.setReady();
};
diff --git a/modules/pcjs/lib/keyboard.js b/modules/pcjs/lib/keyboard.js
index 71cca2663..db3a85286 100644
--- a/modules/pcjs/lib/keyboard.js
+++ b/modules/pcjs/lib/keyboard.js
@@ -566,6 +566,11 @@ Keyboard.KEYSTATES[Keyboard.SIMCODE.SCROLL_LOCK] = Keyboard.STATE.SCROLL_LOCK;
/**
* Maps CLICKCODE (string) to SIMCODE (number).
*
+ * NOTE: Unlike SOFTCODES, CLICKCODES are upper-case and use underscores instead of dashes, so that this
+ * and other components can reference them using "dot" property syntax; using upper-case merely adheres to
+ * our convention for constants. setBinding() will automatically convert any incoming CLICKCODE bindings
+ * that use lower-case and dashes to upper-case and underscores before performing property lookup.
+ *
* @enum {number}
*/
Keyboard.CLICKCODES = {
diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js
index 5838ee74b..1f2b36d9a 100644
--- a/modules/pcjs/lib/video.js
+++ b/modules/pcjs/lib/video.js
@@ -165,7 +165,7 @@ function Video(parmsVideo, canvas, context, textarea, container)
*/
var fSmoothing = parmsVideo['smoothing'];
var sSmoothing = Component.parmsURL['smoothing'];
- if (sSmoothing) fSmoothing = (sSmoothing == "true")? true : false;
+ if (sSmoothing) fSmoothing = (sSmoothing == "true");
if (fSmoothing != null) {
for (i = 0; i < asWebPrefixes.length; i++) {
sEvent = asWebPrefixes[i];
@@ -4560,8 +4560,8 @@ Video.prototype.removeCursor = function()
/*
* If we're using an off-screen buffer in text mode, then we need to keep it in sync with "reality".
*/
- if (this.contextScreenBuffer) {
- this.updateChar(col, row, data, this.contextScreenBuffer);
+ if (this.contextBuffer) {
+ this.updateChar(col, row, data, this.contextBuffer);
}
/*
* While updating the on-screen canvas directly could open us up to potential subpixel artifacts again,
@@ -4856,11 +4856,11 @@ Video.prototype.setDimensions = function()
}
/*
- * In text modes, we have the option of setting all the *ScreenBuffer variables to null instead of
+ * In text modes, we have the option of setting all the *Buffer variables to null instead of
* allocating them, because updateChar(), as currently written, is capable of writing characters to
* either an off-screen or on-screen context.
*
- * this.imageScreenBuffer = this.canvasScreenBuffer = this.contextScreenBuffer = null;
+ * this.imageBuffer = this.canvasBuffer = this.contextBuffer = null;
*/
this.cxBuffer = this.cyBuffer = 0;
if (font) {
@@ -4888,11 +4888,11 @@ Video.prototype.setDimensions = function()
/*
* Allocate the off-screen buffers
*/
- this.imageScreenBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
- this.canvasScreenBuffer = document.createElement("canvas");
- this.canvasScreenBuffer.width = this.cxBuffer;
- this.canvasScreenBuffer.height = this.cyBuffer;
- this.contextScreenBuffer = this.canvasScreenBuffer.getContext("2d");
+ this.imageBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
+ this.canvasBuffer = document.createElement("canvas");
+ this.canvasBuffer.width = this.cxBuffer;
+ this.canvasBuffer.height = this.cyBuffer;
+ this.contextBuffer = this.canvasBuffer.getContext("2d");
/*
* Since cxCell and cyCell were originally defined in terms of cxScreen/nCols and cyScreen/nRows, you might think
@@ -5676,7 +5676,7 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
if (!this.fCellCacheValid || data !== this.aCellCache[iCell]) {
var col = iCell % this.nCols;
var row = (iCell / this.nCols)|0;
- this.updateChar(col, row, data, this.contextScreenBuffer);
+ this.updateChar(col, row, data, this.contextBuffer);
this.aCellCache[iCell] = data;
cUpdated++;
}
@@ -5686,8 +5686,8 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
this.fCellCacheValid = true;
- if (cUpdated && this.contextScreenBuffer) {
- this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.cxBuffer, this.cyBuffer, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
+ if (cUpdated && this.contextBuffer) {
+ this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.cxBuffer, this.cyBuffer, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset);
}
};
@@ -5725,7 +5725,7 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
if (x < xDirty) xDirty = x;
for (var iPixel = 0; iPixel < nPixelsPerCell; iPixel++) {
var bPixel = (wPixels & (wMask >>= nPixelShift)) >> (nShift -= nPixelShift);
- this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]);
+ this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
}
if (x > xMaxDirty) xMaxDirty = x;
if (y < yDirty) yDirty = y;
@@ -5748,30 +5748,30 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
this.fCellCacheValid = true;
/*
- * Instead of blasting the ENTIRE imageScreenBuffer into contextScreenBuffer, and then blasting the ENTIRE
- * canvasScreenBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about
+ * Instead of blasting the ENTIRE imageBuffer into contextBuffer, and then blasting the ENTIRE
+ * canvasBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about
* the update (well, to the extent that the canvas APIs permit).
*/
if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty;
- // this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0);
- this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
+ // this.contextBuffer.putImageData(this.imageBuffer, 0, 0);
+ this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
/*
- * While ideally I would draw only the dirty portion of canvasScreenBuffer, there usually isn't a 1-1 pixel mapping
- * between canvasScreenBuffer and contextScreen. In fact, the WHOLE POINT of the canvasScreenBuffer is to leverage
+ * While ideally I would draw only the dirty portion of canvasBuffer, there usually isn't a 1-1 pixel mapping
+ * between canvasBuffer and contextScreen. In fact, the WHOLE POINT of the canvasBuffer is to leverage
* drawImage()'s scaling ability; for example, a CGA graphics mode might be 640x200, whereas the canvas representing
* the screen might be 960x400. In those situations, if we draw interior rectangles, we often end up with subpixel
- * artifacts along the edges of those rectangles. So it appears I must continue to redraw the entire canvasScreenBuffer
+ * artifacts along the edges of those rectangles. So it appears I must continue to redraw the entire canvasBuffer
* on every change.
*
var xScreen = (((xDirty * this.cxScreen) / this.nCols) | 0);
var yScreen = (((yDirty * this.cyScreen) / this.nRows) | 0);
var cxScreen = (((cxDirty * this.cxScreen) / this.nCols) | 0);
var cyScreen = (((cyDirty * this.cyScreen) / this.nRows) | 0);
- this.contextScreen.drawImage(this.canvasScreenBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
+ this.contextScreen.drawImage(this.canvasBuffer, xDirty, yDirty, cxDirty, cyDirty, xScreen, yScreen, cxScreen, cyScreen);
*/
- this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
+ this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
}
};
@@ -5863,7 +5863,7 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
* index, which is what this code requires.
*/
var bPixel = Video.aEGADWToByte[dwPixel] || 0;
- this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]);
+ this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
data <<= 1;
}
if (x > xMaxDirty) xMaxDirty = x;
@@ -5888,8 +5888,8 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty;
- this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
- this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
+ this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
+ this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
}
};
@@ -5957,7 +5957,7 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
if (nPixels) {
if (x < xDirty) xDirty = x;
for (iPixel = 0; iPixel < nPixels; iPixel++) {
- this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[data & 0xff]);
+ this.setPixel(this.imageBuffer, x++, y, aPixelColors[data & 0xff]);
data >>= 8;
}
if (x > xMaxDirty) xMaxDirty = x;
@@ -5984,8 +5984,8 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty;
- this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
- this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
+ this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
+ this.contextScreen.drawImage(this.canvasBuffer, 0, 0, this.nCols, this.nRows, 0, 0, this.cxScreen, this.cyScreen);
}
};