Layout-independent key events

Hello,

I wonder how to get key press events independently of the current layout. Like getting on AZERTY: key ‘Q’ instead of ‘A’, ‘W’ instead of ‘Z’, etc.

I know there is such API in SDL, how does one access it in openfl/lime?

SDL has “keycodes” and “scancodes”, we implement key codes in Lime, but do not do scan codes, which would be layout independent.

However, SDL has a API to convert from key codes to scan codes, which may be the best way to handle this. Then the Lime events come through as key events (as they do now), but with an API call, it will be possible to convert the value to a scan code.

Another option might be to introduce a new set of events designed for scan codes instead of key codes, or to change the signature of Lime key events. I’m not certain if either of these approaches would be as good, though.

Open to suggestions, thank you :slight_smile:

I don’t know if there are limitations of the conversion approach (do all keys support this?), but I think it’s OK, because one of the things I’d want to do is receiving and handling the scancodes, whereas showing the keys on the screen (like in game tutorials, settings or QTE) in the user’s native layout (keycodes).

On the other hand, we’d need the conversion for constants to compare with, too. Not sure how it could be made more elegant than “if (get_scancode(keycode) == get_scancode(“Q”))”. And also, for simplicity’s sake, it may be better to mimic the SDL API for now. Or is it breaking change to openfl/lime to receive scan codes together with key codes?

Another related question: I just noticed that there are ‘charCode’ and ‘keyCode’ in KeyboardEvent class of openfl. Is it the same as what I ask for, or what is the difference? (EDIT: it seems this is for case-independence)

Thank you

Lime dispatches events in a “flat” manner, such as onKeyDown (keyCode:KeyCode, modifier:KeyModifier);

If we added another value (such as scancode) it would break all key down listeners. In Flash and OpenFL, events use event objects, which are more expensive but allow you to add an infinite number of values to each dispatched event without changing the signature for listeners.

The argument for constants is a good one. As a quick thought, perhaps the API could look like this:

package lime.ui;

@:enum abstract ScanCode(Int) from Int to Int {
    
    var A = 123;
    var B = 124;

    ...
    
    public static function fromKeyCode (code:KeyCode):ScanCode {
        
    }
    
}

The basic idea is lime.ui.ScanCode would contain constant values, as well as a way to convert from key codes to scan codes. In fact (as an abstract) we could even handle the conversion through casting, if that isn’t too weird?

var keyCode = KeyCode.A;
var scanCode:ScanCode = keyCode;

trace (scanCode); // ScanCode.Q

Looks good!
I’d also add the reverse conversion, depending on the application developer, he may want to store keycodes in some variables and sometimes convert to scancode, or the other way round.
And the other thought: will Haxe throw the error if we write just A, without the abstract name? Because it’d be confusing if not.

I’ve opened an issue here to track it:

lime.ui.ScanCode is now available in development builds :smiley: