Créer un mode de saisie

Un éditeur de mode de saisie (IME) est une commande utilisateur qui permet aux utilisateurs de saisir du texte. Android fournit un framework de mode de saisie étendu qui permet aux applications de fournir aux utilisateurs d'autres modes de saisie, tels que des claviers à l'écran ou la saisie vocale. Après avoir installé les IME, l'utilisateur peut en sélectionner un dans les paramètres système et l'utiliser sur l'ensemble du système. Un seul IME peut être activé à la fois.

Pour ajouter un IME au système Android, créez une application Android contenant une classe qui étend InputMethodService. En outre, vous créez généralement une activité "settings" qui transmet les options au service IME. Vous pouvez également définir une UI de paramètres à afficher dans les paramètres système.

Cette page aborde les sujets suivants:

Si vous n'avez pas utilisé les IME, commencez par lire l'article d'introduction Modes de saisie à l'écran.

Cycle de vie des IME

Le schéma suivant décrit le cycle de vie d'un IME:

Image illustrant le cycle de vie d'un IME.
Figure 1 : Cycle de vie d'un IME.

Les sections suivantes décrivent comment implémenter l'interface utilisateur et le code associés à un IME qui suit ce cycle de vie.

Déclarer des composants IME dans le fichier manifeste

Dans le système Android, un IME est une application Android qui contient un service IME spécial. Le fichier manifeste de l'application doit déclarer le service, demander les autorisations nécessaires, fournir un filtre d'intent correspondant à l'action action.view.InputMethod et fournir des métadonnées qui définissent les caractéristiques de l'IME. En outre, pour fournir une interface de paramètres permettant à l'utilisateur de modifier le comportement de l'IME, vous pouvez définir une activité de paramètres qui peut être lancée à partir des paramètres système.

L'extrait de code suivant déclare un service IME. Elle demande l'autorisation BIND_INPUT_METHOD pour permettre au service de connecter l'IME au système, de configurer un filtre d'intent correspondant à l'action android.view.InputMethod et de définir les métadonnées pour l'IME:

<!-- Declares the input method service. -->
<service android:name="FastInputIME"
    android:label="@string/fast_input_label"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data android:name="android.view.im"
               android:resource="@xml/method" />
</service>

L'extrait suivant déclare l'activité de paramétrage de l'IME. Il comporte un filtre d'intent pour ACTION_MAIN qui indique que cette activité est le point d'entrée principal de l'application IME:

<!-- Optional: an activity for controlling the IME settings. -->
<activity android:name="FastInputIMESettings"
    android:label="@string/fast_input_settings">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>

Vous pouvez également fournir un accès aux paramètres de l'IME directement depuis son interface utilisateur.

API de méthode de saisie

Les classes spécifiques aux IME se trouvent dans les packages android.inputmethodservice et android.view.inputmethod. La classe KeyEvent est importante pour gérer les caractères du clavier.

La partie centrale d'un IME est un composant de service, c'est-à-dire une classe qui étend InputMethodService. En plus d'implémenter le cycle de vie normal du service, cette classe comporte des rappels permettant de fournir l'interface utilisateur de l'IME, de gérer les entrées utilisateur et de diffuser du texte dans le champ ciblé. Par défaut, la classe InputMethodService fournit la majeure partie de l'implémentation pour gérer l'état et la visibilité de l'IME et communiquer avec le champ de saisie actuel.

Les classes suivantes sont également importantes:

BaseInputConnection
Définit le canal de communication entre un InputMethod et l'application qui reçoit son entrée. Elle permet de lire le texte situé autour du curseur, de valider du texte dans la zone de texte et d'envoyer des événements de touche bruts à l'application. Les applications doivent étendre cette classe plutôt que d'implémenter l'interface de base InputConnection.
KeyboardView
Extension de View qui affiche un clavier et répond aux événements d'entrée utilisateur. La disposition du clavier est spécifiée par une instance de Keyboard, que vous pouvez définir dans un fichier XML.

Concevoir l'interface utilisateur du mode de saisie

Un IME comporte deux principaux éléments visuels: la vue input (entrée) et la vue candidates (candidats). Il vous suffit d'implémenter les éléments pertinents pour le mode de saisie que vous concevez.

Vue d'entrée

La vue d'entrée est l'interface utilisateur dans laquelle l'utilisateur saisit du texte sous la forme de clics sur des touches, d'écriture manuscrite ou de gestes. Lorsque l'IME est affiché pour la première fois, le système appelle le rappel onCreateInputView(). Dans l'implémentation de cette méthode, créez la mise en page que vous souhaitez afficher dans la fenêtre IME et renvoyez-la au système. L'extrait de code suivant montre un exemple d'implémentation de la méthode onCreateInputView():

Kotlin

override fun onCreateInputView(): View {
    return layoutInflater.inflate(R.layout.input, null).apply {
        if (this is MyKeyboardView) {
            setOnKeyboardActionListener(this@MyInputMethod)
            keyboard = latinKeyboard
        }
    }
}

Java

@Override
public View onCreateInputView() {
    MyKeyboardView inputView =
        (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null);

    inputView.setOnKeyboardActionListener(this);
    inputView.setKeyboard(latinKeyboard);

    return inputView;
}

Dans cet exemple, MyKeyboardView est une instance d'une implémentation personnalisée de KeyboardView qui affiche un Keyboard.

Vue "Candidats"

La vue des candidats est l'interface utilisateur dans laquelle l'IME affiche des corrections de mots ou des suggestions potentielles que l'utilisateur peut sélectionner. Dans le cycle de vie de l'IME, le système appelle onCreateCandidatesView() lorsqu'il est prêt à afficher la vue des candidats. Dans votre implémentation de cette méthode, renvoyez une mise en page qui affiche des suggestions de mots, ou renvoyez la valeur "null" si vous ne souhaitez afficher aucune information. Une réponse nulle est le comportement par défaut. Vous n'avez donc pas besoin de l'implémenter si vous ne fournissez pas de suggestions.

Considérations de conception de l'interface utilisateur

Cette section décrit quelques points à prendre en compte concernant la conception de l'interface utilisateur pour les IME.

Gérer plusieurs tailles d'écran

L'interface utilisateur de votre IME doit pouvoir s'adapter à différentes tailles d'écran, et gérer les orientations paysage et portrait. En mode IME qui n'est pas en plein écran, laissez suffisamment d'espace pour que l'application affiche le champ de texte et tout contexte associé, de sorte que l'IME n'occupe pas plus de la moitié de l'écran. En mode IME en plein écran, ce n'est pas un problème.

Gérer différents types d'entrées

Les champs de texte Android vous permettent de définir un type d'entrée spécifique, tel que du texte au format libre, des chiffres, des URL, des adresses e-mail et des chaînes de recherche. Lorsque vous implémentez un nouvel IME, détectez le type d'entrée de chaque champ et fournissez l'interface appropriée. Toutefois, vous n'avez pas besoin de configurer votre IME pour vérifier si l'utilisateur saisit du texte valide pour le type d'entrée. Cela relève de la responsabilité de l'application propriétaire du champ de texte.

Par exemple, voici l'interface fournie par l'IME latin pour la saisie de texte de la plate-forme Android:

Image montrant une entrée de texte dans un IME latin
Figure 2 : Saisie de texte IME en latin.

Voici l'interface fournie par l'IME latin pour l'entrée numérique de la plate-forme Android:

Image montrant une entrée numérique dans un IME latin
Figure 3 : Entrée numérique IME latin.

Lorsqu'un champ de saisie est sélectionné et que votre IME démarre, le système appelle onStartInputView(), en transmettant un objet EditorInfo contenant des informations sur le type d'entrée et d'autres attributs du champ de texte. Dans cet objet, le champ inputType contient le type d'entrée du champ de texte.

Le champ inputType est une valeur int qui contient des motifs de bits pour différents paramètres de type d'entrée. Pour tester le type d'entrée du champ de texte, masquez-le avec la constante TYPE_MASK_CLASS, comme ceci:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

Le modèle de bits du type d'entrée peut avoir l'une des valeurs suivantes:

TYPE_CLASS_NUMBER
Champ de texte permettant de saisir des chiffres. Comme l'illustre la figure 3, l'IME latin affiche un pavé numérique pour les champs de ce type.
TYPE_CLASS_DATETIME
Champ de texte permettant de saisir une date et une heure.
TYPE_CLASS_PHONE
Champ de texte permettant de saisir des numéros de téléphone.
TYPE_CLASS_TEXT
Champ de texte permettant de saisir des caractères acceptés.

Ces constantes sont décrites plus en détail dans la documentation de référence de InputType.

Le champ inputType peut contenir d'autres bits qui indiquent une variante du type de champ de texte, par exemple:

TYPE_TEXT_VARIATION_PASSWORD
Variante de TYPE_CLASS_TEXT pour saisir des mots de passe. La méthode de saisie affiche les symboles au lieu du texte réel.
TYPE_TEXT_VARIATION_URI
Variante de TYPE_CLASS_TEXT permettant de saisir des URL Web et d'autres URI (Uniform Resource Identifier).
TYPE_TEXT_FLAG_AUTO_COMPLETE
Variante de TYPE_CLASS_TEXT permettant de saisir du texte que l'application saisit automatiquement à partir d'un dictionnaire, d'une recherche ou d'une autre fonction.

Masquez inputType avec la constante appropriée lorsque vous testez ces variantes. Les constantes de masque disponibles sont répertoriées dans la documentation de référence de InputType.

Envoyer un SMS à l'application

Lorsque l'utilisateur saisit du texte avec votre IME, vous pouvez envoyer du texte à l'application en envoyant des événements de touche individuels ou en modifiant le texte autour du curseur dans le champ de texte de l'application. Dans les deux cas, utilisez une instance de InputConnection pour diffuser le texte. Pour obtenir cette instance, appelez InputMethodService.getCurrentInputConnection().

Modifier le texte autour du curseur

Lorsque vous modifiez du texte existant, voici quelques méthodes utiles dans BaseInputConnection:

getTextBeforeCursor()
Renvoie une CharSequence contenant le nombre de caractères demandés avant la position actuelle du curseur.
getTextAfterCursor()
Renvoie une CharSequence contenant le nombre de caractères demandés après la position actuelle du curseur.
deleteSurroundingText()
Supprime le nombre de caractères spécifié avant et après la position actuelle du curseur.
commitText()
Valide un CharSequence dans le champ de texte et définit une nouvelle position du curseur.

Par exemple, l'extrait de code suivant montre comment remplacer les quatre caractères situés à gauche du curseur par le texte "Hello!":

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.deleteSurroundingText(4, 0)
    ic.commitText("Hello", 1)
    ic.commitText("!", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);

Aide à la rédaction de texte avant la validation

Si votre IME prédit du texte ou nécessite plusieurs étapes pour composer un glyphe ou un mot, vous pouvez afficher la progression dans le champ de texte jusqu'à ce que l'utilisateur valide le mot, puis remplacer la composition partielle par le texte terminé. Vous pouvez appliquer un traitement spécial au texte en y ajoutant un span lorsque vous le transmettez à setComposingText().

L'extrait de code suivant montre comment afficher la progression dans un champ de texte:

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.setComposingText("Composi", 1)
    ic.setComposingText("Composin", 1)
    ic.commitText("Composing ", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);

Intercepter les événements de touche matérielle

Même si la fenêtre du mode de saisie n'a pas de focus explicite, elle reçoit d'abord les événements de touche matérielle et peut les utiliser ou les transférer vers l'application. Par exemple, vous pouvez utiliser les touches directionnelles pour naviguer dans votre interface utilisateur lors de la sélection des candidats lors de la composition. Vous pouvez également piéger la touche Retour pour fermer toutes les boîtes de dialogue provenant de la fenêtre du mode de saisie.

Pour intercepter les clés matérielles, remplacez onKeyDown() et onKeyUp().

Appelez la méthode super() pour les touches que vous ne souhaitez pas gérer vous-même.

Créer un sous-type IME

Les sous-types permettent à l'IME d'exposer plusieurs modes de saisie et langues pris en charge par un IME. Un sous-type peut représenter les éléments suivants:

  • Des paramètres régionaux, comme en_US ou fr_FR
  • Un mode de saisie (voix, clavier ou écriture manuscrite, par exemple)
  • Autres styles, formulaires ou propriétés de saisie spécifiques à l'IME, tels que les dispositions de clavier à 10 touches ou QWERTY

Il peut s'agir de n'importe quel texte ("clavier" ou "voix", par exemple). Un sous-type peut également exposer une combinaison de ces éléments.

Les informations sur les sous-types sont utilisées pour une boîte de dialogue de changement d'IME, disponible à partir de la barre de notification, et pour les paramètres IME. Ces informations permettent également au framework d'afficher directement un sous-type spécifique d'un IME. Lorsque vous créez un IME, utilisez la fonction de sous-type, car elle aide l'utilisateur à identifier les différents modes et langages IME, et à basculer entre eux.

Définissez des sous-types dans l'un des fichiers de ressources XML de la méthode d'entrée, à l'aide de l'élément <subtype>. L'extrait de code suivant définit un IME avec deux sous-types: un sous-type de clavier pour l'anglais américain et un autre sous-type de clavier pour le français pour la France:

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
        android:settingsActivity="com.example.softkeyboard.Settings"
        android:icon="@drawable/ime_icon">
    <subtype android:name="@string/display_name_english_keyboard_ime"
            android:icon="@drawable/subtype_icon_english_keyboard_ime"
            android:languageTag="en-US"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="somePrivateOption=true" />
    <subtype android:name="@string/display_name_french_keyboard_ime"
            android:icon="@drawable/subtype_icon_french_keyboard_ime"
            android:languageTag="fr-FR"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="someVariable=30,someInternalOption=false" />
    <subtype android:name="@string/display_name_german_keyboard_ime" ... />
</input-method>

Pour vous assurer que vos sous-types sont correctement libellés dans l'interface utilisateur, utilisez "%s" pour obtenir un libellé de sous-type identique au libellé des paramètres régionaux du sous-type. Cela est illustré dans les deux extraits de code suivants. Le premier extrait montre une partie du fichier XML de la méthode d'entrée:

<subtype
    android:label="@string/label_subtype_generic"
    android:imeSubtypeLocale="en_US"
    android:icon="@drawable/icon_en_us"
    android:imeSubtypeMode="keyboard" />

L'extrait suivant fait partie du fichier strings.xml de l'IME. La ressource de chaîne label_subtype_generic, utilisée par la définition de l'interface utilisateur du mode de saisie pour définir l'étiquette du sous-type, est définie comme suit:

<string name="label_subtype_generic">%s</string>

Avec ce paramètre, le nom à afficher du sous-type correspond aux paramètres régionaux. Par exemple, dans n'importe quel paramètre régional, le nom à afficher est "Anglais (États-Unis)".

Choisir des sous-types d'IME dans la barre de notification

Le système Android gère tous les sous-types exposés par tous les IME. Les sous-types IME sont traités comme des modes de l'IME auquel ils appartiennent. L'utilisateur peut naviguer depuis la barre de notification ou l'application Paramètres vers un menu des sous-types d'IME disponibles, comme illustré dans la figure suivante:

Image montrant le menu &quot;Langues et saisie&quot; du système
Figure 4 : Menu système Langues et saisie.

Choisissez des sous-types IME dans les paramètres système

L'utilisateur peut également contrôler l'utilisation des sous-types dans le panneau des paramètres Langue et saisie dans les paramètres système:

Image montrant le menu de sélection des langues
Figure 5 : Menu système Langues

Basculer entre les sous-types d'IME

Vous pouvez permettre aux utilisateurs de basculer facilement entre les sous-types d'IME en fournissant une touche de basculement, comme l'icône de langue en forme de globe sur le clavier. Cela améliore la facilité d'utilisation du clavier et est pratique pour l'utilisateur. Pour activer cette fonctionnalité, procédez comme suit:

  1. Déclarez supportsSwitchingToNextInputMethod = "true" dans les fichiers de ressources XML de la méthode d'entrée. Votre déclaration doit ressembler à l'extrait de code suivant :
    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
            android:supportsSwitchingToNextInputMethod="true">
    
  2. Appelez la méthode shouldOfferSwitchingToNextInputMethod().
  3. Si la méthode renvoie la valeur "true", affichez une touche de commutation.
  4. Lorsque l'utilisateur appuie sur la touche de basculement, appelez switchToNextInputMethod() en transmettant la valeur "false". La valeur "false" indique au système de traiter tous les sous-types de manière égale, quel que soit l'IME auquel ils appartiennent. Si vous spécifiez "true", le système doit parcourir les sous-types dans l'IME actuel.

Considérations générales liées aux IME

Voici d'autres éléments à prendre en compte lorsque vous implémentez votre IME:

  • Permettez aux utilisateurs de définir des options directement depuis l'interface utilisateur de l'IME.
  • Offrez aux utilisateurs un moyen de passer à un autre IME directement depuis l'interface utilisateur du mode de saisie, car plusieurs IME peuvent être installés sur l'appareil.
  • Affichez rapidement l'interface utilisateur de l'IME. Préchargez ou chargez à la demande les ressources volumineuses afin que les utilisateurs voient l'IME dès qu'ils appuient sur un champ de texte. Mettez en cache les ressources et les vues pour les appels suivants du mode de saisie.
  • Libérez de grandes allocations de mémoire immédiatement après le masquage de la fenêtre du mode de saisie, afin que les applications aient suffisamment de mémoire pour s'exécuter. Utilisez un message retardé pour libérer des ressources si l'IME est masqué pendant quelques secondes.
  • Assurez-vous que les utilisateurs peuvent saisir autant de caractères que possible pour la langue ou les paramètres régionaux associés à l'IME. Les utilisateurs peuvent utiliser des signes de ponctuation dans les mots de passe ou les noms d'utilisateur. Par conséquent, votre IME doit fournir de nombreux caractères différents pour permettre aux utilisateurs de saisir un mot de passe et d'accéder à l'appareil.