Skip to content

Commit 6e38fcd

Browse files
committed
inputMethods.ts: Changed Keyboard layout spacing, new NUMERIC_WITH_DELETE layout, NUMERIC_ONLY_POSITIVE layout, NUMERIC. Reworked specialBtn behaviours to point to shared functions. It's easier to add new keyboards now. Changed those 3 Numeric keyboard layouts.
1 parent 5a27959 commit 6e38fcd

1 file changed

Lines changed: 160 additions & 99 deletions

File tree

inputMethods.ts

Lines changed: 160 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
namespace microgui {
32
import AppInterface = user_interface_base.AppInterface
43
import Scene = user_interface_base.Scene
@@ -190,20 +189,22 @@ namespace microgui {
190189
. . . c 1 1 d d d b b f . . . .
191190
. . c c c c c f f f f f f . . .
192191
. . . c b c b c b c c f . . . .
193-
. . . c 1 c d c d c b f d . . .
194-
. . . c 1 c d c d c b f d . . .
195-
. . . c 1 c d c d c b f d . . .
196-
. . . c 1 c d c d c b f d . . .
197-
. . . c 1 1 d d d b b f d . . .
198-
. . . c 1 1 d d d b b f d . . .
199-
. . . . c c c f f f f d . . . .
192+
. . . c 1 c d c d c b f . . . .
193+
. . . c 1 c d c d c b f . . . .
194+
. . . c 1 c d c d c b f . . . .
195+
. . . c 1 c d c d c b f . . . .
196+
. . . c 1 1 d d d b b f . . . .
197+
. . . c 1 1 d d d b b f . . . .
198+
. . . . c c c f f f f . . . . .
200199
. . . . . . . . . . . . . . . .
201200
. . . . . . . . . . . . . . . .
202201
`
203202

204203
export enum KeyboardLayouts {
205204
QWERTY,
206-
NUMERIC
205+
NUMERIC,
206+
NUMERIC_POSITIVE_ONLY,
207+
NUMERIC_WITH_DELETE
207208
}
208209

209210
interface IKeyboard {
@@ -219,7 +220,7 @@ namespace microgui {
219220
}
220221

221222
type KeyboardBtnFn = (btn: Button, kb: IKeyboard) => void;
222-
type SpecialBtnData = { btnRow: number, btnCol: number, behaviour: (btn: Button, kb: IKeyboard) => void };
223+
type SpecialBtnData = { btnRow: number, btnCol: number, behaviour: KeyboardBtnFn };
223224
type KeyboardLayoutData = {
224225
[id: number]: {
225226
btnTexts: (string | Bitmap)[][],
@@ -228,6 +229,68 @@ namespace microgui {
228229
}
229230
};
230231

232+
const __kbBehaviourNumericDefault: KeyboardBtnFn = (btn: Button, kb: IKeyboard) => { // Default Behaviour: Prevent leading zeroes
233+
const btnChar = btn.state[0];
234+
const txt = kb.getText();
235+
const txtLen = txt.length;
236+
237+
if (txtLen == 0) {
238+
kb.appendText(btnChar)
239+
return;
240+
}
241+
242+
// Illegal cases: where there's a "0" or a "-0" and you want to add anything except a '.'
243+
// The decimal point '.' is allowed via the specialBtnBehaviour.
244+
const leadingZeroCase1 = txtLen == 1 && txt[0] == "0";
245+
const leadingZeroCase2 = txtLen == 2 && txt[0] == "-" && txt[1] == "0";
246+
if (leadingZeroCase1 || leadingZeroCase2)
247+
kb.shakeText()
248+
else
249+
kb.appendText(btnChar)
250+
251+
} // End of: default behaviour: Prevent leading zeroes
252+
253+
const __kbBehaviourNumericMinus: KeyboardBtnFn = (btn: Button, kb: IKeyboard) => { // Minus symbol: Toggle "-" at the start.
254+
const txt = kb.getText();
255+
256+
// Remove "-" if its already there:
257+
if (txt[0] == btn.state[0])
258+
if (txt.length == 1)
259+
kb.setText("")
260+
else
261+
kb.setText(txt.slice(1))
262+
else // Add in "-":
263+
kb.setText("-" + txt)
264+
} // END OF: Minus symbol: Toggle "-" at the start.
265+
266+
267+
const __kbBehaviourNumericDeimcal: KeyboardBtnFn = (btn: Button, kb: IKeyboard) => { // Decimal point
268+
const txt = kb.getText();
269+
const len = txt.length;
270+
const decimalAlreadyPresent = txt.includes(".")
271+
if (len == 0 || txt[len - 1] == "-" || decimalAlreadyPresent)
272+
kb.shakeText()
273+
else
274+
kb.appendText(".")
275+
} // END OF: Decimal point
276+
277+
const __kbBehaviourNumericEnter: KeyboardBtnFn = (btn: Button, kb: IKeyboard) => { // Enter
278+
const txt = kb.getText();
279+
const len = txt.length;
280+
const lenRule = txt[len - 1] != "-";
281+
const noDecimalEnding = txt[len - 1] != "."; // Illegal: 0. , -0. , -10. Okay: -0.00.. and 0.000 (becomes 0 later)
282+
283+
if (len > 0 && lenRule && noDecimalEnding) { // Last rule could be removed, casting "1." to number is valid.
284+
// Turn -0 and -0.000... into 0 before returning
285+
const txtAsNum: number = +txt;
286+
if (txtAsNum == 0 || txtAsNum == -0)
287+
kb.setText("0")
288+
kb.nextScene()
289+
} else {
290+
kb.shakeText()
291+
}
292+
} // END OF: ENTER
293+
231294
const __keyboardLayout: KeyboardLayoutData = {
232295
[KeyboardLayouts.QWERTY]: {
233296
btnTexts: [
@@ -254,88 +317,60 @@ namespace microgui {
254317
*/
255318
[KeyboardLayouts.NUMERIC]: {
256319
btnTexts: [
257-
["0", "1", "2", "3", "4"],
258-
["5", "6", "7", "8", "9"],
259-
[btn_delete, "<-", "-", ".", "ENTER"]
320+
["1", "2", "3", "<-"],
321+
["4", "5", "6", ".", "-"],
322+
["7", "8", "9", "0", "ENTER"]
260323
],
261-
defaultBtnBehaviour: (btn: Button, kb: IKeyboard) => { // Default Behaviour: Prevent leading zeroes
262-
const btnChar = btn.state[0];
263-
const txt = kb.getText();
264-
const txtLen = txt.length;
265-
266-
if (txtLen == 0) {
267-
kb.appendText(btnChar)
268-
return;
269-
}
324+
defaultBtnBehaviour: __kbBehaviourNumericDefault,
325+
specialBtnBehaviours: [
326+
{ btnRow: 0, btnCol: 3, behaviour: (btn: Button, kb: IKeyboard) => kb.deletePriorCharacters(1) }, // Backspace
327+
{ btnRow: 1, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericMinus(b, kb) },
328+
{ btnRow: 1, btnCol: 3, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericDeimcal(b, kb) },
329+
{ btnRow: 2, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericEnter(b, kb) }
330+
]
331+
},
270332

271-
// Illegal cases: where there's a "0" or a "-0" and you want to add anything except a '.'
272-
// The decimal point '.' is allowed via the specialBtnBehaviour.
273-
const leadingZeroCase1 = txtLen == 1 && txt[0] == "0";
274-
const leadingZeroCase2 = txtLen == 2 && txt[0] == "-" && txt[1] == "0";
275-
if (leadingZeroCase1 || leadingZeroCase2)
276-
kb.shakeText()
277-
else
278-
kb.appendText(btnChar)
333+
/**
334+
* Ensures that the user inputs result in a valid number.
335+
* E.g: prevents two decimal places, - only at start, etc
336+
*/
337+
[KeyboardLayouts.NUMERIC_POSITIVE_ONLY]: {
338+
btnTexts: [
339+
["1", "2", "3", "<-"],
340+
["4", "5", "6", "."],
341+
["7", "8", "9", "0", "ENTER"]
342+
],
343+
defaultBtnBehaviour: __kbBehaviourNumericDefault,
344+
specialBtnBehaviours: [
345+
{ btnRow: 0, btnCol: 3, behaviour: (b: Button, kb: IKeyboard) => kb.deletePriorCharacters(1) }, // Backspace
346+
{ btnRow: 1, btnCol: 3, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericDeimcal(b, kb) }, // Decimal point
347+
{ btnRow: 2, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericEnter(b, kb) } // Enter
348+
]
349+
},
279350

280-
}, // End of: default behaviour: Prevent leading zeroes
351+
/**
352+
* Same as above, but we have a Trashcan bitmap for a custom delete fn.
353+
* This is used by MicroCode; so its DigitWidget (this keyboard) can be deleted like other elements.
354+
*/
355+
[KeyboardLayouts.NUMERIC_WITH_DELETE]: {
356+
btnTexts: [
357+
["1", "2", "3", "<-", btn_delete],
358+
["4", "5", "6", ".", "-"],
359+
["7", "8", "9", "0", "ENTER"]
360+
],
361+
defaultBtnBehaviour: __kbBehaviourNumericDefault,
281362
specialBtnBehaviours: [
282-
{
283-
btnRow: 2, btnCol: 0, behaviour: (btn: Button, kb: IKeyboard) => { // btn_delete
284-
kb.deleteFn();
285-
}
286-
}, // END OF: btn_delete
287-
{ btnRow: 2, btnCol: 1, behaviour: (btn: Button, kb: IKeyboard) => kb.deletePriorCharacters(1) }, // Backspace
288-
{
289-
btnRow: 2, btnCol: 2, behaviour: (btn: Button, kb: IKeyboard) => { // Minus symbol: Toggle "-" at the start.
290-
const txt = kb.getText();
291-
292-
// Remove "-" if its already there:
293-
if (txt[0] == btn.state[0])
294-
if (txt.length == 1)
295-
kb.setText("")
296-
else
297-
kb.setText(txt.slice(1))
298-
else // Add in "-":
299-
kb.setText("-" + txt)
300-
}
301-
}, // END OF: Minus symbol: Toggle "-" at the start.
302-
{
303-
btnRow: 2, btnCol: 3, behaviour: (btn: Button, kb: IKeyboard) => { // Decimal point
304-
const txt = kb.getText();
305-
const len = txt.length;
306-
const decimalAlreadyPresent = txt.includes(".")
307-
if (len == 0 || txt[len - 1] == "-" || decimalAlreadyPresent)
308-
kb.shakeText()
309-
else
310-
kb.appendText(".")
311-
}
312-
}, // END OF: Decimal point
313-
{
314-
btnRow: 2, btnCol: 4, behaviour: (btn: Button, kb: IKeyboard) => { // Enter
315-
const txt = kb.getText();
316-
const len = txt.length;
317-
const lenRule = txt[len - 1] != "-";
318-
const noDecimalEnding = txt[len - 1] != ".";
319-
320-
// Handle -0:
321-
const txtAsNum: number = +txt;
322-
323-
if (txtAsNum == 0 || txtAsNum == -0)
324-
kb.setText("0")
325-
326-
if (len > 0 && lenRule && noDecimalEnding) // Last rule could be removed, casting "1." to number is valid.
327-
kb.nextScene()
328-
else
329-
kb.shakeText()
330-
}
331-
} // END OF: ENTER
363+
{ btnRow: 0, btnCol: 3, behaviour: (b: Button, kb: IKeyboard) => kb.deletePriorCharacters(1) }, // Backspace
364+
{ btnRow: 0, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => kb.deleteFn() }, // btn_delete
365+
{ btnRow: 1, btnCol: 3, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericDeimcal(b, kb) },// Decimal point
366+
{ btnRow: 1, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericMinus(b, kb) }, // Minus
367+
{ btnRow: 2, btnCol: 4, behaviour: (b: Button, kb: IKeyboard) => __kbBehaviourNumericEnter(b, kb) } // Enter
332368
]
333369
}
334370
};
335371

336372
const KEYBOARD_FRAME_COUNTER_CURSOR_ON = 20;
337373
export class Keyboard extends CursorScene implements IKeyboard {
338-
339374
private btns: Button[][]
340375
private text: string;
341376
private isUpperCase: boolean;
@@ -401,7 +436,6 @@ namespace microgui {
401436
this.passedBackBtn = (opts.backBtn) ? opts.backBtn : () => { };
402437
}
403438

404-
405439
startup() {
406440
super.startup()
407441

@@ -413,35 +447,61 @@ namespace microgui {
413447

414448
const ySpacing = (this.keyboardBounds.height - charHeight) / (data.btnTexts.length);
415449

450+
const btnXPositions: number[][] =
451+
data.btnTexts.map(row =>
452+
row.map((txtOrBitmap: string | Bitmap) => {
453+
if (typeof (txtOrBitmap) == "string")
454+
// return (charWidth * (txtOrBitmap.length + 1) >> 1);
455+
return charWidth * (txtOrBitmap.length + 1);
456+
else
457+
// return txtOrBitmap.width - (txtOrBitmap.width >> 1);
458+
return txtOrBitmap.width - txtOrBitmap.width;
459+
})
460+
);
461+
462+
const btnBitmapWidths: number[][] =
463+
data.btnTexts.map(row =>
464+
row.map((txtOrBitmap: (string | Bitmap)) => {
465+
if (typeof (txtOrBitmap) == "string")
466+
return (charWidth * txtOrBitmap.length) + (charWidth >> 1);
467+
else
468+
return txtOrBitmap.width;
469+
})
470+
);
471+
472+
const btnXPositionAnchor: number =
473+
btnXPositions.map(rowWidth =>
474+
rowWidth.reduce((sum: number, current: number) => sum + current, 0)
475+
)
476+
.reduce((widest: number, current: number) => Math.max(widest, current), 0);
477+
478+
const longestRowLen = data.btnTexts.map(btnTexts => btnTexts.length).reduce((longest, current) => Math.max(longest, current), 0);
479+
// const xSpacing = (this.keyboardBounds.width - btnXPositionAnchor) / (longestRowLen + 1);
480+
416481
for (let row = 0; row < data.btnTexts.length; row++) {
417-
const bitmapWidths = data.btnTexts[row].map((txtOrBitmap: string | Bitmap) => {
418-
if (typeof (txtOrBitmap) == "string")
419-
return charWidth * (txtOrBitmap.length + 1) - 4;
420-
else
421-
return txtOrBitmap.width + 3;
422-
});
482+
// const xSpacing = ((this.keyboardBounds.width - btnXPositionAnchor) / (data.btnTexts[row].length + 1));
483+
const xSpacing = ((this.keyboardBounds.width - btnXPositionAnchor) / (longestRowLen + 1));
484+
// const xSpacing = (this.keyboardBounds.width - btnXPositions[row].reduce((sum, current) => sum + current, 0)) / (data.btnTexts[row].length + 1);
423485

424-
const totalWidth: number = bitmapWidths.reduce((total: number, w: number) => total + w, 0);
425-
const xSpacing = (this.keyboardBounds.width - totalWidth) / (bitmapWidths.length + 2);
486+
let x = -Screen.HALF_WIDTH + xSpacing + (data.btnTexts[row].length >> 1);
426487

427-
let x = -Screen.HALF_WIDTH + xSpacing;
428488
for (let col = 0; col < data.btnTexts[row].length; col++) {
429489
const btnState: (string | Bitmap) = data.btnTexts[row][col];
430-
const bitmapWidth = bitmapWidths[col]
490+
const bitmapWidth = btnBitmapWidths[row][col];
431491

432-
x += (bitmapWidths[col] + xSpacing) >> 1
492+
x += (btnXPositions[row][col] + xSpacing) >> 1
433493
this.btns[row][col] =
434494
new Button({
435495
parent: null,
436496
style: ButtonStyles.Transparent,
437497
icon: (typeof (btnState) == "string") ? bitmaps.create(bitmapWidth, charHeight) : btnState,
438498
ariaId: "",
439-
x,
499+
x: x,
440500
y: -(charHeight >> 1) + (ySpacing * row),
441501
onClick: (btn: Button) => data.defaultBtnBehaviour(btn, this),
442-
state: (typeof (btnState) == "string") ? [btnState] : []
502+
state: (typeof (btnState) == "string") ? [btnState] : [] // String only btnStates; for default QWERTY and NUMERIC behaviours.
443503
})
444-
x += (bitmapWidths[col] + xSpacing) >> 1
504+
x += (btnXPositions[row][col] + xSpacing) >> 1;
445505
}
446506
}
447507

@@ -453,7 +513,7 @@ namespace microgui {
453513
}
454514
)
455515

456-
context.onEvent(ControllerButtonEvent.Pressed, controller.B.id, () => this.passedBackBtn(this.text))
516+
context.onEvent(ControllerButtonEvent.Pressed, controller.B.id, () => this.passedBackBtn(this.text));
457517
this.navigator.setBtns(this.btns);
458518
}
459519

@@ -639,7 +699,8 @@ namespace microgui {
639699
const btn = this.btns[i][j];
640700
const btnText = (btn.state.length > 0) ? btn.state[0] : null;
641701

642-
const x = (screen().width / 2) + btn.xfrm.localPos.x - (btn.icon.width / 2) + 1
702+
const X_SHIFT = 3; // small adjustment to get the btnText to line up with the cursor
703+
const x = (screen().width / 2) + btn.xfrm.localPos.x - (btn.icon.width / 2) + X_SHIFT
643704
const y = (screen().height / 2) + btn.xfrm.localPos.y + charHeight - 12
644705

645706
btn.draw()

0 commit comments

Comments
 (0)