Pages

Friday, March 27, 2020

How to add keyboard on Phaser file

How to add on-screen keyboard (on mobile) to an already-made Phaser game

First, understand the concept of ‘focus’ in HTML and how Phaser detects user clicks.
When you click on any elements in a HTML webpage, the element becomes the ‘focus’. You can also forcefully change the focus to an element in JavaScript by calling ‘HTMLElement.focus()’.

The way Phaser detects user clicks is usually through the events ‘onInputDown’ or ‘onInputUp’. The official Phaser documentation for ‘onInputDown’ states that:

“This signal is dispatched if the Game Object has inputEnabled set to true, and receives a down event from a Phaser.Pointer. This effectively means the Pointer has been pressed down (but not yet released) on the Game Object.”

The context of ‘onInputDown’ and ‘onInputUp’ inside JavaScript is somewhere along the lines of:

‘variable.onInputDown.add(function, this)’

How we make the on-screen keyboard appear.

As browsers automatically open the on-screen keyboard on mobile when you focus on an input box. We will make use of an invisible input box on the webpage that will help us open the on-screen keyboard automatically when we need it to.

With the basic concepts out of the way, let’s move on to the coding.


  1. First, open ‘index.html’ , the viewport need to maximize for better mobile experience, type this into the <head> . Read about it here https://www.w3schools.com/css/css_rwd_viewport.asp
  2. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  3. Second, navigate to where the <body>  element is and enter the following codes “<input id="inputDummy" type="number" style="opacity: 0"/>” on a new line. Example:
  4. <input id="inputDummy" type="number" style="opacity: 0"/> <!--inputDummy was added, type can change if need to text opacity:0 is to hide the inputDummy from view --> You should change the type to whichever type that you need accordingly.
  5.  *To find out more on input types check out either one of the following links https://www.w3schools.com/html/html_form_input_types.asp  https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
  6. Next, we may also need to type in <script>
    //Double click to enter/exit fullscreen
    document.ondblclick = function (event) {
    var canvas = document.getElementsByTagName("canvas");
    if (document.fullscreenElement) {
    document.exitFullscreen()
    .then(() => console.log("Document Exited form Full screen mode"))
    .catch((err) => console.error(err))
    } else {
    document.documentElement.requestFullscreen()
    // canvas[0].requestFullscreen().catch(err => {
    // alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
    // })
    }
    }
    // screen.orientation.lock("landscape");
    </script><!--to fullscreen to prevent mobile keyboard from leaving and the interactive begin in the zoom position -->
  7. Next, go to scripts folder and open ‘game.js’, then press Ctrl + F and type ‘onInputDown’. Press ‘enter’ to navigate through all instances of ‘onInputDown’ in the script and identify the variables representing the input boxes that are calling ‘onInputDown’.
  8. Example:
  9. Read through the script and figure out how the input system is handled in the game, we will need the corresponding functions later.Example: this is already inside the old codes
  10. In the above example, the inputs were directly read from ‘onDown’ events fired by the Phaser input system when a key is pressed on the keyboard. The ‘onDown’ events then call the ‘press[n]’ function that handles the corresponding keypress event.
  11. Go to the start of the createQuestion function that contains the ‘onInputDown’ that you have identified and enter the following:  
  12. //lookang start
    var showKeyboard = true;
    var inputBox = document.getElementById("inputDummy");
    //console.log("Test");

    inputBox.style = "position: absolute; top: 50%; left: 50%; opacity: 0;";

    function onInputFocus(e) {
    if (inputBox.value != "") {
    inputBox.value = "";
    }
    e.preventDefault();
    //console.log("focus");
    document.inputEnabled = false;
    }

    inputBox.onfocus = onInputFocus;

    inputBox.oninput = handleInput.bind(this);
    inputBox.onblur = onBlur;
    function onBlur() {
    //console.log("WUT");
    //console.log(document.activeElement);
    document.inputEnabled = true;
    if (showKeyboard) {
    inputBox.focus();
    showKeyboard = false;
    }
    }

    function handleInput() {
    //console.log(inputBox.value);
    inputBox.value = inputBox.value.slice(-1); //to only accept one digit
    var number = parseInt(inputBox.value);
    switch (number) {
    case 0:
    this.press0();
    break;
    case 1:
    this.press1();
    break;
    case 2:
    this.press2();
    break;
    case 3:
    this.press3();
    break;
    case 4:
    this.press4();
    break;
    case 5:
    this.press5();
    break;
    case 6:
    this.press6();
    break;
    case 7:
    this.press7();
    break;
    case 8:
    this.press8();
    break;
    case 9:
    this.press9();
    break;
    }
    } // lookang end
  13. *Note that the codes in ‘onInputFocus’ and especially ‘handleinput’, will most definitely have to change according to how the specific script you are working with is coded.
  14. In the above example, the input box in the game only contains one number at any given time. Hence, in ‘handleInput’ the value of the input box is always cut until only the last entered character is left - “inputBox.value = inputBox.value.slice(-1);
  15. The way the input is handled in the above example as shown in Step 12, is by calling “this.press[n]();” directly from keypress events, hence the value in the input box is converted to integer then checked before calling the corresponding function (mimicking a keypress). If you want to debug and see what is currently in the invisible input box, simply remove ‘opacity: 0;’ from ‘inputBox.style = " position: absolute; top: 50%; left: 50%; opacity: 0;";’ 
  16. Finally, go back to all the relevant ‘onInputDown’ instances that you have found in Step 10 and enter:
  17. inputBox.focus();
  18. console.log("Test1"); // change the log for each box number to debug more easily
  19. showKeyboard = true;
  20. at the end of the ‘onInputDown’ functions inside positit2Btn each box1 to box7
  21. it seems box5 and box6 not do have there own onInputDown.add(function) type these lines just after box 4

  22. //added by lookang box5 start
    box5.onInputDown.add(function () {
    inputBox.focus();
    console.log("Test5");
    showKeyboard = true;
    }, this);//added by lookang box5 end

  23. similarly for box6
  24. //added by lookang box6 start
    box6.onInputDown.add(function () {
    inputBox.focus();
    console.log("Test6");
    showKeyboard = true;
    }, this);//added by lookang box6 end
  25. Sometimes, the original script may have disabled the box5 and box6, so need to look into the scripts say if (questionStage == 3) {} add

  26. box5.inputEnabled=true; // lookang to force box5 to be inputEnabledbox6.inputEnabled=true; // lookang to force box6 to be inputEnabled 
  27. similarly, in if (questionStage == 5) {} add this line

  28. box7.inputEnabled=true; // lookang to force box7 to be inputEnabled

  29. And you are done! Run and test the Phaser game again to see if it works according to how you want it to. If not, check and change your ‘handleInput’ and ‘onInputFocus’ accordingly.


Many thanks to Z C for his tutorial.












No comments:

Post a Comment