|
|
|
@ -1182,141 +1182,90 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
w.init = wifiInit; |
|
|
|
|
w.startScanning = startScanning; |
|
|
|
|
})(window.WiFi = {}); |
|
|
|
|
(function() { |
|
|
|
|
/** |
|
|
|
|
* Terminal module |
|
|
|
|
*/ |
|
|
|
|
var Term = (function () { |
|
|
|
|
var W, H; |
|
|
|
|
var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false}; |
|
|
|
|
var Screen = (function () { |
|
|
|
|
var W, H; // dimensions
|
|
|
|
|
var inited = false; |
|
|
|
|
|
|
|
|
|
var cursor = { |
|
|
|
|
a: false, // active (blink state)
|
|
|
|
|
x: 0, // 0-based coordinates
|
|
|
|
|
y: 0, |
|
|
|
|
fg: 7, // colors 0-15
|
|
|
|
|
bg: 0, |
|
|
|
|
bold: false, |
|
|
|
|
suppress: false, // do not turn on in blink interval (for safe moving)
|
|
|
|
|
hidden: false // do not show
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var screen = []; |
|
|
|
|
var blinkIval; |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
/!** Clear screen *!/ |
|
|
|
|
function cls() { |
|
|
|
|
screen.forEach(function(cell, i) { |
|
|
|
|
/** Clear screen */ |
|
|
|
|
function _clear() { |
|
|
|
|
for (var i = W*H-1; i>=0; i--) { |
|
|
|
|
var cell = screen[i]; |
|
|
|
|
cell.t = ' '; |
|
|
|
|
cell.fg = 7; |
|
|
|
|
cell.bg = 0; |
|
|
|
|
blit(cell); |
|
|
|
|
}); |
|
|
|
|
cell.bg = cursor.bg; |
|
|
|
|
cell.fg = cursor.fg; |
|
|
|
|
cell.bold = false; |
|
|
|
|
_draw(cell); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/** Set text and color at XY */ |
|
|
|
|
function cellAt(y, x) { |
|
|
|
|
function _cellAt(y, x) { |
|
|
|
|
return screen[y*W+x]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Get cell under cursor */ |
|
|
|
|
function cursorCell() { |
|
|
|
|
return cellAt(cursor.y, cursor.x); |
|
|
|
|
function _curCell() { |
|
|
|
|
return screen[cursor.y*W + cursor.x]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
/!** Enable or disable cursor visibility *!/ |
|
|
|
|
function cursorEnable(enable) { |
|
|
|
|
/** Enable or disable cursor visibility */ |
|
|
|
|
function _cursorEnable(enable) { |
|
|
|
|
cursor.hidden = !enable; |
|
|
|
|
cursor.a &= enable; |
|
|
|
|
blit(cursorCell(), cursor.a); |
|
|
|
|
_draw(_curCell()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/!** Safely move cursor *!/ |
|
|
|
|
/** Safely move cursor */ |
|
|
|
|
function cursorSet(y, x) { |
|
|
|
|
// Hide and prevent from showing up during the move
|
|
|
|
|
cursor.suppress = true; |
|
|
|
|
blit(cursorCell(), false); |
|
|
|
|
|
|
|
|
|
_draw(_curCell(), false); |
|
|
|
|
cursor.x = x; |
|
|
|
|
cursor.y = y; |
|
|
|
|
|
|
|
|
|
// Show again
|
|
|
|
|
cursor.suppress = false; |
|
|
|
|
blit(cursorCell(), cursor.a); |
|
|
|
|
_draw(_curCell()); |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/** Update cell on display. inv = invert (for cursor) */ |
|
|
|
|
function blit(cell, inv) { |
|
|
|
|
function _draw(cell, inv) { |
|
|
|
|
if (typeof inv == 'undefined') { |
|
|
|
|
inv = cursor.a && cursor.x == cell.x && cursor.y == cell.y; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var e = cell.e, fg, bg; |
|
|
|
|
// Colors
|
|
|
|
|
fg = inv ? cell.bg : cell.fg; |
|
|
|
|
bg = inv ? cell.fg : cell.bg; |
|
|
|
|
// Update
|
|
|
|
|
e.innerText = (cell.t+' ')[0]; |
|
|
|
|
e.className = 'fg'+fg+' bg'+bg; |
|
|
|
|
e.innerText = (cell.t + ' ')[0]; |
|
|
|
|
e.className = 'fg' + fg + ' bg' + bg + (cell.bold ? ' bold' : ''); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Show entire screen */ |
|
|
|
|
function blitAll() { |
|
|
|
|
screen.forEach(function(cell, i) { |
|
|
|
|
/* Invert if under cursor & cursor active */ |
|
|
|
|
var inv = cursor.a && (i == cursor.y*W+cursor.x); |
|
|
|
|
blit(cell, inv); |
|
|
|
|
}); |
|
|
|
|
function _drawAll() { |
|
|
|
|
for (var i = W*H-1; i>=0; i--) { |
|
|
|
|
_draw(screen[i]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Load screen content from a 'binary' sequence */ |
|
|
|
|
function load(obj) { |
|
|
|
|
cursor.x = obj.x; |
|
|
|
|
cursor.y = obj.y; |
|
|
|
|
cursor.hidden = !obj.cv; |
|
|
|
|
|
|
|
|
|
// full re-init if size changed
|
|
|
|
|
if (obj.w != W || obj.h != H) { |
|
|
|
|
Term.init(obj); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Simple compression - hexFG hexBG 'ASCII' (r/s/t/u NUM{1,2,3,4})?
|
|
|
|
|
// comma instead of both colors = same as before
|
|
|
|
|
|
|
|
|
|
var i = 0, ci = 0, str = obj.screen; |
|
|
|
|
var fg = 7, bg = 0; |
|
|
|
|
while(i < str.length && ci<W*H) { |
|
|
|
|
var cell = screen[ci++]; |
|
|
|
|
|
|
|
|
|
var j = str[i]; |
|
|
|
|
if (j != ',') { // comma = repeat last colors
|
|
|
|
|
fg = cell.fg = parseInt(str[i++], 16); |
|
|
|
|
bg = cell.bg = parseInt(str[i++], 16); |
|
|
|
|
} else { |
|
|
|
|
i++; |
|
|
|
|
cell.fg = fg; |
|
|
|
|
cell.bg = bg; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var t = cell.t = str[i++]; |
|
|
|
|
|
|
|
|
|
var repchars = 0; |
|
|
|
|
switch(str[i]) { |
|
|
|
|
case 'r': repchars = 1; break; |
|
|
|
|
case 's': repchars = 2; break; |
|
|
|
|
case 't': repchars = 3; break; |
|
|
|
|
case 'u': repchars = 4; break; |
|
|
|
|
default: repchars = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (repchars > 0) { |
|
|
|
|
var rep = parseInt(str.substr(i+1,repchars)); |
|
|
|
|
i = i + repchars + 1; |
|
|
|
|
for (; rep>0 && ci<W*H; rep--) { |
|
|
|
|
cell = screen[ci++]; |
|
|
|
|
cell.fg = fg; |
|
|
|
|
cell.bg = bg; |
|
|
|
|
cell.t = t; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
blitAll(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Init the terminal */ |
|
|
|
|
function init(obj) { |
|
|
|
|
W = obj.w; |
|
|
|
|
H = obj.h; |
|
|
|
|
function _rebuild(rows, cols) { |
|
|
|
|
W = cols; |
|
|
|
|
H = rows; |
|
|
|
|
|
|
|
|
|
/* Build screen & show */ |
|
|
|
|
var e, cell, scr = qs('#screen'); |
|
|
|
@ -1344,36 +1293,120 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
/* The cell */ |
|
|
|
|
scr.appendChild(e); |
|
|
|
|
|
|
|
|
|
cell = {t: ' ', fg: 7, bg: 0, e: e}; |
|
|
|
|
cell = { |
|
|
|
|
t: ' ', |
|
|
|
|
fg: cursor.fg, |
|
|
|
|
bg: cursor.bg, |
|
|
|
|
e: e, |
|
|
|
|
x: i % W, |
|
|
|
|
y: Math.floor(i / W), |
|
|
|
|
}; |
|
|
|
|
screen.push(cell); |
|
|
|
|
blit(cell); |
|
|
|
|
_draw(cell); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Init the terminal */ |
|
|
|
|
function _init() { |
|
|
|
|
/* Cursor blinking */ |
|
|
|
|
clearInterval(blinkIval); |
|
|
|
|
blinkIval = setInterval(function() { |
|
|
|
|
blinkIval = setInterval(function () { |
|
|
|
|
cursor.a = !cursor.a; |
|
|
|
|
if (cursor.hidden) { |
|
|
|
|
cursor.a = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!cursor.suppress) { |
|
|
|
|
blit(cursorCell(), cursor.a); |
|
|
|
|
_draw(_curCell(), cursor.a); |
|
|
|
|
} |
|
|
|
|
}, 500); |
|
|
|
|
inited = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Decode two-byte number */ |
|
|
|
|
function parse2B(s, i) { |
|
|
|
|
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var SEQ_SET_COLOR = 1; |
|
|
|
|
var SEQ_REPEAT = 2; |
|
|
|
|
|
|
|
|
|
load(obj); |
|
|
|
|
/** Load screen content from a binary sequence (new) */ |
|
|
|
|
function load(str) { |
|
|
|
|
var i = 0, ci = 0, j, jc, num, num2, t = ' ', fg, bg, bold, cell; |
|
|
|
|
|
|
|
|
|
if (!inited) _init(); |
|
|
|
|
|
|
|
|
|
// Set size
|
|
|
|
|
num = parse2B(str, i); i += 2; |
|
|
|
|
num2 = parse2B(str, i); i += 2; |
|
|
|
|
if (num != H || num2 != W) { |
|
|
|
|
_rebuild(num, num2); |
|
|
|
|
} |
|
|
|
|
console.log("Size ",num, num2); |
|
|
|
|
|
|
|
|
|
// Cursor position
|
|
|
|
|
num = parse2B(str, i); i += 2; |
|
|
|
|
num2 = parse2B(str, i); i += 2; |
|
|
|
|
cursorSet(num, num2); |
|
|
|
|
console.log("Cursor at ",num, num2); |
|
|
|
|
|
|
|
|
|
// Attributes
|
|
|
|
|
num = parse2B(str, i); i += 2; |
|
|
|
|
cursor.fg = num & 0x0F; |
|
|
|
|
cursor.bg = (num & 0xF0) >> 4; |
|
|
|
|
cursor.bold = !!(num & 0x100); |
|
|
|
|
cursor.hidden = !(num & 0x200); |
|
|
|
|
console.log("FG ",cursor.fg, ", BG ", cursor.bg,", BOLD ", cursor.bold, ", HIDE ", cursor.hidden); |
|
|
|
|
|
|
|
|
|
fg = cursor.fg; |
|
|
|
|
bg = cursor.bg; |
|
|
|
|
bold = cursor.bold; |
|
|
|
|
|
|
|
|
|
// Here come the content
|
|
|
|
|
while(i < str.length && ci<W*H) { |
|
|
|
|
|
|
|
|
|
j = str[i++]; |
|
|
|
|
jc = j.charCodeAt(0); |
|
|
|
|
if (jc == SEQ_SET_COLOR) { |
|
|
|
|
num = parse2B(str, i); i += 2; |
|
|
|
|
fg = num & 0x0F; |
|
|
|
|
bg = (num & 0xF0) >> 4; |
|
|
|
|
bold = !!(num & 0x100); |
|
|
|
|
console.log("Switch to ",fg,bg,bold); |
|
|
|
|
} |
|
|
|
|
else if (jc == SEQ_REPEAT) { |
|
|
|
|
num = parse2B(str, i); i += 2; |
|
|
|
|
console.log("Repeat x ",num); |
|
|
|
|
for (; num>0 && ci<W*H; num--) { |
|
|
|
|
cell = screen[ci++]; |
|
|
|
|
cell.fg = fg; |
|
|
|
|
cell.bg = bg; |
|
|
|
|
cell.t = t; |
|
|
|
|
cell.bold = bold; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
cell = screen[ci++]; |
|
|
|
|
// Unique cell character
|
|
|
|
|
t = cell.t = j; |
|
|
|
|
cell.fg = fg; |
|
|
|
|
cell.bg = bg; |
|
|
|
|
cell.bold = bold; |
|
|
|
|
console.log("Symbol ", j); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_drawAll(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// publish
|
|
|
|
|
return { |
|
|
|
|
init: init, |
|
|
|
|
load: load |
|
|
|
|
load: load, // full load (string)
|
|
|
|
|
}; |
|
|
|
|
})(); |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
/** Handle connections */ |
|
|
|
|
var Conn = (function() { |
|
|
|
|
/** Handle connections */ |
|
|
|
|
var Conn = (function() { |
|
|
|
|
var ws; |
|
|
|
|
|
|
|
|
|
function onOpen(evt) { |
|
|
|
@ -1391,7 +1424,7 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
try { |
|
|
|
|
console.log("RX: ", evt.data); |
|
|
|
|
// Assume all our messages are screen updates
|
|
|
|
|
Term.load(JSON.parse(evt.data)); |
|
|
|
|
Screen.load(evt.data); |
|
|
|
|
} catch(e) { |
|
|
|
|
console.error(e); |
|
|
|
|
} |
|
|
|
@ -1399,6 +1432,7 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
|
|
|
|
|
function doSend(message) { |
|
|
|
|
console.log("TX: ", message); |
|
|
|
|
if (!ws) return; // for dry testing
|
|
|
|
|
if (ws.readyState != 1) { |
|
|
|
|
console.error("Socket not ready"); |
|
|
|
|
return; |
|
|
|
@ -1423,12 +1457,10 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
init: init, |
|
|
|
|
send: doSend |
|
|
|
|
}; |
|
|
|
|
})(); |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Keyboard (& mouse) input
|
|
|
|
|
//
|
|
|
|
|
var Input = (function() { |
|
|
|
|
/** User input */ |
|
|
|
|
var Input = (function() { |
|
|
|
|
function sendStrMsg(str) { |
|
|
|
|
Conn.send("STR:"+str); |
|
|
|
|
} |
|
|
|
@ -1456,6 +1488,7 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
//console.log("Down ", code, e);
|
|
|
|
|
switch(code) { |
|
|
|
|
case 8: sendStrMsg('\x08'); break; |
|
|
|
|
case 10: |
|
|
|
|
case 13: sendStrMsg('\x0d\x0a'); break; |
|
|
|
|
case 27: sendStrMsg('\x1b'); break; // this allows to directly enter control sequences
|
|
|
|
|
case 37: sendStrMsg('\x1b[D'); break; |
|
|
|
@ -1476,12 +1509,10 @@ function tr(key) { return _tr[key] || '?'+key+'?'; } |
|
|
|
|
init: init, |
|
|
|
|
onTap: sendPosMsg |
|
|
|
|
}; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
window.termInit = function (obj) { |
|
|
|
|
Term.init(obj); |
|
|
|
|
window.termInit = function (str) { |
|
|
|
|
Screen.load(str); |
|
|
|
|
Conn.init(); |
|
|
|
|
Input.init(); |
|
|
|
|
}; |
|
|
|
|
})(); |
|
|
|
|
}; |
|
|
|
|