Space Invaders works on the desktop now

This commit is contained in:
Jeff Parsons 2016-05-14 23:12:39 -07:00
commit f09189c121
9 changed files with 269 additions and 116 deletions

View file

@ -6,7 +6,8 @@ description: >
PCjs: The Original IBM PC in a Browser. PCjs: The Original IBM PC in a Browser.
Classic computer simulations in JavaScript. Classic computer simulations in JavaScript.
Includes an archive of historical PC software and publications. 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 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" url: "http://www.pcjs.org" # "http://jeffpar.github.io" or "http://www.pcjs.org"
twitter_username: jeffpar twitter_username: jeffpar

View file

@ -18,6 +18,7 @@
</menu> </menu>
</video> </video>
<chipset id="chipset" model="SI1978"/> <chipset id="chipset" model="SI1978"/>
<keyboard id="keyboard"/>
<panel ref="/devices/pc8080/panel/left.xml"/> <panel ref="/devices/pc8080/panel/left.xml"/>
<debugger id="debugger" commands="s 8086"/> <debugger id="debugger" commands="s 8086"/>
</machine> </machine>

View file

@ -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)}; 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&& 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} (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.tc.length;a++)this.tc[a]||(this.tc[a]=ge);this.X[84]=he;this.X[99]=ie;if(80386<=this.ja){var c;this.Wf=0;this.Cc|=196608;this.X[100]=je;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.tc.length;a++)this.tc[a]||(this.tc[a]=ge);this.X[84]=he;this.X[99]=ie;if(80386<=this.ja){var c;this.Wf=0;this.Cc|=196608;this.X[100]=je;this.X[101]=
ke;this.X[102]=le;this.X[103]=me;for(c in M)this.tc[+c]=M[c];80546<=this.Uc&&80562>=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)} ke;this.X[102]=le;this.X[103]=me;for(c in M)this.tc[+c]=M[c];80546<=this.Uc&&80562>=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;b<a.Gd;b++)a.sa[b]=a.me;a.kd=new B;a.ag=Array(512);a.oe=0}else for(var c=0;c<a.Hd.length;c++){b=a.Hd[c];var d=a.sa[b];512>a.oe&&(a.ag[a.oe++]=d);a.sa[b]=a.me}a.Hd=[]}function Ub(a){a.Za&-2147483648&&re(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;b<a.Gd;b++)a.sa[b]=a.me;a.kd=new B;a.ag=Array(512);a.oe=0}else for(var c=0;c<a.Hd.length;c++){b=a.Hd[c];var d=a.sa[b];512>a.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<f&&83==a.ra)return!1;d.push(f|(c?0:128));for(b=65<=b&&90>=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;c<d.length;c++)e=a,f=d[c],e.A&&(20>e.A.length?(A(e)&&y(e,"scan code "+t(f)+" buffered"),e.A.push(f),1== 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<f&&83==a.ra)return!1;d.push(f|(c?0:128));for(b=65<=b&&90>=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;c<d.length;c++)e=a,f=d[c],e.A&&(20>e.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<a.length;b++){var c=a[b],d=jb(c),d=new mm(d);mb(d,c)}}); 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<a.length;b++){var c=a[b],d=jb(c),d=new mm(d);mb(d,c)}});
function Z(a,b,c,d,e){var f=this;this.qf=Ga("Gecko/");var g=["","moz","ms","webkit"];Ua.call(this,"Video",a,Z,262144);this.ja=a.model;var h=Fm[this.ja]||Fm.mda;this.Ua=h[0];this.Ed=a.memory||0;this.bg=a.switches;this.wa=a.mode;if(null==this.wa||null==Gm[this.wa])this.wa=h[1];this.kd=a.charCols;this.le=a.charRows;if(void 0===this.kd||void 0===this.le)this.kd=Gm[this.wa][0],this.le=Gm[this.wa][1];this.ra=a.screenWidth;this.Ea=a.screenHeight;this.Wf=a.scale;this.tn=12<=Math.round(this.ra/this.kd);this.ka= function Z(a,b,c,d,e){var f=this;this.qf=Ga("Gecko/");var g=["","moz","ms","webkit"];Ua.call(this,"Video",a,Z,262144);this.ja=a.model;var h=Fm[this.ja]||Fm.mda;this.Ua=h[0];this.Ed=a.memory||0;this.bg=a.switches;this.wa=a.mode;if(null==this.wa||null==Gm[this.wa])this.wa=h[1];this.kd=a.charCols;this.le=a.charRows;if(void 0===this.kd||void 0===this.le)this.kd=Gm[this.wa][0],this.le=Gm[this.wa][1];this.ra=a.screenWidth;this.Ea=a.screenHeight;this.Wf=a.scale;this.tn=12<=Math.round(this.ra/this.kd);this.ka=
b;this.fa=c;this.V=(this.vk=d)||b||null;b=a.smoothing;(c=Ya.smoothing)&&(b="true"==c?!0:!1);if(null!=b)for(c=0;c<g.length;c++)if(d=(d=g[c])?d+"ImageSmoothingEnabled":"imageSmoothingEnabled",void 0!==this.fa[d]){this.fa[d]=b;break}this.gg=a.touchScreen;this.me=Hm;this.W=null;this.pi=a.autoLock;this.ob=this.ac=0;this.Oa=[];this.Ca=Array(this.Ua==dm?256:16);this.rb=!1;if(this.ia=e)if(this.ia.We=e.requestFullscreen||e.msRequestFullscreen||e.mozRequestFullScreen||e.webkitRequestFullscreen,this.ia.We){for(c= b;this.fa=c;this.V=(this.vk=d)||b||null;b=a.smoothing;(c=Ya.smoothing)&&(b="true"==c);if(null!=b)for(c=0;c<g.length;c++)if(d=(d=g[c])?d+"ImageSmoothingEnabled":"imageSmoothingEnabled",void 0!==this.fa[d]){this.fa[d]=b;break}this.gg=a.touchScreen;this.me=Hm;this.W=null;this.pi=a.autoLock;this.ob=this.ac=0;this.Oa=[];this.Ca=Array(this.Ua==dm?256:16);this.rb=!1;if(this.ia=e)if(this.ia.We=e.requestFullscreen||e.msRequestFullscreen||e.mozRequestFullScreen||e.webkitRequestFullscreen,this.ia.We){for(c=
0;c<g.length;c++)if(d=g[c]+"fullscreenchange","on"+d in document){document.addEventListener(d,function(){Im(f,document.fullscreenElement||document.msFullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement?!0:!1)},!1);break}for(c=0;c<g.length;c++)if(d=g[c]+"fullscreenerror","on"+d in document){document.addEventListener(d,function(){Im(f,null)},!1);break}}this.V&&(this.V.onfocus=function(){return f.Gg(!0)},this.V.onblur=function(){return f.Gg(!1)},this.V.De=this.V.requestPointerLock|| 0;c<g.length;c++)if(d=g[c]+"fullscreenchange","on"+d in document){document.addEventListener(d,function(){Im(f,document.fullscreenElement||document.msFullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement?!0:!1)},!1);break}for(c=0;c<g.length;c++)if(d=g[c]+"fullscreenerror","on"+d in document){document.addEventListener(d,function(){Im(f,null)},!1);break}}this.V&&(this.V.onfocus=function(){return f.Gg(!0)},this.V.onblur=function(){return f.Gg(!1)},this.V.De=this.V.requestPointerLock||
this.V.mozRequestPointerLock||this.V.webkitRequestPointerLock,this.V.sk=this.V.exitPointerLock||this.V.mozExitPointerLock||this.V.webkitExitPointerLock,this.V.De&&(e=function(){f.Vf(document.pointerLockElement===f.V||document.mozPointerLockElement===f.V||document.webkitPointerLockElement===f.V)},"onpointerlockchange"in document?document.addEventListener("pointerlockchange",e,!1):"onmozpointerlockchange"in document?document.addEventListener("mozpointerlockchange",e,!1):"onwebkitpointerlockchange"in this.V.mozRequestPointerLock||this.V.webkitRequestPointerLock,this.V.sk=this.V.exitPointerLock||this.V.mozExitPointerLock||this.V.webkitExitPointerLock,this.V.De&&(e=function(){f.Vf(document.pointerLockElement===f.V||document.mozPointerLockElement===f.V||document.webkitPointerLockElement===f.V)},"onpointerlockchange"in document?document.addEventListener("pointerlockchange",e,!1):"onmozpointerlockchange"in document?document.addEventListener("mozpointerlockchange",e,!1):"onwebkitpointerlockchange"in
document&&document.addEventListener("webkitpointerlockchange",e,!1)));if(a=a.fontROM)"json"!=ga(a)&&(a=xa()+"/api/v1/dump?file="+a+"&format=bytes"),va(a,null,!0,function(a,b,c){Jm(f,a,b,c)})}db(Z); document&&document.addEventListener("webkitpointerlockchange",e,!1)));if(a=a.fontROM)"json"!=ga(a)&&(a=xa()+"/api/v1/dump?file="+a+"&format=bytes"),va(a,null,!0,function(a,b,c){Jm(f,a,b,c)})}db(Z);

View file

@ -79,7 +79,7 @@ function Ec(a,b,c){var d=a.A,e=a.sb,f=d.ia.ja,g=d.ia.ya;if(!c){if(!(d.ia.type&51
v(d,d.fa(h+g)));c&&d.bb(h+0,f);d.Pa|=8;return!0}l.save=function(){return[this.ja,this.ya,this.Za,this.lb,this.id,this.Tf,this.sb,this.nc,this.hc,this.Nc,this.sa,this.U,this.N,this.type,this.C]};l.restore=function(a){"number"==typeof a?this.load(a):(this.ja=a[0],this.ya=a[1],this.Za=a[2],this.lb=a[3],this.id=a[4],this.Tf=a[5],this.sb=a[6],this.nc=a[7],this.hc=a[8],this.Nc=a[9]||2,this.sa=a[10]||65535,this.U=a[11]||2,this.N=a[12]||65535,this.type=a[13]||this.lb&7936,this.C=a[14]||(this.Za>>>0)+1)}; v(d,d.fa(h+g)));c&&d.bb(h+0,f);d.Pa|=8;return!0}l.save=function(){return[this.ja,this.ya,this.Za,this.lb,this.id,this.Tf,this.sb,this.nc,this.hc,this.Nc,this.sa,this.U,this.N,this.type,this.C]};l.restore=function(a){"number"==typeof a?this.load(a):(this.ja=a[0],this.ya=a[1],this.Za=a[2],this.lb=a[3],this.id=a[4],this.Tf=a[5],this.sb=a[6],this.nc=a[7],this.hc=a[8],this.Nc=a[9]||2,this.sa=a[10]||65535,this.U=a[11]||2,this.N=a[12]||65535,this.type=a[13]||this.lb&7936,this.C=a[14]||(this.Za>>>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= 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} 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.Zc.length;a++)this.Zc[a]||(this.Zc[a]=od);this.ma[84]=pd;this.ma[99]=qd;if(80386<=this.ca){var c;this.qh=0;this.od|= 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.Zc.length;a++)this.Zc[a]||(this.Zc[a]=od);this.ma[84]=pd;this.ma[99]=qd;if(80386<=this.ca){var c;this.qh=0;this.od|=
196608;this.ma[100]=rd;this.ma[101]=td;this.ma[102]=ud;this.ma[103]=vd;for(c in B)this.Zc[+c]=B[c];80546<=this.pd&&80562>=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); 196608;this.ma[100]=rd;this.ma[101]=td;this.ma[102]=ud;this.ma[103]=vd;for(c in B)this.Zc[+c]=B[c];80546<=this.pd&&80562>=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;b<a.mf;b++)a.S[b]=a.pf;a.Zd=new q;a.sh=Array(512);a.qf=0}else for(var c=0;c<a.nf.length;c++){b=a.nf[c];var d=a.S[b];512>a.qf&&(a.sh[a.qf++]=d);a.S[b]=a.pf}a.nf=[]} 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;b<a.mf;b++)a.S[b]=a.pf;a.Zd=new q;a.sh=Array(512);a.qf=0}else for(var c=0;c<a.nf.length;c++){b=a.nf[c];var d=a.S[b];512>a.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<f&&83==a.Z)return!1;d.push(f|(c?0:128));for(b=65<=b&&90>=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;c<d.length;c++)e=a,f=d[c],e.Pb&&(20>e.Pb.length?(e.Pb.push(f),1==e.Pb.length&&e.R&&Yj(e.R,f)):20==e.Pb.length&& 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<f&&83==a.Z)return!1;d.push(f|(c?0:128));for(b=65<=b&&90>=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;c<d.length;c++)e=a,f=d[c],e.Pb&&(20>e.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<a.length;b++){var c=a[b],d=Wa(c),d=new nk(d);Ya(d,c)}}); e.Pb.push(255));d=!0}return d}Ea(function(){for(var a=Za(document,"pcjs","keyboard"),b=0;b<a.length;b++){var c=a[b],d=Wa(c),d=new nk(d);Ya(d,c)}});
function Y(a,b,c,d,e){var f=this;this.$c=ya("Gecko/");var g=["","moz","ms","webkit"];Ia.call(this,"Video",a,Y);this.ca=a.model;var h=Fk[this.ca]||Fk.mda;this.Ra=h[0];this.Wc=a.memory||0;this.qd=a.switches;this.la=a.mode;if(null==this.la||null==Gk[this.la])this.la=h[1];this.Ob=a.charCols;this.wc=a.charRows;if(void 0===this.Ob||void 0===this.wc)this.Ob=Gk[this.la][0],this.wc=Gk[this.la][1];this.ea=a.screenWidth;this.pa=a.screenHeight;this.dd=a.scale;this.Zd=12<=Math.round(this.ea/this.Ob);this.Y=b; function Y(a,b,c,d,e){var f=this;this.$c=ya("Gecko/");var g=["","moz","ms","webkit"];Ia.call(this,"Video",a,Y);this.ca=a.model;var h=Fk[this.ca]||Fk.mda;this.Ra=h[0];this.Wc=a.memory||0;this.qd=a.switches;this.la=a.mode;if(null==this.la||null==Gk[this.la])this.la=h[1];this.Ob=a.charCols;this.wc=a.charRows;if(void 0===this.Ob||void 0===this.wc)this.Ob=Gk[this.la][0],this.wc=Gk[this.la][1];this.ea=a.screenWidth;this.pa=a.screenHeight;this.dd=a.scale;this.Zd=12<=Math.round(this.ea/this.Ob);this.Y=b;
this.P=c;this.G=(this.ae=d)||b||null;b=a.smoothing;(c=La.smoothing)&&(b="true"==c?!0:!1);if(null!=b)for(c=0;c<g.length;c++)if(d=(d=g[c])?d+"ImageSmoothingEnabled":"imageSmoothingEnabled",void 0!==this.P[d]){this.P[d]=b;break}this.rd=a.touchScreen;this.xc=Hk;this.K=null;this.Yd=a.autoLock;this.cb=this.Fb=0;this.xa=[];this.oa=Array(this.Ra==ek?256:16);this.La=!1;if(this.W=e)if(this.W.ke=e.requestFullscreen||e.msRequestFullscreen||e.mozRequestFullScreen||e.webkitRequestFullscreen,this.W.ke){for(c=0;c< this.P=c;this.G=(this.ae=d)||b||null;b=a.smoothing;(c=La.smoothing)&&(b="true"==c);if(null!=b)for(c=0;c<g.length;c++)if(d=(d=g[c])?d+"ImageSmoothingEnabled":"imageSmoothingEnabled",void 0!==this.P[d]){this.P[d]=b;break}this.rd=a.touchScreen;this.xc=Hk;this.K=null;this.Yd=a.autoLock;this.cb=this.Fb=0;this.xa=[];this.oa=Array(this.Ra==ek?256:16);this.La=!1;if(this.W=e)if(this.W.ke=e.requestFullscreen||e.msRequestFullscreen||e.mozRequestFullScreen||e.webkitRequestFullscreen,this.W.ke){for(c=0;c<g.length;c++)if(d=
g.length;c++)if(d=g[c]+"fullscreenchange","on"+d in document){document.addEventListener(d,function(){Ik(f,document.fullscreenElement||document.msFullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement?!0:!1)},!1);break}for(c=0;c<g.length;c++)if(d=g[c]+"fullscreenerror","on"+d in document){document.addEventListener(d,function(){Ik(f,null)},!1);break}}this.G&&(this.G.onfocus=function(){return f.Nf(!0)},this.G.onblur=function(){return f.Nf(!1)},this.G.Pd=this.G.requestPointerLock|| g[c]+"fullscreenchange","on"+d in document){document.addEventListener(d,function(){Ik(f,document.fullscreenElement||document.msFullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement?!0:!1)},!1);break}for(c=0;c<g.length;c++)if(d=g[c]+"fullscreenerror","on"+d in document){document.addEventListener(d,function(){Ik(f,null)},!1);break}}this.G&&(this.G.onfocus=function(){return f.Nf(!0)},this.G.onblur=function(){return f.Nf(!1)},this.G.Pd=this.G.requestPointerLock||this.G.mozRequestPointerLock||
this.G.mozRequestPointerLock||this.G.webkitRequestPointerLock,this.G.pj=this.G.exitPointerLock||this.G.mozExitPointerLock||this.G.webkitExitPointerLock,this.G.Pd&&(e=function(){f.bf(document.pointerLockElement===f.G||document.mozPointerLockElement===f.G||document.webkitPointerLockElement===f.G)},"onpointerlockchange"in document?document.addEventListener("pointerlockchange",e,!1):"onmozpointerlockchange"in document?document.addEventListener("mozpointerlockchange",e,!1):"onwebkitpointerlockchange"in this.G.webkitRequestPointerLock,this.G.pj=this.G.exitPointerLock||this.G.mozExitPointerLock||this.G.webkitExitPointerLock,this.G.Pd&&(e=function(){f.bf(document.pointerLockElement===f.G||document.mozPointerLockElement===f.G||document.webkitPointerLockElement===f.G)},"onpointerlockchange"in document?document.addEventListener("pointerlockchange",e,!1):"onmozpointerlockchange"in document?document.addEventListener("mozpointerlockchange",e,!1):"onwebkitpointerlockchange"in document&&document.addEventListener("webkitpointerlockchange",
document&&document.addEventListener("webkitpointerlockchange",e,!1)));if(a=a.fontROM)"json"!=ga(a)&&(a=qa()+"/api/v1/dump?file="+a+"&format=bytes"),pa(a,null,!0,function(a,b,c){Jk(f,a,b,c)})}Qa(Y); e,!1)));if(a=a.fontROM)"json"!=ga(a)&&(a=qa()+"/api/v1/dump?file="+a+"&format=bytes"),pa(a,null,!0,function(a,b,c){Jk(f,a,b,c)})}Qa(Y);
var ek=7,Fk={mda:[1,7],cga:[3,3],ega:[5,3],vga:[ek,3]},Kk={2:{Jf:15700,If:208,Of:85,Pf:96},3:{Jf:18432,If:364,Of:85,Pf:96},4:{Jf:21850,If:364,Of:85,Pf:96},7:{Jf:16700,If:480,Of:85,Pf:83}},Lk={6:[1,3,!0],7:[2,3,!0],8:[6,3,!0],9:[4,3,!0],10:[3,1,!0],11:[3,2,!0],0:[1,3,!1],1:[2,3,!1],2:[6,3,!1],3:[4,3,!1],4:[3,1,!1],5:[3,2,!1]},Gk=[,[40,25,1,0,3],,[80,25,1,0,3],[320,200,8,192],,[640,200,16,192],[80,25,1,0,1]];Gk[13]=[320,200,8];Gk[14]=[640,200,8];Gk[15]=[640,350,8];Gk[16]=[640,350,8]; var ek=7,Fk={mda:[1,7],cga:[3,3],ega:[5,3],vga:[ek,3]},Kk={2:{Jf:15700,If:208,Of:85,Pf:96},3:{Jf:18432,If:364,Of:85,Pf:96},4:{Jf:21850,If:364,Of:85,Pf:96},7:{Jf:16700,If:480,Of:85,Pf:83}},Lk={6:[1,3,!0],7:[2,3,!0],8:[6,3,!0],9:[4,3,!0],10:[3,1,!0],11:[3,2,!0],0:[1,3,!1],1:[2,3,!1],2:[6,3,!1],3:[4,3,!1],4:[3,1,!1],5:[3,2,!1]},Gk=[,[40,25,1,0,3],,[80,25,1,0,3],[320,200,8,192],,[640,200,16,192],[80,25,1,0,1]];Gk[13]=[320,200,8];Gk[14]=[640,200,8];Gk[15]=[640,350,8];Gk[16]=[640,350,8];
Gk[17]=[640,480,8];Gk[18]=[640,480,8];Gk[19]=[320,200,1];Gk[20]=[320,240,4];Gk[21]=[320,400,4];Gk[0]=Gk[1];Gk[2]=Gk[3];Gk[5]=Gk[4]; Gk[17]=[640,480,8];Gk[18]=[640,480,8];Gk[19]=[320,200,1];Gk[20]=[320,240,4];Gk[21]=[320,400,4];Gk[0]=Gk[1];Gk[2]=Gk[3];Gk[5]=Gk[4];
var Mk=[[0,0,0,255],[127,192,127,255],[127,192,127,255],[127,255,127,255],[127,255,127,255]],Nk=[0,1,2,2,2,2,2,2,0,3,4,4,4,4,4,4],Ok=[[0,0,0,255],[0,0,170,255],[0,170,0,255],[0,170,170,255],[170,0,0,255],[170,0,170,255],[170,85,0,255],[170,170,170,255],[85,85,85,255],[85,85,255,255],[85,255,85,255],[85,255,255,255],[255,85,85,255],[255,85,255,255],[255,255,85,255],[255,255,255,255]],Pk=[2,4,6],Qk=[3,5,7],Rk=[0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63],Sk=[0,255,65280,65535,16711680,16711935,16776960, var Mk=[[0,0,0,255],[127,192,127,255],[127,192,127,255],[127,255,127,255],[127,255,127,255]],Nk=[0,1,2,2,2,2,2,2,0,3,4,4,4,4,4,4],Ok=[[0,0,0,255],[0,0,170,255],[0,170,0,255],[0,170,170,255],[170,0,0,255],[170,0,170,255],[170,85,0,255],[170,170,170,255],[85,85,85,255],[85,85,255,255],[85,255,85,255],[85,255,255,255],[255,85,85,255],[255,85,255,255],[255,255,85,255],[255,255,255,255]],Pk=[2,4,6],Qk=[3,5,7],Rk=[0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63],Sk=[0,255,65280,65535,16711680,16711935,16776960,

View file

@ -107,24 +107,24 @@ Component.subclass(ChipSet);
ChipSet.SI_1978 = { ChipSet.SI_1978 = {
MODEL: 1978.1, MODEL: 1978.1,
STATUS0: { STATUS0: { // NOTE: STATUS0 not used by the SI_1978 ROMs; refer to STATUS1 instead
PORT: 0, PORT: 0,
DIP4: 0x01, // self-test request at power up? DIP4: 0x01, // self-test request at power up?
ALWAYS_SET: 0x0E, // always set
FIRE: 0x10, // 1 = fire FIRE: 0x10, // 1 = fire
LEFT: 0x20, // 1 = move left LEFT: 0x20, // 1 = left
RIGHT: 0x40, // 1 = move right RIGHT: 0x40, // 1 = right
PORT7: 0x80 // some connection to (undocumented) port 7 PORT7: 0x80, // some connection to (undocumented) port 7
ALWAYS_SET: 0x0E // always set
}, },
STATUS1: { STATUS1: {
PORT: 1, PORT: 1,
CREDIT: 0x01, // credit (coin slot) CREDIT: 0x01, // credit (coin slot)
P2: 0x02, // 1 = 2P start P2: 0x02, // 1 = 2P start
P1: 0x04, // 1 = 1P start P1: 0x04, // 1 = 1P start
ALWAYS_SET: 0x08, // always set P1_FIRE: 0x10, // 1 = fire (P1 fire if cocktail machine?)
P1_FIRE: 0x10, // 1 = P1 fire (cocktail machines only?) P1_LEFT: 0x20, // 1 = left (P1 left if cocktail machine?)
P1_LEFT: 0x20, // 1 = P1 left (cocktail machines only?) P1_RIGHT: 0x40, // 1 = right (P1 right if cocktail machine?)
P1_RIGHT: 0x40 // 1 = P1 right (cocktail machines only?) ALWAYS_SET: 0x08 // always set
}, },
STATUS2: { STATUS2: {
PORT: 2, PORT: 2,
@ -134,7 +134,8 @@ ChipSet.SI_1978 = {
P2_FIRE: 0x10, // 1 = P2 fire (cocktail machines only?) P2_FIRE: 0x10, // 1 = P2 fire (cocktail machines only?)
P2_LEFT: 0x20, // 1 = P2 left (cocktail machines only?) P2_LEFT: 0x20, // 1 = P2 left (cocktail machines only?)
P2_RIGHT: 0x40, // 1 = P2 right (cocktail machines only?) P2_RIGHT: 0x40, // 1 = P2 right (cocktail machines only?)
DIP7: 0x80 // 0 = display coin info on demo ("attract") screen DIP7: 0x80, // 0 = display coin info on demo ("attract") screen
ALWAYS_SET: 0x00
}, },
SHIFT_RESULT: { // bits 0-7 of barrel shifter result SHIFT_RESULT: { // bits 0-7 of barrel shifter result
PORT: 3 PORT: 3
@ -273,9 +274,9 @@ ChipSet.prototype.powerDown = function(fSave, fShutdown)
*/ */
ChipSet.prototype.reset = function() ChipSet.prototype.reset = function()
{ {
this.bStatus0 = 0; this.bStatus0 = ChipSet.SI_1978.STATUS0.ALWAYS_SET;
this.bStatus1 = 0; this.bStatus1 = ChipSet.SI_1978.STATUS1.ALWAYS_SET;
this.bStatus2 = 0; this.bStatus2 = ChipSet.SI_1978.STATUS2.ALWAYS_SET;
this.wShiftData = 0; this.wShiftData = 0;
this.bShiftCount = 0; this.bShiftCount = 0;
this.bSound1 = this.bSound2 = 0; this.bSound1 = this.bSound2 = 0;
@ -351,6 +352,45 @@ ChipSet.prototype.stop = function()
*/ */
}; };
/**
* updateStatus0(bit, fSet)
*
* @this {ChipSet}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus0 = function(bit, fSet)
{
this.bStatus0 &= ~bit;
if (fSet) this.bStatus0 |= bit;
};
/**
* updateStatus1(bit, fSet)
*
* @this {ChipSet}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus1 = function(bit, fSet)
{
this.bStatus1 &= ~bit;
if (fSet) this.bStatus1 |= bit;
};
/**
* updateStatus2(bit, fSet)
*
* @this {ChipSet}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus2 = function(bit, fSet)
{
this.bStatus2 &= ~bit;
if (fSet) this.bStatus2 |= bit;
};
/** /**
* inSIStatus0(port, addrFrom) * inSIStatus0(port, addrFrom)
* *

View file

@ -37,8 +37,7 @@ if (NODE) {
var web = require("../../shared/lib/weblib"); var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component"); var Component = require("../../shared/lib/component");
var Messages = require("./messages"); var Messages = require("./messages");
var State = require("./state"); var ChipSet = require("./chipset");
var CPU = require("./cpu");
} }
/** /**
@ -52,6 +51,8 @@ function Keyboard(parmsKbd)
{ {
Component.call(this, "Keyboard", parmsKbd, Keyboard, Messages.KEYBOARD); Component.call(this, "Keyboard", parmsKbd, Keyboard, Messages.KEYBOARD);
this.reset();
this.setReady(); this.setReady();
} }
@ -122,6 +123,16 @@ Keyboard.KEYCODE = {
/* 0x2E */ DEL: 46, /* 0x2E */ DEL: 46,
/* 0x2E */ FF_PERIOD: 46, /* 0x2E */ FF_PERIOD: 46,
/* 0x2F */ FF_SLASH: 47, /* 0x2F */ FF_SLASH: 47,
/* 0x30 */ ZERO: 48,
/* 0x31 */ ONE: 49,
/* 0x32 */ TWO: 50,
/* 0x33 */ THREE: 51,
/* 0x34 */ FOUR: 52,
/* 0x35 */ FIVE: 53,
/* 0x36 */ SIX: 54,
/* 0x37 */ SEVEN: 55,
/* 0x38 */ EIGHT: 56,
/* 0x39 */ NINE: 57,
/* 0x3B */ FF_SEMI: 59, /* 0x3B */ FF_SEMI: 59,
/* 0x3D */ FF_EQUALS: 61, /* 0x3D */ FF_EQUALS: 61,
/* 0x5B */ CMD: 91, // aka WIN /* 0x5B */ CMD: 91, // aka WIN
@ -210,6 +221,62 @@ Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.RBRACK] = Keyboard.ASCII[']']; // 2
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.QUOTE] = Keyboard.ASCII["'"]; // 222 -> 39 Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.QUOTE] = Keyboard.ASCII["'"]; // 222 -> 39
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.FF_DASH] = Keyboard.ASCII['-']; 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) * setBinding(sHTMLType, sBinding, control, sValue)
* *
@ -257,68 +324,24 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
control.onkeydown = function onKeyDown(event) { control.onkeydown = function onKeyDown(event) {
return kbd.onKeyDown(event, true); return kbd.onKeyDown(event, true);
}; };
control.onkeypress = function onKeyPressKbd(event) {
return kbd.onKeyPress(event);
};
control.onkeyup = function onKeyUp(event) { control.onkeyup = function onKeyUp(event) {
return kbd.onKeyDown(event, false); return kbd.onKeyDown(event, false);
}; };
return true; 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: default:
/* if (Keyboard.SOFTCODES[sBinding] !== undefined) {
* 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") {
this.bindings[id] = control; this.bindings[id] = control;
control.onclick = function(kbd, sKey, simCode) { var fnDown = function(kbd, sSoftCode) {
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) {
return function onMouseOrTouchDownKeyboard(event) { return function onMouseOrTouchDownKeyboard(event) {
kbd.addActiveKey(simCode); kbd.onSoftKeyDown(sSoftCode, true);
}; };
}(this, sBinding, Keyboard.SOFTCODES[sBinding]); }(this, sBinding);
var fnUp = function (kbd, sKey, simCode) { var fnUp = function (kbd, sSoftCode) {
return function onMouseOrTouchUpKeyboard(event) { return function onMouseOrTouchUpKeyboard(event) {
kbd.removeActiveKey(simCode); kbd.onSoftKeyDown(sSoftCode, false);
}; };
}(this, sBinding, Keyboard.SOFTCODES[sBinding]); }(this, sBinding);
if ('ontouchstart' in window) { if ('ontouchstart' in window) {
control.ontouchstart = fnDown; control.ontouchstart = fnDown;
control.ontouchend = fnUp; control.ontouchend = fnUp;
@ -328,19 +351,92 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
} }
return true; return true;
} }
else if (sValue) { break;
/* }
* 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 return false;
* 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) { * initBus(cmp, bus, cpu, dbg)
if (kbd.cmp) kbd.cmp.updateFocus(); *
return kbd.injectKeys(sValue); * @this {Keyboard}
}; * @param {Computer} cmp
return true; * @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; break;
} }
} }

View file

@ -245,6 +245,16 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0; this.nPixelsPerCell = (16 / this.nBitsPerPixel)|0;
this.initCache(); 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(); this.setReady();
}; };

View file

@ -566,6 +566,11 @@ Keyboard.KEYSTATES[Keyboard.SIMCODE.SCROLL_LOCK] = Keyboard.STATE.SCROLL_LOCK;
/** /**
* Maps CLICKCODE (string) to SIMCODE (number). * 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} * @enum {number}
*/ */
Keyboard.CLICKCODES = { Keyboard.CLICKCODES = {

View file

@ -165,7 +165,7 @@ function Video(parmsVideo, canvas, context, textarea, container)
*/ */
var fSmoothing = parmsVideo['smoothing']; var fSmoothing = parmsVideo['smoothing'];
var sSmoothing = Component.parmsURL['smoothing']; var sSmoothing = Component.parmsURL['smoothing'];
if (sSmoothing) fSmoothing = (sSmoothing == "true")? true : false; if (sSmoothing) fSmoothing = (sSmoothing == "true");
if (fSmoothing != null) { if (fSmoothing != null) {
for (i = 0; i < asWebPrefixes.length; i++) { for (i = 0; i < asWebPrefixes.length; i++) {
sEvent = asWebPrefixes[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 we're using an off-screen buffer in text mode, then we need to keep it in sync with "reality".
*/ */
if (this.contextScreenBuffer) { if (this.contextBuffer) {
this.updateChar(col, row, data, this.contextScreenBuffer); this.updateChar(col, row, data, this.contextBuffer);
} }
/* /*
* While updating the on-screen canvas directly could open us up to potential subpixel artifacts again, * 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 * allocating them, because updateChar(), as currently written, is capable of writing characters to
* either an off-screen or on-screen context. * 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; this.cxBuffer = this.cyBuffer = 0;
if (font) { if (font) {
@ -4888,11 +4888,11 @@ Video.prototype.setDimensions = function()
/* /*
* Allocate the off-screen buffers * Allocate the off-screen buffers
*/ */
this.imageScreenBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer); this.imageBuffer = this.contextScreen.createImageData(this.cxBuffer, this.cyBuffer);
this.canvasScreenBuffer = document.createElement("canvas"); this.canvasBuffer = document.createElement("canvas");
this.canvasScreenBuffer.width = this.cxBuffer; this.canvasBuffer.width = this.cxBuffer;
this.canvasScreenBuffer.height = this.cyBuffer; this.canvasBuffer.height = this.cyBuffer;
this.contextScreenBuffer = this.canvasScreenBuffer.getContext("2d"); this.contextBuffer = this.canvasBuffer.getContext("2d");
/* /*
* Since cxCell and cyCell were originally defined in terms of cxScreen/nCols and cyScreen/nRows, you might think * 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]) { if (!this.fCellCacheValid || data !== this.aCellCache[iCell]) {
var col = iCell % this.nCols; var col = iCell % this.nCols;
var row = (iCell / this.nCols)|0; var row = (iCell / this.nCols)|0;
this.updateChar(col, row, data, this.contextScreenBuffer); this.updateChar(col, row, data, this.contextBuffer);
this.aCellCache[iCell] = data; this.aCellCache[iCell] = data;
cUpdated++; cUpdated++;
} }
@ -5686,8 +5686,8 @@ Video.prototype.updateScreenText = function(addrScreen, addrScreenLimit, iCell,
this.fCellCacheValid = true; this.fCellCacheValid = true;
if (cUpdated && this.contextScreenBuffer) { if (cUpdated && this.contextBuffer) {
this.contextScreen.drawImage(this.canvasScreenBuffer, 0, 0, this.cxBuffer, this.cyBuffer, this.xScreenOffset, this.yScreenOffset, this.cxScreenOffset, this.cyScreenOffset); 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; if (x < xDirty) xDirty = x;
for (var iPixel = 0; iPixel < nPixelsPerCell; iPixel++) { for (var iPixel = 0; iPixel < nPixelsPerCell; iPixel++) {
var bPixel = (wPixels & (wMask >>= nPixelShift)) >> (nShift -= nPixelShift); 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 (x > xMaxDirty) xMaxDirty = x;
if (y < yDirty) yDirty = y; if (y < yDirty) yDirty = y;
@ -5748,30 +5748,30 @@ Video.prototype.updateScreenGraphicsCGA = function(addrScreen, addrScreenLimit)
this.fCellCacheValid = true; this.fCellCacheValid = true;
/* /*
* Instead of blasting the ENTIRE imageScreenBuffer into contextScreenBuffer, and then blasting the ENTIRE * Instead of blasting the ENTIRE imageBuffer into contextBuffer, and then blasting the ENTIRE
* canvasScreenBuffer onto contextScreen, even for the smallest change, let's try to be a bit smarter about * 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). * the update (well, to the extent that the canvas APIs permit).
*/ */
if (xDirty < this.nCols) { if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty; var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty; var cyDirty = yMaxDirty - yDirty;
// this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0); // this.contextBuffer.putImageData(this.imageBuffer, 0, 0);
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty); 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 * While ideally I would draw only the dirty portion of canvasBuffer, there usually isn't a 1-1 pixel mapping
* between canvasScreenBuffer and contextScreen. In fact, the WHOLE POINT of the canvasScreenBuffer is to leverage * 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 * 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 * 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. * on every change.
* *
var xScreen = (((xDirty * this.cxScreen) / this.nCols) | 0); var xScreen = (((xDirty * this.cxScreen) / this.nCols) | 0);
var yScreen = (((yDirty * this.cyScreen) / this.nRows) | 0); var yScreen = (((yDirty * this.cyScreen) / this.nRows) | 0);
var cxScreen = (((cxDirty * this.cxScreen) / this.nCols) | 0); var cxScreen = (((cxDirty * this.cxScreen) / this.nCols) | 0);
var cyScreen = (((cyDirty * this.cyScreen) / this.nRows) | 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. * index, which is what this code requires.
*/ */
var bPixel = Video.aEGADWToByte[dwPixel] || 0; var bPixel = Video.aEGADWToByte[dwPixel] || 0;
this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]); this.setPixel(this.imageBuffer, x++, y, aPixelColors[bPixel]);
data <<= 1; data <<= 1;
} }
if (x > xMaxDirty) xMaxDirty = x; if (x > xMaxDirty) xMaxDirty = x;
@ -5888,8 +5888,8 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
if (xDirty < this.nCols) { if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty; var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty; var cyDirty = yMaxDirty - yDirty;
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty); this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
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);
} }
}; };
@ -5957,7 +5957,7 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
if (nPixels) { if (nPixels) {
if (x < xDirty) xDirty = x; if (x < xDirty) xDirty = x;
for (iPixel = 0; iPixel < nPixels; iPixel++) { 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; data >>= 8;
} }
if (x > xMaxDirty) xMaxDirty = x; if (x > xMaxDirty) xMaxDirty = x;
@ -5984,8 +5984,8 @@ Video.prototype.updateScreenGraphicsVGA = function(addrBuffer, addrScreen, addrS
if (xDirty < this.nCols) { if (xDirty < this.nCols) {
var cxDirty = xMaxDirty - xDirty; var cxDirty = xMaxDirty - xDirty;
var cyDirty = yMaxDirty - yDirty; var cyDirty = yMaxDirty - yDirty;
this.contextScreenBuffer.putImageData(this.imageScreenBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty); this.contextBuffer.putImageData(this.imageBuffer, 0, 0, xDirty, yDirty, cxDirty, cyDirty);
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);
} }
}; };