Mercurial > hg > rlgwebd
view rlgterm.js @ 9:826a7ced69f8
Make the emulator screen resizable.
author | John "Elwin" Edwards <elwin@sdf.org> |
---|---|
date | Wed, 09 May 2012 13:38:05 -0700 |
parents | 21738794755e |
children | ef6127ed6da3 |
line wrap: on
line source
/* rlgterm.js: Roguelike Gallery's driver for termemu.js */ // A state machine that keeps track of polling the server. var ajaxstate = { state: 0, timerID: null, clear: function () { if (this.timerID != null) { window.clearTimeout(this.timerID); this.timerID = null; } }, set: function (ms) { this.clear(); this.timerID = window.setTimeout(getData, ms); }, gotdata: function () { this.set(100); this.state = 0; }, gotnothing: function () { if (this.state == 0) { this.set(100); this.state = 1; } else if (this.state == 1) { this.set(300); this.state = 2; } else if (this.state == 2) { this.set(1000); this.state = 3; } else { this.set(5000); this.state = 3; } }, posted: function () { this.set(100); this.state = 0; } }; function writeData(hexstr) { var codenum; var codes = []; var nc; var u8wait = 0; /* Stores bits from previous bytes of multibyte sequences. */ var expect = 0; /* The number of 10------ bytes expected. */ /* UTF-8 translation. */ for (var i = 0; i < hexstr.length; i += 2) { nc = Number("0x" + hexstr.substr(i, 2)); if (nc < 0x7F) { /* 0------- */ codes.push(nc); /* Any incomplete sequence will be discarded. */ u8wait = 0; expect = 0; } else if (nc < 0xC0) { /* 10------ : part of a multibyte sequence */ if (expect > 0) { u8wait <<= 6; u8wait += (nc & 0x3F); expect--; if (expect == 0) { codes.push(u8wait); u8wait = 0; } } else { /* Assume an initial byte was missed. */ u8wait = 0; } } /* These will all discard any incomplete sequence. */ else if (nc < 0xE0) { /* 110----- : introduces 2-byte sequence */ u8wait = (nc & 0x1F); expect = 1; } else if (nc < 0xF0) { /* 1110---- : introduces 3-byte sequence */ u8wait = (nc & 0x0F); expect = 2; } else if (nc < 0xF8) { /* 11110--- : introduces 4-byte sequence */ u8wait = (nc & 0x07); expect = 3; } else if (nc < 0xFC) { /* 111110-- : introduces 5-byte sequence */ u8wait = (nc & 0x03); expect = 4; } else if (nc < 0xFE) { /* 1111110- : introduces 6-byte sequence */ u8wait = (nc & 0x01); expect = 5; } else { /* 1111111- : should never appear */ u8wait = 0; expect = 0; } /* Supporting all 31 bits is probably overkill... */ } termemu.write(codes); return; } /* Processes a message from the server, returning true or false if it was a * data message with or without data, null if not data. */ function processMsg(msg) { var msglines = msg.split("\n"); var havedata = null; if (!msglines[0]) return null; if (msglines[0].charAt(0) == 'd') { if (msglines[1]){ writeData(msglines[1]); havedata = true; } else { havedata = false; } } else if (msglines[0] == "E1") { logout(); } else if (msglines[0].charAt(0) == "T") { setTitle(msglines[1]); } else if (msglines[0] == "q1") { logout(); } else { debug(1, "Unrecognized server message " + msglines[0]); } return havedata; } function getData() { if (termemu.sessid == null) return; var datareq = new XMLHttpRequest(); datareq.onreadystatechange = function () { if (datareq.readyState == 4 && datareq.status == 200) { var wasdata = processMsg(datareq.responseText); if (wasdata != null) { if (wasdata) ajaxstate.gotdata(); else ajaxstate.gotnothing(); } return; } }; datareq.open('POST', '/feed', true); datareq.send("id=" + termemu.sessid); return; } function postResponseHandler() { if (this.readyState == 4 && this.status == 200) { // We might want to do something with wasdata someday. var wasdata = processMsg(this.responseText); ajaxstate.posted(); return; } } function sendback(str) { /* For responding to terminal queries. */ var datareq = new XMLHttpRequest(); datareq.onreadystatechange = postResponseHandler; datareq.open('POST', '/feed', true); datareq.send("id=" + termemu.sessid + "&keys=" + str); return; } function sendkey(ev) { if (termemu.sessid == null) return; var keynum = ev.keyCode; var code; if (keynum >= ev.DOM_VK_A && keynum <= ev.DOM_VK_Z) { /* Letters. This assumes the codes are 65-90. */ if (ev.ctrlKey) keynum -= 64; else if (!ev.shiftKey) keynum += 32; code = keynum.toString(16); if (code.length < 2) code = "0" + code; } else if (keynum >= ev.DOM_VK_0 && keynum <= ev.DOM_VK_9) { /* The number row, NOT the numpad. */ if (ev.shiftKey) { code = numShifts[keynum - 48].toString(16); } else { code = keynum.toString(16); } } else if (keynum in keyHexCodes) { if (ev.shiftKey) code = keyHexCodes[keynum][1]; else code = keyHexCodes[keynum][0]; } else if (keynum == ev.DOM_VK_SHIFT || keynum == ev.DOM_VK_CONTROL || keynum == ev.DOM_VK_ALT || keynum == ev.DOM_VK_CAPS_LOCK) { return; } else { debug(1, "Ignoring keycode " + keynum); return; } if (termemu.sessid != null) ev.preventDefault(); var datareq = new XMLHttpRequest(); datareq.onreadystatechange = postResponseHandler; datareq.open('POST', '/feed', true); datareq.send("id=" + termemu.sessid + "&keys=" + code); return; } var charshifts = { '-': "5f", '=': "2b", '[': "7b", ']': "7d", '\\': "7c", ';': "3a", '\'': "22", ',': "3c", '.': "3e", '/': "3f", '`': "7e" } function vkey(c) { if (termemu.sessid == null) return; var keystr; if (c.match(/^[a-z]$/)) { if (termemu.ctrlp()) { var n = c.charCodeAt(0) - 96; keystr = n.toString(16); if (keystr.length < 2) keystr = "0" + keystr; } else if (termemu.shiftp()) keystr = c.toUpperCase().charCodeAt(0).toString(16); else keystr = c.charCodeAt(0).toString(16); } else if (c.match(/^[0-9]$/)) { if (termemu.shiftp()) keystr = numShifts[c.charCodeAt(0) - 48].toString(16); else keystr = c.charCodeAt(0).toString(16); } else if (c == '\n') keystr = "0a"; else if (c == '\t') keystr = "09"; else if (c == '\b') keystr = "08"; else if (c == ' ') keystr = "20"; else if (c in charshifts) { if (termemu.shiftp()) keystr = charshifts[c]; else keystr = c.charCodeAt(0).toString(16); } else return; //writeData("Sending " + keystr); var datareq = new XMLHttpRequest(); datareq.onreadystatechange = postResponseHandler; datareq.open('POST', '/feed', true); datareq.send("id=" + termemu.sessid + "&keys=" + keystr); return; } function setup() { keyHexCodes.init(); termemu.init("termwrap", 24, 80); setTitle("Not connected."); return; } function toggleshift() { termemu.toggleshift(); keydiv = document.getElementById("shiftkey"); if (termemu.shiftp()) keydiv.className = "keysel"; else keydiv.className = "key"; return; } function togglectrl() { termemu.togglectrl(); keydiv = document.getElementById("ctrlkey"); if (termemu.ctrlp()) keydiv.className = "keysel"; else keydiv.className = "key"; return; } function formlogin(ev) { ev.preventDefault(); if (termemu.sessid != null) return; var formname = document.getElementById("input_name").value; var formpass = document.getElementById("input_pw").value; var formgame = document.getElementById("input_game").value; var formdata = "game=" + encodeURIComponent(formgame) + "&name=" + encodeURIComponent(formname) + "&pw=" + encodeURIComponent(formpass); var req = new XMLHttpRequest(); req.onreadystatechange = function () { if (req.readyState == 4 && req.status == 200) { var datalines = req.responseText.split("\n"); if (datalines[0] == 'l1') { /* Success */ termemu.sessid = datalines[1]; setTitle("Playing as " + formname); debug(1, "Logged in with id " + termemu.sessid); document.getElementById("loginform").style.display = "none"; getData(); } else { debug(1, "Could not start game: " + datalines[1]); document.getElementById("input_name").value = ""; document.getElementById("input_pw").value = ""; } } }; req.open('POST', '/login', true); req.send(formdata); return; } function logout() { if (termemu.sessid == null) return; termemu.sessid = null; setTitle("Game over."); document.getElementById("loginform").style.display = "block"; return; } function stop() { var req = new XMLHttpRequest(); req.onreadystatechange = function () { if (req.readyState == 4 && req.status == 200) { processMsg(req.responseText); return; } }; req.open('POST', '/feed', true); req.send("id=" + termemu.sessid + "&quit=quit"); return; } function debug(level, msg) { if (level < debugSuppress) return; var msgdiv = document.createElement("div"); var msgtext = document.createTextNode(msg); msgdiv.appendChild(msgtext); document.getElementById("debug").appendChild(msgdiv); return; } function textsize(larger) { var cssSize = termemu.view.style.fontSize; if (!cssSize) { return; } var match = cssSize.match(/\d*/); if (!match) { return; } var csize = Number(match[0]); var nsize; if (larger) { if (csize >= 48) nsize = 48; else if (csize >= 20) nsize = csize + 4; else if (csize >= 12) nsize = csize + 2; else if (csize >= 8) nsize = csize + 1; else nsize = 8; } else { if (csize <= 8) nsize = 8; else if (csize <= 12) nsize = csize - 1; else if (csize <= 20) nsize = csize - 2; else if (csize <= 48) nsize = csize - 4; else nsize = 48; } document.getElementById("term").style.fontSize = nsize.toString() + "px"; termemu.fixsize(); debug(1, "Changing font size to " + nsize.toString()); return; } function bell(on) { var imgnode = document.getElementById("bell"); if (on) { imgnode.style.visibility = "visible"; window.setTimeout(bell, 1500, false); } else imgnode.style.visibility = "hidden"; return; }