ソフトウェアキーボードアプリの作成方法についてまとめました.
0.環境
開発環境 Android Studio 1.0
実行環境 Minimum Required SDK 2.2 (テストはNexus7で行っています.)
1. プロジェクトの作成
新規プロジェクトを作成します.
Activityは不要なので、Create Activityのチェックは外してください.
2.AndroidManifest.xml の修正
Input Method Editor (IME)としてAndroidに認識してもらうServiceを、マニフェストに定義します.
applicationタグ内に以下のタグを追加します.
1 2 3 4 5 6 7 8 9 |
<service android:name=".FiftyKeys" android:label="@string/fifty_keys" android:permission="android.permission.BIND_INPUT_METHOD" > <meta-data android:name="android.view.im" android:resource="@xml/method"/> <intent-filter> <action android:name="android.view.InputMethod" /> </intent-filter> </service> |
ポイントは、permissionにBIND_INPUT_METHODを指定している箇所と、actionのandroid.view.InputMethodに応答するようにしている箇所です.
このコード内で利用している資源を新規作成します.
作成が必要なのは以下の資源です.
- android:name に定義した名前のクラスファイル.InputMethodServiceを継承させる
- res/xml res > 右クリック > New >Directory から作成
- res/xml/method.xml 詳細は後ほど記載するので、いったん空のXMLを作成してください
- string/fifty_keys ここは作成するアプリにあわせて適当な文字列を定義してください
3. method.xml の作成
res/xmlにmethod.xmlを作成します.
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <input-method xmlns:android="http://schemas.android.com/apk/res/android"> <subtype android:label="@string/fifty_keys" android:imeSubtypeLocale="jp_JP" android:imeSubtypeMode="keyboard" /> </input-method> |
今回は日本語のキーボードを作成するため、android:imeSubtypeLocaleをjp_JPにしています.
英語のキーボードであればen_USというように、localeにあわせて適切な値を設定してください.
android:imeSubtypeModeはkeyboardにしています.
4.layoutファイルの作成
キーボードに必要なレイアウトは、1.KeyboardViewのみを含んだキーボード自身のレイアウトと、2.キーを押した時に表示されるプレビュー用のレイアウトの2種類になります.
1.KeyboardViewのみを含んだキーボード自身のレイアウト
作成ファイルは、res/layout/keyboard.xml とします.
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0" encoding="utf-8"?> <android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/keyboard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:keyPreviewLayout ="@layout/preview" /> |
このファイルは作成するアプリの種類に応じて変更すべきところはありません.せいぜいidやkeyPreviewLayoutの値を好きな名前に変更するぐらいです.
ポイントは android:layout_alignParentBottomで、これをtrueにすることで画面下に寄ったレイアウトとなります.
2.キーを押した時に表示されるプレビュー用のレイアウト
作成ファイルは、res/layout/preview.xml とします.
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="#ffff00" android:textStyle="bold" android:textSize="45sp" > </TextView> |
背景色やテキストサイズ・スタイルを好みに合わせて修正してください.
5.キーボードの配列作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="utf-8"?> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:keyWidth="10%p" android:horizontalGap="0px" android:verticalGap="0px" android:keyHeight="60dp" > <Row> <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/> <Key android:codes="50" android:keyLabel="2"/> <Key android:codes="51" android:keyLabel="3"/> <Key android:codes="52" android:keyLabel="4"/> <Key android:codes="53" android:keyLabel="5"/> <Key android:codes="54" android:keyLabel="6"/> <Key android:codes="55" android:keyLabel="7"/> <Key android:codes="56" android:keyLabel="8"/> <Key android:codes="57" android:keyLabel="9"/> <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/> </Row> </Keyboard> |
Keyboardのパラメータを簡単に紹介します.
- keyWidth : キーの横幅です.%pは親の幅に対する割合を表しています.
- keyHeight : キーの立て幅です.
Key のパラメータを紹介します.
- codes : キーを押したときに入力される文字の文字コード
- keyLabel : キーのラベル
上に挙げたサンプルコードの要領で、キーボード配列を定義していきます.
6.Serviceクラスの作成
いよいよメイン処理のInputMethodServiceを継承したクラスを実装します.
InputMethodServiceに加えて、OnKeyboardActionListenerを実装してキーボードの入力イベントを拾います.
onCreateInputViewの中で各種初期化処理を行いますが、そこで4.で作成したLayoutXMLを読み込んだり、5.で作成したキーボードの配列を設定したりします.
1 2 3 4 5 6 7 8 9 |
@Override public View onCreateInputView() { kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null); keyboard = new Keyboard(this, R.xml.fifty_keys); kv.setKeyboard(keyboard); kv.setOnKeyboardActionListener(this); am = (AudioManager)getSystemService(AUDIO_SERVICE); return kv; } |
続いて、OnKeyboardActionListenerのonKeyでキーボードの入力を拾います.
getCurrentInputConnectionを利用して他のアプリケーションのインプットフィールドに接続します.
ポイントはswitch文です.
Deleteキー(文字列の削除)、Shiftキー(CapsLock制御)、Enterキー(実行・完了イベント)の場合はそれぞれ個別処理を実施します.
それ以外のキーが押された場合は、文字に変換してインプットフィールドに書き出します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Override public void onKey(int primaryCode, int[] keyCodes) { InputConnection ic = getCurrentInputConnection(); switch(primaryCode) { case Keyboard.KEYCODE_DELETE: ic.deleteSurroundingText(1, 0); break; case Keyboard.KEYCODE_SHIFT: caps = !caps; keyboard.setShifted(caps); kv.invalidateAllKeys(); break; case Keyboard.KEYCODE_DONE: ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); break; default: char code = (char) primaryCode; if (caps && Character.isLetter(code)) { code = Character.toUpperCase(code); } ic.commitText(String.valueOf(code), 1); break; } } |
全体のソースはこのようになります.
java/tb.android.fiftykeysboard/FiftyKeys.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
package tb.android.fiftykeysboard; import android.app.Service; import android.content.Intent; import android.inputmethodservice.InputMethodService; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.media.AudioManager; import android.os.IBinder; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.InputConnection; /** * Created by tubo on 2015/02/25. */ public class FiftyKeys extends InputMethodService implements KeyboardView.OnKeyboardActionListener{ private KeyboardView kv; private Keyboard keyboard; private boolean caps = false; @Override public View onCreateInputView() { kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null); keyboard = new Keyboard(this, R.xml.fifty_keys); kv.setKeyboard(keyboard); kv.setOnKeyboardActionListener(this); am = (AudioManager)getSystemService(AUDIO_SERVICE); return kv; } @Override public void onPress(int primaryCode) { } @Override public void onRelease(int primaryCode) { } @Override public void onKey(int primaryCode, int[] keyCodes) { InputConnection ic = getCurrentInputConnection(); switch(primaryCode) { case Keyboard.KEYCODE_DELETE: ic.deleteSurroundingText(1, 0); break; case Keyboard.KEYCODE_SHIFT: caps = !caps; keyboard.setShifted(caps); kv.invalidateAllKeys(); break; case Keyboard.KEYCODE_DONE: ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); break; default: char code = (char) primaryCode; if (caps && Character.isLetter(code)) { code = Character.toUpperCase(code); } ic.commitText(String.valueOf(code), 1); break; } } @Override public void onText(CharSequence text) { } @Override public void swipeLeft() { } @Override public void swipeRight() { } @Override public void swipeDown() { } @Override public void swipeUp() { } } |