Files
Landon Curt Noll 09750f8899 release winning entries of IOCCC28 under the year 2024
Congratulations to:

* 2024/anders - Prize in sound coding - layered music generator
* 2024/burton - Prize in pentagrammatology - wordle hard mode solver
* 2024/cable1 - Prize in bot talk - LLM inference engine
* 2024/cable2 - Prize in murky waters - salmon recipe
* 2024/carlini - Prize in perfect timing - Intel 4004 emulation
* 2024/codemeow - Prize in tray planting - bonsai generator
* 2024/endoh1 - Prize in patient pointillism - slow ray tracer in CPP
* 2024/endoh2 - Prize in solid body physics - rotating rigid body simulation
* 2024/ferguson1 - Prize in diabolical logistics - Oregon trail pact with the devil
* 2024/ferguson2 - Prize in yil-tas - Navajo code talker translator
* 2024/howe - Nice accent eh-ward - mini vi
* 2024/kramer - Prize in linguistic arithmetic - natural language numerical calculator
* 2024/kurdyukov1 - Prize in phased periodicity - phase of the Moon
* 2024/kurdyukov2 - Prize in art restoration - JPEG artifact removal
* 2024/kurdyukov3 - Prize in virtual quietus - gaming VM and doom
* 2024/kurdyukov4 - Prize in embiggening - encode without literals
* 2024/maffiodo - Prize in creative interpretation - Jav\*script interpreter
* 2024/mills - Prize in ℤ₃ - Infocom v3 story interpreter
* 2024/stedolan - Best one liner - icon from MD5
* 2024/straadt - Prize in imitative rebooting - OpenRISC CPU and Linux
* 2024/tmarrec - Prize in cyclonic coding - 3D tornado simulation
* 2024/tompng - Prize in quasi bijection - vortex encryptor decryptor
* 2024/weaver - Sur prize - rickroll

Ran `make update` to perform the above.
 	new file:   2024/burton/.entry.json
2025-08-02 14:43:07 -07:00

1094 lines
34 KiB
HTML

<!doctype html>
<html lang="en">
<title>Emulator</title>
<meta charset="UTF-8"/>
<style>
.terminal {
border: 0px solid black;
font-family: courier, fixed, swiss, monospace, sans-serif;
font-size: 12px;
color: #bbbbbb;
background: #000000;
border-collapse: collapse;
}
</style>
<table id="tty" class="terminal" cellpadding="0" cellspacing="0"></table>
<script>
"use strict";
function UTF8StreamToUnicode() {
this.stream = new Uint8Array(5);
this.ofs = 0;
this.Put = function (key) {
this.stream[this.ofs] = key;
this.ofs++;
switch (this.ofs) {
case 1:
if (this.stream[0] < 0x80) {
this.ofs = 0;
return this.stream[0];
}
break;
case 2:
if ((this.stream[0] & 0xE0) == 0xC0)
if ((this.stream[1] & 0xC0) == 0x80) {
this.ofs = 0;
return ((this.stream[0] & 0x1F) << 6) |
((this.stream[1] & 0x3F) << 0);
}
break;
case 3:
if ((this.stream[0] & 0xF0) == 0xE0)
if ((this.stream[1] & 0xC0) == 0x80)
if ((this.stream[2] & 0xC0) == 0x80) {
this.ofs = 0;
return ((this.stream[0] & 0xF) << 12) |
((this.stream[1] & 0x3F) << 6) |
((this.stream[2] & 0x3F) << 0);
}
break;
case 4:
if ((this.stream[0] & 0xF8) == 0xF0)
if ((this.stream[1] & 0xC0) == 0x80)
if ((this.stream[2] & 0xC0) == 0x80)
if ((this.stream[3] & 0xC0) == 0x80) {
this.ofs = 0;
return ((this.stream[0] & 0x7) << 18) |
((this.stream[1] & 0x3F) << 12) |
((this.stream[2] & 0x3F) << 6) |
((this.stream[3] & 0x3F) << 0);
}
this.ofs = 0;
return -1; //obviously illegal character, so reset
break;
default:
this.ofs = 0;
return -1;
break;
}
return -1;
}
}
function UnicodeToUTF8Stream(key) {
key = key | 0;
if (key < 0x80) {
return [key];
} else if (key <= 0x7FF) {
return [
(key >> 6) | 0xC0,
(key & 0x3F) | 0x80
];
} else if (key <= 0xFFFF) {
return [
(key >> 12) | 0xE0,
((key >> 6) & 0x3F) | 0x80,
(key & 0x3F) | 0x80
];
} else if (key <= 0x10FFFF) {
return [
(key >> 18) | 0xF0,
((key >> 12) & 0x3F) | 0x80,
((key >> 6) & 0x3F) | 0x80,
(key & 0x3F) | 0x80
];
} else {
//console.log("Error in utf-8 encoding: Invalid key");
}
return [];
}
function UTF8Length(s) {
var length = 0;
for (var i = 0; i < s.length; i++) {
var key = s.charCodeAt(i);
if (key < 0x80) {
length += 1;
} else if (key <= 0x7FF) {
length += 2;
} else if (key <= 0xFFFF) {
length += 3;
} else if (key <= 0x10FFFF) {
length += 4;
} else {
}
}
return length;
}
const Colors = ["#000000", "#BB0000", "#00BB00", "#BBBB00",
"#0000BB", "#BB00BB", "#00BBBB", "#BBBBBB",
// brighter colors
"#555555", "#FF5555", "#55FF55", "#FFFF55",
"#5555FF", "#FF55FF", "#55FFFF", "#FFFFFF",
// dimmed colors
"#000000", "#770000", "#007700", "#777700",
"#000077", "#770077", "#007777", "#777777"];
// constructor
function Terminal(nrows, ncolumns, elemId) {
let i;
this.nrows = nrows;
this.ncolumns = ncolumns;
let ele = document.getElementById(elemId);
this.Table = ele;
this.rowelements = new Array(this.nrows);
for (i = 0; i < nrows; i++) {
let TR = this.Table.insertRow(0);
let TD = document.createElement("td");
this.rowelements[i] = TD;
TR.appendChild(TD);
}
// after appending new elements, Firefox needs some form of reset of the root class.
this.Table.className = this.Table.className;
this.cursorvisible = false;
this.escapetype = 0;
this.escapestring = "";
this.cursorx = 0;
this.cursory = 0;
this.scrolltop = 0;
this.cursortype = 1;
this.scrollbottom = this.nrows - 1;
this.attr_color = 0x7;
this.attr_reverse = false;
this.attr_italic = false;
this.attr_intensity = 0x1;
this.pauseblink = false;
this.OnCharReceived = function () {
};
this.framerequested = false;
this.timeout = 30; // the time in ms when the next frame is drawn
this.updaterow = new Uint8Array(this.nrows);
this.utf8converter = new UTF8StreamToUnicode();
this.screen = new Array(this.nrows);
this.color = new Array(this.nrows);
for (i = 0; i < this.nrows; i++) {
this.updaterow[i] = 1;
this.screen[i] = new Uint16Array(this.ncolumns);
this.color[i] = new Uint16Array(this.ncolumns);
for (let j = 0; j < this.ncolumns; j++) {
this.screen[i][j] = 0x20;
this.color[i][j] = this.attr_color;
}
}
this.UpdateScreen();
this.Blink();
}
Terminal.prototype.GetColor = function () {
let c = this.attr_color;
if (this.attr_reverse) {
c = ((c & 0x7) << 8) | ((c >> 8)) & 0x7;
}
if (this.attr_intensity === 2) {
c = c | 0x8;
} else if (this.attr_intensity === 0) {
c = c | 0x10;
}
return c;
}
Terminal.prototype.Blink = function () {
this.cursorvisible = !this.cursorvisible;
if (!this.pauseblink) this.PrepareUpdateRow(this.cursory, this.cursorx);
window.setTimeout(this.Blink.bind(this), 500); // update every half second
};
Terminal.prototype.DeleteRow = function (row) {
for (let j = 0; j < this.ncolumns; j++) {
this.screen[row][j] = 0x20;
this.color[row][j] = this.attr_color;
}
this.PrepareUpdateRow(row);
};
Terminal.prototype.DeleteArea = function (row, column, row2, column2) {
for (let i = row; i <= row2; i++) {
for (let j = column; j <= column2; j++) {
this.screen[i][j] = 0x20;
this.color[i][j] = this.attr_color;
}
this.PrepareUpdateRow(i);
}
};
Terminal.prototype.UpdateScreen = function () {
let nupdated = 0;
for (let i = 0; i < this.nrows; i++) {
if (!this.updaterow[i]) continue;
this.UpdateRowTable(i);
nupdated++;
this.updaterow[i] = 0;
}
this.framerequested = false;
if (nupdated >= (this.nrows - 1)) {
this.timeout = 100;
} else {
this.timeout = 30;
}
}
Terminal.prototype.UpdateRowTable = function (row) {
let column;
let line = this.screen[row];
let c = this.color[row][0] | 0;
let n = 0;
let html = "";
for (column = 0; column < this.ncolumns; column++) {
let cnew = this.color[row][column] | 0;
if (this.cursorvisible)
if (row === this.cursory)
if (column === this.cursorx) {
cnew |= 0x600;
}
if (c !== cnew) {
html += this.GetSpan(c, line, column - n, n);
c = cnew;
n = 0;
}
n++;
}
html += this.GetSpan(c, line, column - n, n);
this.rowelements[this.nrows - row - 1].innerHTML = html;
};
Terminal.prototype.GetSpan = function (c, line, idx, n) {
let html = "<span style=\"color:" + Colors[c & 0x1F] + ";background-color:" + Colors[(c >> 8) & 0x1F] + "\">";
for (let i = 0; i < n; i++) {
switch (line[idx + i]) {
case 0x20:
html += "&nbsp;";
break;
case 0x26: // '&'
html += "&amp;";
break;
case 0x3C: // '<'
html += "&lt;";
break;
case 0x3E: // '>'
html += "&gt;";
break;
default:
html += String.fromCharCode(line[idx + i]);
break;
}
}
html += "</span>";
return html;
}
Terminal.prototype.PrepareUpdateRow = function (row) {
this.updaterow[row] = 1;
if (this.framerequested) return;
window.setTimeout(this.UpdateScreen.bind(this), this.timeout);
this.framerequested = true;
}
Terminal.prototype.ScrollDown = function (draw) {
let tempscreen = this.screen[this.scrollbottom];
let tempcolor = this.color[this.scrollbottom];
for (let i = this.scrollbottom - 1; i >= this.scrolltop; i--) {
if (i === this.nrows - 1) continue;
this.screen[i + 1] = this.screen[i];
this.color[i + 1] = this.color[i];
if (draw) this.PrepareUpdateRow(i + 1);
}
this.screen[this.scrolltop] = tempscreen;
this.color[this.scrolltop] = tempcolor;
this.DeleteRow(this.scrolltop);
if (draw) this.PrepareUpdateRow(this.scrolltop);
}
Terminal.prototype.ScrollUp = function (draw) {
let tempscreen = this.screen[this.scrolltop];
let tempcolor = this.color[this.scrolltop];
for (let i = this.scrolltop + 1; i <= this.scrollbottom; i++) {
if (i === 0) continue;
this.screen[i - 1] = this.screen[i];
this.color[i - 1] = this.color[i];
if (draw) this.PrepareUpdateRow(i - 1);
}
this.screen[this.scrollbottom] = tempscreen;
this.color[this.scrollbottom] = tempcolor;
this.DeleteRow(this.scrollbottom);
if (draw) this.PrepareUpdateRow(this.scrollbottom);
};
Terminal.prototype.LineFeed = function () {
if (this.cursory !== this.scrollbottom) {
this.cursory++;
if (this.cursorvisible) {
this.PrepareUpdateRow(this.cursory - 1); // delete old cursor position
this.PrepareUpdateRow(this.cursory); // show new cursor position
}
return;
}
this.ScrollUp(true);
};
Terminal.prototype.ChangeCursor = function (Numbers) {
switch (Numbers.length) {
case 0:
this.cursorx = 0;
this.cursory = 0;
break;
case 1:
this.cursory = Numbers[0];
if (this.cursory) this.cursory--;
break;
case 2:
default:
// TODO check for boundaries
this.cursory = Numbers[0];
this.cursorx = Numbers[1];
if (this.cursorx) this.cursorx--;
if (this.cursory) this.cursory--;
break;
}
if (this.cursorx >= this.ncolumns) this.cursorx = this.ncolumns - 1;
if (this.cursory >= this.nrows) this.cursory = this.nrows - 1;
};
Terminal.prototype.ChangeColor = function (Numbers) {
if (Numbers.length === 0) { // reset;
this.attr_color = 0x7;
this.attr_reverse = false;
this.attr_italic = false;
this.attr_intensity = 1;
return;
}
let c = this.attr_color;
for (let i = 0; i < Numbers.length; i++) {
switch (Number(Numbers[i])) {
case 0: // reset
c = 0x7;
this.attr_reverse = false;
this.attr_italic = false;
this.attr_intensity = 1;
break;
case 1: // brighter foreground color
this.attr_intensity = 2;
break;
case 2: // dimmed foreground color
this.attr_intensity = 0;
break;
case 3: // italic
this.attr_italic = true;
break;
case 4: // underline ignored
break;
case 5: // extended colors or blink ignored
//i++;
break;
case 7: // reversed
this.attr_reverse = true;
break;
case 8: // hidden ignored
break;
case 10: // reset mapping ?
break;
case 21:
case 22:
this.attr_intensity = 1;
break;
case 23:
this.attr_italic = false;
break;
case 27: // no reverse
this.attr_reverse = false;
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
c = c & (0xFFF8) | (Numbers[i] - 30) & 0x7;
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
c = c & (0x00FF) | (((Numbers[i] - 40) & 0x7) << 8);
break;
case 39:
c = c & (0xFF00) | 0x7; // set standard foreground color
break;
case 49:
c = c & 0x00FF; // set standard background color
break;
default:
console.log("Color " + Numbers[i] + " not found");
break;
}
}
this.attr_color = c | 0;
};
Terminal.prototype.ChangeMode = function (numbers, question, onoff) {
for (let i = 0; i < numbers.length; i++) {
switch (numbers[i]) {
case 4: // insert mode
break;
case 7: // auto wrap on off
break;
case 25: // cursor on/off
this.cursortype = onoff;
break;
case 1000: //
break;
case 1006: //
break;
case 1005: //
break;
default:
console.log("Mode term parameter " + this.escapestring + " unknown");
break;
}
}
}
Terminal.prototype.ChangeCursorType = function (numbers, question) {
if (!question) {
console.log("cursor parameter unknown");
return;
}
for (let i = 0; i < numbers.length; i++) {
switch (numbers[i]) {
case 0:
//this.cursorvisible = false;
//this.cursortype = 0;
break;
case 1:
//this.cursortype = 1;
break;
default:
console.log("Term parameter " + this.escapestring + " unknown");
break;
}
}
}
Terminal.prototype.HandleEscapeSequence = function () {
//console.log("Escape sequence:'" + this.escapestring+"'");
let i = 0;
if (this.escapestring === "[J") {
this.DeleteArea(this.cursory, this.cursorx, this.cursory, this.ncolumns - 1);
this.DeleteArea(this.cursory + 1, 0., this.nrows - 1, this.ncolumns - 1);
return;
} else if (this.escapestring === "M") {
this.ScrollDown(true);
return;
}
// Testing for [x;y;z
let s = this.escapestring;
if (s.charAt(0) !== "[") {
console.log("Short escape sequence unknown:'" + this.escapestring + "'");
return; // the short escape sequences must be handled earlier
}
s = s.substr(1); // delete first sign
let lastsign = s.substr(s.length - 1); // extract command
s = s.substr(0, s.length - 1); // remove command
let question = false;
if (s.charAt(0) === '?') {
question = true;
s = s.substr(1); // delete question mark
}
let numbers = s.split(";"); // if there are multiple numbers, split them
if (numbers[0].length === 0) {
numbers = [];
}
// the array must contain of numbers and not strings. Make this sure
for (i = 0; i < numbers.length; i++) {
numbers[i] = Number(numbers[i]);
}
let oldcursory = this.cursory; // save current cursor position
let count = 0;
switch (lastsign) {
case 'l':
this.ChangeMode(numbers, question, true);
return;
case 'h':
this.ChangeMode(numbers, question, false);
return;
case 'c':
this.ChangeCursorType(numbers, question);
return;
}
if (question) {
console.log("Escape sequence unknown:'" + this.escapestring + "'");
return;
}
let j;
let top = 0;
switch (lastsign) {
case 'm': // colors
this.ChangeColor(numbers);
return;
case 'A': // move cursor up
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
this.cursory -= count;
break;
case 'B': // move cursor down
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
this.cursory += count;
break;
case 'C': // move cursor right
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
this.cursorx += count;
break;
case 'D': // move cursor left
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
this.cursorx -= count;
if (this.cursorx < 0) this.cursorx = 0;
break;
case 'E': // move cursor down
count = numbers.length ? numbers[0] : 1;
this.cursory += count;
this.cursorx = 0;
break;
case 'F': // move cursor up
count = numbers.length ? numbers[0] : 1;
this.cursory -= count;
if (this.cursory < 0) this.cursory = 0;
this.cursorx = 0;
break;
case 'G': // change cursor column
count = numbers.length ? numbers[0] : 1;
this.cursorx = count;
if (this.cursorx) this.cursorx--;
break;
case 'H': // cursor position
case 'd':
case 'f':
this.ChangeCursor(numbers);
break;
case 'K': // erase
count = numbers.length ? numbers[0] : 1;
if (!numbers.length) {
this.DeleteArea(this.cursory, this.cursorx, this.cursory, this.ncolumns - 1);
} else if (numbers[0] == 1) {
this.DeleteArea(this.cursory, 0., this.cursory, this.cursorx);
} else if (numbers[0] == 2) {
this.DeleteRow(this.cursory);
}
break;
case 'L': // scroll down
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
top = this.scrolltop;
this.scrolltop = this.cursory;
if (count === 1) {
this.ScrollDown(true);
} else {
for (j = 0; j < count - 1; j++) {
this.ScrollDown(false);
}
this.ScrollDown(true);
}
this.scrolltop = top;
break;
case 'M': // scroll up
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
top = this.scrolltop;
this.scrolltop = this.cursory;
if (count === 1) {
this.ScrollUp(true);
} else {
for (j = 0; j < count - 1; j++) {
this.ScrollUp(false);
}
this.ScrollUp(true);
}
this.scrolltop = top;
break;
case 'P': /* shift left from cursor and fill with zero */
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
let n = 0;
for (j = this.cursorx + count; j < this.ncolumns; j++) {
this.screen[this.cursory][this.cursorx + n] = this.screen[this.cursory][j];
this.color[this.cursory][this.cursorx + n] = this.color[this.cursory][j];
n++;
}
this.DeleteArea(this.cursory, this.ncolumns - count, this.cursory, this.ncolumns - 1);
this.PrepareUpdateRow(this.cursory);
break;
case 'r': // set scrolling region
if (numbers.length === 0) {
this.scrolltop = 0;
this.scrollbottom = this.nrows - 1;
} else {
this.scrolltop = numbers[0];
this.scrollbottom = numbers[1];
if (this.scrolltop) this.scrolltop--;
if (this.scrollbottom) this.scrollbottom--;
}
return;
case 'X': // erase only number of characters in current line
count = numbers.length ? numbers[0] : 1;
if (count === 0) count = 1;
for (j = 0; j < count; j++) {
this.screen[this.cursory][this.cursorx + j] = 0x20;
this.color[this.cursory][this.cursorx + j] = this.GetColor();
}
this.PrepareUpdateRow(this.cursory);
break;
default:
console.log("Escape sequence unknown:'" + this.escapestring + "'");
break;
}
if (this.cursorvisible) {
this.PrepareUpdateRow(this.cursory);
if (this.cursory !== oldcursory) {
this.PrepareUpdateRow(oldcursory);
}
}
};
Terminal.prototype.PutChar = function (c) {
//console.log("Char:" + c + " " + String.fromCharCode(c));
// escape sequence (CS)
if (this.escapetype === 2) {
this.escapestring += String.fromCharCode(c);
if ((c >= 64) && (c <= 126)) {
this.HandleEscapeSequence();
this.escapetype = 0;
}
return;
}
// escape sequence
if ((this.escapetype === 0) && (c === 0x1B)) {
this.escapetype = 1;
this.escapestring = "";
return;
}
// starting escape sequence
if (this.escapetype === 1) {
this.escapestring += String.fromCharCode(c);
// Control Sequence Introducer ([)
if (c === 0x5B) {
this.escapetype = 2;
return;
}
this.HandleEscapeSequence();
this.escapetype = 0;
return;
}
switch (c) {
case 0xA:
// line feed
this.LineFeed();
this.OnCharReceived("\n");
return;
case 0xD:
// carriage return
this.cursorx = 0;
this.PrepareUpdateRow(this.cursory);
return;
case 0x7:
// beep
return;
case 0x8:
// back space
this.cursorx--;
if (this.cursorx < 0) {
this.cursorx = 0;
}
this.PrepareUpdateRow(this.cursory);
return;
case 0x9:
// horizontal tab
let spaces = 8 - (this.cursorx & 7);
do {
if (this.cursorx >= this.ncolumns) {
this.PrepareUpdateRow(this.cursory);
this.LineFeed();
this.cursorx = 0;
}
this.screen[this.cursory][this.cursorx] = 0x20;
this.color[this.cursory][this.cursorx] = this.attr_color;
this.cursorx++;
} while (spaces--);
this.PrepareUpdateRow(this.cursory);
return;
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x0B:
case 0x0C:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
case 0x7F:
console.log("unknown character " + c);
return;
}
if (this.cursorx >= this.ncolumns) {
this.LineFeed();
this.cursorx = 0;
}
c = this.utf8converter.Put(c);
if (c === -1) return;
let cx = this.cursorx;
let cy = this.cursory;
this.screen[cy][cx] = c;
this.color[cy][cx] = this.GetColor();
this.cursorx++;
//console.log("Write: " + String.fromCharCode(c));
this.PrepareUpdateRow(cy);
this.OnCharReceived(String.fromCharCode(c));
};
function TerminalInput(SendChars) {
this.CTRLpressed = false;
this.ALTpressed = false;
this.SendChars = SendChars;
this.enabled = true;
document.addEventListener("keypress", this.OnKeyPress.bind(this))
document.addEventListener("keydown", this.OnKeyDown.bind(this))
document.addEventListener("keyup", this.OnKeyUp.bind(this))
}
TerminalInput.prototype.OnKeyPress = function (e) {
if (!this.enabled) {
return;
}
var key = 0;
key = e.charCode;
if (key == 0) {
return false;
}
// Define that the control key has this effect only if special keys have been pressed A..Z a..z. Otherwise some foreign keyboards will not work
if ((this.CTRLpressed) && (((key >= 0x41) && (key <= 0x5A)) || ((key >= 0x61) && (key <= 0x7A)))) {
key &= 0x1F;
}
this.SendChars(UnicodeToUTF8Stream(key));
return false;
};
TerminalInput.prototype.OnKeyUp = function (e) {
if (!this.enabled) {
return;
}
var keycode = e.keyCode;
var unicode = e.charCode;
if (keycode === 17) {
this.CTRLpressed = false;
} else if (keycode === 18) {
this.ALTpressed = false;
}
return false;
};
TerminalInput.prototype.OnKeyDown = function (e) {
if (!this.enabled) {
return;
}
let keycode = e.keyCode;
let unicode = e.charCode;
// CTRL + x key handling for chrome
if ((this.CTRLpressed) && (!this.ALTpressed) && (keycode >= 65) && (keycode <= 90)) {
this.SendChars([(keycode - 32) & 0x1F]);
e.preventDefault();
return false;
}
switch (keycode) {
case 8:
// del
this.SendChars([0x7F]);
e.preventDefault();
return false;
break;
case 9:
//tab
break;
case 16:
// shift
return;
break;
case 38:
// up
this.SendChars([0x1B, 0x5B, 0x41]);
e.preventDefault();
return false;
break;
case 37:
// left
this.SendChars([0x1B, 0x5B, 0x44]);
e.preventDefault();
return false;
break;
case 39:
// right
this.SendChars([0x1B, 0x5B, 0x43]);
e.preventDefault();
return false;
break;
case 40:
// down
this.SendChars([0x1B, 0x5B, 0x42]);
e.preventDefault();
return false;
break;
case 112:
case 113:
case 114:
case 115:
case 116:
// F1 - F5
this.SendChars([0x1B, 0x5B, 0x5B, keycode - 112 + 0x41]);
e.preventDefault();
return false;
case 117:
case 118:
case 119:
// F6 - F8
this.SendChars([0x1B, 0x5B, 0x31, keycode - 117 + 0x37, 0x7E]);
e.preventDefault();
return false;
case 120:
case 121:
// F9 - F10
this.SendChars([0x1B, 0x5B, 0x32, keycode - 120 + 0x30, 0x7E]);
e.preventDefault();
return false;
case 36:
// pos1
this.SendChars([0x1b, 0x5b, 0x48]);
e.preventDefault();
return false;
case 35:
// end
this.SendChars([0x1b, 0x5b, 0x46]);
e.preventDefault();
return false;
case 33:
// Page up
this.SendChars([0x1b, 0x5b, 0x35, 0x7e]);
e.preventDefault();
return false;
case 34:
// Page down
this.SendChars([0x1b, 0x5b, 0x36, 0x7e]);
e.preventDefault();
return false;
case 45:
// ins
this.SendChars([0x1b, 0x5b, 0x32, 0x7e]);
e.preventDefault();
return false;
case 46:
// del
this.SendChars([0x1b, 0x5b, 0x33, 0x7e]);
e.preventDefault();
return false;
case 17:
// CTRL
this.CTRLpressed = true;
//e.preventDefault();
//return false;
return;
case 18:
// Alt
this.ALTpressed = true;
return;
}
if ((keycode != 0) && (keycode <= 0x1F)) {
this.SendChars([keycode]);
e.preventDefault();
return false;
}
return;
};
async function loadImage() {
const response = await fetch("a");
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status} - Could not fetch ${wasmFilePath}. Make sure the file exists and the server is configured correctly (MIME types).`);
}
let buffer = new Uint8Array(await response.arrayBuffer())
return buffer
}
async function loadWasm(a, terminal) {
const wasmFilePath = "prog.wasm";
const response = await fetch(wasmFilePath);
let m = null
let terminalInputBuffer = []
new TerminalInput(function (e) {
terminalInputBuffer = terminalInputBuffer.concat(e)
})
const importObject = {
env: {
read: function (d1, cp) {
if (terminalInputBuffer.length === 0) {
m[cp] = 0
return 0;
}
m[cp] = terminalInputBuffer.shift();
return 1;
},
write: function (d1, cp) {
terminal.PutChar(m[cp])
},
fread: function () {}
}
};
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status} - Could not fetch ${wasmFilePath}. Make sure the file exists and the server is configured correctly (MIME types).`);
}
const {instance, module} = await WebAssembly.instantiateStreaming(response, importObject);
console.log("Wasm Module:", module);
console.log("Wasm Instance:", instance);
console.log("Available Exports:", instance.exports);
m = new Uint8Array(instance.exports.memory.buffer);
for (let i = 0; i < a.length; i++) {
m[instance.exports.k.value + i + (1 << 18)] = a[i]
}
return instance.exports.e
}
function Loop(e) {
e();
setTimeout(function () {
Loop(e)
}, 0)
}
document.addEventListener('DOMContentLoaded', async () => {
let term = new Terminal(24, 80, "tty");
let a = await loadImage()
let e = await loadWasm(a, term);
Loop(e)
});
</script>
</html>