theom Posted July 10, 2018 Share Posted July 10, 2018 Has anyone implemented dead key support for the InputText control? If not, I'm going to give it a try. Quote Link to comment Share on other sites More sharing options...
brianzinn Posted July 10, 2018 Share Posted July 10, 2018 I would look at this pull request. If you wanted to use "shift + space" - maybe this is a good start? https://github.com/BabylonJS/Babylon.js/pull/3368 Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 Thanks, I'll take a look. Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 Here's what I've got so far. What I'm trying to achieve is to be able to very easily configure different custom key mappings outside of Babylon and to be able to switch between them at runtime. This is all done in a callback I give to InputText. I can modify the entered character and event prevent it from being added to the input. This enables me, for example, to easily add dead key support or to just allow numbers to be entered. I think this also solves the "input mask" case we talked about here: Here's an incomplete dead key handler: let input = new gui.InputText(); input.onBeforeKeyAdd = (target, key) => { if (target.deadKey) { switch (key) { case "a": key = "á"; break; case "A": key = "Á"; break; } target.deadKey = false; } return { add: true, key: key }; }; And here's a handler that only allows numbers to be entered: let input = new gui.InputText(); input.onBeforeKeyAdd = (target, key) => { let add = false; if (key >= "0" && key <= "9") { add = true; } return { add: add, key: key }; }; What I'd also like to do is to bundle a set of these key modifiers along with Babylon so user's can pick the ones they need but I'm unsure of the best way to do that (where to put them). Any ideas? brianzinn 1 Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 Sorry about my stupid question: what is a dead key? Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 A dead key is a key that does not output anything when hit, but is used to modify the next key. For example, Icelandic has several characters that have a diacritic above them (á, í, é ...) and we use a dead key to enter those characters (dead key (diacritic) + a = á). What I did in the InputText was to keep the state of the dead key to enable the key modifier to act on it if it likes. Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 woot! this is cool to add then Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 Any thoughts on where to put the modifiers/callbacks? Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 Definitely in the textbox class Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 Just to make sure we are talking about the same thing: I'm wondering where it's best to keep the various callback definitions the InputText can be configured to use. For example, for those who might want to use the Icelandic version of the dead key callback they can pick it up from this place and plug it into their instances of InputText; if they want to limit the input to only numbers they can pick up the number input mask and plug it in, etc. Sorry if this was obvious to you. Given this 'plugin' nature, does it make sense to keep the callback definitions in the InputText class (I assume you meant that class when you say textbox)? I was more seeing this as something maintained externally to the InputText which then could be built up over time to include several different keyboard "mappings" and input masks. Maybe have some directory structure like this in the controls directory: InputTextModifiers KeyboardMapping InputMasks Maybe I'm taking this too far here but to me it doesn't feel right to keep the callbacks within the InputText class. Or I misunderstood you Quote Link to comment Share on other sites More sharing options...
brianzinn Posted July 10, 2018 Share Posted July 10, 2018 I think DK means that those onBeforeKeyAdd types of methods are useful for others. We could use them to intercept the keypress to prevent event propagation - we do that normally in html (maybe 'onKeyDown') by calling evt.preventDefault() or whatever. That could activate deadkey in your case (shift + space?) or disallow non-numeric input depending on the implementation as you have done. So, we could change the current method - or perhaps there is a better place. I have not fully looked through the GUI code (https://github.com/BabylonJS/Babylon.js/blob/master/gui/src/2D/controls/inputText.ts#L314? public processKeyboard(evt: KeyboardEvent): void { this.processKey(evt.keyCode, evt.key); } Then add what you have (using maybe something like a template method pattern) to make it pluggable into InputText. public processKeyboard(evt: KeyboardEvent): void { // in your onBeforeKeyAdd you need to check: // var shiftKeyPressed = evt.shiftKey, but also caps-lock can be enabled on Virtual Keyboard mode, so that may be confusing! let beforeResult = this.onBeforeKeyAdd(evt: KeyboardEvent); if (beforeResult.add === true) { this.processKey(evt.keyCode, evt.key); } } That logic means you would need a default implementation, like perhaps: onBeforeKeyAdd = (target, key) => { return { add: true, key: key }; }; Otherwise you need to check if there is an implementation or not. I think you could go a step further and change the virtual keyboard or long-press virtual keyboard buttons like phone keyboard modifiers - looks like a fun project! Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 Well @brianzinn this is exactly what I struggle to said I think we should have way to configure the InputText provided within the InputText. Then dead keys or modifiers can then be plugged into these "entry points" Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 @brianzinn @Deltakosh It seems to me that we are talking about the same thing, i.e. re-use of the key modifiers. The way I have done this in InputText is very similar to what @brianzinn suggests, except I check for the presence of the callback: class InputText ... private _onBeforeKeyAdd: (target: InputText, key: string) => { add: boolean, key: string }; ... /** Sets the callback that's called before the entered key is added to the input text */ public set onBeforeKeyAdd(cb: (target: InputText, key: string) => { add: boolean, key: string }) { this._onBeforeKeyAdd = cb; } ... public processKey(keyCode: number, key?: string) { // Specific cases switch (keyCode) { ... case 222: // Dead this.deadKey = true; return; } // Printable characters if ( (keyCode === -1) || // Direct access (keyCode === 32) || // Space (keyCode > 47 && keyCode < 58) || // Numbers (keyCode > 64 && keyCode < 91) || // Letters (keyCode > 185 && keyCode < 193) || // Special characters (keyCode > 218 && keyCode < 223) || // Special characters (keyCode > 95 && keyCode < 112)) { // Numpad let add = true; if (this._onBeforeKeyAdd) { if (key) { ({ add, key } = this._onBeforeKeyAdd(this, key)); } if (!key) { add = false; } } if (add) { if (this._cursorOffset === 0) { this.text += key; } else { let insertPosition = this._text.length - this._cursorOffset; this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition); } } } } What confuses me is how the virtual keyboard comes into this? Is all keyboard input, desktop and mobile, routed through the virtual keyboard? Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 I can put up a PR for you to review. Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 1. I would recommend using an observable se we could have multiple subscribers 2. Do you mean the GUI Virtual keyboard? Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 1. I first looked into using an observable but dismissed it because I wanted to return a value to the InputText key processing code at the point of the call to the modifier. I couldn't see how to do that using an observable. But let me mull it over a bit. 2. Yes. Are there more than one virtual keyboard? Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 1. Every observable can make change to the event passed as parameter 2. I also thought about the phone or tablet virtual keyboard. But never mind, I'm with you now, so in the virtual keyboard case we also need to expose the dead keys as new letters to display on the layout. I honestly did not put too much thoughts on it so far but as the keyboard call the processKey function on the InputText we should be fine to add what we need there Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 Example of a consultation using Observable: https://www.babylonjs-playground.com/ts.html#Q4BXX6 Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 1. Exactly. I'll see how I can deliver the feedback that way. And thanks for the example. 2. I'm focusing on the desktop at the moment, but the virtual keyboard is something we need to look into eventually. Quote Link to comment Share on other sites More sharing options...
Guest Posted July 10, 2018 Share Posted July 10, 2018 Agree Quote Link to comment Share on other sites More sharing options...
theom Posted July 10, 2018 Author Share Posted July 10, 2018 I have a working version that uses an observable. I'll have to do some more testing and once I'm satisfied with it I'll send you a PR. Quote Link to comment Share on other sites More sharing options...
brianzinn Posted July 10, 2018 Share Posted July 10, 2018 1 hour ago, theom said: the virtual keyboard is something we need to look into eventually It's a lot more effort when you consider the virtual keyboard, but really interested to see your PR. If you want to see how the virtual keyboard is created here is the default keyboard: https://github.com/BabylonJS/Babylon.js/blob/master/gui/src/2D/controls/virtualKeyboard.ts#L226 People in VR mode or mobile devices likely don't have keyboard input otherwise, but if you are focusing on Desktop that is OK, too Quote Link to comment Share on other sites More sharing options...
theom Posted July 11, 2018 Author Share Posted July 11, 2018 Yes, it's true that making the virtual keyboard more configurable is a bit more work, but it doesn't look that bad. We just need to create different layouts for each country (new Create.. methods) and it's probably best to get the keyPressObserver to behave like a desktop keyboard regarding the special keys. That way the InputText can stay the same and do its thing. Quote Link to comment Share on other sites More sharing options...
Guest Posted July 11, 2018 Share Posted July 11, 2018 Wonderful! this is a really good PR Just need to udpate GUI doc now Quote Link to comment Share on other sites More sharing options...
theom Posted July 11, 2018 Author Share Posted July 11, 2018 Thanks DK Documentation is done and pushed as a PR. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.