tty part 2 - theoretically

This commit is contained in:
Lisa Milne 2023-12-12 17:03:04 +10:00
parent b1e45d7627
commit c5917c0e81
3 changed files with 120 additions and 586 deletions

View file

@ -424,18 +424,26 @@ bios.input.keyboard = {
switch (key) {
case "Down":
case "ArrowDown":
k.char = String.fromCharCode(17);
k.lchr = k.char;
k.code = 17;
break;
case "Up":
case "ArrowUp":
k.char = String.fromCharCode(18);
k.lchr = k.char;
k.code = 18;
break;
case "Left":
case "ArrowLeft":
k.char = String.fromCharCode(19);
k.lchr = k.char;
k.code = 19;
break;
case "Right":
case "ArrowRight":
k.char = String.fromCharCode(20);
k.lchr = k.char;
k.code = 20;
break;
case "Enter":
@ -445,9 +453,13 @@ bios.input.keyboard = {
break;
case "Esc":
case "Escape":
k.char = String.fromCharCode(27);
k.lchr = k.char;
k.code = 27;
break;
case "Shift":
k.char = String.fromCharCode(15);
k.lchr = k.char;
k.code = 15;
break;
case "Tab":

View file

@ -548,6 +548,7 @@ license.txt:/etc/license:0:0:-rw-r--r--`;
}
}
function init5(env,io) {
clite.tty.clear(0);
clite.proc.setLogin(io.pid,1);
clite.lib.exec('/bin/sh',['sh'],env,io);
}
@ -2217,6 +2218,22 @@ clite.tty = {
}else{
clite.console.drawAt(updateX,updateY,clite.tty.data.ttys[id].data[updateY][updateX]);
}
},
popLine:function(t) {
var off = -1;
var l = '';
for (var i=0; i<t.buff.length; i++) {
if (t.buff[i].code == 10) {
off = i+1;
break;
}
l += t.buff[i].char;
}
if (off < 0)
return null;
t.buff = t.buff.slice(off);
return l;
}
},
init:function(vfsapi) {
@ -2229,7 +2246,18 @@ clite.tty = {
}
}
var id = clite.tty.data.ttys.length;
var t = {id:id,x:0,y:0,fg:15,bg:0,data:l};
var t = {
id:id,
x:0,
y:0,
fg:15,
bg:0,
data:l,
rcb:null,
buff:[],
raw:false,
echo:true
};
clite.tty.data.ttys.push(t);
@ -2251,11 +2279,60 @@ clite.tty = {
return t;
}
clite.tty.internal.genTTY();
clite.tty.data.active = clite.tty.internal.genTTY();
if (!clite.tty.data.active)
return false;
clite.tty.data.activeID = clite.tty.data.active.id;
return true;
},
input:function(key) {
if (!clite.tty.data.active)
return;
var t = clite.tty.data.active;
if (t.echo)
clite.tty.write(t.id,key.char);
if (t.raw) {
if (typeof t.rcb === 'function') {
t.rcb(key.char);
}else{
t.buff.push(key);
}
return;
}
t.buff.push(key);
if (key.code != 10)
return;
if (typeof t.rcb !== 'function')
return;
var l = clite.tty.internal.popLine(t);
if (!l)
return;
t.rcb(l);
t.rcb = null;
},
read:function(id,cb) {
if (id<0 || id>=clite.tty.data.ttys.length)
return false;
var t = clite.tty.data.ttys[id];
if (t.raw) {
if (t.buff.length > 0) {
var k = t.buff.shift();
cb(k.char);
return true;
}
}else{
var l = clite.tty.internal.popLine(t);
if (l != null) {
cb(l);
return true;
}
}
clite.tty.data.ttys[id].rcb = cb;
return true;
},
write:function(id,str) {
if (id<0 || id>=clite.tty.data.ttys.length)
@ -2278,6 +2355,27 @@ clite.tty = {
clite.tty.internal.write(id,ch);
}
}
},
clear:function(id) {
if (id<0 || id>=clite.tty.data.ttys.length)
return;
var t = clite.tty.data.ttys[id];
for (var y=0; y<25; y++) {
t.data[y] = [];
for (var x=0; x<80; x++) {
t.data[y].push({bg:t.bg,fg:t.fg,bk:false,ch:' '});
}
}
t.x = 0;
t.y = 0;
if (id != clite.tty.data.activeID)
return;
clite.console.drawBuff(t.data);
clite.console.setCursor(0,0);
}
};
@ -2314,10 +2412,10 @@ clite.console = {
if (clite.console.data.state == 1) {
for (var y=0; y<25; y++) {
for (var x=0; x<80; x++) {
unix.vga.io.write(x,y,buff[y][x].ch);
unix.vga.io.writeSet(0,x,y,buff[y][x].bg);
unix.vga.io.writeSet(1,x,y,buff[y][x].fg);
unix.vga.io.writeSet(2,x,y,buff[y][x].bk);
clite.console.data.vgaio.write(x,y,buff[y][x].ch);
clite.console.data.vgaio.writeSet(0,x,y,buff[y][x].bg);
clite.console.data.vgaio.writeSet(1,x,y,buff[y][x].fg);
clite.console.data.vgaio.writeSet(2,x,y,buff[y][x].bk);
}
}
}
@ -2325,10 +2423,10 @@ clite.console = {
drawLine:function(y,buff) {
if (clite.console.data.state == 1) {
for (var x=0; x<80; x++) {
unix.vga.io.write(x,y,buff[x].ch);
unix.vga.io.writeSet(0,x,y,buff[x].bg);
unix.vga.io.writeSet(1,x,y,buff[x].fg);
unix.vga.io.writeSet(2,x,y,buff[x].bk);
clite.console.data.vgaio.write(x,y,buff[x].ch);
clite.console.data.vgaio.writeSet(0,x,y,buff[x].bg);
clite.console.data.vgaio.writeSet(1,x,y,buff[x].fg);
clite.console.data.vgaio.writeSet(2,x,y,buff[x].bk);
}
}
},

View file

@ -1,576 +0,0 @@
var bios = {
data:{
version:0.1,
vga:null,
id:'BIOS'
},
lib:{
code:{
base:null,
load:function(name,callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
var file = '';
if (bios.lib.code.base != null)
file += bios.lib.code.base+'/';
file +=name+'.js';
script.type = 'text/javascript';
script.src = file;
script.onload = callback;
head.appendChild(script);
}
},
getHex:function(s) {
if (typeof s === 'string')
s = parseInt(s);
if (typeof s !== 'number')
return '0';
return s.toString(16).toUpperCase();
},
writeStringVC:function(x,y,v) {
for (var i=0; i<v.length; i++) {
if (x+i >= 80)
break;
bios.video.internal.write(x+i,y,v[i]);
}
},
writeStringVGA:function(x,y,v,fg) {
for (var i=0; i<v.length; i++) {
if (x+i >= 80)
break;
bios.data.vga.write(x+i,y,v[i]);
}
if (typeof fg === 'undefined')
return;
for (var i=0; i<v.length; i++) {
if (x+i >= 80)
break;
bios.data.vga.writeSet(1,x+i,y,fg);
}
}
},
input:{
el:null,
devices:[],
readers:[],
device:{
register:function(name,data) {
if (typeof bios.input.devices[name] !== 'undefined')
return false;
if (typeof data !== 'object')
return false;
if (typeof data.element === 'undefined')
return false;
bios.input.devices[name] = data;
bios.input.el = document.getElementById('input');
bios.input.el.appendChild(data.element);
return true;
},
deregister:function(name) {
}
},
reader:{
register:function(name,caller) {
if (typeof bios.input.devices[name] === 'undefined')
return null;
bios.input.readers[caller] = name;
return bios.input.devices[name];
},
deregister:function(name) {
if (typeof bios.input.readers[name] === 'undefined')
return;
delete bios.input.readers[name];
}
}
},
output:{
el:null,
devices:{},
writers:[],
device:{
register:function(name,data) {
if (typeof bios.output.devices[name] !== 'undefined')
return false;
if (typeof data !== 'object')
return false;
if (typeof data.element === 'undefined')
return false;
bios.output.devices[name] = data;
if (name === 'vga')
return true;
if (data.element) {
bios.output.el = document.getElementById('output');
bios.output.el.appendChild(data.element);
}
return true;
},
deregister:function(name) {
if (typeof bios.output.devices[name] === 'undefined')
return;
if (name !== 'vga' && bios.output.devices[name].element)
bios.output.el.removeChild(bios.output.devices[name].element);
delete bios.output.devices[name];
}
},
writer:{
register:function(name,caller) {
if (typeof bios.output.devices[name] === 'undefined')
return null;
bios.output.writers[caller] = name;
return bios.output.devices[name];
},
deregister:function(name) {
if (typeof bios.output.writers[name] === 'undefined')
return;
delete bios.output.writers[name];
}
},
},
io:{
data:{
interrupts:{}
},
read:function(c) {
switch (c) {
case 0:
return bios.data.id;
break;
default:;
}
return null;
},
write:function(c,d) {
switch (c) {
case 0:
bios.data.id = d;
document.title = d;
break;
case 1:
bios.fault.data.handler = d;
break;
case 2:
bios.io.interrupt.setHandler('kbd',d);
break;
default:;
}
},
wait:function(cb,ms) {
if (bios.fault.data.faulted)
return;
setTimeout(function() {
try{
cb();
}catch(e) {
bios.fault.process(e);
}
},ms);
},
interrupt:{
create:function(name,faults) {
if (typeof bios.io.data.interrupts[name] !== 'undefined')
return false;
bios.io.data.interrupts[name] = {
name:name,
crit:faults,
handler:null
};
return true;
},
setHandler:function(name,cb) {
if (typeof bios.io.data.interrupts[name] === 'undefined')
return false;
bios.io.data.interrupts[name].handler = cb;
return true;
},
fire:function(name,data) {
if (typeof bios.io.data.interrupts[name] === 'undefined')
return;
if (bios.io.data.interrupts[name].handler == null) {
if (bios.io.data.interrupts[name].crit) {
bios.fault.process(new Error('Unhandled Interrupt'));
}
return;
}
try{
bios.io.data.interrupts[name].handler(data);
}catch(e) {
bios.fault.process(new Error('Unhandled Interrupt'));
}
}
},
setCPU:function(data) {},
getCPU:function() {}
},
fault:{
data:{
handler:null,
faulted:false
},
process:function(e) {
if (!bios.fault.data.handler)
return bios.fault.triple(e);
try{
bios.fault.data.handler(e.message);
}catch(err) {
bios.fault.triple(e);
}
},
triple:function(e) {
bios.fault.data.faulted = true;
console.log('Triple Fault');
throw e;
}
},
init:function() {
bios.io.write(0,'WEB BIOS '+bios.data.version);
bios.video.init();
bios.lib.writeStringVC(2,0,'JS Basic Input Output System');
var v = bios.data.version.toString();
bios.lib.writeStringVC(78-v.length,0,v);
bios.lib.writeStringVC(3,1,'Initialising...');
bios.lib.writeStringVC(3,2,'Video Core:');
bios.lib.writeStringVC(25,2,'Done');
bios.lib.writeStringVC(3,3,'Video Graphics Array:');
bios.video.initVGA();
bios.data.vga = bios.output.writer.register('vga','biosvga');
if (bios.data.vga == null) {
bios.lib.writeStringVC(25,3,'Failed');
return;
}
for (var i=0; i<80; i++) {
bios.data.vga.writeSet(0,i,0,15);
bios.data.vga.writeSet(1,i,0,0);
}
for (var i=25; i<30; i++) {
bios.data.vga.writeSet(1,i,2,2);
}
bios.lib.writeStringVGA(25,3,'Done',2);
bios.lib.writeStringVGA(3,4,'Keyboard:');
bios.keyboard.init();
bios.lib.writeStringVGA(25,4,'Done',2);
bios.lib.writeStringVGA(3,5,'Audio:');
bios.audio.init();
bios.lib.writeStringVGA(25,5,'Done',2);
bios.lib.writeStringVGA(3,7,'Seeking Bootable Device...');
var d = bios.storage.io.test();
for (var i=0; i<d.length; i++) {
bios.storage.io.test(d[i]);
}
bios.lib.writeStringVGA(3,8,d.toString());
bios.output.writer.deregister('biosvga');
bios.audio.bell();
bios.proc.init();
},
power:{
off:function() {
var pb = document.createElement('button');
pb.className = 'power';
pb.id = 'power';
pb.type = 'button';
pb.innerText = 'Power On';
pb.onclick = bios.power.on;
var v = document.getElementById('vga');
v.innerHTML = '';
v.appendChild(pb);
},
on:function() {
var pb = document.getElementById('power');
pb.parentNode.removeChild(pb);
setTimeout(bios.init,10);
}
}
};
bios.video = {
data:{
el:null,
isinit:false
},
internal:{
write:function(x,y,v) {
if (x < 0 || x > 79 || y < 0 || y > 24)
return;
var c = bios.video.getPix(x,y);
c.textContent = v;
},
setBG:function(x,y,id) {
if (id < 0 || id > 15)
return;
var c = bios.video.getPix(x,y);
c.data.bg = bios.lib.getHex(id);
c.className = bios.video.internal.dataToClass(c.data);
},
setFG:function(x,y,id) {
if (id < 0 || id > 15)
return;
var c = bios.video.getPix(x,y);
c.data.fg = bios.lib.getHex(id);
c.className = bios.video.internal.dataToClass(c.data);
},
setBlink:function(x,y,id) {
if (typeof id !== 'boolean')
return;
var c = bios.video.getPix(x,y);
c.data.bk = id;
c.className = bios.video.internal.dataToClass(c.data);
},
writeSet:function(name,x,y,id) {
if (x < 0 || x > 79 || y < 0 || y > 24)
return;
switch(name) {
case 0:
bios.video.internal.setBG(x,y,id);
break;
case 1:
bios.video.internal.setFG(x,y,id);
break;
case 2:
bios.video.internal.setBlink(x,y,id);
break;
default:;
}
},
dataToClass:function(d) {
var c = 'vga-b'+d.bg+' vga-f'+d.fg;
if (d.bk)
c += ' vga-blink';
return c;
}
},
io:{},
getElement:function() {
bios.video.data.el = document.getElementById('vga');
if (typeof bios.video.data.el !== 'undefined' && bios.video.data.el != null)
return bios.video.data.el;
bios.video.data.el = document.createNode('div');
bios.video.data.el.id = 'vga';
bios.video.data.el.className = 'vga';
document.body.appendChild(bios.video.data.el);
return bios.video.data.el;
},
getPix:function(x,y) {
return document.getElementById('vga-'+y+'-'+x);
},
setMode:function(modedata) {
if (modedata === null || typeof modedata !== 'object')
return false;
if (typeof modedata.write !== 'function')
return false;
if (typeof modedata.el === 'undefined')
modedata.el = bios.video.getElement();
if (bios.video.data.el == modedata.el) {
modedata.el.innerHTML = '';
}else{
if (modedata.el.parentNode != bios.video.data.el)
bios.video.data.el.appendChild(modedata.el);
}
bios.video.io = modedata;
return true;
},
init:function() {
bios.video.internal.el = bios.video.getElement();
if (!bios.video.setMode(bios.video.internal))
return false;
bios.video.data.el.innerHTML = '';
var ypx;
var xpx;
var c = document.createElement('span');
c.textContent = 'W';
bios.video.data.el.appendChild(c);
ypx = c.offsetHeight;
xpx = c.offsetWidth;
bios.video.data.el.innerHTML = '';
bios.video.data.el.style.width = (xpx*80)+'px';
bios.video.data.el.style.height = (ypx*25)+'px';
bios.video.data.el.style.position = 'relative';
for (var y=0; y<25; y++) {
for (var x=0; x<80; x++) {
var c = document.createElement('div');
c.className = 'vga-b0 vga-fF';
c.style.position = 'absolute';
c.style.top = (y*ypx)+'px';
c.style.left = (x*xpx)+'px';
c.style.width = xpx+'px';
c.style.height = ypx+'px';
c.data = {bg:'0',fg:'F',bk:false};
c.id = 'vga-'+y+'-'+x;
bios.video.data.el.appendChild(c);
}
}
bios.video.data.isinit = true;
return bios.video.data.isinit;
},
initVGA:function() {
var e = bios.video.getElement();
e.style.cursor = 'none';
bios.output.device.register('vga',{element:e,write:bios.video.io.write,writeSet:bios.video.io.writeSet,reinit:bios.video.reinit});
},
reinit:function() {
}
};
bios.keyboard = {
data:{
el:null
},
internal:{
rawDown:function(e) {
if (e.isComposing)
return;
var k = {
down:true,
code:0,
char:0,
lchr:0
};
if (e.key.length == 1) {
k.char = e.key;
k.lchr = e.key.toLowerCase();
k.code = k.lchr.charCodeAt(0);
}else{
bios.keyboard.internal.getKeyData(e.key,k);
}
//console.log('rawDown: "'+k.char+'":"'+k.lchr+'":"'+k.code+'"');
if (k.code == 0)
return false;
bios.io.interrupt.fire('kbd',k);
return false;
},
rawUp:function(e) {
if (e.isComposing)
return;
var k = {
down:false,
code:0,
char:0,
lchr:0
};
if (e.key.length == 1) {
k.char = e.key;
k.lchr = e.key.toLowerCase();
k.code = k.lchr.charCodeAt(0);
}else{
bios.keyboard.internal.getKeyData(e.key,k);
}
if (k.code == 0)
return false;
bios.io.interrupt.fire('kbd',k);
return false;
},
resetFocus:function(e) {
bios.io.wait(function() {document.getElementById('kbd').focus()},1);
return false;
},
getKeyData:function(key,k) {
switch (key) {
case "Down":
case "ArrowDown":
k.code = 17;
break;
case "Up":
case "ArrowUp":
k.code = 18;
break;
case "Left":
case "ArrowLeft":
k.code = 19;
break;
case "Right":
case "ArrowRight":
k.code = 20;
break;
case "Enter":
k.char = String.fromCharCode(10);
k.lchr = k.char;
k.code = 10;
break;
case "Esc":
case "Escape":
k.code = 27;
break;
case "Shift":
k.code = 15;
break;
case "Tab":
k.char = String.fromCharCode(9);
k.lchr = k.char;
k.code = 9;
break;
case "Delete":
k.char = String.fromCharCode(127);
k.lchr = k.char;
k.code = 127;
break;
default:
k.code = key;
}
}
},
getElement:function() {
bios.keyboard.data.el = document.getElementById('kbd');
if (typeof bios.keyboard.data.el === 'undefined' || bios.keyboard.data.el == null) {
bios.keyboard.data.el = document.createElement('textarea');
bios.keyboard.data.el.id = 'kbd';
bios.keyboard.data.el.className = 'kbd';
bios.keyboard.data.el.style.zIndex = '100';
bios.keyboard.data.el.style.display = 'block';
}
bios.keyboard.data.el.addEventListener('keydown',bios.keyboard.internal.rawDown);
bios.keyboard.data.el.addEventListener('keyup',bios.keyboard.internal.rawUp);
bios.keyboard.data.el.addEventListener('focusout',bios.keyboard.internal.resetFocus);
return bios.keyboard.data.el;
},
init:function() {
var e = bios.keyboard.getElement();
bios.io.interrupt.create('kbd',false);
// register the device without a read call, as this device fires interrupts
bios.input.device.register('kbd',{element:e,read:null,reinit:bios.video.reinit});
e.focus();
bios.keyboard.internal.resetFocus();
},
reinit:function() {
}
};
bios.audio = {
data:{
isinit:false,
noped:false,
bell:null,
output:null,
input:null
},
init:function() {
bios.audio.data.output = new Audio();
bios.audio.data.bell = new Audio('beep.mp3');
bios.audio.data.bell.addEventListener("canplaythrough", function(e) {
// play it as soon as possible to test if audio is possible
var promise = bios.audio.data.bell.play();
if (promise !== undefined) {
promise.then(_ => {
bios.audio.data.isinit = true;
}).catch(error => {
bios.audio.data.noped = true;
});
}
});
bios.output.device.register('bell',{element:null,write:bios.audio.bell,writeSet:function() {},reinit:function() {}});
},
bell:function() {
if (!bios.audio.data.isinit)
return;
bios.audio.data.bell.play();
},
reinit:function() {
}
};