[GLFW] keyboard layout

Hi,

I’m playing with GLFW since it is now the window system for LWJGL.

I intercept key events from a GLFWKeyCallback (i’m not using the unicode char version because i want handle special keys like CAPS_LOCKS…)

I’m french and have an AZERTY keyboard and GLFW don’t do any keyboard layout mapping and provide always keycode in the US-Layout (So it’s QWERTY).
That mean, if i press “A” on my keyboard i receive the event “Q” from GLFW.

I’m starting to perform the mapping manually regarding the country of the swing method :

InputContext.getInstance().getLocale();

But it’s a pain, dirty and i’m not sure to achieve this with a robust solution.

So, have you other alternatives ?

At this time what tried to consider ?

  • using scancode instead of keycode on a way that i can convert it to an awt key code by example (but i don’t find anything on it)
  • Be able to change GLFW configration in order that it do the keyboard layout itself (but, it seems that their standard behaviour is to map to US-Keyboard only)
  • using a third-party that will do that better than me :stuck_out_tongue: (but at this time i don’t find it)

Best regards,

Here my local mapping that i use but it’s not cool:


   private enum KeyboardLayout {
		Qwerty,
		Qwertz,
		Azerty;
	}
	
	private static String 		  country = null;
	private static KeyboardLayout layout  = null;  


   private static int mapKeyboardLayout( int glfwKeyCode ) {
		if( country == null ) {
			Locale locale = InputContext.getInstance().getLocale();
			if( locale == null ) locale = Locale.getDefault();
			country = locale.getCountry().toLowerCase();
			layout  = getKeyboardLayout(country);
		}
		switch( layout ) {
			case Qwerty : return toQwertyLayout( glfwKeyCode , country );
			case Qwertz : return toQwertzLayout( glfwKeyCode , country );
			case Azerty : return toAzertyLayout( glfwKeyCode , country );
		}
		return glfwKeyCode;
	}
	
	private static KeyboardLayout getKeyboardLayout( String country ) {
		if( country.equals("fr") ) return KeyboardLayout.Azerty;   // FRANCE                                          
		if( country.equals("hr") ) return KeyboardLayout.Qwertz;   // CROATIA 
		if( country.equals("si") ) return KeyboardLayout.Qwertz;   // SLOVENIA
		if( country.equals("cz") ) return KeyboardLayout.Qwertz;   // CZECH REPUBLIC
		if( country.equals("hu") ) return KeyboardLayout.Qwertz;   // HUNGARY
		if( country.equals("pl") ) return KeyboardLayout.Qwertz;   // POLAND
		if( country.equals("sk") ) return KeyboardLayout.Qwertz;   // SLOVAKIA (Slovak Republic)
		if( country.equals("DE") ) return KeyboardLayout.Qwertz;   // GERMANY
		return KeyboardLayout.Qwerty;
	}

	private static int toQwertyLayout( int glfwKeyCode , String country ) {
		return glfwKeyCode;
	}
	
	private static int toQwertzLayout( int glfwKeyCode , String country ) {
		switch( glfwKeyCode ) {
			case GLFW.GLFW_KEY_Z             : return GLFW.GLFW_KEY_Y;
			case GLFW.GLFW_KEY_Y             : return GLFW.GLFW_KEY_Z;
			default                          : return glfwKeyCode;
		}
	}
	
	private static int toAzertyLayout( int glfwKeyCode , String country ) {
		switch( glfwKeyCode ) {
			case GLFW.GLFW_KEY_A             : return GLFW.GLFW_KEY_Q;
			case GLFW.GLFW_KEY_Q             : return GLFW.GLFW_KEY_A;
			case GLFW.GLFW_KEY_W             : return GLFW.GLFW_KEY_Z;
			case GLFW.GLFW_KEY_Z             : return GLFW.GLFW_KEY_W;
			// ....... and so one
			default                          : return glfwKeyCode;
		}
	}

I did a quick google, and it seems like you can use the scancode passed in the key callback to get the key no matter what the physical layout is.

Fix should be out in GLFW 3.1

I believe there are other “nice” things in 3.1 so when it is released I suspect LWJGL3 will be quick to pick it up

I checked the version of GLFW used by my LWJGL version and it’s:

3.1.0 Win32 WGL VisualC

So, if we read the https://github.com/glfw/glfw/issues/114 , we can see that they fix the behaviour in order to provide only the keycode in the US-Layout whatever you have in your OS.

It seems, that before they fix it, it worked like i would want it work for me :-/

Yes, but i don’t know how to convert a scancode in a keycode that depends of the current keyboard layout.

LWJGL 3 uses a custom GLFW build with all features/fixes added in 3.1. Which means it includes the fix for #114.

With that said, you should never have to map keys between keyboard layouts. There are two separate ways to handle keyboard input:

a) Physical keys. For example, you want the default keys for moving around to be WASD (as they appear on a QWERTY keyboard, which is how GLFW understands it). You use GLFW_KEY_W/A/S/D. Now, lets say a user with an AZERTY keyboards tries your application. When they press ZQSD, you’ll still get GLFW_KEY_W/A/S/D in the key callback. The mapping is automatic, you don’t have to do anything. The only thing to worry about is writing your app so that it works with the physical layout of a US keyboard.

b) Text input. You have to use GLFWCharCallback or GLFWCharModsCallback. These are keyboard layout and locale dependent, and again, you don’t have to worry about specific layouts or mappings.

I understood the concept behind their choices,

But If you let the player to choose a key and click on “A” from my AZERTY keyboard. I have to use 2 callbacks (the unicode version + keycode version) in order to be able to show him the “A” (render text) but retains internally the keycode “Q” for catch events accordingly.
In this simple case, i don’t found anything that let you to provide a “display name” from a keyCode (that is near the unicode codepoint but maybe i miss it).

In other way, if you have a game (or an application) that don’t let the user to configure keys and have an action of the logical key “A” (since it show the user “you can press A for doing you magical stuff”). You must register a char-callback that can return you so many codepoint for the same key (minuscule, majuscule, accents,…) but in this case it would be easier to have a virtual keycode instead of a physical keycode.

In a naive reflection, when they talk about “physical” keys, when we press the real physical key “A” (i see a “A” in my hardware keyboard), we can be able to think about receiving a “A” keycode instead of the “Q”

So, i’m confident with the WSAD common problem, but it don’t help me to much :-/

I think what you’re looking for is glfwGeyKeyName, which has not been added to 3.1 yet, see issue #117.

this

glfwGetKeyName 

will be an option for performing local keyboard mapping ( at least for printable keys )
But won’t help for not printable keys.

Thanks a lot,
Best regards,