Add VT100 termional app
parent
daf7e745ec
commit
812a4cfaf4
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4cA///w8h7fOm2V/8fjkf/Gt58jKf4AtiVJkmSARFICK3PlnyCJ1t03aEcBZjCBVJCP4R/CK9N8gRPpmUEaGSuRHP+1KCJ8m5AjgI4PyNZ+cAQIQCwgjKCgQRNdP4R/CL4PJAQIRWAH4ApA=="))
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
/* 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();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 393 B |
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "terminal",
|
||||
"name": "VT100 Terminal",
|
||||
"shortName":"Terminal",
|
||||
"version":"0.01",
|
||||
"description": "Terminal and Keyboard that can be used as a REPL. You can type JS commands into Bangle.js's own REPL and execute them, or you can connect to other Bluetooth LE UART devices (like other Espruinos) and issue commands.",
|
||||
"icon": "app.png",
|
||||
"tags": "terminal,tool,bluetooth",
|
||||
"screenshots" : [ { "url":"screenshot1.png" }, { "url":"screenshot2.png" } ],
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"terminal.app.js","url":"app.js"},
|
||||
{"name":"terminal.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Loading…
Reference in New Issue