Skip to content

Commit

Permalink
Add support for system keyboard in string/number prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
riknoll committed Jan 8, 2024
1 parent 888d92d commit 9b12ed9
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 20 deletions.
96 changes: 86 additions & 10 deletions libs/game/numberprompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ namespace game {
* Ask the player for a number value.
* @param message The message to display on the text-entry screen
* @param answerLength The maximum number of digits the user can enter (1 - 10)
* @param useSystemKeyboard Use the computer keyboard for typing if the game is being played in the simulator
*/
//% weight=10 help=game/ask-for-number
//% blockId=gameaskfornumber block="ask for number %message || and max length %answerLength"
//% blockId=gameaskfornumber
//% block="ask for number $message || and max length $answerLength use system keyboard $useSystemKeyboard"
//% message.shadow=text
//% message.defl=""
//% answerLength.defl="6"
//% answerLength.min=1
//% answerLength.max=10
//% group="Prompt"
export function askForNumber(message: any, answerLength = 6) {
export function askForNumber(message: any, answerLength = 6, useSystemKeyboard = false) {
answerLength = Math.max(0, Math.min(10, answerLength));
let p = new game.NumberPrompt();
const result = p.show(console.inspect(message), answerLength);
const result = p.show(console.inspect(message), answerLength, useSystemKeyboard);
return result;
}

Expand Down Expand Up @@ -123,6 +125,14 @@ namespace game {
private blink: boolean;
private frameCount: number;

private useSystemKeyboard: boolean;

private renderable: scene.Renderable;
private selectionStart: number;
private selectionEnd: number;

private changeTime = 0;

constructor(theme?: PromptTheme) {
if (theme) {
this.theme = theme;
Expand All @@ -146,19 +156,43 @@ namespace game {
this.inputIndex = 0;
}

show(message: string, answerLength: number) : number {
show(message: string, answerLength: number, useSystemKeyboard = false) : number {
this.message = message;
this.answerLength = answerLength;
this.inputIndex = 0;

controller._setUserEventsEnabled(false);
game.pushScene()

this.draw();
this.registerHandlers();
this.confirmPressed = false;
if (useSystemKeyboard && control.deviceDalVersion() === "sim") {
this.useSystemKeyboard = true;
this.draw();
helpers._promptForText(this.answerLength, true);
this.selectionEnd = 0;
this.selectionStart = 0;
control.onEvent(_KEYBOARD_CHANGE_EVENT, 0, () => {
this.result = helpers._getTextPromptString().substr(0, this.answerLength);

for (let i = 0; i < this.inputs.length; i++) {
this.drawInput(this.inputs[i].image, this.result.charAt(i) || "", this.theme.colorInput)
}

this.changeTime = game.runtime();

this.selectionStart = helpers._getTextPromptSelectionStart();
this.selectionEnd = helpers._getTextPromptSelectionEnd();
})

control.waitForEvent(_KEYBOARD_ENTER_EVENT, 0);
}
else {
this.useSystemKeyboard = false;
this.draw();
this.registerHandlers();
this.confirmPressed = false;
pauseUntil(() => this.confirmPressed);
}

pauseUntil(() => this.confirmPressed);

game.popScene();
controller._setUserEventsEnabled(true);
Expand All @@ -168,9 +202,51 @@ namespace game {

private draw() {
this.drawPromptText();
this.drawNumpad();
this.drawInputarea();
this.drawBottomBar();

if (!this.useSystemKeyboard) {
this.drawNumpad();
this.drawBottomBar();
}

this.renderable = scene.createRenderable(this.inputs[0].z - 1, () => {
if (!this.useSystemKeyboard) return;

if (this.selectionStart === this.selectionEnd) {
const input = this.inputs[this.selectionStart];
if (input && !(Math.idiv(game.runtime() - this.changeTime, 500) & 1)) {
screen.fillRect(input.left, input.top, 1, input.height, this.theme.colorInput);
}
}
else {
let currentY = undefined;
let startX = undefined;
let endX = undefined;
for (let i = this.selectionStart; i < this.selectionEnd; i++) {
const current = this.inputs[i];

if (!current) break;

if (!currentY) {
currentY = current.top;
startX = current.left
endX = current.right;
}
else if (current.top !== currentY) {
screen.fillRect(startX, currentY, endX - startX, this.inputs[0].height, this.theme.colorCursor);

currentY = current.top;
startX = current.left
endX = current.right;
}
else {
endX = current.right;
}
}

screen.fillRect(startX, currentY, endX - startX, this.inputs[0].height, this.theme.colorCursor);
}
});
}

private drawPromptText() {
Expand Down
98 changes: 88 additions & 10 deletions libs/game/prompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace game {
export const _KEYBOARD_CHANGE_EVENT = 7339;
export const _KEYBOARD_ENTER_EVENT = 7340;

export interface PromptTheme {
colorPrompt: number;
colorInput: number;
Expand All @@ -15,18 +18,20 @@ namespace game {
* Ask the player for a string value.
* @param message The message to display on the text-entry screen
* @param answerLength The maximum number of characters the user can enter (1 - 24)
* @param useSystemKeyboard Use the computer keyboard for typing if the game is being played in the simulator
*/
//% weight=10 help=game/ask-for-string
//% blockId=gameaskforstring block="ask for string %message || and max length %answerLength"
//% blockId=gameaskforstring
//% block="ask for string $message || and max length $answerLength use system keyboard $useSystemKeyboard"
//% message.shadow=text
//% message.defl=""
//% answerLength.defl="12"
//% answerLength.min=1
//% answerLength.max=24
//% group="Prompt"
export function askForString(message: any, answerLength = 12) {
export function askForString(message: any, answerLength = 12, useSystemKeyboard = false) {
let p = new game.Prompt();
const result = p.show(console.inspect(message), answerLength);
const result = p.show(console.inspect(message), answerLength, useSystemKeyboard);
return result;
}

Expand Down Expand Up @@ -135,6 +140,13 @@ namespace game {
private inputIndex: number;
private blink: boolean;
private frameCount: number;
private useSystemKeyboard: boolean;

private renderable: scene.Renderable;
private selectionStart: number;
private selectionEnd: number;

private changeTime = 0;

constructor(theme?: PromptTheme) {
if (theme) {
Expand All @@ -159,19 +171,43 @@ namespace game {
this.inputIndex = 0;
}

show(message: string, answerLength: number) {
show(message: string, answerLength: number, useSystemKeyboard = false) {
this.message = message;
this.answerLength = answerLength;
this.inputIndex = 0;

controller._setUserEventsEnabled(false);
game.pushScene()

this.draw();
this.registerHandlers();
this.confirmPressed = false;
if (useSystemKeyboard && control.deviceDalVersion() === "sim") {
this.useSystemKeyboard = true;
this.draw();
helpers._promptForText(this.answerLength, false);
this.selectionEnd = 0;
this.selectionStart = 0;
control.onEvent(_KEYBOARD_CHANGE_EVENT, 0, () => {
this.result = helpers._getTextPromptString().substr(0, this.answerLength);

for (let i = 0; i < this.inputs.length; i++) {
this.drawInput(this.inputs[i].image, this.result.charAt(i) || "", this.theme.colorInput)
}

this.changeTime = game.runtime();

this.selectionStart = helpers._getTextPromptSelectionStart();
this.selectionEnd = helpers._getTextPromptSelectionEnd();
})

control.waitForEvent(_KEYBOARD_ENTER_EVENT, 0);
}
else {
this.useSystemKeyboard = false;
this.draw();
this.registerHandlers();
this.confirmPressed = false;
pauseUntil(() => this.confirmPressed);
}

pauseUntil(() => this.confirmPressed);

game.popScene();
controller._setUserEventsEnabled(true);
Expand All @@ -181,9 +217,51 @@ namespace game {

private draw() {
this.drawPromptText();
this.drawKeyboard();
this.drawInputarea();
this.drawBottomBar();

if (!this.useSystemKeyboard) {
this.drawKeyboard();
this.drawBottomBar();
}

this.renderable = scene.createRenderable(this.inputs[0].z - 1, () => {
if (!this.useSystemKeyboard) return;

if (this.selectionStart === this.selectionEnd) {
const input = this.inputs[this.selectionStart];
if (input && !(Math.idiv(game.runtime() - this.changeTime, 500) & 1)) {
screen.fillRect(input.left, input.top, 1, input.height, this.theme.colorInput);
}
}
else {
let currentY = undefined;
let startX = undefined;
let endX = undefined;
for (let i = this.selectionStart; i < this.selectionEnd; i++) {
const current = this.inputs[i];

if (!current) break;

if (!currentY) {
currentY = current.top;
startX = current.left
endX = current.right;
}
else if (current.top !== currentY) {
screen.fillRect(startX, currentY, endX - startX, this.inputs[0].height, this.theme.colorCursor);

currentY = current.top;
startX = current.left
endX = current.right;
}
else {
endX = current.right;
}
}

screen.fillRect(startX, currentY, endX - startX, this.inputs[0].height, this.theme.colorCursor);
}
});
}

private drawPromptText() {
Expand Down
2 changes: 2 additions & 0 deletions libs/game/pxt.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"description": "The game and sprite library - beta",
"files": [
"ns.ts",
"systemKeyboard.d.ts",
"systemKeyboard.cpp",
"gameoverrides.ts",
"basesprite.ts",
"constants.ts",
Expand Down
27 changes: 27 additions & 0 deletions libs/game/systemKeyboard.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "pxt.h"

namespace Keyboard {

//%
void promptForText(int maxLength, bool numberOnly) {
}

//%
void cancelTextPrompt() {
}

//%
ManagedString getTextPromptString() {
return NULL;
}

//%
int getTextPromptSelectionStart() {
return 0;
}

//%
int getTextPromptSelectionEnd() {
return 0;
}
}
20 changes: 20 additions & 0 deletions libs/game/systemKeyboard.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

/**
* These shims are for enabling system keyboard support in text/number prompts.
*/
declare namespace helpers {
//% shim=Keyboard::promptForText
function _promptForText(maxLength: number, numbersOnly: boolean): void;

//% shim=Keyboard::cancelTextPrompt
function _cancelTextPrompt(): void;

//% shim=Keyboard::getTextPromptString
function _getTextPromptString(): string;

//% shim=Keyboard::getTextPromptSelectionStart
function _getTextPromptSelectionStart(): number;

//% shim=Keyboard::getTextPromptSelectionEnd
function _getTextPromptSelectionEnd(): number;
}

0 comments on commit 9b12ed9

Please sign in to comment.