Search code examples
ioskeyboardinternationalizationuitextfieldautosuggest

iOS detect keyboard layout (e.g. QWERTY, AZERTY)


I am building a custom suggestion/autocorrection feature in an iOS app. It must detect accidental adjacent keypresses and compare this to a known word list to suggest the word it thinks the user intended to type.

For example, if the custom word list contains cat, dog, monkey, and the user types cst, the app can determine that the most likely word was cat (because s is adjacent to the a key)

QWERTY keyboard showing cst

This will work on a standard QWERTY keyboard, but what happens if the user is using an AZERTY keyboard?

enter image description here

For the autocorrect/suggest to work reliably, the app must be able to detect the keyboard layout in use.

In iOS, it is possible to obtain a UITextInputMode object from a UITextField. This object has a primaryLanguage (string) property, which will display the locale (e.g. en-GB), but this does not contain enough granularity to distinguish between English (Australia) QWERTY and English (Australia) AZERTY. In both cases, the primaryLanguage is en-AU.

Is it possible to detect the keyboard layout in iOS?


Solution

  • I have not been able to find a clean solution to this problem. Maybe this would be worth a TSI ticket to discuss it with Apple employees.

    I know that this will not be a satisfying answer, but I would still like to share my thoughts here for future readers:

    1. Private API of UITextInputMode:

      textField.textInputMode?.value(forKey: "identifierWithLayouts")

      This will return a string like de_DE@sw=QWERTZ-German;hw=Automatic from which you can infer the keyboard layout.

    2. UserDefaults

      UserDefaults.standard.object(forKey: "AppleKeyboards")

      This will return a list of all keyboards that the user has installed. In most cases, this will only be one language (besides the emoji keyboard). For example:

      Optional(<__NSCFArray 0x600003b8e6c0>(en_US@sw=QWERTY;hw=Automatic,emoji@sw=Emoji))

      You could also iterate over UserDefaults.standard.dictionaryRepresentation() and search for QWERTZ/QWERTY/AZERTY within the values.

    3. With much manual effort, you could maybe encode UITextInputModes to binary data in all ambiguous cases like en_AU. Something like NSKeyedArchiver.archivedData(withRootObject:textField.textInputMode, requiringSecureCoding: false) can then be used to compare binary encodings of the user's textInputMode at runtime.