android input method editor

44
antislashn.org Android - Input Method Editor C - 1/44 Input Method Editor

Upload: franck-simon

Post on 26-Jun-2015

2.348 views

Category:

Technology


2 download

DESCRIPTION

Annexe de mon support de formation sur Android. Un exemple d'IME pour un clavier physique est expliqué. Cette annexe sera complétée avec d'autres exemples.

TRANSCRIPT

Page 1: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 1/44

Input Method Editor

Page 2: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 2/44

Introduction

● IMF : Input Method Framework● apparu avec le SDK 1.5● permet de développer des moyens de saisie

– clavier software– clavier physique– voix– reconnaissance d'écriture– …

Page 3: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 3/44

Introduction

● La saisie est effectuée via un IME● Input Method Editor

● IMF supporte une grand nombre d'IME● En général l'utilisateur accède à un IME software

particulier de manière transparente● lors de la saisie d'un champ

– texte, date, heure, mot de passe, …● Android arrange automatiquement le bureau

– "pan and scan" qui permet le défilement de l'écran de l'application afin que la zone de saisie soit toujours visible

– "fullscrenn" qui est utilisé si l'IME est trop large pour partager l'espace avec l'écran de l'application

Page 4: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 4/44

Introduction

● "pan and scan"

source : Google

Page 5: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 5/44

Introduction

● "fullscreen"

source : Google

Page 6: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 6/44

Contrôle de l'IME

● Les attributs XML des zones d'édition permettent de contrôle le type d'IME qui sera utilisé● dans le fichier XML du layout● android:inputType qui peut prendre les valeurs

– android:password, android:numeric, android:phoneNumber, …

<EditText android:id="@+id/edtInput" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine" android:imeOptions="actionSend|flagNoEnterAction" android:maxLines="4" android:maxLength="2000" android:hint="@string/compose_hint"/>

Page 7: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 7/44

Contrôle de l'IME

● Permettre le redimensionnement● dans le fichier AndroidManifest.xml

– attribut android:windowSoftInput de l'élément <activity>

● adjustResize, adjustPan, stateVisible

<activity name="EditContactActivity" android:windowSoftInputMode="stateVisible|adjustResize"> ...</activity>

Page 8: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 8/44

Contrôle de l'IME

● Comportement des boutons● la touche Enter d'un clavier virtuel passe au champ

suivant– si le champ en cours de saisie n'est pas multilingues

● en mode "fullscreen", l'IME peut ajouter un bouton à la droite du champ en saisie

● L'élément <TextView> possède un attribut android:imeOption qui peut prendre les valeurs● actionGo, actionSearch,actionNone, actionSend,actionNext,actionDone– actionDone ou actionNext par défaut

Page 9: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 9/44

Créer son IME

● La création d'un IME permet de● créer un nouveau clavier virtuel

– ABCDEF au lieu du classique AZERTY● ajouter des options lors de l'appui long sur un caractère● créer un mapping personnalisé pour un clavier réel● changer le mode de saisie : voix, reconnaissance

écriture● changer le mode de prédilection de la saisie● ...

Page 10: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 10/44

Créer son IME

● L'ajout d'un IME passe par la spécialisation de la classe InputMethodService● l'IME apparaît lors dans les paramètres de saisie

– il peut avoir ses propres écrans de paramétrage

● L'IME représente un moyen de saisie● il possède un cycle de vie● il peut inter-agir avec le champs en cours de saisie● il peut posséder des vues secondaires ("candidates

views")– correction, suggestion

Page 11: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 11/44

Créer son IME

● Les types de saisie peuvent être différents– email, texte, numéro de télephone, …

● l'IME peut détecter le type de saisie en cours– auprès de la classe EditorInfo

● paramètre de la méthode onStartInputView()● champ inputType

– masque de constantes ● TYPE_CLASS_TEXT, TYPE_CLASS_PHONE,...

source : Google

Page 12: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 12/44

Créer son IME

● Classes principales● InputMethodService

– classe à redéfinir pour créer son IME et sa prise en charge par Android

● BaseInputConnection– canal de communication entre le champ en cours de saisie et InputMethodService

● peut être null si aucune saisie en cours

● KeyboardView– vue du clavier virtuel, définit en général dans un fichier XML

● KeyEvent– événements générés lors de l'appui d'une touche

Page 13: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 13/44

Créer son IME

● Cycle de vie de l'IME● méthodes callback de InputMethodService

Page 14: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 14/44

Créer son IME

● La classe BaseInputConnection possède des méthodes de gestion du texte en cours de saisie● getTextBeforCursor()● getTextAfterCursor()● deleteSurroundingText()● commitText()● sendKeyEvent()● ...

Page 15: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 15/44

Créer son IME – exemple 1

● Cet exemple montre comment redéfinir le mapping d'un clavier physique● Android prend en charge pas défaut le QWERTY● cet exemple est volontairement très simple

● Un clavier envoi au système un scancode● correspondant à la position physique des touches

– peut dépendre des claviers● le scancode est ensuite transformé en un code de

touche● puis le comportement de la touche est adapté en

fonction des autres touches Shift, Atl, Ctrl, ...

Page 16: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 16/44

Créer son IME – exemple 1

● Pour effectuer les transformations entre scancode, code de la touche et comportement, Android utilise deux fichiers de base● system/usr/keylayout/Generic.kl

– scancode vers touche● les code touches Android sont des constantes de KeyEvent

● system/usr/keychars/Generic.kcm– description du comportement de la touche

● Des fichiers tiers peuvent être présents● exemple : Vendor_xxxx_Product_yyyy.kl

– xxxx est le VID (Vendor ID)– yyyy est le PID (Product ID)

Page 17: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 17/44

Créer son IME – exemple 1

● Si votre téléphone est rooté, ou si vous créez votre propre ROM il est donc aisé d'ajouter un fichier spécifique.● sous Android voir le fichier /proc/bus/input/devices

I: Bus=0005 Vendor=0a5c Product=8502 Version=011bN: Name="BeeWi BBK300 Bluetooth Azerty Keyboard"P: Phys=4C:AA:16:8B:93:AAS: Sysfs=/devices/platform/tegra_uart.2/tty/ttyHS2/hci0/hci0:12/input8U: Uniq=00:24:94:C0:07:8CH: Handlers=event5 keychord B: PROP=0B: EV=12001fB: KEY=70000 10000 2008007 ff9f387a d941d7ff febeffdf ffefffff ffffffff fffffffeB: REL=3B: ABS=f00 0B: MSC=10B: LED=1f

Page 18: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 18/44

Créer son IME – exemple 1

● Extrait de Generic.klkey 1 ESCAPEkey 2 1key 3 2key 4 3key 5 4key 6 5key 7 6key 8 7key 9 8key 10 9key 11 0key 12 MINUSkey 13 EQUALSkey 14 DELkey 15 TABkey 16 Qkey 17 Wkey 18 Ekey 19 Rkey 20 T

Page 19: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 19/44

Créer son IME – exemple 1

● Extrait de Generic.kcm

key A { label: 'A' base: 'a' shift, capslock: 'A' ctrl, alt, meta: none}

key B { label: 'B' base: 'b' shift, capslock: 'B' ctrl, alt, meta: none}

Page 20: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 20/44

Créer son IME – exemple 1

● Extrait de Generic.kcm● de manière générale

● où le modificateur peut être : alt, ralt, lalt, shift, rshift, lshift, ctrl, rctrl, lctrl, capslock, meta, rmeta, lmeta– le code de touche peut aussi être sous format unicode

key [keycode] { label: '[label]' base: '[key without any modifiers]' [modifier]: '[key with modifier]' [modifier]+[modifier]: '[key with both modifiers]' [modifier],[modifier]: '[key with any of listed modifiers]' [modifier]: fallback [magic key] # read below [modifier],[modifier]: none}

shift, capslock: 'A'ralt: '\u0105'

source : http://forum.xda-developers.com/showthread.php?t=1568760

Page 21: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 21/44

Créer son IME – exemple 1

● Extrait de Generic.kcm● le fallback magic key correspond à certaines

commandes comme HOM, SEARCH, MENU, ...

key D { label: 'D' base: 'd' shift, capslock: 'D' meta: fallback HOME # show desktop alt: none}

source : http://forum.xda-developers.com/showthread.php?t=1568760

Page 22: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 22/44

Créer son IME – exemple 1

● Afin de refaire le mapping d'un clavier, il est nécessaire de connaître les scancodes qui sont générés● soit en écoutant les événements sur adb

– commande adb shell getevent

● soit en créant une application dédiée– cf. slides suivants

scancode en hexa – ici touche 'A'd'un clavier AZERTY BeeWi

touche appuyée

touche relâchée

Page 23: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 23/44

Créer son IME – exemple 1

● Code permettant de récupérer le scancode● ne fonctionne pas pour toutes les touches, car certaines

sont prisent en compte au niveau d'Android, et non pas de l'activité– HOME, SEARCH, ...

Page 24: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 24/44

Créer son IME – exemple 1

● Extrait du code de l'activitépublic boolean onKeyDown(int keyCode, KeyEvent event){

StringBuilder builder = new StringBuilder();builder.append("KeyCode : ").append(keyCode).append(" [").append(String.format("0x%04X", keyCode)).append("]\n");builder.append("event.getScanCode() : ").append(event.getScanCode()).append(" [").append(String.format("0x%04X", event.getScanCode())).append("]\n");builder.append("event.getAction() : ").append(event.getAction()).append('\n');builder.append("event.getUnicodeChar() : ").append(event.getUnicodeChar()).append(" [").

append(String.format("0x%04X", event.getUnicodeChar())).append("]\n");builder.append("character : ").append(Character.toString((char)event.getUnicodeChar())).append('\n');builder.append("event.getScanCode() : ").append(event.getScanCode()).append('\n');builder.append("event.getDisplayLabel() : ").append(event.getDisplayLabel()).append('\n');builder.append("event.getNumber() : ").append(event.getNumber()).append('\n');int modifiers = event.getMetaState();if((modifiers & KeyEvent.META_ALT_ON) != 0)

builder.append("ALT\n");if((modifiers & KeyEvent.META_ALT_LEFT_ON) != 0)...

Page 25: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 25/44

Créer son IME – exemple 1

● Nous pouvons passer à notre mapping du clavier physique

– clavier bluetooth dans notre exemple● création du fichier de mapping

– l'objectif est de mapper les touches alphanumérique dans l'ordre ABCDE au lieu de AZERTY

● création de notre classe InputMethodService● déclaration dans le fichier manifeste● … puis test

Page 26: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 26/44

Créer son IME – exemple 1

● Le fichier de mapping est placé dans le répertoire assets du projet Eclipse

# format# scancode;code android;code android Shift;# le code android est calqué sur les constantes de la classe android.view.KeyCode# exemple : le scancode décimal 16 est associé à la touche A dans le clavier AZERTY# le code android est KEYCODE_A, le code dans le fichier est A# le séparateur est le caractère ;16;A17;B18;C19;D20;E21;F22;G23;H24;I

Page 27: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 27/44

Créer son IME – exemple 1

● Une classe utilitaire Key encapsule le scancode et le code Android

package org.antislashn.android.clavier;

public class Key {int scancode;int androidKeyCode;

public Key(int scanCode, int androidKeyCode) {this.scancode = scanCode;this.androidKeyCode = androidKeyCode;

}}

Page 28: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 28/44

Créer son IME – exemple 1

● Une classe utilitaire FileParser lit le fichier et crée une collection de Key

public class FileParser {static private String separator = ";";static private String prefix = "KEYCODE_";static private String tag = "FileParser";

public static SparseArray<Key> parse(Context context,String fileName) throws IOException{

...

return mapping;}

private static int getAndroidCode(String code) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

...

}}

Page 29: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 29/44

Créer son IME – exemple 1

● Détail de la méthode parse()

public static SparseArray<Key> parse(Context context,String fileName) throws IOException{BufferedReader file = new BufferedReader(new InputStreamReader(context.getAssets().open(fileName)));String line = null;SparseArray<Key> mapping = new SparseArray<Key>();while((line=file.readLine())!=null){

line = line.trim();if(line.charAt(0) == '#' || line.length() == 0)

continue;String[] fields = line.split(separator);if(fields.length<2)

continue;int scanCode = Integer.parseInt(fields[0]);int androidCode;try {

androidCode = getAndroidCode(fields[1]);Key key = new Key(scanCode,androidCode);mapping.append(scanCode, key);

} catch (Exception e) {Log.e(tag,"=> Erreur sur la rechecher de "+fields[1],e);

}}file.close();file = null;return mapping;

}

Page 30: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 30/44

Créer son IME – exemple 1

● Détail de la méthode getAndroidCode()● utilisation de la réflexivité, ce qui permet de s'affranchir

des tests sur les différents niveaux de SDK

private static int getAndroidCode(String code) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

String fieldName = prefix + code.toUpperCase(Locale.US);Field attribut = KeyEvent.class.getDeclaredField(fieldName); if(attribut != null)

return attribut.getInt(null);return 0;}

}

Page 31: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 31/44

Créer son IME – exemple 1

● Classe spécialisant InputMethodServicepublic class ClavierImeService extends InputMethodService {

private static String tag = "ClavierImeService";private static SparseArray<Key> mapping;private static String fileName = "beewi.txt";

@Overridepublic void onCreate() {

...}

@Overridepublic boolean onEvaluateFullscreenMode() {

return false;}

@Overridepublic boolean onEvaluateInputViewShown() {

return false;}

...

private void log(String methodName, int keyCode, KeyEvent event) {...

}

}

car clavier physique

car clavier physique

Page 32: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 32/44

Créer son IME – exemple 1

● méthode onCreate() de ClavierImeService

public void onCreate() {super.onCreate();Log.d(tag, ">>>>>>>>>>>> onCreate");try {

mapping = FileParser.parse(this, fileName);} catch (Exception e) {

Log.e(tag, ">>> onCreate ERROR :", e);} finally {

Log.d(tag, ">>> onCreate - chargement du fichier " + fileName);}

}

Page 33: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 33/44

Créer son IME – exemple 1

● méthode remapKey() de ClavierImeService

private boolean remapKey(KeyEvent event) {boolean keySended = false;Key key = mapping.get(event.getScanCode());if (key != null) {

Log.d(tag, "+++ caractère remplacé");event = new KeyEvent(event.getDownTime(), event.getEventTime(),

event.getAction(), key.androidKeyCode,event.getRepeatCount(), event.getMetaState(),event.getDeviceId(), event.getScanCode(),event.getFlags());

Log.d(tag, "+++ event.getUnicodeChar() : " + event.getUnicodeChar()+ " [" + Character.toString((char) event.getUnicodeChar())+ "]");

InputConnection inputConnection = getCurrentInputConnection();if (inputConnection != null) {

Log.d(tag, "+++ caractère envoyé");inputConnection.sendKeyEvent(event);keySended = true;

}}return keySended;

}

création d'un nouvel événementavec les caractéristiques de l'anciensauf le code touche

si un champ est en saisie, on envoie lenouvel élément

Page 34: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 34/44

Créer son IME – exemple 1

● méthode onKeyUp() et onKeyDown() de ClavierImeService

public boolean onKeyUp(int keyCode, KeyEvent event) {log("onKeyUp", keyCode, event);if(remapKey(event))

return true;else

return super.onKeyUp(event.getKeyCode(), event);}

public boolean onKeyDown(int keyCode, KeyEvent event) {log("onKeyDown", keyCode, event);if(remapKey(event))

return true;else

return super.onKeyDown(event.getKeyCode(), event);}

si le nouvel événement a été envoyéon renvoie true pour indiquer auframework que l'événement a ététraité

sinon on repasse l'événement au framework

Page 35: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 35/44

Créer son IME – exemple 1

● méthode log() de ClavierImeServiceprivate void log(String methodName, int keyCode, KeyEvent event) {

Log.d(tag, ">>>>>>>>>>>>>>>> " + methodName + " <<<<<<<<<<<<<<<<<<<<<<");Log.d(tag, "=> keyCode : " + keyCode);Log.d(tag, "=> event.getKeyCode() : " + event.getKeyCode() + " [ "

+ Character.toString((char) event.getKeyCode()) + " ]");Log.d(tag, "=> event.getUnicodeChar() : " + event.getUnicodeChar()

+ " [ " + Character.toString((char) event.getUnicodeChar())+ " ]");

Log.d(tag, "=> event.scanCode() : " + event.getScanCode());Log.d(tag, "=> event.getUnicodeChar() : " + event.getUnicodeChar());Log.d(tag, "=> event.getDisplayLabel() : " + event.getDisplayLabel());Log.d(tag, "=> event.getAction() : " + event.getAction());

}

Page 36: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 36/44

Créer son IME – exemple 1

● Déclaration de l'InputMethodService dans le fichier manifeste

<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name="org.antislashn.android.clavier.ClavierImeService" 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> </application>

permission nécessaire

<input-method xmlns:android="http://schemas.android.com/apk/res/android" />

publication d'éventuelles infossupplémentaires pour l'IME

Page 37: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 37/44

Prise en compte des touches de contrôle

● L'ensemble des touches de contrôle d'un clavier sont référencées● avec la constante type KEYCODE_

– qui associe un sancode et une touche– exemple scancode de 15 et KEYCODE_TAB

● avec la constante type META– qui caractérise une touche et les touches de modification de

comportement (modifier key)

● L'appui sur une touche déclenche un KeyEvent qui comprends le code de la touche appuyée et les touches muettes associées

Page 38: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 38/44

Prise en compte des touches de contrôle

● Exemple● appui sur Ctrl et A● l'affichage de l'événement donnera

– keycode : 29 (constante KEYCODE_A)

– valeur des métas : 0x3000● obtenu par la méthode getMetaState● qui est composé d'un OU logique des maques suivants

– META_CTRL_ON (valeur : 0x00001000)– META_CTRL_LEFT_ON (valeur : 0x00002000)

Page 39: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 39/44

Prise en compte des touches de contrôle

● Tout un ensemble de méthodes de KeyEvent permet de connaître les touches appuyées● isShiftPressed(), isAltPressed(), …

● Pour changer le comportement par défaut des combinaisons de touches il faut :● ne pas transmettre l'état des métas à l'événement qui

sera recréé● agir sur les métas du InputConnection de la saisie

en cours

Page 40: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 40/44

Prise en compte des touches de contrôle

● Par exemple nous souhaitons afficher la lettre C avec la combinaison Ctrl + A● suppression des métas dans l'événement recréé

private KeyEvent changeKeyEvent(KeyEvent event) {return new KeyEvent(event.getDownTime(),event.getEventTime(),

event.getAction(), androidKeyCode,event.getRepeatCount(), 0,event.getDeviceId(),event.getScanCode(),event.getFlags());

}

mise à zéro de l'état des métas

Page 41: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 41/44

Prise en compte des touches de contrôle

● puis masque avec la valeur des métas à ne pas prendre en compte sur InputConnection

private boolean sendKeyEvent(KeyEvent event){boolean keySended = false;InputConnection inputConnection = imeService.getCurrentInputConnection();if (inputConnection != null) {

Log.d(tag, "+++ caractère envoyé");inputConnection.clearMetaKeyStates(maskMeta);inputConnection.sendKeyEvent(event);keySended = true;

}return keySended;

}

mise à zéro des métas – le masque appliquédépend des métas à inhiber

Page 42: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 42/44

Envoi d'un code Unicode

● Un caractère unicode n'a pas de constante spécifique● pas de constante KEYCODE_

● Il faut donc directement utiliser les fonctions d'édition du InputConnection● dans l'exemple suivant, nous enverrons le caractère

0x212B correspondant à Ä

Page 43: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 43/44

Envoi d'un caractère Unicode

● exemple de code

private boolean sendKeyEvent(KeyEvent event){boolean keySended = false;InputConnection inputConnection = imeService.getCurrentInputConnection();if (inputConnection != null) {

Log.d(tag, "+++ caractère envoyé");inputConnection.clearMetaKeyStates(maskMeta);if(event.getAction()==KeyEvent.ACTION_UP){

String car = new String(new char[]{0x212B});inputConnection.commitText(car, 1);

}keySended = true;

}return keySended;

}

construction du caractère Ä

affichage du caractère par compositiondu texte dans le InputConnection

envoi uniquement sur latouche relachée

Page 44: Android   Input Method Editor

antislashn.org Android - Input Method Editor C - 44/44

Ressources

● Web● http://developer.android.com/guide/topics/text/creating-input-method.html● http://android-developers.blogspot.fr/2009/04/updating-applications-for-on-screen.html● http://forum.xda-developers.com/showthread.php?t=1568760