mirror of https://github.com/espruino/BangleApps
263 lines
6.5 KiB
JavaScript
263 lines
6.5 KiB
JavaScript
/* Espruino VT100 JS REPL
|
|
|
|
|
|
TODO: Add option to connect to a remote BLE device
|
|
|
|
*/
|
|
|
|
var settings = Object.assign({
|
|
// default values
|
|
textSize: 1,
|
|
loopAround: 1,
|
|
oneToOne: 0,
|
|
speedScaling: 24
|
|
}, /*require('Storage').readJSON("repl.settings.json", true) || */{});
|
|
|
|
// Key Maps for Keyboard
|
|
var KEYMAPLOWER = [
|
|
"`1234567890-=\b\b",
|
|
"\tqwertyuiop[]\n\n",
|
|
"\2asdfghjkl;'#\x82\n",
|
|
"\2\\zxcvbnm,./\x80\x83\x81",
|
|
];
|
|
var KEYMAPUPPER = [
|
|
"¬!\"£$%^&*()_+\b\b",
|
|
"\tQWERTYUIOP{}\n\n",
|
|
"\2ASDFGHJKL:@~\x82\n",
|
|
"\2|ZXCVBNM<>?\x80\x83\x81",
|
|
];
|
|
var KEYIMGL = Graphics.createImage(`
|
|
|
|
# #
|
|
## #
|
|
######
|
|
## #
|
|
# #
|
|
|
|
|
|
#
|
|
###
|
|
#####
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
`);
|
|
KEYIMGL.transparent = 0;
|
|
var KEYIMGR = Graphics.createImage(`
|
|
|
|
|
|
#
|
|
##
|
|
#########
|
|
##
|
|
#
|
|
|
|
|
|
|
|
#######
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#####
|
|
###
|
|
#
|
|
|
|
#
|
|
###
|
|
#####
|
|
|
|
|
|
# #
|
|
## ##
|
|
### ##### ###
|
|
## ### ##
|
|
# # #
|
|
|
|
`);
|
|
KEYIMGR.transparent = 0;
|
|
/* If a char in the keymap is >=128,
|
|
subtract 128 and look in this array for
|
|
multi-character key codes*/
|
|
var KEYEXTRA = [
|
|
String.fromCharCode(27, 91, 68), // 0x80 left
|
|
String.fromCharCode(27, 91, 67), // 0x81 right
|
|
String.fromCharCode(27, 91, 65), // 0x82 up
|
|
String.fromCharCode(27, 91, 66), // 0x83 down
|
|
String.fromCharCode(27, 91, 53, 126), // 0x84 page up
|
|
String.fromCharCode(27, 91, 54, 126), // 0x85 page down
|
|
];
|
|
|
|
// state
|
|
const R = Bangle.appRect;
|
|
var kbx = 0,
|
|
kby = 0,
|
|
kbdx = 0,
|
|
kbdy = 0,
|
|
kbShift = false,
|
|
flashToggle = false;
|
|
const PX = 12,
|
|
PY = 16,
|
|
DRAGSCALE = settings.speedScaling;
|
|
var xoff = 0,
|
|
yoff = g.getHeight() - PY * 4;
|
|
|
|
function draw() {
|
|
"ram";
|
|
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
|
//g.drawImage(KEYIMG,0,yoff);
|
|
g.reset().setFont("6x8:2");
|
|
g.clearRect(R.x, yoff, R.x2, R.y2);
|
|
if (kbx >= 0)
|
|
g.setColor(g.theme.bgH).fillRect(xoff + kbx * PX, yoff + kby * PY, xoff + (kbx + 1) * PX - 1, yoff + (kby + 1) * PY - 1).setColor(g.theme.fg);
|
|
g.drawImage(KEYIMGL, xoff - 1, yoff + PY, { scale: 2 });
|
|
g.drawImage(KEYIMGR, xoff + PX * 12, yoff, { scale: 2 });
|
|
var replace = /[\x80\x81\x82\x83\x84\x85]/g;
|
|
g.drawString(map[0].replace(replace," "), xoff, yoff);
|
|
g.drawString(map[1].replace(replace," "), xoff, yoff + PY);
|
|
g.drawString(map[2].replace(replace," "), xoff, yoff + PY * 2);
|
|
g.drawString(map[3].replace(replace," "), xoff, yoff + PY * 3);
|
|
g.flip();
|
|
}
|
|
|
|
function startTerminal(dataOutCallback) {
|
|
g.reset().clearRect(R);
|
|
// Set up the terminal
|
|
term = require("VT100").connect(g, {
|
|
charWidth: 6,
|
|
charHeight: 8
|
|
});
|
|
term.oy = R.y;
|
|
term.h = yoff; // we added this - it's not usually part of it
|
|
term.consoleHeight = 0 | ((term.h - term.oy) / term.charH);
|
|
term.scrollDown = function() {
|
|
g.setClipRect(R.x, term.y, R.x2, term.oy + term.h);
|
|
g.scroll(0, -this.charH);
|
|
g.setClipRect(R.x, R.y, R.x2, R.y2);
|
|
this.y--;
|
|
};
|
|
term.fgCol = g.theme.fg;
|
|
term.bgCol = g.theme.bg;
|
|
draw();
|
|
var flashInterval = setInterval(() => {
|
|
flashToggle = !flashToggle;
|
|
draw();
|
|
}, 1000);
|
|
|
|
function keyPress(kbx, kby) {
|
|
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
|
var ch = map[kby][kbx];
|
|
if (ch == "\2")
|
|
kbShift = !kbShift;
|
|
else {
|
|
if (ch.charCodeAt(0) > 127)
|
|
ch = KEYEXTRA[ch.charCodeAt(0) - 128];
|
|
dataOutCallback(ch);
|
|
}
|
|
Bangle.buzz(20);
|
|
draw();
|
|
}
|
|
|
|
Bangle.setUI({
|
|
mode: "custom",
|
|
drag: e => {
|
|
if (settings.oneToOne) {
|
|
kbx = Math.max(Math.min(Math.floor((e.x - 16) / (6 * 2)), 13), 0);
|
|
kby = Math.max(Math.min(Math.floor((e.y - 120) / (8 * 2)), 3), 0);
|
|
//print(e.y, kby, e.x, kbx);
|
|
}
|
|
|
|
if (!settings.oneToOne) {
|
|
kbdx += e.dx;
|
|
kbdy += e.dy;
|
|
var dx = Math.round(kbdx / DRAGSCALE),
|
|
dy = Math.round(kbdy / DRAGSCALE);
|
|
kbdx -= dx * DRAGSCALE;
|
|
kbdy -= dy * DRAGSCALE;
|
|
if (dx || dy) {
|
|
if (settings.loopAround) {
|
|
kbx = (kbx + dx + 15) % 15;
|
|
kby = (kby + dy + 4) % 4;
|
|
} else {
|
|
kbx = Math.max(Math.min((kbx + dx), 13), 0);
|
|
kby = Math.max(Math.min((kby + dy), 3), 0);
|
|
}
|
|
}
|
|
}
|
|
draw();
|
|
|
|
if (!e.b && e.y > Bangle.appRect.y && settings.oneToOne /*&& settings.releaseToSelect*/ )
|
|
keyPress(kbx, kby);
|
|
},
|
|
touch: () => {
|
|
if (!settings.oneToOne /*|| !settings.releaseToSelect*/ )
|
|
keyPress(kbx, kby);
|
|
}
|
|
});
|
|
let catchSwipe = () => {
|
|
E.stopEventPropagation && E.stopEventPropagation();
|
|
};
|
|
Bangle.prependListener && Bangle.prependListener('swipe', catchSwipe); // Intercept swipes on fw2v19 and later. Should not break on older firmwares.
|
|
return {
|
|
dataReceived : function(d) {
|
|
g.reset().setFont("6x8");
|
|
// USB.write(e); // optionally mirror back to the PC
|
|
// Send characters to the terminal
|
|
for (var i in d) term.char(d[i]);
|
|
// update the screen
|
|
g.flip();
|
|
}
|
|
};
|
|
}
|
|
|
|
function mainMenu() {
|
|
E.showMenu({
|
|
"":{title:"Terminal"},
|
|
/*LANG*/"JS REPL" : function() {
|
|
var t = startTerminal(function(d) {
|
|
LoopbackB.write(d);
|
|
});
|
|
LoopbackB.on('data', function(d) {
|
|
t.dataReceived(d);
|
|
});
|
|
// Now move the console to Loopback
|
|
LoopbackA.setConsole();
|
|
},
|
|
/*LANG*/"Bluetooth" : function() {
|
|
Bangle.setUI();
|
|
E.showMessage(/*LANG*/"Scanning...", /*LANG*/"Bluetooth");
|
|
NRF.findDevices(function(devices) {
|
|
if (!devices.length)
|
|
return E.showAlert("No devices found").then(() => mainMenu());
|
|
var menu = { "" : { title: /*LANG*/"Bluetooth", back : () => mainMenu() } };
|
|
devices.forEach(dev => {
|
|
var name = dev.name || dev.id.substr(0,17);
|
|
menu[name] = function() {
|
|
Bangle.setUI();
|
|
E.showMessage(/*LANG*/"Connecting...", /*LANG*/"Bluetooth");
|
|
require("ble_uart").connect(dev).then(function(uart) {
|
|
var t = startTerminal(function(d) {
|
|
uart.write(d);
|
|
});
|
|
t.dataReceived("Connected to:\n "+name+"\n")
|
|
uart.on('data', function(d) { t.dataReceived(d); });
|
|
}).catch(err => {
|
|
E.showAlert(err.toString()).then(() => mainMenu());
|
|
});
|
|
};
|
|
});
|
|
E.showMenu(menu);
|
|
}, { filters: [{ services: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e'] }], timeout: 2000, active:true });
|
|
}
|
|
});
|
|
}
|
|
|
|
mainMenu(); |