I’ve got a Unity app that accepts text input via KeyDown events (in OnGUI). In Mac builds only, this fails to properly receive accented characters — if I type option-E, E, for example, it should produce é, but instead produces a plain (unaccented) e. It works correctly in the Unity editor, and on non-Mac platform builds.
Logging the contents of the KeyEvent directly from OnGUI, in the editor I get:
KeyDown event: \0 (0), modifiers Alt, keyCode E
KeyDown event: \0 (0), modifiers None, keyCode E
KeyDown event: é (233), modifiers None, keyCode None
But in a build I get:
KeyDown event: \0 (0), modifiers Alt, keyCode E
KeyDown event: \0 (0), modifiers None, keyCode E
KeyDown event: e (101), modifiers None, keyCode None
As you can see, what I get in the build is a plain old “e”, not the proper accented one.
This looks like something I can’t solve or work around in my code, because I’m getting bogus data from Unity itself. But it’s odd that it works in the editor; that gives me some hope that there may be a solution?
Anybody have a clue? Is there a build setting somewhere that affects this, or…?
Well this is interesting — testing again today, it is failing in the editor as well as in a build. (Tested in both 2021.3.25f1 and 2022.3.4f1.)
That suggests… what? It’s some sort of state, which is initialized in an unpredictable way?
Well, just to close the loop on this, I’m giving up on OnGUI KeyDown events — they appear to have decayed, and it seems nobody at Unity cares about keeping them working anymore.
Per the recommendation here, I’ll enable “both” input systems in my project (I still have a lot of code that relies on the old simple input system in other ways), but get text by hooking into Keyboard.current.onTextInput.
Well, frick. I take it back; that doesn’t reliably solve it either. It solved it at first, but now that I’ve done some more (unrelated) coding, and I’m testing again, my Keyboard.current.onTextInput event is getting called with plain ASCII characters even when I enter the two-key sequence for é (which in my first test, actually gave me a é).
This is super frustrating. Isn’t Unity located in Europe? How can they be so bad at this?
OK. My simple test project, which was still open in another copy of Unity (same version), is still showing correct output. The code is simple:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class KeyboardInputTest : MonoBehaviour
{
private int m_Position;
private string m_Text;
protected void OnEnable()
{
Keyboard.current.onTextInput += OnTextInput;
}
protected void OnDisable()
{
Keyboard.current.onTextInput -= OnTextInput;
}
private void OnTextInput(char ch)
{
Debug.Log($"OnTextInput({ch}, int {(int)ch})");
}
}
And when I press option-E, E, this correctly shows é (int 233). But this exact same code in my real project, which worked five minutes ago, is now showing e (int 101). Both in the editor and in a build.
So whatever weirdness is at play here, it’s not at the operating system level. It appears to be something nondeterministic in Unity itself. It gets into a state where it’s apparently ignoring the accent key (option-E), and just giving me the plain, unaccented version of the second keypress. And it does this in both the classic input system (KeyDown events in OnGUI), and in the new InputSystem (Keyboard.current.onTextInput).
I’m tearing my hair out here, and I really don’t have any to spare. Anyone have any idea?
Another interesting observation — onTextInput works correctly if an InputField also has the focus.
I was curious whether the problem also affected Unity’s own InputField (TextMeshPro). So I just threw one into a canvas that was already on the screen. My other script (above) was still running on another object at the same time. The result:
When the InputField has the focus, accented characters work correctly in the field, and in my onTextInput handler! And as soon as I click away from the InputField, onTextInput goes back to broken behavior. This appears to be 100% reproducible; I can make onTextInput work correctly or incorrectly by clicking into and out of the text field as much as I like.
So I guess a workaround might be to stick a hidden/invisible InputField somewhere, but that’s obviously a skanky hack. It means that this is some Unity internal state, and InputField knows how to manipulate it into “please handle accented characters correctly” mode. Surely there’s some way I can do that in my own code, too?
EUREKA!
From poking around in the TMP_InputField source code, I found this line:
EventSystem.current.currentInputModule.input.imeCompositionMode = IMECompositionMode.On;
This appears to be the magic incantation that makes it handle multi-key characters properly. Huzzah!
(Of course I thought I had it solved before, too… watch this space to see if I come back disappointed yet again.)