KeyHoleTV開発者のブログ

日々の質問や開発の日記

Android Native Activityによるキーボード処理 (その1)

Native Activityでのソフトウェアキーボードの利用の困難さ

Native Activity のOpenGL ESを使ったアプリケーションは、Androidが提供する様々な機能が利用できない。最も大きいのは、ソフトウェアキーボードだろう。 Androidアプリケーションで、名前の入力やURLの入力には、ソフトウェアキーボードが表示され、そこで、入力した文字や記号が入力領域(EditText)に反映される。 日本語対応のソフトウェアキーボードでは、連文節かな漢字変換をおこなったり、予測変換の文字列が表示されたりする。 候補をタップすることで、候補の文字列が入力領域にはいる。

ソフトウェアキーボードをNative Activity のOpenGL ES環境下で、表示するには、

groups.google.com

に示されているが、NDKでイベントを扱うには、結局

codeday.me

の回答にあるように、

static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
{

    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
    {
          lint32_t key_val = AKeyEvent_getKeyCode(event);
          fprintf("Received key event: %d\n", key_val);

          if*1
          {
                 fprintf("Got a letter");
           }

   }
   return 0;

}

となる。 

AKeyEvent_getKeyCode(event); で、全てのコードが取得できればよいが、取得できるコードは、

developer.android.com

で定義されているコードだけになるようだ。 例えば、!マークや%記号のコードは、定義されていない。これらの記号は、お使いのキーボードをご覧になれば、一目瞭然で、シフトキーを押したときのコードになる。 更に、かなや漢字などの文字列が、上記の入力処理のeventに送られてくるはずがない。

AndroidのJAVAの入力領域(EditText)とキーボードは、別のアプリケーションになっている。 しかし、その間を取り持つインターフェースは、inputconnection となっていて、両者が密接に関係している。 下記のサイトは、独自のキーボードの実装をコードベースで説明している。

qiita.com

上記のNewKeyboard.java中の、commitText("1", 1); で、文字列を入力領域に送っている。 この入力をNative Activity のOpenGL・ESのアプリで取得するためには、JNIを使って取得する必要がありそうだ。さて、JAVAのアプリでは,どのような記述でキーボードを表示しているか見てみる。

akira-watson.com

上記のサイトによると、JAVAのコードでは、

public class MainActivity extends AppCompatActivity {

   private EditText editText;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
     ...
     editText = findViewById(R.id.edit_text);

    ...

となっていている。 ソフトウェアキーボードは、アクティビティの起動時に既に表示されている。で、自動的に入力領域(EditText)にソフトウェアキーボードで入力した文字や記号が反映される仕組みになっているようだ。 すなわちソフトウェアキーボードで入力した文字や記号は、

commitText("入力した文字や記号、文字列など", X); でどこかに送信され、アプリケーションがその情報を取得して、入力領域(EditText)に反映していることになる。 JAVAのアプリケーションプログラマは、commitTextで送信された情報を取得したり、入力領域(EditText)に表示する処理を記述する必要はない。 これらは、Android用JAVAの部品が行っている。 しかし、Native Activity のOpneGL・ESで構築されたアプリケーションでは、この一連の処理を自分で記述する必要がある。

Native Activity では、OpenGL の表示処理やイベントの入力のためのメインループがある。 このメインループは、何らかの処理を呼び出して、その処理が終了するまで、待機させることができない。 待機させると、画面の書き換えが起こらないため、フリーズしたようになる。 他のアプリケーションが、commitText を発行した時に、どのようなイベントが発生するのか、また、何かのコールバックが呼ばれるのか、ネットで検索しても記述を発見できなかった。 

単純に英数字だけの入力なら、ソフトウェアキーボードを利用することができると予想する。 しかし、かなや漢字がある場合、その利用が困難になる。 記号の場合も同様で、

Input  |  Android NDK  |  Android Developersに表現されてる場合、コードが求まるが、そうでない記号は、上述のcommitTextで記号が送られてくると予想される。

GUIライブラリでのソフトウェアキーボードの実装

Androidに付属しているソフトウェアキーボードは、Native Activity のOpenGL ES環境下のアプリケーションでは、表示ができても、記号などの入力を獲得することが難しい。 更に日本語などは、実装が更にハードルが上がり、殆ど不可能に近い。 そこで、GUIライブラリ(

Android, WindowsCE KeyHoleTV - KeyHoleTV開発者のブログ)の表示機能を使ったキーボードを実装した。 実装にあたり、次の要件を満たすようにした。

(1)英字キーボードの配列は、101と同じにする。

(2)記号と数値は、Shitを押して操作するのではなく、記号や数値ボタンをタップして、記号キーボードや数値キーボードを表示する。

(3)UTF-16LEの入力機構をもち、コードで文字の入力を可能にする。

(4)ひらがな2文字までの漢字辞書を持ち、候補を表示する。

(5)ひらがな3文字以上は、連文節かな漢字変換を用いる。 連文節かな漢字変換は、ネットワークを利用したエンジンを利用する。

(6)入力領域の移動(キーボードとか重ならないように)

 GUIライブラリで、実装したキーボードは、

f:id:KeyHoleTV:20190819142204j:plain

GUIライブラリのキーボード

となっている。 qが少し濃くなっているのは、WindowsCEやLinuxのナビゲーションボタンや帰ボードの矢印キーで、キーを移動させる現在選択されてるキーを示している。 また、「文字列を入れる」と表示されている入力領域は、キーボードの表示に伴い移動する。 仮名文字の入力のための「KANA」キー、全角入力のための「WIDE」キー、数値とUTF-16LEを入力する「123」キー、記号を入力する「#@」キーがある。 こらのキーをタップすることで、キーボードが変換する。 「KANA」キーをタップした時、

f:id:KeyHoleTV:20190819143454j:plain

日本語キーボード

上記のようなキーボードになる。 かなを連続タップすることで、「あ」→「い」→「う」→「え」→「お」と入力文字が変わる。 一定時間経過すると連続タップ期間が終了して、文字が固定される。 上記の例では、2文字入力されて、その候補が表示されている。 この候補はGUIライブラリに内臓されている辞書を使っている。

「ローマ字」ボタンをタップすると、

f:id:KeyHoleTV:20190820043208j:plain

ローマ字キーボード

となる。 3文字以上入力されているので、ネットのかな漢字変換のエンジンを利用した結果を表示している。

GUIライブラリは、ネット上にあるGoogleのかな漢字変換を利用している。 このかな漢字変換は、

www.google.co.jp


で、CGIに元の文字列を送って、リスト形式の結果をもらって、それらを表示している。 CGIで「へんかん」という文字列を送信するためには、TCP/IPを使って、http://www.google.comに接続し、
GET /transliterate?langpair=ja-Hira|ja&text==%E3%81%B8%E3%82%93%E3%81%8B%E3%82%93

HTTP/1.1

User-Agent: kanakanji [ja]

の文字列を送信すればよい。 すると、相手からから

HTTP/1.1 200 OK
Date: xx, day month year time GMT
Pragma: no-cache
Expires: xx, day month year time GMT
Cache-Control: no-cache, must-revalidate
Content-Type: text/javascript; charset=UTF-8
X-Content-Type-Options: nosniff
Content-Disposition: attachment; filename="f.txt"
Server: Google Input Server/1.0
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic,p=0.Transfer-Encoding: chunkedmak

4d
"へんかん",["変換","返還","偏官","へんかん","ヘンカン"]
0

が送られてくるので、["変換","返還","偏官","へんかん","ヘンカン"]の部分を取り出して、それぞれ”変換","返還","偏官","へんかん","ヘンカン"を表示する。 ただ、文節を移動する機構を作っていないので、連文節かな漢字変換は、厳密にはできない。 

英字キーボードの状態で、「WIDE」をタップすると、

f:id:KeyHoleTV:20190820101129j:plain

全角キーボード

となって、全角入力ができる。 キーボードに←と→がついて、全角を表している。 また、日本語入力キーボードやローマ字入力のキーボードの状態で、「123」や「#@」をタップすると、全角モードの数値や記号の入力になる。 「半角」をタップすると、全角入力が解除される。 

全角入力が解除された状態で、「123」キーをタップすると、

f:id:KeyHoleTV:20190822094247j:plain

             数値・UTF-16LEキーボード

となって、数値や数値に関係する記号が入力できる。 「TAP HERE」をタップすると、UTF-16LE入力モードになる。

f:id:KeyHoleTV:20190823055504p:plain

UTF-16LF キーボード

0ー9までの数値と、A-Fまでの記号で、16進数のUTF-16LEのコードを入力できる。 UTF-16LEのコード入力で、グリフが定義されていない場合、16進表記が入力領域に表示される。

f:id:KeyHoleTV:20181209010504p:plain

上記の例では、009Eと入力した結果が表示されている。

全角入力が解除された状態で、「#@」キーをタップすると、記号入力になり、

f:id:KeyHoleTV:20190825124846p:plain

記号のキーボード

となる。 三角をたっぷすると、別の記号が表示される。 

 

なお、KeyHoleTVのダウンロード・プレミアムモジュールキーのご購入は、

www.oiseyer.com

 まで。 また、GUIライブラリは、無償で提供していますので、メールにてお知らせください。

メールで ZIP か tar.gz でお送りします。

 

*1:key_val >= AKEYCODE_A && key_val <= AKEYCODE_Z