From 86e90c2dc25f40ff6966ce951b34ec9fa81a7467 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Sat, 27 Feb 2021 18:30:37 +0100 Subject: [PATCH 1/3] Make name entry on mobile browsers possible Prior to this change, there wasn't a way in mobile browsers to show the virtual keyboard in order to enter the player name. With this change, the name entry is now done via a hidden input field, which enables the use if a virtual keyboard. Mobile browsers are not special cased, the desktop browsers will also use the input field. --- front/src/Phaser/Components/TextInput.ts | 42 +++++++++++++----------- front/src/Phaser/Login/LoginScene.ts | 17 ++++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/front/src/Phaser/Components/TextInput.ts b/front/src/Phaser/Components/TextInput.ts index 1e01029b..89e772bf 100644 --- a/front/src/Phaser/Components/TextInput.ts +++ b/front/src/Phaser/Components/TextInput.ts @@ -1,7 +1,9 @@ +import {HtmlUtils} from "../../WebRtc/HtmlUtils"; export class TextInput extends Phaser.GameObjects.BitmapText { private minUnderLineLength = 4; private underLine: Phaser.GameObjects.Text; + private onChange: (text: string) => void; constructor(scene: Phaser.Scene, x: number, y: number, maxLength: number, text: string, onChange: (text: string) => void) { super(scene, x, y, 'main_font', text, 32); @@ -10,19 +12,30 @@ export class TextInput extends Phaser.GameObjects.BitmapText { this.underLine = this.scene.add.text(x, y+1, this.getUnderLineBody(text.length), { fontFamily: 'Arial', fontSize: "32px", color: '#ffffff'}) this.underLine.setOrigin(0.5) + this.onChange = onChange; + // Use a hidden input field so that on mobile browsers the virtual + // keyboard will be displayed + const mainContainer = HtmlUtils.getElementByIdOrFail('main-container'); + const inputElement = document.createElement('input'); + inputElement.id = 'playerName'; + inputElement.maxLength = maxLength + // Make sure that now scolling is needed and that the input field is + // not visible + inputElement.setAttribute('style', 'opacity:0;position:absolute;bottom:0'); + mainContainer.appendChild(inputElement); - this.scene.input.keyboard.on('keydown', (event: KeyboardEvent) => { - if (event.keyCode === 8 && this.text.length > 0) { - this.deleteLetter(); - } else if ((event.keyCode === 32 || (event.keyCode >= 48 && event.keyCode <= 90)) && this.text.length < maxLength) { - this.addLetter(event.key); - } - this.underLine.text = this.getUnderLineBody(this.text.length); - onChange(this.text); - }); + inputElement.addEventListener('input', this.onInput.bind(this) as EventListener); } - + + private onInput(event: InputEvent) { + const inputElement = event.target; + // Truncate the text to the maximum length, this is needed for mobile + // browsers that don't support the input field `maxLength` attribute + this.text = inputElement.value.substr(0, inputElement.maxLength) + this.onChange(this.text); + } + private getUnderLineBody(textLength:number): string { if (textLength < this.minUnderLineLength) textLength = this.minUnderLineLength; let text = '_______'; @@ -32,15 +45,6 @@ export class TextInput extends Phaser.GameObjects.BitmapText { return text; } - private deleteLetter() { - this.text = this.text.substr(0, this.text.length - 1); - } - - - private addLetter(letter: string) { - this.text += letter; - } - getText(): string { return this.text; } diff --git a/front/src/Phaser/Login/LoginScene.ts b/front/src/Phaser/Login/LoginScene.ts index 9ca6dcd2..4055fdd3 100644 --- a/front/src/Phaser/Login/LoginScene.ts +++ b/front/src/Phaser/Login/LoginScene.ts @@ -1,3 +1,4 @@ +import {HtmlUtils} from "../../WebRtc/HtmlUtils"; import {gameManager} from "../Game/GameManager"; import {TextField} from "../Components/TextField"; import {TextInput} from "../Components/TextInput"; @@ -41,6 +42,22 @@ export class LoginScene extends ResizableScene { this.name = text; }); + // Mobile Browsers need an input field, so that a virtual keyboard + // gets shown + const nameInputElement = HtmlUtils.getElementByIdOrFail('playerName'); + // As we need an input field for mobile browsers, use it also for + // the desktop. Therefore make sure that is has the focus when the page + // is loaded, so that all keyboard events are handled by that input + // field. + nameInputElement.focus() + // Mobile browsers won't show the virtual keyboard on page load, hence + // re-focus to make it pop up. On desktop browsers it doesn't do any + // harm. + this.input.on('pointerdown', () => { + nameInputElement.blur(); + nameInputElement.focus(); + }); + this.pressReturnField = new TextField(this, this.game.renderer.width / 2, 130, 'Press enter to start'); this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon); From 52acc143f61ab8e24089c48a3f67ad51258b916d Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Sun, 28 Feb 2021 16:41:57 +0100 Subject: [PATCH 2/3] Make sure the virtual keyboard isn't visible in the next scene --- front/src/Phaser/Login/LoginScene.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/front/src/Phaser/Login/LoginScene.ts b/front/src/Phaser/Login/LoginScene.ts index 4055fdd3..a57eac5f 100644 --- a/front/src/Phaser/Login/LoginScene.ts +++ b/front/src/Phaser/Login/LoginScene.ts @@ -72,6 +72,11 @@ export class LoginScene extends ResizableScene { } this.login(this.name); }); + + this.events.on('destroy', () => { + // Make sure the virtual keyboard isn't visible in the next scene + nameInputElement.blur() + }) } update(time: number, delta: number): void { From 4b2af705a34346642d4246be1ddff4af5bb5fe3c Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Sun, 28 Feb 2021 17:26:15 +0100 Subject: [PATCH 3/3] Put hidden input field at the top The input field was placed at the bottom, but that lead to some cutting of the top on mobile Chrome. Putting it at the top seems to work fine in both Chrome and Fennec. --- front/src/Phaser/Components/TextInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/Phaser/Components/TextInput.ts b/front/src/Phaser/Components/TextInput.ts index 89e772bf..9dbe5d6c 100644 --- a/front/src/Phaser/Components/TextInput.ts +++ b/front/src/Phaser/Components/TextInput.ts @@ -22,7 +22,7 @@ export class TextInput extends Phaser.GameObjects.BitmapText { inputElement.maxLength = maxLength // Make sure that now scolling is needed and that the input field is // not visible - inputElement.setAttribute('style', 'opacity:0;position:absolute;bottom:0'); + inputElement.setAttribute('style', 'opacity:0;position:absolute;top:0'); mainContainer.appendChild(inputElement); inputElement.addEventListener('input', this.onInput.bind(this) as EventListener);