pxt-common-packages 12.2.3 → 12.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/libs/azureiot/built/debug/binary.js +461 -461
  2. package/libs/color/built/debug/binary.js +8 -8
  3. package/libs/color-sensor/built/debug/binary.js +8 -8
  4. package/libs/controller/built/debug/binary.js +7120 -7120
  5. package/libs/controller---none/built/debug/binary.js +7100 -7100
  6. package/libs/datalogger/built/debug/binary.js +63 -63
  7. package/libs/edge-connector/built/debug/binary.js +8 -8
  8. package/libs/esp32/built/debug/binary.js +462 -462
  9. package/libs/game/_locales/game-jsdoc-strings.json +2 -0
  10. package/libs/game/_locales/game-strings.json +2 -2
  11. package/libs/game/built/debug/binary.js +7039 -7039
  12. package/libs/game/numberprompt.ts +36 -444
  13. package/libs/game/prompt.ts +222 -258
  14. package/libs/game/pxt.json +2 -0
  15. package/libs/game/systemKeyboard.cpp +32 -0
  16. package/libs/game/systemKeyboard.d.ts +23 -0
  17. package/libs/lcd/built/debug/binary.js +8 -8
  18. package/libs/light-spectrum-sensor/built/debug/binary.js +8 -8
  19. package/libs/lora/built/debug/binary.js +8 -8
  20. package/libs/matrix-keypad/built/debug/binary.js +8 -8
  21. package/libs/mqtt/built/debug/binary.js +176 -176
  22. package/libs/net/built/debug/binary.js +176 -176
  23. package/libs/net-game/built/debug/binary.js +19979 -18810
  24. package/libs/palette/built/debug/binary.js +7038 -7038
  25. package/libs/pixel/built/debug/binary.js +8 -8
  26. package/libs/power/built/debug/binary.js +8 -8
  27. package/libs/proximity/built/debug/binary.js +8 -8
  28. package/libs/radio/built/debug/binary.js +8 -8
  29. package/libs/radio-broadcast/built/debug/binary.js +8 -8
  30. package/libs/rotary-encoder/built/debug/binary.js +8 -8
  31. package/libs/screen/_locales/screen-jsdoc-strings.json +2 -0
  32. package/libs/screen/_locales/screen-strings.json +4 -0
  33. package/libs/screen/built/debug/binary.js +50 -50
  34. package/libs/screen/fieldeditors.ts +1 -0
  35. package/libs/screen/image.d.ts +24 -0
  36. package/libs/screen/image.ts +25 -0
  37. package/libs/servo/built/debug/binary.js +8 -8
  38. package/libs/sprite-scaling/built/debug/binary.js +7038 -7038
  39. package/libs/storyboard/built/debug/binary.js +7038 -7038
  40. package/package.json +1 -1
@@ -1,4 +1,8 @@
1
1
  namespace game {
2
+ export const _KEYBOARD_CHANGE_EVENT = 7339;
3
+ export const _KEYBOARD_ENTER_EVENT = 7340;
4
+ export const _KEYBOARD_CANCEL_EVENT = 7341;
5
+
2
6
  export interface PromptTheme {
3
7
  colorPrompt: number;
4
8
  colorInput: number;
@@ -15,18 +19,20 @@ namespace game {
15
19
  * Ask the player for a string value.
16
20
  * @param message The message to display on the text-entry screen
17
21
  * @param answerLength The maximum number of characters the user can enter (1 - 24)
22
+ * @param useSystemKeyboard Use the computer keyboard for typing if the game is being played in the simulator
18
23
  */
19
24
  //% weight=10 help=game/ask-for-string
20
- //% blockId=gameaskforstring block="ask for string %message || and max length %answerLength"
25
+ //% blockId=gameaskforstring
26
+ //% block="ask for string $message || and max length $answerLength use system keyboard $useSystemKeyboard"
21
27
  //% message.shadow=text
22
28
  //% message.defl=""
23
29
  //% answerLength.defl="12"
24
30
  //% answerLength.min=1
25
31
  //% answerLength.max=24
26
32
  //% group="Prompt"
27
- export function askForString(message: any, answerLength = 12) {
33
+ export function askForString(message: any, answerLength = 12, useSystemKeyboard = false) {
28
34
  let p = new game.Prompt();
29
- const result = p.show(console.inspect(message), answerLength);
35
+ const result = p.show(console.inspect(message), answerLength, useSystemKeyboard);
30
36
  return result;
31
37
  }
32
38
 
@@ -35,8 +41,6 @@ namespace game {
35
41
  const font = image.font8; // FONT8-TODO
36
42
  //% whenUsed=true
37
43
  const PADDING = 4;
38
- //% whenUsed=true
39
- const PROMPT_LINE_SPACING = 2;
40
44
 
41
45
  //% whenUsed=true
42
46
  const NUM_LETTERS = 26;
@@ -66,7 +70,7 @@ namespace game {
66
70
  //% whenUsed=true
67
71
  const BLANK_PADDING = 1;
68
72
  //% whenUsed=true
69
- const ROW_LEFT = PADDING + CELL_WIDTH / 2 + Math.floor((CONTENT_WIDTH - (CELL_WIDTH * ALPHABET_ROW_LENGTH)) / 2);
73
+ const ROW_LEFT = PADDING + Math.floor((CONTENT_WIDTH - (CELL_WIDTH * ALPHABET_ROW_LENGTH)) / 2);
70
74
 
71
75
  // Dimensions of the bottom bar
72
76
  //% whenUsed=true
@@ -74,8 +78,6 @@ namespace game {
74
78
  //% whenUsed=true
75
79
  const BOTTOM_BAR_HEIGHT = PADDING + BOTTOM_BAR_ALPHABET_MARGIN + CELL_HEIGHT;
76
80
  //% whenUsed=true
77
- const BOTTOM_BAR_TOP = screen.height - BOTTOM_BAR_HEIGHT;
78
- //% whenUsed=true
79
81
  const BOTTOM_BAR_BUTTON_WIDTH = PADDING * 2 + font.charWidth * 3;
80
82
  //% whenUsed=true
81
83
  const BOTTOM_BAR_TEXT_Y = (BOTTOM_BAR_HEIGHT - font.charHeight) / 2;
@@ -100,10 +102,6 @@ namespace game {
100
102
  //% whenUsed=true
101
103
  const INPUT_TOP = ALPHABET_TOP - INPUT_HEIGHT - ALPHABET_INPUT_MARGIN;
102
104
 
103
- // Dimensions of prompt message area
104
- //% whenUsed=true
105
- const PROMPT_HEIGHT = INPUT_TOP - CONTENT_TOP;
106
-
107
105
  //% whenUsed=true
108
106
  const lowerShiftText = "ABC";
109
107
  //% whenUsed=true
@@ -121,20 +119,20 @@ namespace game {
121
119
  answerLength: number;
122
120
  result: string;
123
121
 
124
- private cursor: Sprite;
125
- private shiftButton: Sprite;
126
- private confirmButton: Sprite;
122
+ protected confirmPressed: boolean;
123
+ protected cursorRow: number;
124
+ protected cursorColumn: number;
125
+ protected upper: boolean;
126
+ protected useSystemKeyboard: boolean;
127
+
128
+ protected renderable: scene.Renderable;
129
+ protected selectionStart: number;
130
+ protected selectionEnd: number;
127
131
 
128
- private letters: Sprite[];
129
- private inputs: Sprite[];
132
+ protected keyboardRows: number;
133
+ protected keyboardColumns: number;
130
134
 
131
- private confirmPressed: boolean;
132
- private cursorRow: number;
133
- private cursorColumn: number;
134
- private upper: boolean;
135
- private inputIndex: number;
136
- private blink: boolean;
137
- private frameCount: number;
135
+ private changeTime = 0;
138
136
 
139
137
  constructor(theme?: PromptTheme) {
140
138
  if (theme) {
@@ -156,22 +154,63 @@ namespace game {
156
154
  this.cursorRow = 0;
157
155
  this.cursorColumn = 0;
158
156
  this.upper = false;
159
- this.inputIndex = 0;
157
+ this.result = "";
158
+ this.keyboardColumns = ALPHABET_ROW_LENGTH;
159
+ this.keyboardRows = NUM_ROWS;
160
+ this.selectionStart = 0;
161
+ this.selectionEnd = 0;
160
162
  }
161
163
 
162
- show(message: string, answerLength: number) {
164
+ show(message: string, answerLength: number, useSystemKeyboard = false) {
163
165
  this.message = message;
164
166
  this.answerLength = answerLength;
165
- this.inputIndex = 0;
166
167
 
167
168
  controller._setUserEventsEnabled(false);
168
169
  game.pushScene()
169
170
 
170
- this.draw();
171
- this.registerHandlers();
171
+ this.createRenderable();
172
172
  this.confirmPressed = false;
173
173
 
174
- pauseUntil(() => this.confirmPressed);
174
+ if (useSystemKeyboard && control.deviceDalVersion() === "sim" && helpers._isSystemKeyboardSupported()) {
175
+ this.useSystemKeyboard = true;
176
+ helpers._promptForText(this.answerLength, this.numbersOnly());
177
+ this.selectionEnd = 0;
178
+ this.selectionStart = 0;
179
+ control.onEvent(_KEYBOARD_CHANGE_EVENT, 0, () => {
180
+ this.result = helpers._getTextPromptString().substr(0, this.answerLength);
181
+
182
+ this.changeTime = game.runtime();
183
+
184
+ this.selectionStart = helpers._getTextPromptSelectionStart();
185
+ this.selectionEnd = helpers._getTextPromptSelectionEnd();
186
+ })
187
+
188
+ let cancelled = false;
189
+ let finished = false;
190
+
191
+ control.onEvent(_KEYBOARD_CANCEL_EVENT, 0, () => {
192
+ cancelled = true;
193
+ });
194
+
195
+ control.onEvent(_KEYBOARD_ENTER_EVENT, 0, () => {
196
+ finished = true;
197
+ });
198
+
199
+ pauseUntil(() => cancelled || finished);
200
+
201
+ if (cancelled) {
202
+ this.useSystemKeyboard = false;
203
+ this.selectionStart = this.result.length;
204
+ this.selectionEnd = this.selectionStart;
205
+ this.registerHandlers();
206
+ pauseUntil(() => this.confirmPressed);
207
+ }
208
+ }
209
+ else {
210
+ this.useSystemKeyboard = false;
211
+ this.registerHandlers();
212
+ pauseUntil(() => this.confirmPressed);
213
+ }
175
214
 
176
215
  game.popScene();
177
216
  controller._setUserEventsEnabled(true);
@@ -179,147 +218,170 @@ namespace game {
179
218
  return this.result;
180
219
  }
181
220
 
182
- private draw() {
183
- this.drawPromptText();
184
- this.drawKeyboard();
185
- this.drawInputarea();
186
- this.drawBottomBar();
221
+ protected numbersOnly() {
222
+ return false;
187
223
  }
188
224
 
189
- private drawPromptText() {
190
- const prompt = sprites.create(layoutText(this.message, CONTENT_WIDTH, PROMPT_HEIGHT, this.theme.colorPrompt), -1);
191
- prompt.x = screen.width / 2
192
- prompt.y = CONTENT_TOP + Math.floor((PROMPT_HEIGHT - prompt.height) / 2) + Math.floor(prompt.height / 2);
225
+ protected createRenderable() {
226
+ if (this.renderable) {
227
+ this.renderable.destroy();
228
+ }
229
+
230
+ const promptText = new sprites.RenderText(this.message, CONTENT_WIDTH);
231
+ const systemKeyboardText = new sprites.RenderText("Type your response using your keyboard and hit ENTER", CONTENT_WIDTH);
232
+
233
+ this.renderable = scene.createRenderable(-1, () => {
234
+ promptText.draw(screen, (screen.width >> 1) - (promptText.width >> 1), CONTENT_TOP, this.theme.colorPrompt, 0, 2)
235
+ this.drawInputArea();
236
+
237
+ if (!this.useSystemKeyboard) {
238
+ this.drawKeyboard();
239
+ this.drawBottomBar();
240
+ return;
241
+ }
242
+
243
+ screen.fillRect(0, screen.height - (PADDING << 1) - systemKeyboardText.height, screen.width, screen.height, this.theme.colorBottomBackground);
244
+ systemKeyboardText.draw(screen, PADDING, screen.height - PADDING - systemKeyboardText.height, this.theme.colorBottomText);
245
+ });
193
246
  }
194
247
 
195
- private drawInputarea() {
248
+ protected drawInputArea() {
196
249
  const answerLeft = ROW_LEFT + Math.floor(
197
250
  ((CELL_WIDTH * ALPHABET_ROW_LENGTH) -
198
251
  CELL_WIDTH * Math.min(this.answerLength, ALPHABET_ROW_LENGTH)) / 2);
199
252
 
200
- this.inputs = [];
201
253
  for (let i = 0; i < this.answerLength; i++) {
202
- const blank = image.create(CELL_WIDTH, CELL_HEIGHT);
203
- this.drawInput(blank, "", this.theme.colorInput);
204
-
205
254
  const col = i % ALPHABET_ROW_LENGTH;
206
255
  const row = Math.floor(i / ALPHABET_ROW_LENGTH);
207
256
 
208
- const s = sprites.create(blank, -1);
209
- s.x = answerLeft + col * CELL_WIDTH;
210
- s.y = INPUT_TOP + row * CELL_HEIGHT;
211
- this.inputs.push(s);
212
- }
213
- }
214
-
215
- private drawKeyboard() {
216
- const cursorImage = image.create(CELL_WIDTH, CELL_HEIGHT);
217
- cursorImage.fill(this.theme.colorCursor);
218
- this.cursor = sprites.create(cursorImage, -1);
219
- this.cursor.z = -1;
220
- this.updateCursor();
221
-
222
- this.letters = [];
223
- for (let j = 0; j < 36; j++) {
224
- const letter = image.create(CELL_WIDTH, CELL_HEIGHT);
225
-
226
- const col2 = j % ALPHABET_ROW_LENGTH;
227
- const row2 = Math.floor(j / ALPHABET_ROW_LENGTH);
257
+ if (this.selectionStart !== this.selectionEnd && i >= this.selectionStart && i < this.selectionEnd) {
258
+ screen.fillRect(
259
+ answerLeft + col * CELL_WIDTH,
260
+ INPUT_TOP + row * CELL_HEIGHT,
261
+ CELL_WIDTH,
262
+ CELL_HEIGHT,
263
+ this.theme.colorCursor
264
+ );
265
+ }
228
266
 
229
- const t = sprites.create(letter, -1);
230
- t.x = ROW_LEFT + col2 * CELL_WIDTH;
231
- t.y = ALPHABET_TOP + row2 * CELL_HEIGHT;
267
+ screen.fillRect(
268
+ answerLeft + col * CELL_WIDTH + BLANK_PADDING,
269
+ INPUT_TOP + row * CELL_HEIGHT + CELL_HEIGHT - 1,
270
+ CELL_WIDTH - BLANK_PADDING * 2,
271
+ 1,
272
+ !this.useSystemKeyboard && !this.blink() && i === this.selectionStart ? this.theme.colorInputHighlighted : this.theme.colorInput
273
+ );
274
+
275
+ if (i < this.result.length) {
276
+ const char = this.result.charAt(i);
277
+ screen.print(
278
+ char,
279
+ answerLeft + col * CELL_WIDTH + LETTER_OFFSET_X,
280
+ INPUT_TOP + row * CELL_HEIGHT + LETTER_OFFSET_Y,
281
+ this.theme.colorInputText,
282
+ font
283
+ );
284
+ }
285
+ }
232
286
 
233
- this.letters.push(t);
287
+ // draw the blinking text cursor
288
+ if (this.useSystemKeyboard) {
289
+ if (this.selectionStart === this.selectionEnd && this.selectionStart < this.answerLength) {
290
+ const col = this.selectionStart % ALPHABET_ROW_LENGTH;
291
+ const row = Math.floor(this.selectionStart / ALPHABET_ROW_LENGTH);
292
+ if (!this.blink()) {
293
+ screen.fillRect(
294
+ answerLeft + col * CELL_WIDTH,
295
+ INPUT_TOP + row * CELL_HEIGHT,
296
+ 1,
297
+ CELL_HEIGHT,
298
+ this.theme.colorCursor
299
+ );
300
+ }
301
+ }
234
302
  }
235
- this.updateKeyboard();
236
303
  }
237
304
 
238
- private drawBottomBar() {
239
- const bg = image.create(screen.width, BOTTOM_BAR_HEIGHT);
240
- bg.fill(this.theme.colorBottomBackground);
241
-
242
- const bgSprite = sprites.create(bg, -1);
243
- bgSprite.x = screen.width / 2;
244
- bgSprite.y = BOTTOM_BAR_TOP + BOTTOM_BAR_HEIGHT / 2;
245
- bgSprite.z = -1;
305
+ protected drawKeyboard() {
306
+ const top = screen.height - BOTTOM_BAR_HEIGHT - this.keyboardRows * CELL_HEIGHT - PADDING;
307
+ const left = (screen.width >> 1) - ((CELL_WIDTH * this.keyboardColumns) >> 1)
308
+ for (let j = 0; j < this.keyboardRows * this.keyboardColumns; j++) {
309
+ const col = j % this.keyboardColumns;
310
+ const row = Math.idiv(j, this.keyboardColumns);
311
+
312
+ if (col === this.cursorColumn && row === this.cursorRow) {
313
+ screen.fillRect(
314
+ left + col * CELL_WIDTH,
315
+ top + row * CELL_HEIGHT,
316
+ CELL_WIDTH,
317
+ CELL_HEIGHT,
318
+ this.theme.colorCursor
319
+ )
320
+ }
246
321
 
247
- this.shiftButton = sprites.create(image.create(BOTTOM_BAR_BUTTON_WIDTH, BOTTOM_BAR_HEIGHT), -1);
248
- this.shiftButton.x = Math.floor(BOTTOM_BAR_BUTTON_WIDTH / 2);
249
- this.shiftButton.y = BOTTOM_BAR_TOP + Math.ceil(BOTTOM_BAR_HEIGHT / 2);
322
+ screen.print(
323
+ this.getSymbolForIndex(j),
324
+ left + col * CELL_WIDTH + LETTER_OFFSET_X,
325
+ top + row * CELL_HEIGHT + LETTER_OFFSET_Y,
326
+ this.theme.colorAlphabet
327
+ )
328
+ }
329
+ }
250
330
 
251
- this.confirmButton = sprites.create(image.create(BOTTOM_BAR_BUTTON_WIDTH, BOTTOM_BAR_HEIGHT), -1);
252
- this.confirmButton.x = CONFIRM_BUTTON_LEFT + Math.floor(BOTTOM_BAR_BUTTON_WIDTH / 2);
253
- this.confirmButton.y = BOTTOM_BAR_TOP + Math.ceil(BOTTOM_BAR_HEIGHT / 2);
331
+ protected drawBottomBar() {
332
+ this.drawBottomBarBackground();
333
+ this.drawShift(this.cursorRow === 3 && !(this.cursorColumn & 1));
334
+ this.drawConfirm(this.cursorRow === 3 && !!(this.cursorColumn & 1));
335
+ }
254
336
 
255
- this.updateButtons();
337
+ protected drawBottomBarBackground() {
338
+ screen.fillRect(0, screen.height - BOTTOM_BAR_HEIGHT, screen.width, BOTTOM_BAR_HEIGHT, this.theme.colorBottomBackground);
256
339
  }
257
340
 
258
- private updateButtons() {
259
- if (this.cursorRow === 3 && this.cursorColumn % 2 !== 1) {
260
- this.shiftButton.image.fill(this.theme.colorCursor);
261
- }
262
- else {
263
- this.shiftButton.image.fill(this.theme.colorBottomBackground);
341
+ protected drawShift(highlighted: boolean) {
342
+ if (highlighted) {
343
+ screen.fillRect(
344
+ 0,
345
+ screen.height - BOTTOM_BAR_HEIGHT,
346
+ BOTTOM_BAR_BUTTON_WIDTH,
347
+ BOTTOM_BAR_HEIGHT,
348
+ this.theme.colorCursor
349
+ );
264
350
  }
265
351
 
352
+ let shiftText = lowerShiftText;
266
353
  if (this.upper) {
267
- this.shiftButton.image.print(upperShiftText, BOTTOM_BAR_SHIFT_X, BOTTOM_BAR_TEXT_Y);
354
+ shiftText = upperShiftText;
268
355
  }
269
- else {
270
- this.shiftButton.image.print(lowerShiftText, BOTTOM_BAR_SHIFT_X, BOTTOM_BAR_TEXT_Y);
271
- }
272
-
273
-
274
- if (this.cursorRow === 3 && this.cursorColumn % 2) {
275
- this.confirmButton.image.fill(this.theme.colorCursor);
276
- }
277
- else {
278
- this.confirmButton.image.fill(this.theme.colorBottomBackground);
279
- }
280
-
281
- this.confirmButton.image.print(confirmText, BOTTOM_BAR_CONFIRM_X, BOTTOM_BAR_TEXT_Y);
356
+ screen.print(
357
+ shiftText,
358
+ BOTTOM_BAR_SHIFT_X,
359
+ screen.height - BOTTOM_BAR_HEIGHT + BOTTOM_BAR_TEXT_Y,
360
+ this.theme.colorBottomText
361
+ )
282
362
  }
283
363
 
284
- private updateCursor() {
285
- if (this.cursorRow === 3) {
286
- this.cursor.image.fill(0);
287
- this.updateButtons();
288
- }
289
- else {
290
- this.cursor.x = ROW_LEFT + this.cursorColumn * CELL_WIDTH;
291
- this.cursor.y = ALPHABET_TOP + this.cursorRow * CELL_HEIGHT;
364
+ protected drawConfirm(highlighted: boolean) {
365
+ if (highlighted) {
366
+ screen.fillRect(
367
+ CONFIRM_BUTTON_LEFT,
368
+ screen.height - BOTTOM_BAR_HEIGHT,
369
+ BOTTOM_BAR_BUTTON_WIDTH,
370
+ BOTTOM_BAR_HEIGHT,
371
+ this.theme.colorCursor
372
+ );
292
373
  }
293
- }
294
374
 
295
- private updateSelectedInput() {
296
- if (this.inputIndex < this.answerLength) {
297
- const u = this.inputs[this.inputIndex];
298
- if (this.blink) {
299
- this.drawInput(u.image, "", this.theme.colorInput);
300
- }
301
- else {
302
- this.drawInput(u.image, "", this.theme.colorInputHighlighted)
303
- }
304
- }
375
+ screen.print(
376
+ confirmText,
377
+ CONFIRM_BUTTON_LEFT + BOTTOM_BAR_CONFIRM_X,
378
+ screen.height - BOTTOM_BAR_HEIGHT + BOTTOM_BAR_TEXT_Y,
379
+ this.theme.colorBottomText
380
+ )
305
381
  }
306
382
 
307
- private updateKeyboard() {
308
- const len = this.letters.length;
309
- for (let k = 0; k < len; k++) {
310
- const img = this.letters[k].image;
311
- img.fill(0);
312
- img.print(getCharForIndex(k, this.upper), LETTER_OFFSET_X, LETTER_OFFSET_Y);
313
- }
314
- }
315
-
316
- private drawInput(img: Image, char: string, color: number) {
317
- img.fill(0);
318
- img.fillRect(BLANK_PADDING, CELL_HEIGHT - 1, CELL_WIDTH - BLANK_PADDING * 2, 1, color)
319
-
320
- if (char) {
321
- img.print(char, LETTER_OFFSET_X, LETTER_OFFSET_Y, this.theme.colorInputText, font);
322
- }
383
+ protected getSymbolForIndex(index: number) {
384
+ return getCharForIndex(index, this.upper);
323
385
  }
324
386
 
325
387
  private registerHandlers() {
@@ -346,79 +408,56 @@ namespace game {
346
408
  controller.B.onEvent(SYSTEM_KEY_DOWN, () => {
347
409
  this.delete();
348
410
  });
349
-
350
-
351
- this.frameCount = 0;
352
- this.blink = true;
353
-
354
- game.onUpdate(() => {
355
- this.frameCount = (this.frameCount + 1) % 30;
356
-
357
- if (this.frameCount === 0) {
358
- this.blink = !this.blink;
359
-
360
- this.updateSelectedInput();
361
- }
362
- })
363
411
  }
364
412
 
365
- private moveVertical(up: boolean) {
413
+ protected moveVertical(up: boolean) {
366
414
  if (up) {
367
- if (this.cursorRow === 3) {
368
- this.cursor.image.fill(this.theme.colorCursor);
369
- this.cursorRow = 2;
415
+ if (this.cursorRow === this.keyboardRows) {
416
+ this.cursorRow = this.keyboardRows - 1;
370
417
 
371
418
  if (this.cursorColumn % 2) {
372
- this.cursorColumn = ALPHABET_ROW_LENGTH - 1;
419
+ this.cursorColumn = this.keyboardColumns - 1;
373
420
  }
374
421
  else {
375
422
  this.cursorColumn = 0;
376
423
  }
377
-
378
- this.updateButtons();
379
424
  }
380
425
  else {
381
426
  this.cursorRow = Math.max(0, this.cursorRow - 1);
382
427
  }
383
428
  }
384
429
  else {
385
- this.cursorRow = Math.min(3, this.cursorRow + 1);
430
+ this.cursorRow = Math.min(this.keyboardRows, this.cursorRow + 1);
386
431
 
387
- if (this.cursorRow === 3) {
432
+ if (this.cursorRow === this.keyboardRows) {
388
433
  // Go to closest button
389
434
  this.cursorColumn = this.cursorColumn > 5 ? 1 : 0;
390
435
  }
391
436
  }
392
-
393
- this.updateCursor();
394
437
  }
395
438
 
396
- private moveHorizontal(right: boolean) {
439
+ protected moveHorizontal(right: boolean) {
397
440
  if (right) {
398
- this.cursorColumn = (this.cursorColumn + 1) % ALPHABET_ROW_LENGTH;
441
+ this.cursorColumn = (this.cursorColumn + 1) % this.keyboardColumns;
399
442
  }
400
443
  else {
401
- this.cursorColumn = (this.cursorColumn + (ALPHABET_ROW_LENGTH - 1)) % ALPHABET_ROW_LENGTH;
444
+ this.cursorColumn = (this.cursorColumn + (this.keyboardColumns - 1)) % this.keyboardColumns;
402
445
  }
403
-
404
- this.updateCursor();
405
446
  }
406
447
 
407
- private confirm() {
448
+ protected confirm() {
408
449
  if (this.cursorRow === 3) {
409
450
  if (this.cursorColumn % 2) {
410
451
  this.confirmPressed = true;
411
452
  }
412
453
  else {
413
454
  this.upper = !this.upper;
414
- this.updateKeyboard();
415
- this.updateButtons();
416
455
  }
417
456
  }
418
457
  else {
419
- if (this.inputIndex >= this.answerLength) return;
458
+ if (this.selectionStart >= this.answerLength) return;
420
459
 
421
- const index = this.cursorColumn + this.cursorRow * ALPHABET_ROW_LENGTH
460
+ const index = this.cursorColumn + this.cursorRow * this.keyboardColumns
422
461
  const letter = getCharForIndex(index, this.upper);
423
462
 
424
463
  if (!this.result) {
@@ -428,102 +467,27 @@ namespace game {
428
467
  this.result += letter;
429
468
  }
430
469
 
431
- const sprite = this.inputs[this.inputIndex];
470
+ this.changeTime = game.runtime();
471
+
432
472
  this.changeInputIndex(1);
433
- this.drawInput(sprite.image, letter, this.theme.colorInput);
434
473
  }
435
474
  }
436
475
 
437
- private delete() {
438
- if (this.inputIndex <= 0) return;
439
-
440
- if (this.inputIndex < this.answerLength) {
441
- this.drawInput(this.inputs[this.inputIndex].image, "", this.theme.colorInput);
442
- }
476
+ protected delete() {
477
+ if (this.selectionStart <= 0) return;
443
478
 
444
479
  this.result = this.result.substr(0, this.result.length - 1);
445
-
446
480
  this.changeInputIndex(-1);
447
481
  }
448
482
 
449
- private changeInputIndex(delta: number) {
450
- this.inputIndex += delta;
451
- this.frameCount = 0
452
- this.blink = false;
453
- this.updateSelectedInput();
454
- }
455
- }
456
-
457
- function layoutText(message: string, width: number, height: number, color: number) {
458
- const lineHeight = font.charHeight + PROMPT_LINE_SPACING;
459
-
460
- const lineLength = Math.floor(width / font.charWidth);
461
- const numLines = Math.floor(height / lineHeight);
462
-
463
- let lines: string[] = [];
464
- let word: string;
465
- let line: string;
466
-
467
- let pushWord = () => {
468
- if (line) {
469
- if (line.length + word.length + 1 > lineLength) {
470
- lines.push(line);
471
- line = word;
472
- }
473
- else {
474
- line = line + " " + word;
475
- }
476
- }
477
- else {
478
- line = word;
479
- }
480
-
481
- word = null;
482
- }
483
-
484
- for (let l = 0; l < message.length; l++) {
485
- const char = message.charAt(l);
486
-
487
- if (char === " ") {
488
- if (word) {
489
- pushWord();
490
- }
491
- else {
492
- word = " ";
493
- }
494
- }
495
- else if (!word) {
496
- word = char;
497
- }
498
- else {
499
- word += char;
500
- }
483
+ protected changeInputIndex(delta: number) {
484
+ this.selectionStart += delta;
485
+ this.selectionEnd = this.selectionStart;
501
486
  }
502
487
 
503
- if (word) {
504
- pushWord();
488
+ protected blink() {
489
+ return Math.idiv(game.runtime() - this.changeTime, 500) & 1;
505
490
  }
506
-
507
- if (line) {
508
- lines.push(line);
509
- }
510
-
511
- let maxLineWidth = 0;
512
- for (let m = 0; m < lines.length; m++) {
513
- maxLineWidth = Math.max(maxLineWidth, lines[m].length);
514
- }
515
-
516
- const actualWidth = maxLineWidth * font.charWidth;
517
- const actualHeight = lines.length * lineHeight;
518
-
519
- const res = image.create(actualWidth, actualHeight);
520
-
521
- for (let n = 0; n < lines.length; n++) {
522
- if ((n + 1) > numLines) break;
523
- res.print(lines[n], 0, n * lineHeight, color, font);
524
- }
525
-
526
- return res;
527
491
  }
528
492
 
529
493
  function getCharForIndex(index: number, upper: boolean) {
@@ -3,6 +3,8 @@
3
3
  "description": "The game and sprite library - beta",
4
4
  "files": [
5
5
  "ns.ts",
6
+ "systemKeyboard.d.ts",
7
+ "systemKeyboard.cpp",
6
8
  "gameoverrides.ts",
7
9
  "basesprite.ts",
8
10
  "constants.ts",