I'm converting an old terminal-mode text game to JavaScript.
The gameplay conversion is simple and nearly done. But a part of the UI -- getting user input -- is proving so difficult that I'm turning to the experts on StackOverflow for help. I have been through SO exhaustively and found similar answers but nothing directly applicable.
One of my goals is to preserve the game's 1970s-era input style:
- All text is displayed on a single screen (no pop-up dialogs or isolated/visible input boxes).
- User input is obtained by displaying a prompt message, followed by waiting for the player to enter a response.
- The individual character of the user's response are displayed on the screen.
- The characters entered can be removed in reverse order by pressing the Backspace key.
- The number of characters that can be entered is limited.
- All other game processing is suspended until the user presses the Return key.
- When the Return key is pressed, all characters entered are returned to the calling function as a string.
- When the result string is obtained by the calling function, processing in the main gameplay code resumes.
I have successfully figured out steps 1 and 3-5. I create an Input element in HTML, move it offscreen in CSS, and set the focus to that element. When a key is pressed, if it's an alphanumeric I use appendChild() to add it as a text node to the content element so that it's displayed on the main screen; if it's the Backspace key I remove the tail child node to remove the character from the screen; and if it's the Return key I copy the text from the input field to a local variable to return it to the calling program and clear the input field.
After some effort, the code to print and backspace characters in a content area is working. What I have been unable to figure out is how to suspend other processing until the user has typed some keys and hit Return.
I've spent the last three days trawling StackOverflow and every other site I could find that had a reference to this kind of thing, plus trying every combination of semaphoring I could think of myself. A prompt dialog or visible input box fails requirement #1. A naive while-loop does halt processing, but it also prevents keypresses from being recognized. Timers and intervals risk missing keypresses. And I'd rather avoid yield() in order to support older browsers. (I'd like to preserve cross-browser compatibility as far as possible.)
Similar questions have generated answers that reference asynchrony (via callback), but that is exactly what I do not want -- I want the main gameplay code to stop running, but still allow keypresses to be detected, until the user presses the Return key, after which the main gameplay loop can resume.
Is there any way to accomplish this? I'm open to some rethinking of how the main gameplay loop is structured if there is no relatively clean way to simulate the prompt dialog's modal text entry in JavaScript.
Note: If sample code is offered, examples in straight HTML/CSS/JavaScript would be much more helpful to me than jQuery. Thanks!
Edit: The part of the program that's working is creating a listener for keypresses and displaying alphanumeric characters to the content area:
form.addEventListener("keydown", function (e) {
if (e.keyCode == 13) {
istr = inputBox.value; // save user's text as a string
inputBox.value = ""; // clear input element
}
else if (e.keyCode == 8)
backspace(); // remove last char from content area
else if (e.keyCode >= 48 && e.keyCode <= 90)
printCharST(String.fromCharCode(e.keyCode)); // put char in content area
inputBox.focus(); // bring focus back to input textbox
}, false);
This is not the part of the code I'm asking about. (I'm including it here so that it's clear that I do have code to detect key presses and operate on them.)
The part I'm having trouble with is the calling program -- how do I get it to suspend until the user presses Return, and I put their string into istr
and return it to the caller who's been waiting for user input? Simply telling the caller to repeatedly poll istr
(or any other flag variable set by the key listener) until it's not empty chews up so much CPU that it prevents key presses from being recognized.
I'll be happy to provide any additional information that would help clarify what I'm trying to achieve. Also, if there are any specific comments on how this question could be better formatted, I'll gladly revise it.