mirror of https://github.com/espruino/BangleApps
Accented characters and extended mode
parent
77f82b7c1e
commit
34c35532ed
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Accents and extended mode characters
|
||||||
|
|
|
@ -12,7 +12,14 @@ To display the in app character chart, long press the screen; you can scroll thr
|
||||||
|
|
||||||
For a full character chart see [EwChart.pdf](EwChart.pdf)
|
For a full character chart see [EwChart.pdf](EwChart.pdf)
|
||||||
|
|
||||||
**Supported:** Letters (including capitals), numbers, backspace, word backspace, space, punctuation, new line, and some cursor controls (left, right, word left/right, home, end).
|
**Supported:** Letters (including capitals), numbers, backspace, word backspace, space, punctuation, new line, accents, extended mode (if characters are supported by the vector font), and some cursor controls (left, right, word left/right, home, end).
|
||||||
|
|
||||||
**Unsupported:** Extended mode, accents, and word-level stroking.
|
**Unsupported:** Word-level stroking.
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
Font size can be selected in Settings app > "Apps" > "EdgeWrite Keyboard"
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Woogal [github](https://github.com/retcurve)
|
||||||
|
|
|
@ -193,17 +193,93 @@
|
||||||
"2425": "`",
|
"2425": "`",
|
||||||
"31": " \n",
|
"31": " \n",
|
||||||
"24": " ",
|
"24": " ",
|
||||||
|
"46": "\xb7",
|
||||||
|
"432146": "\xb0",
|
||||||
|
"412346": "\xb0",
|
||||||
|
"123246": "\xae",
|
||||||
|
"2123246": "\xae",
|
||||||
|
"123146": "\xae",
|
||||||
|
"2123146": "\xae",
|
||||||
|
"2346": "\xac",
|
||||||
|
"32146": "\xa9",
|
||||||
|
"41236": "\xa2",
|
||||||
|
"24316": "\xd7",
|
||||||
|
"31246": "\xd7",
|
||||||
|
"316": "\xf7",
|
||||||
|
"136": "\xf7",
|
||||||
|
"232146": "\x80",
|
||||||
|
"23246": "\x80",
|
||||||
|
"132146": "\x80",
|
||||||
|
"412316": "\x80",
|
||||||
|
"323146": "\x80",
|
||||||
|
"324146": "\x80",
|
||||||
|
"24346": "\xa5",
|
||||||
|
"243416": "\xa5",
|
||||||
|
"2143416": "\xa5",
|
||||||
|
"34146": "\xf0",
|
||||||
|
"342146": "\xf0",
|
||||||
|
"343146": "\xf0",
|
||||||
|
"4214346": "\xf0",
|
||||||
|
"414346": "\xf0",
|
||||||
|
"434146": "\xf0",
|
||||||
|
"123416": "\xf0",
|
||||||
|
"2123416": "\xf0",
|
||||||
|
"1346": "\xe6",
|
||||||
|
"1246": "\xe6",
|
||||||
|
"13416": "\xe6",
|
||||||
|
"12416": "\xe6",
|
||||||
|
"3214346": "\xe6",
|
||||||
|
"21416": "\xdf",
|
||||||
|
"213416": "\xdf",
|
||||||
|
"212416": "\xdf",
|
||||||
|
"141216": "\xdf",
|
||||||
|
"1341216": "\xdf",
|
||||||
|
"121416": "\xdf",
|
||||||
|
"1232416": "\xdf",
|
||||||
|
"1231416": "\xdf",
|
||||||
|
"21232416": "\xdf",
|
||||||
|
"21231416": "\xdf",
|
||||||
|
"2321416": "\xdf",
|
||||||
|
"2146": "\xa3",
|
||||||
|
"21436": "\xb5",
|
||||||
|
"214346": "\xb5",
|
||||||
|
"121436": "\xb5",
|
||||||
|
"1214346": "\xb5",
|
||||||
|
"3214316": "\xf8",
|
||||||
|
"3412316": "\xf8",
|
||||||
|
"4126": "\xbf",
|
||||||
|
"216": "\xa1",
|
||||||
|
"346": "\xa6",
|
||||||
|
"21236": "\xb1",
|
||||||
|
"212326": "\xb1",
|
||||||
|
"31426": "\xa4",
|
||||||
|
"24136": "\xa4",
|
||||||
|
"3146": "\xab",
|
||||||
|
"2416": "\xbb",
|
||||||
"32": "#bs",
|
"32": "#bs",
|
||||||
"41": "#wbs",
|
"41": "#wbs",
|
||||||
"12": "#pu-on",
|
"12": "#pu-on",
|
||||||
"43": "#pu-on",
|
"43": "#pu-on",
|
||||||
"325": "#pu-off",
|
"325": "#pu-off",
|
||||||
"415": "#pu-off",
|
"415": "#pu-off",
|
||||||
|
"42": "#ex-on",
|
||||||
|
"326": "#ex-off",
|
||||||
|
"416": "#ex-off",
|
||||||
"323": "#cur-left",
|
"323": "#cur-left",
|
||||||
"232": "#cur-right",
|
"232": "#cur-right",
|
||||||
"414": "#cur-word-left",
|
"414": "#cur-word-left",
|
||||||
"141": "#cur-word-right",
|
"141": "#cur-word-right",
|
||||||
"4141": "#cur-home",
|
"4141": "#cur-home",
|
||||||
"1414": "#cur-end"
|
"1414": "#cur-end",
|
||||||
|
"242": "#grave",
|
||||||
|
"313": "#acute",
|
||||||
|
"431": "#circumflex",
|
||||||
|
"421": "#circumflex",
|
||||||
|
"3421": "#tilde",
|
||||||
|
"43412": "#umlaut",
|
||||||
|
"43214": "#ring",
|
||||||
|
"41234": "#ring",
|
||||||
|
"142": "#cedilla",
|
||||||
|
"143": "#cedilla"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,20 @@ exports.input = function(options) {
|
||||||
let chartX = 0;
|
let chartX = 0;
|
||||||
let chartY = 0;
|
let chartY = 0;
|
||||||
|
|
||||||
|
let settings = Object.assign({
|
||||||
|
fontSize: 32,
|
||||||
|
}, require('Storage').readJSON("kbedgewrite.json", true));
|
||||||
|
|
||||||
let shouldShowWidgetBar = Bangle.appRect.y > 0;
|
let shouldShowWidgetBar = Bangle.appRect.y > 0;
|
||||||
|
|
||||||
options = options||{};
|
options = options||{};
|
||||||
let text = options.text;
|
let text = options.text;
|
||||||
|
// Substring doesn't play well with UTF8
|
||||||
|
if (E.isUTF8(text)) {
|
||||||
|
text = E.decodeUTF8(text);
|
||||||
|
}
|
||||||
|
let wrappedText = '';
|
||||||
|
|
||||||
if ('string' != typeof text) text='';
|
if ('string' != typeof text) text='';
|
||||||
|
|
||||||
// Colours for number of corner occurrences
|
// Colours for number of corner occurrences
|
||||||
|
@ -18,40 +28,140 @@ exports.input = function(options) {
|
||||||
|
|
||||||
const cornerSize = g.getWidth() / 3;
|
const cornerSize = g.getWidth() / 3;
|
||||||
let punctuationMode = false;
|
let punctuationMode = false;
|
||||||
|
let extendedMode = false;
|
||||||
let path = '';
|
let path = '';
|
||||||
let cursorPos = text.length;
|
let cursorPos = text.length;
|
||||||
let chartShown = false;
|
let chartShown = false;
|
||||||
|
|
||||||
let characterSet = Object.assign({}, require('Storage').readJSON('kbedgewrite.charset.json', true) || {});
|
let characterSet = Object.assign({}, require('Storage').readJSON('kbedgewrite.charset.json', true) || {});
|
||||||
|
|
||||||
function draw() {
|
const accentedCharacters = {
|
||||||
g.clearRect(Bangle.appRect).setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2);
|
'#grave': {
|
||||||
|
'a': String.fromCharCode(0xE0),
|
||||||
|
'A': String.fromCharCode(0xC0),
|
||||||
|
'e': String.fromCharCode(0xE8),
|
||||||
|
'E': String.fromCharCode(0xC8),
|
||||||
|
'i': String.fromCharCode(0xEC),
|
||||||
|
'I': String.fromCharCode(0xCC),
|
||||||
|
'o': String.fromCharCode(0xF2),
|
||||||
|
'O': String.fromCharCode(0xD2),
|
||||||
|
'u': String.fromCharCode(0xF9),
|
||||||
|
'U': String.fromCharCode(0xD9)
|
||||||
|
},
|
||||||
|
'#acute': {
|
||||||
|
'a': String.fromCharCode(0xE1),
|
||||||
|
'A': String.fromCharCode(0xC1),
|
||||||
|
'e': String.fromCharCode(0xE9),
|
||||||
|
'E': String.fromCharCode(0xC9),
|
||||||
|
'i': String.fromCharCode(0xED),
|
||||||
|
'I': String.fromCharCode(0xCD),
|
||||||
|
'o': String.fromCharCode(0xF3),
|
||||||
|
'O': String.fromCharCode(0xD3),
|
||||||
|
'u': String.fromCharCode(0xFA),
|
||||||
|
'U': String.fromCharCode(0xDA),
|
||||||
|
'y': String.fromCharCode(0xFD),
|
||||||
|
'Y': String.fromCharCode(0xDD)
|
||||||
|
},
|
||||||
|
'#circumflex': {
|
||||||
|
'a': String.fromCharCode(0xE2),
|
||||||
|
'A': String.fromCharCode(0xC2),
|
||||||
|
'e': String.fromCharCode(0xEA),
|
||||||
|
'E': String.fromCharCode(0xCA),
|
||||||
|
'i': String.fromCharCode(0xEE),
|
||||||
|
'I': String.fromCharCode(0xCE),
|
||||||
|
'o': String.fromCharCode(0xF4),
|
||||||
|
'O': String.fromCharCode(0xD4),
|
||||||
|
'u': String.fromCharCode(0xFB),
|
||||||
|
'U': String.fromCharCode(0xDB)
|
||||||
|
},
|
||||||
|
'#umlaut': {
|
||||||
|
'a': String.fromCharCode(0xE4),
|
||||||
|
'A': String.fromCharCode(0xC4),
|
||||||
|
'e': String.fromCharCode(0xEB),
|
||||||
|
'E': String.fromCharCode(0xCB),
|
||||||
|
'i': String.fromCharCode(0xEF),
|
||||||
|
'I': String.fromCharCode(0xCF),
|
||||||
|
'o': String.fromCharCode(0xF6),
|
||||||
|
'O': String.fromCharCode(0xD6),
|
||||||
|
'u': String.fromCharCode(0xFC),
|
||||||
|
'U': String.fromCharCode(0xDC),
|
||||||
|
'y': String.fromCharCode(0xFF)
|
||||||
|
},
|
||||||
|
'#tilde': {
|
||||||
|
'a': String.fromCharCode(0xE3),
|
||||||
|
'A': String.fromCharCode(0xC3),
|
||||||
|
'n': String.fromCharCode(0xF1),
|
||||||
|
'N': String.fromCharCode(0xD1),
|
||||||
|
'o': String.fromCharCode(0xF5),
|
||||||
|
'O': String.fromCharCode(0xD5)
|
||||||
|
},
|
||||||
|
'#ring': {
|
||||||
|
'a': String.fromCharCode(0xE5),
|
||||||
|
'A': String.fromCharCode(0xC5)
|
||||||
|
},
|
||||||
|
'#cedilla': {
|
||||||
|
'c': String.fromCharCode(0xE7),
|
||||||
|
'C': String.fromCharCode(0xC7)
|
||||||
|
},
|
||||||
|
|
||||||
// Draw the text string
|
};
|
||||||
let l = g.setFont('6x8:4').wrapString(text.substring(0, cursorPos) + '_' + text.substring(cursorPos), g.getWidth());
|
|
||||||
if (!l) l = [];
|
function wrapText() {
|
||||||
if (l.length>5) {
|
let stringToWrap = text.substring(0, cursorPos) + '_' + text.substring(cursorPos);
|
||||||
|
let l = [];
|
||||||
|
let startPos = 0;
|
||||||
|
|
||||||
|
g.setFont("Vector", settings.fontSize); // set the font so we can calculate a string width
|
||||||
|
|
||||||
|
// Wrap the string into array of lines that will fit the screen width
|
||||||
|
for (let i = 0; i < stringToWrap.length; i++) {
|
||||||
|
// wrap if string is too long or we hit a line break
|
||||||
|
if (stringToWrap.charCodeAt(i) == 10 || g.stringWidth(stringToWrap.substring(startPos, i+1)) > 176) {
|
||||||
|
l.push(stringToWrap.substring(startPos, i));
|
||||||
|
// skip the line break
|
||||||
|
if (stringToWrap.charCodeAt(i) == 10) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
startPos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the final line
|
||||||
|
l.push(stringToWrap.substring(startPos));
|
||||||
|
|
||||||
|
// Number of lines that can fit on the screen
|
||||||
|
let numLines = Math.floor(g.getHeight() / g.getFontHeight());
|
||||||
|
|
||||||
|
// If too many lines, reposition so the cursor can be seen
|
||||||
|
if (l.length > numLines) {
|
||||||
let textPos = 0;
|
let textPos = 0;
|
||||||
let lineNum;
|
let lineNum;
|
||||||
for (lineNum = 0; lineNum < l.length; lineNum++) {
|
for (lineNum = 0; lineNum < l.length; lineNum++) {
|
||||||
textPos = textPos + l[lineNum].length - 1;
|
textPos = textPos + l[lineNum].length;
|
||||||
if (textPos >= cursorPos) break;
|
if (textPos >= cursorPos) break;
|
||||||
}
|
}
|
||||||
l=l.slice(lineNum - l.length - 5);
|
l=l.slice(lineNum - l.length - numLines + 1);
|
||||||
}
|
}
|
||||||
g.setColor(g.theme.fg);
|
|
||||||
g.setFontAlign(-1, -1, 0);
|
|
||||||
g.drawString(l.join('\n'), Bangle.appRect.x, Bangle.appRect.y);
|
|
||||||
|
|
||||||
// Draw punctuation flag
|
wrappedText = l.join('\n');
|
||||||
if (punctuationMode > 0) {
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
g.clearRect(Bangle.appRect).setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2);
|
||||||
|
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setFont("Vector", settings.fontSize);
|
||||||
|
g.setFontAlign(-1, -1, 0);
|
||||||
|
g.drawString(wrappedText, Bangle.appRect.x, Bangle.appRect.y);
|
||||||
|
|
||||||
|
// Draw punctuation or extended flags
|
||||||
|
if (punctuationMode || extendedMode) {
|
||||||
let x = (g.getWidth() / 2) - 12;
|
let x = (g.getWidth() / 2) - 12;
|
||||||
let y = g.getHeight() - 32;
|
let y = g.getHeight() - 32;
|
||||||
g.setColor('#F00');
|
g.setColor(punctuationMode ? '#F00' : '#0F0');
|
||||||
g.fillRect(x,y,x+24,y+32);
|
g.fillRect(x,y,x+24,y+32);
|
||||||
g.setColor('#FFF');
|
g.setColor('#FFF');
|
||||||
g.setFont('6x8:4');
|
g.setFont('6x8:4');
|
||||||
g.drawString('P', x+4, y+4, false);
|
g.drawString(punctuationMode ? 'P' : 'E', x+4, y+4, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw corners
|
// Draw corners
|
||||||
|
@ -69,30 +179,27 @@ exports.input = function(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function processPath() {
|
function processPath() {
|
||||||
let capital = false;
|
|
||||||
|
|
||||||
// Punctuation paths end in 5
|
// Punctuation paths end in 5
|
||||||
if (punctuationMode) {
|
if (punctuationMode) {
|
||||||
path = path + '5';
|
path = path + '5';
|
||||||
}
|
}
|
||||||
|
// Extended paths end in 6
|
||||||
// Capital letters end in 2, remove that and set a capital flag
|
if (extendedMode) {
|
||||||
// but only if the path isn't 232 (cursor right)
|
path = path + '6';
|
||||||
if (path != '232' && path.length > 2 && path.slice(-1) == '2') {
|
|
||||||
path = path.slice(0,-1);
|
|
||||||
capital = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find character from path
|
// Find character from path
|
||||||
let char = characterSet[path];
|
let char = characterSet[path];
|
||||||
|
|
||||||
// Handle capitals
|
// Unknown character, but ends in a 2 so may be a capital letter
|
||||||
if (capital && char != 'undefined') {
|
if (char == 'undefined' && path.slice(-1) == '2') {
|
||||||
if (char.charCodeAt(0)>96 && char.charCodeAt(0)<123) {
|
// Remove the 2 and look for a letter
|
||||||
char = char.toUpperCase();
|
char = characterSet[path.slice(0,-1)];
|
||||||
} else {
|
// Handle capitals
|
||||||
// Anything that can't be capitalised is an invalid path
|
if (char != 'undefined') {
|
||||||
char = undefined;
|
if (char.charCodeAt(0)>96 && char.charCodeAt(0)<123) {
|
||||||
|
char = char.toUpperCase();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +236,17 @@ exports.input = function(options) {
|
||||||
punctuationMode = false;
|
punctuationMode = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Enable extended mode
|
||||||
|
case '#ex-on': {
|
||||||
|
extendedMode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Disable extended mode
|
||||||
|
case '#ex-off': {
|
||||||
|
extendedMode = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Cursor controls
|
||||||
case '#cur-left': {
|
case '#cur-left': {
|
||||||
if (cursorPos > 0) {
|
if (cursorPos > 0) {
|
||||||
cursorPos--;
|
cursorPos--;
|
||||||
|
@ -168,6 +286,22 @@ exports.input = function(options) {
|
||||||
cursorPos = text.length;
|
cursorPos = text.length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Accents
|
||||||
|
case '#grave':
|
||||||
|
case '#acute':
|
||||||
|
case '#circumflex':
|
||||||
|
case '#umlaut':
|
||||||
|
case '#tilde':
|
||||||
|
case '#ring':
|
||||||
|
case '#cedilla':
|
||||||
|
// If the previous character can be accented, replace it with the accented version
|
||||||
|
if (cursorPos > 0) {
|
||||||
|
char = accentedCharacters[char][text.substring(cursorPos-1, cursorPos)];
|
||||||
|
if (char != 'undefined') {
|
||||||
|
text = text.substring(0, cursorPos-1) + char + text.substring(cursorPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
// Append character
|
// Append character
|
||||||
default: {
|
default: {
|
||||||
text = text.substring(0, cursorPos) + char + text.substring(cursorPos);
|
text = text.substring(0, cursorPos) + char + text.substring(cursorPos);
|
||||||
|
@ -184,6 +318,7 @@ exports.input = function(options) {
|
||||||
if (!chartShown) {
|
if (!chartShown) {
|
||||||
if (e.b == 0) { // Finger lifted, process completed path
|
if (e.b == 0) { // Finger lifted, process completed path
|
||||||
processPath();
|
processPath();
|
||||||
|
wrapText();
|
||||||
draw();
|
draw();
|
||||||
} else {
|
} else {
|
||||||
let corner = 0;
|
let corner = 0;
|
||||||
|
@ -220,6 +355,7 @@ exports.input = function(options) {
|
||||||
// Draw initial string
|
// Draw initial string
|
||||||
require("widget_utils").hide();
|
require("widget_utils").hide();
|
||||||
g.setBgColor(g.theme.bg);
|
g.setBgColor(g.theme.bg);
|
||||||
|
wrapText();
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
{ "id": "kbedgewrite",
|
{ "id": "kbedgewrite",
|
||||||
"name": "EdgeWrite keyboard",
|
"name": "EdgeWrite keyboard",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "A library for text input via EdgeWrite swipe gestures",
|
"description": "A library for text input via EdgeWrite swipe gestures",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type":"textinput",
|
"type":"textinput",
|
||||||
"tags": "keyboard",
|
"tags": "keyboard",
|
||||||
"supports" : ["BANGLEJS2"],
|
"supports" : ["BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
"screenshots" : [ { "url":"screenshot.png" } ],
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"textinput","url":"lib.js"},
|
{"name":"textinput","url":"lib.js"},
|
||||||
{"name":"kbedgewrite.charset.json","url":"characterset.json"}
|
{"name":"kbedgewrite.charset.json","url":"characterset.json"},
|
||||||
|
{"name":"kbedgewrite.settings.js","url":"settings.js"}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"name":"kbedgewrite.json"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
|
@ -0,0 +1,40 @@
|
||||||
|
(function(back) {
|
||||||
|
var FILE = 'kbedgewrite.json';
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
var settings = Object.assign({
|
||||||
|
fontSize: 32
|
||||||
|
}, require('Storage').readJSON(FILE, true) || {});
|
||||||
|
|
||||||
|
function setSetting(key,value) {
|
||||||
|
settings[key] = value;
|
||||||
|
require('Storage').writeJSON(FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method which uses int-based menu item for set of string values and their labels
|
||||||
|
function stringItems(key, startvalue, values, labels) {
|
||||||
|
return {
|
||||||
|
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
|
||||||
|
format: v => labels[v],
|
||||||
|
min: 0,
|
||||||
|
max: values.length - 1,
|
||||||
|
wrap: true,
|
||||||
|
step: 1,
|
||||||
|
onchange: v => {
|
||||||
|
setSetting(key,values[v]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method which breaks string set settings down to local settings object
|
||||||
|
function stringInSettings(name, values, labels) {
|
||||||
|
return stringItems(name,settings[name], values, labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the menu
|
||||||
|
E.showMenu({
|
||||||
|
'' : { 'title' : 'EdgeWrite' },
|
||||||
|
'< Back' : () => back(),
|
||||||
|
'Font Size': stringInSettings('fontSize', [24, 32, 48], ['Small', 'Medium', 'Large'])
|
||||||
|
});
|
||||||
|
})
|
Loading…
Reference in New Issue