インプット メソッドを作成する

インプット メソッド エディタ(IME)は、ユーザーがテキストを入力できるようにするユーザー コントロールです。Android には、拡張可能な入力方式フレームワークが用意されています。このフレームワークを使用すると、アプリで画面キーボードや音声入力などの代替入力方式をユーザーに提供できます。IME をインストールした後、ユーザーはシステム設定から IME を選択して、システム全体で使用できます。一度に有効にできる IME は 1 つだけです。

Android システムに IME を追加するには、InputMethodService を拡張するクラスを含む Android アプリを作成します。また、通常は IME サービスにオプションを渡す「設定」アクティビティを作成します。また、システム設定の一部として表示される設定 UI を定義することもできます。

このページでは、次のトピックについて説明します。

IME を使用したことがない場合は、まず画面上の入力方法の紹介記事をご覧ください。

IME のライフサイクル

次の図は、IME のライフサイクルを示しています。

IME のライフサイクルを示す画像。
図 1. IME のライフサイクル。

以降のセクションでは、このライフサイクルに沿った IME に関連する UI とコードを実装する方法について説明します。

マニフェスト内で IME コンポーネントを宣言する

Android システムでは、IME は特別な IME サービスを含む Android アプリです。アプリのマニフェスト ファイルでは、サービスを宣言し、必要な権限をリクエストし、アクション action.view.InputMethod に一致するインテント フィルタを指定し、IME の特性を定義するメタデータを指定する必要があります。また、ユーザーが IME の動作を変更できる設定インターフェースを提供するために、システム設定から起動できる「設定」アクティビティを定義できます。

IME サービスを宣言するスニペットを以下に示します。サービスが IME をシステムに接続できるようにする権限 BIND_INPUT_METHOD をリクエストし、アクション android.view.InputMethod に一致するインテント フィルタを設定して、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>

次のスニペットは、IME の設定アクティビティを宣言しています。このアクティビティが IME アプリケーションのメインのエントリ ポイントであることを示す ACTION_MAIN のインテント フィルタがあります。

<!-- 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>

IME の UI から IME の設定に直接アクセスできるようにすることもできます。

インプット メソッド API

IME 固有のクラスは、android.inputmethodservice パッケージと android.view.inputmethod パッケージにあります。KeyEvent クラスは、キーボード文字を処理するうえで重要です。

IME の中心となるのは、InputMethodService を拡張するクラスであるサービス コンポーネントです。このクラスは、通常のサービス ライフサイクルを実装するだけでなく、IME の UI の提供、ユーザー入力の処理、フォーカスのあるフィールドへのテキストの配信を行うためのコールバックを備えています。デフォルトでは、InputMethodService クラスが、IME の状態と可視性の管理、現在の入力フィールドとの通信を行うための実装のほとんどを提供します。

次のクラスも重要です。

BaseInputConnection
InputMethod から入力を受け取るアプリケーションへの通信チャネルを定義します。このクラスを使用すると、カーソルの周囲のテキストを読み取り、テキスト ボックスにテキストをコミットし、未加工のキーイベントをアプリに送信できます。アプリは、ベース インターフェース InputConnection を実装するのではなく、このクラスを拡張する必要があります。
KeyboardView
View の拡張機能。キーボードをレンダリングし、ユーザー入力イベントに応答します。キーボード レイアウトは、XML ファイルで定義できる Keyboard のインスタンスによって指定されます。

インプット メソッド UI を設計する

IME には、入力ビューと候補ビューという 2 つの主要な視覚要素があります。設計する入力方法に関連する要素のみを実装する必要があります。

入力ビュー

入力ビューは、ユーザーがキークリック、手書き、ジェスチャーでテキストを入力する UI です。IME が初めて表示されると、システムは onCreateInputView() コールバックを呼び出します。このメソッドの実装では、IME ウィンドウに表示するレイアウトを作成し、そのレイアウトをシステムに返します。次のスニペットは、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;
}

この例では、MyKeyboardView は Keyboard をレンダリングする KeyboardView のカスタム実装のインスタンスです。

候補ビュー

候補ビューは、IME がユーザーに選択してもらうために、修正候補や予測候補を表示する UI です。IME のライフサイクルでは、候補ビューを表示する準備が整うと、システムが onCreateCandidatesView() を呼び出します。このメソッドの実装では、単語の候補を表示するレイアウトを返すか、何も表示しない場合は null を返します。null レスポンスがデフォルトの動作であるため、候補を提供しない場合は、これを実装する必要はありません。

UI 設計に関する考慮事項

このセクションでは、IME の UI 設計に関する考慮事項について説明します。

さまざまな画面サイズを処理する

IME の UI は、さまざまな画面サイズに合わせてスケーリングでき、横向きと縦向きの両方に対応できる必要があります。全画面表示以外の IME モードでは、アプリがテキスト フィールドと関連するコンテキストを表示するのに十分なスペースを確保し、IME が画面の半分以上を占有しないようにします。全画面 IME モードでは、これは問題になりません。

さまざまな入力タイプを処理する

Android のテキスト フィールドでは、自由形式のテキスト、数字、URL、メールアドレス、検索文字列など、特定の入力タイプを設定できます。新しい IME を実装する場合は、各フィールドの入力タイプを検出し、適切なインターフェースを提供します。ただし、ユーザーが入力タイプに対して有効なテキストを入力しているかどうかを確認するように IME を設定する必要はありません。これは、テキスト フィールドを所有するアプリの責任です。

たとえば、Latin IME が Android プラットフォームのテキスト入力用に提供するインターフェースは次のとおりです。

ラテン文字 IME でのテキスト入力を示す画像
図 2. ラテン文字 IME のテキスト入力。

以下は、Latin IME が Android プラットフォームの数値入力用に提供するインターフェースです。

ラテン語 IME での数字入力を示す画像
図 3. ラテン語 IME の数値入力。

入力フィールドがフォーカスを受け取り、IME が起動すると、システムは onStartInputView() を呼び出し、入力タイプやテキスト フィールドのその他の属性に関する詳細を含む EditorInfo オブジェクトを渡します。このオブジェクトの inputType フィールドには、テキスト フィールドの入力タイプが含まれます。

inputType フィールドは、さまざまな入力タイプ設定のビットパターンを含む int です。テキスト フィールドの入力タイプをテストするには、次のように定数 TYPE_MASK_CLASS でマスクします。

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

入力タイプのビットパターンには、次のいずれかの値を指定できます。

TYPE_CLASS_NUMBER
数値を入力するためのテキスト フィールド。図 3 に示すように、ラテン語 IME では、このタイプのフィールドにテンキーが表示されます。
TYPE_CLASS_DATETIME
日付と時刻を入力するためのテキスト フィールド。
TYPE_CLASS_PHONE
電話番号を入力するためのテキスト フィールド。
TYPE_CLASS_TEXT
サポートされている文字を入力するためのテキスト フィールド。

これらの定数について詳しくは、InputType のリファレンス ドキュメントをご覧ください。

inputType フィールドには、テキスト フィールド タイプのバリエーションを示す他のビットを含めることができます。次に例を示します。

TYPE_TEXT_VARIATION_PASSWORD
パスワードを入力するための TYPE_CLASS_TEXT のバリエーション。入力方法では、実際のテキストではなくディンバットが表示されます。
TYPE_TEXT_VARIATION_URI
ウェブ URL やその他の Uniform Resource Identifier(URI)を入力するための TYPE_CLASS_TEXT のバリエーション。
TYPE_TEXT_FLAG_AUTO_COMPLETE
TYPE_CLASS_TEXT のバリエーション。アプリケーションが辞書、検索、その他の機能から自動補完するテキストを入力するためのものです。

これらのバリアントをテストする場合は、inputType を適切な定数でマスクします。使用可能なマスク定数のリストは、InputType のリファレンス ドキュメントに掲載されています。

テキストをアプリに送信する

ユーザーが IME でテキストを入力すると、個々のキーイベントを送信するか、アプリケーションのテキスト フィールドでカーソルの周囲のテキストを編集することで、アプリケーションにテキストを送信できます。どちらの場合も、InputConnection のインスタンスを使用してテキストを配信します。このインスタンスを取得するには、InputMethodService.getCurrentInputConnection() を呼び出します。

カーソルの周囲のテキストを編集する

既存のテキストの編集を処理する場合、BaseInputConnection の便利なメソッドには次のようなものがあります。

getTextBeforeCursor()
現在のカーソル位置より前にある、リクエストされた文字数を含む CharSequence を返します。
getTextAfterCursor()
現在のカーソル位置に続く、リクエストされた文字数を含む CharSequence を返します。
deleteSurroundingText()
現在のカーソル位置の前後の指定された文字数を削除します。
commitText()
CharSequence をテキスト フィールドに commit し、新しいカーソル位置を設定します。

たとえば、次のスニペットは、カーソルの左側にある 4 文字をテキスト「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);

確定前のテキスト作成をサポート

IME がテキストを予測する場合や、グリフや単語を作成するために複数のステップが必要な場合は、ユーザーが単語を確定するまでテキスト フィールドに進行状況を表示し、部分的な作成を完了したテキストに置き換えることができます。テキストを setComposingText() に渡すときに、スパンを追加することで、テキストに特別な処理を適用できます。

次のスニペットは、テキスト フィールドに進行状況を表示する方法を示しています。

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);

ハードウェア キーイベントをインターセプトする

入力方法ウィンドウは明示的なフォーカスを持っていませんが、ハードウェア キーイベントを最初に受信し、それらを消費するか、アプリケーションに転送できます。たとえば、方向キーを使用して、コンポジション中に候補を選択するための UI 内を移動できます。また、戻るキーをトラップして、入力方法ウィンドウから発生したダイアログを閉じることもできます。

ハードウェア キーをインターセプトするには、onKeyDown() と onKeyUp() をオーバーライドします。

自分で処理しないキーに対して super() メソッドを呼び出します。

IME サブタイプを作成する

サブタイプを使用すると、IME でサポートされている複数の入力モードと言語を IME で公開できます。サブタイプは、以下を表す場合があります。

  • 言語 / 地域(en_US、fr_FR など)
  • 入力モード(音声、キーボード、手書きなど)
  • 10 キーや QWERTY キーボード レイアウトなど、IME に固有のその他の入力スタイル、フォーム、プロパティ

モードは、「キーボード」や「音声」など、任意のテキストにできます。サブタイプは、これらの組み合わせを公開することもできます。

サブタイプ情報は、通知バーから利用できる IME スイッチャー ダイアログと IME 設定に使用されます。この情報により、フレームワークは IME の特定のサブタイプを直接起動することもできます。IME をビルドする際は、サブタイプ機能を使用します。この機能は、ユーザーがさまざまな IME の言語やモードを識別して切り替えるのに役立ちます。

<subtype> 要素を使用して、入力方法の XML リソース ファイルの 1 つでサブタイプを定義します。次のコード スニペットでは、2 つのサブタイプ(米国英語ロケール用のキーボード サブタイプと、フランスのフランス語ロケール用の別のキーボード サブタイプ)を持つ IME を定義しています。

<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>

UI でサブタイプが正しくラベル付けされるようにするには、「%s」を使用して、サブタイプのロケールラベルと同じサブタイプ ラベルを取得します。次の 2 つのコード スニペットでその方法を示します。最初のスニペットは、入力方法の XML ファイルの一部を示しています。

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

次のスニペットは、IME の strings.xml ファイルの一部を示しています。入力方法の UI 定義でサブタイプのラベルを設定するために使用される文字列リソース label_subtype_generic は、次のように定義されます。

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

この設定により、サブタイプの表示名がロケール設定と一致するようになります。たとえば、英語のロケールでは、表示名は「English (United States)」になります。

通知バーから IME サブタイプを選択する

Android システムは、すべての IME がエクスポーズするすべてのサブタイプを管理します。IME サブタイプは、IME のモードとして扱われます。ユーザーは、次の図に示すように、通知バーまたは設定アプリから、利用可能な IME サブタイプのメニューに移動できます。

[言語と入力] システム メニューを示す画像
図 4. [言語と入力] システム メニュー。

システム設定から IME サブタイプを選択する

ユーザーは、システム設定の [言語と入力] 設定パネルで、サブタイプの使用方法を管理することもできます。

言語選択メニューを示す画像
図 5. 言語システム メニュー

IME サブタイプを切り替える

キーボード上の地球儀型の言語アイコンなどの切り替えキーを提供することで、ユーザーが IME サブタイプを簡単に切り替えられるようにできます。これにより、キーボードのユーザビリティが向上し、ユーザーにとって便利になります。この切り替えを有効にするには、次の操作を行います。

  1. インプット メソッドの XML リソース ファイル内で、supportsSwitchingToNextInputMethod = "true" を宣言します。宣言は、次のコード スニペットのようになります。
    <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. shouldOfferSwitchingToNextInputMethod() メソッドを呼び出します。
  3. メソッドが true を返した場合は、切り替えキーを表示します。
  4. ユーザーがスイッチキーをタップしたら、false を渡して switchToNextInputMethod() を呼び出します。値が false の場合、システムは、どの IME に属しているかにかかわらず、すべてのサブタイプを同じように扱います。true を指定すると、システムは現在の IME のサブタイプを順番に切り替える必要があります。

IME に関する一般的な考慮事項

IME を実装する際に考慮すべきその他の事項は次のとおりです。

  • ユーザーが IME の UI から直接オプションを設定できるようにします。
  • デバイスに複数の IME がインストールされている可能性があるため、ユーザーが入力方法の UI から直接別の IME に切り替える方法を提供します。
  • IME の UI をすばやく表示します。ユーザーがテキスト フィールドをタップするとすぐに IME が表示されるように、大きなリソースをプリロードまたはオンデマンドで読み込みます。入力メソッドの後続の呼び出しのために、リソースとビューをキャッシュに保存します。
  • 入力方法ウィンドウが非表示になった直後に、大きなメモリ割り当てを解放して、アプリケーションが実行するのに十分なメモリを確保します。IME が数秒間非表示になっている場合は、遅延メッセージを使用してリソースを解放します。
  • IME に関連付けられている言語またはロケールで、ユーザーができるだけ多くの文字を入力できるようにします。ユーザーはパスワードやユーザー名に句読点を使用することがあるため、IME は、ユーザーがパスワードを入力してデバイスにアクセスできるように、さまざまな文字を提供する必要があります。