2022-05-05 20:16:06 +00:00
|
|
|
//Multitap logic originally from here: http://www.espruino.com/Morse+Code+Texting
|
|
|
|
|
|
|
|
exports.input = function(options) {
|
2022-05-11 18:11:08 +00:00
|
|
|
options = options||{};
|
2022-05-05 20:16:06 +00:00
|
|
|
var text = options.text;
|
|
|
|
if ("string"!=typeof text) text="";
|
|
|
|
|
2022-05-10 12:23:41 +00:00
|
|
|
var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {};
|
2022-05-11 18:50:02 +00:00
|
|
|
if (settings.firstLaunch===undefined) { settings.firstLaunch = true; }
|
2022-05-10 19:20:43 +00:00
|
|
|
if (settings.charTimeout===undefined) { settings.charTimeout = 500; }
|
2022-05-11 18:17:15 +00:00
|
|
|
if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; }
|
2022-05-10 12:23:41 +00:00
|
|
|
|
2022-05-05 20:16:06 +00:00
|
|
|
var fontSize = "6x15";
|
|
|
|
var Layout = require("Layout");
|
|
|
|
var letters = {
|
|
|
|
"1":".,!?1","2":"ABC2","3":"DEF3",
|
|
|
|
"4":"GHI4","5":"JKL5","6":"MNO6",
|
2022-05-09 12:43:38 +00:00
|
|
|
"7":"PQRS7","8":"TUV80","9":"WXYZ9",
|
2022-05-05 20:16:06 +00:00
|
|
|
};
|
2022-07-03 12:19:53 +00:00
|
|
|
var helpMessage = 'Swipe:\nRight: Space\nLeft:Backspace\nUp: Caps lock\nDown:Move mode';
|
2022-05-05 20:16:06 +00:00
|
|
|
|
|
|
|
var charTimeout; // timeout after a key is pressed
|
|
|
|
var charCurrent; // current character (index in letters)
|
|
|
|
var charIndex; // index in letters[charCurrent]
|
2022-07-03 16:43:57 +00:00
|
|
|
var textIndex = text.length;
|
2022-07-03 16:57:59 +00:00
|
|
|
var textWidth = settings.showHelpBtn ? 10 : 14;
|
2022-05-05 20:16:06 +00:00
|
|
|
var caps = true;
|
|
|
|
var layout;
|
2022-07-03 12:19:53 +00:00
|
|
|
var btnWidth = g.getWidth()/3;
|
|
|
|
|
|
|
|
function getMoveChar(){
|
|
|
|
return "\x00\x0B\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00@\x1F\xE1\x00\x10\x00\x10\x01\x0F\xF0\x04\x01\x00";
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMoreChar(){
|
|
|
|
return "\x00\x0B\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xDB\x1B`\x00\x00\x00";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getCursorChar(){
|
|
|
|
return "\x00\x0B\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xAA\xAA\x80"; }
|
2022-05-05 20:16:06 +00:00
|
|
|
|
2022-05-15 09:52:07 +00:00
|
|
|
function displayText(hideMarker) {
|
2022-05-05 20:16:06 +00:00
|
|
|
layout.clear(layout.text);
|
2022-07-03 12:19:53 +00:00
|
|
|
|
|
|
|
let charsBeforeCursor = textIndex;
|
|
|
|
let charsAfterCursor = Math.min(text.length - textIndex, (textWidth)/2);
|
|
|
|
|
|
|
|
|
|
|
|
let start = textIndex - Math.ceil(textWidth - charsAfterCursor);
|
|
|
|
let startMore = false;
|
|
|
|
if (start > 0) {start++; startMore = true}
|
|
|
|
if (start < 0) start = 0;
|
|
|
|
let cursor = textIndex + 1;
|
|
|
|
|
|
|
|
let end = cursor + Math.floor(start + textWidth - cursor);
|
|
|
|
if (end <= text.length) {end--; if (startMore) end--;}
|
|
|
|
if (end > text.length) end = text.length;
|
|
|
|
|
|
|
|
let pre = (start > 0 ? getMoreChar() : "") + text.slice(start, cursor);
|
|
|
|
let post = text.slice(cursor, end) + (end < text.length - 1 ? getMoreChar() : "");
|
|
|
|
|
|
|
|
layout.text.label = pre + (hideMarker ? " " : (moveMode? getMoveChar():getCursorChar())) + post;
|
2022-05-05 20:16:06 +00:00
|
|
|
layout.render(layout.text);
|
|
|
|
}
|
|
|
|
|
2022-05-15 09:52:07 +00:00
|
|
|
function deactivateTimeout(charTimeout) {
|
2022-05-05 20:16:06 +00:00
|
|
|
if (charTimeout!==undefined) {
|
|
|
|
clearTimeout(charTimeout);
|
|
|
|
charTimeout = undefined;
|
|
|
|
}
|
2022-05-15 09:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function backspace() {
|
|
|
|
deactivateTimeout(charTimeout);
|
2022-05-05 20:16:06 +00:00
|
|
|
text = text.slice(0, -1);
|
2022-07-03 12:19:53 +00:00
|
|
|
if (textIndex > -1) textIndex --;
|
2022-05-05 20:16:06 +00:00
|
|
|
newCharacter();
|
|
|
|
}
|
|
|
|
|
|
|
|
function setCaps() {
|
|
|
|
caps = !caps;
|
|
|
|
for (var key in letters) {
|
|
|
|
layout[key].label = caps ? letters[key].toUpperCase() : letters[key].toLowerCase();
|
|
|
|
}
|
|
|
|
layout.render();
|
|
|
|
}
|
|
|
|
|
|
|
|
function newCharacter(ch) {
|
|
|
|
displayText();
|
2022-07-03 12:19:53 +00:00
|
|
|
if (ch && textIndex < text.length) textIndex ++;
|
2022-05-05 20:16:06 +00:00
|
|
|
charCurrent = ch;
|
|
|
|
charIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function onKeyPad(key) {
|
2022-05-15 09:52:07 +00:00
|
|
|
deactivateTimeout(charTimeout);
|
2022-05-05 20:16:06 +00:00
|
|
|
// work out which char was pressed
|
|
|
|
if (key==charCurrent) {
|
|
|
|
charIndex = (charIndex+1) % letters[charCurrent].length;
|
|
|
|
text = text.slice(0, -1);
|
|
|
|
} else {
|
|
|
|
newCharacter(key);
|
|
|
|
}
|
|
|
|
var newLetter = letters[charCurrent][charIndex];
|
2022-07-03 12:19:53 +00:00
|
|
|
let pre = text.slice(0, textIndex);
|
|
|
|
let post = text.slice(textIndex, text.length);
|
|
|
|
|
|
|
|
text = pre + (caps ? newLetter.toUpperCase() : newLetter.toLowerCase()) + post;
|
|
|
|
|
2022-05-05 20:16:06 +00:00
|
|
|
// set a timeout
|
|
|
|
charTimeout = setTimeout(function() {
|
|
|
|
charTimeout = undefined;
|
|
|
|
newCharacter();
|
2022-05-10 12:23:41 +00:00
|
|
|
}, settings.charTimeout);
|
2022-05-11 17:49:40 +00:00
|
|
|
displayText(charTimeout);
|
2022-05-05 20:16:06 +00:00
|
|
|
}
|
2022-05-09 12:43:38 +00:00
|
|
|
|
2022-07-03 17:07:36 +00:00
|
|
|
var moveMode = false;
|
2022-07-03 12:19:53 +00:00
|
|
|
|
2022-05-09 12:43:38 +00:00
|
|
|
function onSwipe(dirLeftRight, dirUpDown) {
|
2022-07-03 12:19:53 +00:00
|
|
|
if (dirUpDown == -1) {
|
2022-05-09 12:43:38 +00:00
|
|
|
setCaps();
|
2022-07-03 12:19:53 +00:00
|
|
|
} else if (dirUpDown == 1) {
|
|
|
|
moveMode = !moveMode;
|
|
|
|
displayText(false);
|
2022-05-09 12:43:38 +00:00
|
|
|
} else if (dirLeftRight == 1) {
|
2022-07-03 12:19:53 +00:00
|
|
|
if (!moveMode){
|
|
|
|
text += ' ';
|
|
|
|
newCharacter();
|
|
|
|
} else {
|
|
|
|
if (textIndex < text.length) textIndex++;
|
|
|
|
displayText(false);
|
|
|
|
}
|
2022-05-09 12:43:38 +00:00
|
|
|
} else if (dirLeftRight == -1) {
|
2022-07-03 12:19:53 +00:00
|
|
|
if (!moveMode){
|
|
|
|
backspace();
|
|
|
|
} else {
|
|
|
|
if (textIndex > -1) textIndex--;
|
|
|
|
displayText(false);
|
|
|
|
}
|
2022-05-09 12:43:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-10 12:23:41 +00:00
|
|
|
function onHelp(resolve,reject) {
|
|
|
|
Bangle.removeListener("swipe", onSwipe);
|
|
|
|
E.showPrompt(
|
|
|
|
helpMessage, {title: "Help", buttons : {"Ok":true}}
|
|
|
|
).then(function(v) {
|
|
|
|
Bangle.on('swipe', onSwipe);
|
|
|
|
generateLayout(resolve,reject);
|
|
|
|
layout.render();
|
|
|
|
});
|
|
|
|
}
|
2022-05-09 12:43:38 +00:00
|
|
|
|
2022-05-10 12:23:41 +00:00
|
|
|
function generateLayout(resolve,reject) {
|
2022-05-05 20:16:06 +00:00
|
|
|
layout = new Layout( {
|
2022-05-10 12:23:41 +00:00
|
|
|
type:"v", c: [
|
|
|
|
{type:"h", c: [
|
|
|
|
{type:"txt", font:"12x20", label:text.slice(-12), id:"text", fillx:1},
|
2022-05-11 16:23:31 +00:00
|
|
|
(settings.showHelpBtn ? {type:"btn", font:'6x8', label:'?', cb: l=>onHelp(resolve,reject), filly:1 } : {}),
|
2022-05-10 12:23:41 +00:00
|
|
|
]},
|
|
|
|
{type:"h", c: [
|
2022-05-16 09:51:59 +00:00
|
|
|
{type:"btn", font:fontSize, label:letters[1], cb: l=>onKeyPad(1), id:'1', width:btnWidth, filly:1 },
|
|
|
|
{type:"btn", font:fontSize, label:letters[2], cb: l=>onKeyPad(2), id:'2', width:btnWidth, filly:1 },
|
|
|
|
{type:"btn", font:fontSize, label:letters[3], cb: l=>onKeyPad(3), id:'3', width:btnWidth, filly:1 },
|
2022-05-10 12:23:41 +00:00
|
|
|
]},
|
|
|
|
{type:"h", filly:1, c: [
|
2022-05-16 09:51:59 +00:00
|
|
|
{type:"btn", font:fontSize, label:letters[4], cb: l=>onKeyPad(4), id:'4', width:btnWidth, filly:1 },
|
|
|
|
{type:"btn", font:fontSize, label:letters[5], cb: l=>onKeyPad(5), id:'5', width:btnWidth, filly:1 },
|
2022-05-16 09:52:59 +00:00
|
|
|
{type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', width:btnWidth, filly:1 },
|
2022-05-10 12:23:41 +00:00
|
|
|
]},
|
|
|
|
{type:"h", filly:1, c: [
|
2022-05-16 09:51:59 +00:00
|
|
|
{type:"btn", font:fontSize, label:letters[7], cb: l=>onKeyPad(7), id:'7', width:btnWidth, filly:1 },
|
|
|
|
{type:"btn", font:fontSize, label:letters[8], cb: l=>onKeyPad(8), id:'8', width:btnWidth, filly:1 },
|
|
|
|
{type:"btn", font:fontSize, label:letters[9], cb: l=>onKeyPad(9), id:'9', width:btnWidth, filly:1 },
|
2022-05-10 12:23:41 +00:00
|
|
|
]},
|
|
|
|
]
|
2022-05-05 20:16:06 +00:00
|
|
|
},{back: ()=>{
|
2022-05-15 09:52:07 +00:00
|
|
|
deactivateTimeout(charTimeout);
|
2022-05-05 20:16:06 +00:00
|
|
|
Bangle.setUI();
|
2022-05-09 12:43:38 +00:00
|
|
|
Bangle.removeListener("swipe", onSwipe);
|
2022-05-05 20:16:06 +00:00
|
|
|
g.clearRect(Bangle.appRect);
|
|
|
|
resolve(text);
|
|
|
|
}});
|
2022-05-10 12:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new Promise((resolve,reject) => {
|
2022-05-05 20:16:06 +00:00
|
|
|
g.clearRect(Bangle.appRect);
|
2022-05-15 09:52:07 +00:00
|
|
|
if (settings.firstLaunch) {
|
|
|
|
onHelp(resolve,reject);
|
2022-05-10 12:23:41 +00:00
|
|
|
settings.firstLaunch = false;
|
|
|
|
require('Storage').writeJSON("kbmulti.settings.json", settings);
|
|
|
|
} else {
|
|
|
|
generateLayout(resolve,reject);
|
2022-05-15 09:52:07 +00:00
|
|
|
displayText(false);
|
2022-05-10 12:23:41 +00:00
|
|
|
Bangle.on('swipe', onSwipe);
|
|
|
|
layout.render();
|
|
|
|
}
|
2022-05-05 20:16:06 +00:00
|
|
|
});
|
2022-05-09 12:43:38 +00:00
|
|
|
};
|