Search Unity

How to handle multi language in new InputSystem?

Discussion in 'Input System' started by LoneSurvivor82, May 6, 2020.

  1. LoneSurvivor82

    LoneSurvivor82

    Joined:
    Aug 17, 2019
    Posts:
    42
    Hi everyone,

    I have two questions about the new InputSystem.

    1. I have a german Windows10 with a german keyboard-layout. If I add a binding and use "Listen" in the Action type to catch the selected key I get a "Y" if I press a "Z" and vice versa. Is this the behaviour by design?

    upload_2020-5-6_16-8-9.png

    2. In the screenshot above, you can see an Action named "BackToSettings". It has two keys defined, "b" as shortcut for "Back" to return to the main menu if the game language is set to english, and "y" (Z in german, see question 1) for "Zurück" if the game language is set to german.

    In my MenuManager I have these lines of code to react on keypress:

    Code (CSharp):
    1. controls.UISettingsVideoMenu.Enable();
    2. controls.UISettingsVideoMenu.Camera.performed += VideoCamera_performed;
    3. controls.UISettingsVideoMenu.BackToSettings.performed += BackToSettings_performed;
    This is the code from the method:

    Code (CSharp):
    1. private void BackToSettings_performed(InputAction.CallbackContext ctx)
    2.     {
    3.         bool backToSettings = ((KeyControl)ctx.control).keyCode == Key.Escape;
    4.  
    5.         if (!backToSettings)
    6.         {
    7.             LocalizationManager.Read();
    8.  
    9.             switch (LocalizationManager.LCID)
    10.             {
    11.                 case LCIDs.German:
    12.                     if (((KeyControl)ctx.control).keyCode == Key.Y)
    13.                     {
    14.                         backToSettings = true;
    15.                     }
    16.  
    17.                     break;
    18.                 default:
    19.                     if (((KeyControl)ctx.control).keyCode == Key.B)
    20.                     {
    21.                         backToSettings = true;
    22.                     }
    23.  
    24.                     break;
    25.             }
    26.         }
    27.  
    28.         if (backToSettings)
    29.         {
    30.             DisableControls();
    31.             CurrentMenuState = MenuState.Settings;
    32.             SceneManager.LoadScene("Settings");
    33.         }
    34.     }
    It doesn't feels right that I have to differentiate between the languages on the one side. And on the other, I don't like that I have to check for a specific keyCode. On that way I have two places where I have to define the keys to use. Not to speak for that Y/Z-thing... ;-)

    This can't be the best practice, can it?

    Greetings
    Lone
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Yes. Albeit at the same time something that we should make more obvious in the UI.

    The way this works is that all the bindings deal in control names. These names are immutable. The control names for keys on a keyboard are layout-agnostic and fixed to the US keyboard layout for reference (could really be any layout but this one seemed an obvious default choice).

    Put another way, if you bind to the "Y" key, on a German keyboard, this will be the key with "Z" printed on it.

    However, all controls also have display names and these can change around. For a keyboard, the display name is the fully mapped key.

    You *can* bind to keys by their display name using the "By Character Mapped to Key" group under "Keyboard".
    If you bind to "Y" in this way, the key will always be the one generating the "Y" character regardless of where on the keyboard the key is (including not being on the keyboard at all).

    upload_2020-5-6_18-18-26.png

    The above thing solves that.

    There's no support ATM to have bindings become active based on locale. However, it's possible to set up something to that end using control schemes. You could have a "Keyboard (English)" and a "Keyboard (German)" control scheme and then bind them differently and select the control scheme to use in code based on the current locale.
     
  3. LoneSurvivor82

    LoneSurvivor82

    Joined:
    Aug 17, 2019
    Posts:
    42
    Ah okay, I didn't ever have seen this, thanks for the hint.

    For my other problem, if I understood you correctly, you would suggest the following approach?

    I splitted up the control schemes into two separate ones:

    upload_2020-5-7_14-48-3.png

    And the code-line have been reduced to the following as update from my previous posted code:

    Registering the callback-methodx:

    Code (CSharp):
    1. controls.UISettingsVideoMenu.Enable();
    2. controls.UISettingsVideoMenu.Camera.performed += VideoCamera_performed;
    3. LocalizationManager.Read();
    4.  
    5. switch (LocalizationManager.LCID)
    6. {
    7.  case LCIDs.German:
    8.   controls.UISettingsVideoMenu.BackToSettingsDE.performed += BackToSettings_performed;
    9.   break;
    10.  default:
    11.   controls.UISettingsVideoMenu.BackToSettingsEN.performed += BackToSettings_performed;
    12.   break;
    13. }
    The callback-method has reduced to this few lines without any check for pressed keyCodes or language-differentiation:

    Code (CSharp):
    1. private void BackToSettings_performed(InputAction.CallbackContext ctx)
    2.     {
    3.         DisableControls();
    4.         CurrentMenuState = MenuState.Settings;
    5.         SceneManager.LoadScene("Settings");
    6.     }
    I like this approach very much, I hope this implementation was your intention :)
     
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    If it works for you, good :) What I meant was doing it with control schemes.

    upload_2020-5-7_15-18-51.png
     
    LoneSurvivor82 likes this.
  5. LoneSurvivor82

    LoneSurvivor82

    Joined:
    Aug 17, 2019
    Posts:
    42
    Wow, that's even better!

    But how do I set in code, which Control Scheme to use?
     
  6. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    For code generated from .inputactions with "Generate C# Class", this is currently a bit of a manual process. I previously posted some details about this here.

    The key property here is bindingMask which controls which bindings to use and which to ignore. Each control scheme has an associated "binding group" that bindings in the control scheme are associated with.

    Code (CSharp):
    1. var bindingGroup = myControls.controlSchemes.First(x => x.name == "Keyboard (EN)").bindingGroup;
    2. myControls.bindingMask = InputBinding.MaskByGroup(bindingGroup);
     
    LoneSurvivor82 likes this.
  7. LoneSurvivor82

    LoneSurvivor82

    Joined:
    Aug 17, 2019
    Posts:
    42
    Fantastic! This is exactly what I was looking for. Thank you very much :)
     
    Rene-Damm likes this.
  8. LoneSurvivor82

    LoneSurvivor82

    Joined:
    Aug 17, 2019
    Posts:
    42
    One last question:
    The middle mouse button (pressing the mouse wheel to the left/right) some kind acts as cursor left/right keypress.

    Is there a way to deactivate the mouse completely with the InputBinding-methods or ignore its input-signals?

    I tried it with this codeline but it doesn't work:

    _controls.devices = new [] {Keyboard.current};
     
    Last edited: May 9, 2020
  9. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392
    Is there a way to convert a KeyCode to a char, so that the correct character appears in (for example) an on-screen tutorial popup?

    KeyCodes, as mentioned before, are language agnostic and are meant to refer to physical locations on the keyboard, using a US-keyboard as a reference point. That is, KeyCode.Equals will always refer to the key directly left of the backspace key, even though a different symbol might be there for different languages. For example, on German keyboards, little tick marks are next to the backspace key.

    However, what I'd want is a way to, given the KeyCode and the keyboard layout used (as determined by their OS) return what character is printed on that key. That way, Americans who are prompted with "Press [=]" and Germans who are prompted with "Press [`]" are reaching for the same place on their keyboard.
     
  10. Zergling103

    Zergling103

    Joined:
    Aug 16, 2011
    Posts:
    392