KeyCodes for non-US keyboard layouts

Hi there,

I am currently working on an interactive visualization of a typewriter. To make the typing look realistic, I need information about the state of the keys on the keyboard (key is pressed, key is released).

In Unity, as I understand, such things seem to be done with either (for example)

Input.GetKeyDown(KeyCode.LESS)

or, in OnGUI(), with

if((Event.current.type == EventType.KeyDown) &&
(Event.current.keyCode == KeyCode.LESS))
//do things

and their equivalent KeyUp methods. Because things did not do what they should, I looked for what KeyCodes are sent:

if(Event.current.type == EventType.KeyDown)
Debug.Log(Event.current.keyCode)

And I see strange things happening. I am in Germany, my keyboard layout is set to german, nothing is changed from standard settings and works well in the whole (german) Windows system. Keys like `A,S,D,2` do what they should do and print `A,S,D,Alpha2`.

But keys like <,,#,+ print definitely NOT the keyCodes they should - for example, <,#, all print "BACKSLASH".

If I print Event.current.character, everything is fine ("<" prints "<"), but there seem to be localization problems with the keyCodes. I have tested this with different machines with both Unity2.5 and Unity2.6, and the problem persists. Is this a bug?

Is there any way I can get proper key-Events inside Unity without using this Method? Apart from the problems listed here, I would also need a keyCode for the key, but this one isn't even there in Unity (http://panther.unity3d.com/support/documentation/ScriptReference/KeyCode.html).

If there is no other way, I will probably have to write something like a keyHooker DLL, but that would be really not the "way it should be".

Any help would be greatly appreciated.

The [KeyCode documentation][1] says that key codes "map directly to a physical key" -- so I don't understand why we get different codes when keyboard language settings change? I can confirm that it happens, but to me it seems like a bug. (It's now three years after the original post, and I'm using Unity 3.5.6.) [1]: http://docs.unity3d.com/Documentation/ScriptReference/KeyCode.html

3 Answers

3

By slightly changing Mike's Code from another post, I was able to use the system events for determining the state of non-standard buttons.

using UnityEngine;
using System.Collections;

using System.Runtime.InteropServices;

public class keyStateTester : MonoBehaviour {

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
    protected static extern short GetKeyState(int keyCode);

    public int GetEszett()
    {
        ushort i = (ushort)GetKeyState(219);
        return i;
    }

    // Update is called once per frame
    void Update ()
    {
        if(GetEszett() != 0)
            Debug.Log("Eszett has done something");
    }
}

So, this is a way to go by using an external DLL. I would like a solution without using a DLL better, because I initially thought about publishing the project on the web, too...

Maybe someone has a solution without using a dll?

Unless you can get the System.Windows.Forms method of hooking into the system input events working, most likely this is your only route. I did just have an interesting idea though, I'll have a play with it to see if it's viable and let you know later

OK, I mark this thread as solved. It would be great if you manage to go another way, though.

Mike, did you ever get your idea working?

one question ... is Keycode.A mean the actual physical location of A regardless of whether its A or not? say i have a dvorak keyboard would i still need to use qwerty physical markers? on a dvorak , instead of ASDF, its AOEU.. so if i want the user to type O , it would be KeyCode.S ???

if that's the case then simply use the Qwerty equivalent to where our German code is...

The KeyCodes will not correctly map to the keys on your keyboard, as keycodes (unlike character codes) are used to label physical keys, not their mapping to characters. Now, the KeyCode enums will all reflect the key names on a US-keyboard. While that may be misleading, it makes sense, because it's better then having no names at all. So, getting wrong keycodes for your german keyboard layout is by design here. If, however, you are getting the same key code reported for multiple different keys, then something is clearly wrong. Please verify this, and report a bug with instructions to reproduce.

Not sending characters on keyUp events also has somewhat of a reason, which is that with IME input, keystrokes will no longer directly map to characters, as multiple keystrokes may be needed to input a character, or single keystrokes may input multiple characters. I'm not sure how this should be treated for simple mappings, though, and it may be inconsistent right now. I will make a note to do some testing on this.

In Delphi there is a OnKeyDown-Event which returns the keyCode as integer. For example, pressing the ""-Key returns 219. Additionally, there are virtual keyCodes like in Unity, which are just constants (e.g. VK_F1 = 112), not enums. Of course, not every possible physical key has a keyCode-name, but With this method, one is able to use every physical key even if there is no keyCode for it. Maybe there could be implemented an alternative GetKeyDown method like this? :)

KeyCodes in Unity should be exactly the same. 219 maps to VK_OEM_4 in the windows headers, which Unity maps to KeyCode.LeftBracket (which that key is on a US keyboard).

Why Unity3D even only delivers the hardware Scan Code? Every normal application is delivering the virtual key... wasted the whole day trying to map the scan code to a localized char/virtual key, but I couldn't figure out (though I got most keys working, but hacky). There needs to be Event.current.virtualKeyCode. Now I ended up using an Interop keylogger to get the real virtual key codes...

Most likely it's not a bug - if they had to put every unicode character into the enum, it'd be completely unusable

Is there a reason character isn't of any use to you? If i remember correctly, there are functions in .NET to get a system keycode value from one

I was thinking of just (int)yourChar actually. but you're right - it's a bit silly if it's not sending the character on keyup too.