Keyboard Input Hackathon 2023 で Mozc の実験的機能を作りました
Keyboard Input Hackathon 2023 というハッカソンイベントが 2023-04-22 から 2 日間、秋葉原で開催されました。参加者のひとりとして応募をし、Mozc に実験的な機能を作成しましたので、開発内容を紹介します。
開発内容
- IME の UI を一時的に隠す機能
 - 通常キーを IME の機能に割り当てる機能
 - 親指シフト入力(NICOLA 配列)を実現するカスタマイズ設定
 
スライド資料
IME の UI を一時的に隠す機能
この機能を使うと、IME の入力中の文字列や変換候補ウインドウを一時的に隠すことができます。入力中の変換文字列を確定すると機能は解除されて、ふたたび UI が表示されるようになります。たとえば、特殊な自作キーボードでまとまったキーイベントを IME に送信して、IME の変換結果を入力として扱う場合に便利です。(例:漢字や絵文字を入力できるキーボード)
Mozc には U+ に続けて Unicode のコードポイントを入力することで、任意の文字を変換して入力する機能があります。(例: U+9C39 → 鰹) これを利用して、下記のようにキーイベントを自作キーボードから送信することで、キーボードからは直接入力することができない文字でも入力ができます。
| キーイベント | 説明 | 
|---|---|
| IME_ON | かなキー | 
| U+9C39 | 鰹のキーコード (6文字) | 
| 変換 | スペースキー | 
| 確定 | エンターキー | 
| IME_OFF | 英数キー | 
しかし、この場合では IME の UI が入力途中でも表示されるため、入力画面に UI がちらつくことになります。

入力途中でこのような IME の UI が表示されてしまう
ハッカソンでは「IME の UI を一時的に隠す機能」を作成し、自作キーボードから任意の文字が直接入力されているように表現できるようにしてみました。
たとえば、この機能を F17 に割り当てた場合、送信するキーコード列は以下のようになります。

IME 表示オフ機能を F17 に割り当てる(コードの変更をした実験的な機能です)
| キーイベント | 説明 | 
|---|---|
| IME_ON | かなキー | 
| IME 表示オフ | F17 キー | 
| U+9C39 | 鰹のキーコード (6文字) | 
| 変換 | スペースキー | 
| 確定 | エンターキー | 
| IME_OFF | 英数キー | 
これで、自作キーボードのキーを押すと任意の文字が直接入力されたかのような動作することができるようになりました。
Mozc は変換エンジンと UI クライアントは Protocol Buffers で定義されたプロトコルを通じてやりとりしています。変換エンジンから UI クライアントへ送信するプロトコル上のデータを一部削除することで、機能を実現しています。
実際のコミット
ハッカソンイベントでの変更なので、テストや例外処理などは省略しています。
通常キーを IME の機能に割り当てる機能
IME やキー配列をカスタマイズしていくと、通常の文字キー(A や % など)に IME の機能を割り当てると便利になることもあります。たとえば、L キーで英数入力モードに遷移する IME や、Y キーを BS のかわりに使うかなキー配列があります。
ハッカソンでは Mozc の GUI ツールを拡張して、通常の文字キーも機能に割り当てられるように変更しました。

文字キーに機能を割り当てる(コードの変更をした実験的な機能です)
実際のコミット
実は Mozc は現時点でも通常の文字キーを機能に割り当てることは可能です。
動作の保証はありませんが、設定ファイルを手で書けばこの機能を使うことはできます。
親指シフト入力 (NICOLA 配列) のカスタマイズ設定
Mozc のローマ字入力カスタマイズ機能を活用することで、親指シフト入力(NICOLA 配列)ができるようするデモをハッカソンで実装しました。
親指シフト入力の特徴のひとつは、2 つのキーを同時に押す同時打鍵入力です。この同時打鍵入力はすでに実現されていて、Akira.K さんが新下駄配列などを実現するためのサービスを提供してくださっています。
これらの同時打鍵入力方式にくわえて、親指シフト入力では「変換キー」「無変換キー」との同時打鍵が必要です。これまでは、文字キー同士の同時打鍵のみに対応しており、「変換キー」「無変換キー」などの機能キーへは未対応でした。
そこで、ハッカソンでは機能キーとの同時打鍵が可能になるように GUI を拡張しました。

F18, F19 を文字入力キーに割り当てる(コードの変更をした実験的な機能です)
また同時打鍵の判定をするためのタイムアウト時間を設定できるようにした GUI の拡張もハッカソンで行いました。

Timeout 時間の設定(コードの変更をした実験的な機能です)
そして親指シフト(NICOLA 配列)用にローマ字テーブルをカスタマイズして完成です。

親指シフト(NICOLA 配列)用のルールテーブル
実際のコミット
現時点での Mozc でも、通常の機能キーを文字の入力に割り当てやタイムアウトの機能は存在しています。動作の保証はありませんが、設定ファイルを手で書けば、この機能を使うことができます。
親指シフト入力 (NICOLA 配列) の仕組み
さて、親指シフト入力に必要な同時打鍵入力を Mozc でどのように実現しているかをもう少し詳しく説明します。大きく 4 つに分けて順番に説明していきます。
- 一般的なローマ字入力のカスタマイズの仕組み
 - 同時打鍵入力を実現するための仕組み
 - 機能キーを文字入力で使うための仕組み
 - 親指シフトのためのローマ字変換テーブルの作成
 
1. Mozc の一般的なローマ字入力のカスタマイズの仕組み
同時打鍵入力は、Mozc のローマ字変換テーブルをカスタマイズすることで実現しています。同時打鍵入力の方法を説明する前に、Mozc でのローマ字変換テーブルのカスタマイズ方法を説明します。
基本的な入力と出力
「a → あ」や「ka → か」のような基本的な変換方法は、それぞれを入力と出力に指定して設定します。一般的なローマ字のカスタマイズ方法です。
| 入力 | 出力 | 
|---|---|
| a | あ | 
| ka | か | 
状態遷移を実現する「次の入力」
しかしローマ字の中でも「tta → った」の表現は少し複雑です。それぞれを「入力」と「出力」に書くことでも実現できますが、いくつか課題が残ります。
- 「
ttta→ っった」「tttta→ っっった」をさらに別のルールにする必要がある - 「
tta→ った」のルールのもと、ttと入力しても「っ」がまだ表示されない(ttaまで全部入力しないと「った」が全部表示されない) 
これらの課題を解決するために、「次の入力」という項目が用意されています。「次の入力」を活用すると「tta → った」は次のようになります。
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| tt | っ | t | 
| ta | た | 
「tt, っ, t」 という組み合わせは、『tt が入力された場合、「っ」に変換したうえで、t を入力した文字として扱う』という意味になります。
tta の入力を順番に見ていきます。
| 入力 | 表示 | 説明 | 
|---|---|---|
| t | t | 
t 単体の変換ルールはないので、t が入力文字として残る | 
| t | っt | 
tt のルールに従って、「っ」が出力され、次の入力としての t が入力文字として残る | 
| a | った | 
ta のルールに従って、「た」が出力される | 
動作をわかりやすくするために、「入力」と「次の入力」の文字を別にします。
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| xx | っ | t | 
| ta | た | 
この場合での xxa の入力を順番に見ていきます。
| 入力 | 表示 | 説明 | 
|---|---|---|
| x | x | 
x 単体の変換ルールはないので、x が入力文字として残る | 
| x | っt | 
xx のルールに従って、「っ」が出力され、次の入力としての t が入力文字として残る | 
| a | った | 
ta のルールに従って、「た」が出力される | 
2 文字目の x を入力したあとに表示される文字が t であることに注目してください。
かな入力の濁音処理としての「次の入力」
かな入力では「t → か」「@ → ゛」という変換ですので、「t@ → が」というルールが成り立ちます。
| 入力 | 出力 | 
|---|---|
| t | か | 
| t@ | が | 
| @ | ゛ | 
| 3 | あ | 
素直に書くとこの通りなのですが、Mozc の場合 t を入力しても「か」が出力文字として表示されません。これは t か t@ が曖昧な状態なので、入力文字の t がそのまま表示されるからです。続けて 3 を入力すれば t3 となり、 t の曖昧な状態が解消され「かあ」が出力されます。
さて、「次の入力」を応用して次のことを実現します。
- 
tを単体で入力した場合には「か」を表示する - その後 
@を入力した場合には「が」を表示する 
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| t | か | |
| か@ | が | |
| @ | ゛ | |
| 3 | あ | 
変換テーブルが次のように変わりました
- 
tの入力に対して、かを次の入力とする - 
か@の入力に対して、「が」を出力とする 
この変更によって、t を押すとそれは か を入力したことと同じ扱いになります。そのために か が入力された文字として画面に表示されるようになります。そして か@ というルールによって、続けて @ を入力すれば「が」が変換できるようになりました。
2. Mozc の同時打鍵入力を実現するための仕組み
同時打鍵を実現するためには、同時押しなのか、それぞれに押したのかを判断する仕組みが必要です。Mozc では時間の切れ目を表現する特殊なキーを使って実現しています。
タイムアウト特殊キー
Mozc では一定時間内に入力がないと、入力の切れ目を表すための特別なキーを挿入する機能があります。便宜上、この特別なキーをタイムアウト特殊キーと呼び、{!} で表現します。
たとえば、a 押してしばらくしたのちに b を押すと、b を押した時にあわせて {!} も入力されます。つまり、あわせて a{!}b という入力になります。
a と b を同時に押した場合には ab という入力になりますので、
- 
abなら同時打鍵 - 
a{!}bなら逐次打鍵 
という判断ができるようになります。(ba の場合も同様です)
このタイムアウトキーの機能は、デフォルトではオフになっており、GUI からの変更はできませんが、設定ファイルを直接変更することによりミリ秒単位での指定ができます。
同時打鍵の変換テーブル
このタイムアウトキーを組み合わせて、ローマ字変換テーブルを設定することで、Mozc で同時打鍵入力が動作することを実験しました。
たとえば、a と b の文字に対して以下のような同時打鍵を実現するとします。
| 打鍵 | 出力 | 
|---|---|
| a のみ | あ | 
| b のみ | い | 
| ab 同時 | う | 
この場合のローマ字変換テーブルは次のようになります。 {!} がタイムアウトキーを表します。
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| a | あ | |
| あ{!} | あ | |
| あb | う | |
| b | い | |
| い{i} | い | |
| いa | う | 
いくつか例をあげて、このテーブルの動作を説明します。
a のみを入力
- 
aの次の入力として定義されているあが入力文字として使用される - 画面上の表示: 「あ」
 
ab の順で同時押し
- 
aに対してあが入力文字として扱われ、次のbと合わせてあbのルールが適用される - 画面上の表示: 「あ」が瞬間的に表示されたあと「う」が表示される
 
ba の順で同時押し
- 
bに対していが入力文字として扱われ、次のaと合わせていaのルールが適用される - 画面上の表示: 「い」が瞬間的に表示されたあと「う」が表示される
 
a を入力後、しばらくして b を入力
- まずは、
aの次の入力として定義されているあが入力文字として使用される - その後 
bを押した時に、タイムアウト特殊キー{!}が先に入力として扱われる - そのため 
あ{!}のルールがまず適用され、 その後bのルールが適用される - 画面上の表示: 
aの入力で「あ」が表示され、bの入力で「あい」となる 
3. 機能キーを文字入力で使うための仕組み
親指シフトを実現するためには、さらに「親指シフトキー」による入力をローマ字変換ルールで扱える必要があります。「親指シフトキー」は単体では文字を入力するキーではなく、「F1」や「BS」などと同様の機能キーです。また「親指シフトキー」のないキーボードでは、かわりに「変換キー」「無変換キー」の機能キーが使われています。
これらの機能キーは Mozc のローマ字変換テーブルではデフォルトでは扱えないようにしていますが、設定ファイルを直接手で書き換えれば、機能キーを文字入力として割り当てることは可能です。
文字キーとして扱いたい機能キーの、Precomposition (入力前状態)と Composition(入力中状態)の機能を InsertCharacter に割り当てると、機能キーを表す特殊キーが入力できるようになります。たとえば、F1 キーなら {f1} が、変換キーなら {henkan} で表現される特殊キーが入力されます。特殊キーは 1 文字として扱われます。
文字入力キーとして割り当てた特殊キーは、ローマ字入力テーブルでのカスタマイズも必要です。そのままでは無効な入力として無視されてしまいます。
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| {f1} | あ | 
上記の定義の場合、F1 キーを押すと「あ」が入力されるようになります。ただし、環境によっては F1 キーが Mozc に送られてこない場合があります。その場合は OS などの設定を変更するか、別のキーを使用してください。
4. Mozc の親指シフトのためのローマ字変換テーブルの作成
材料がそろいましたので、親指シフト用ローマ字テーブルを作成します。
親指シフトでは y キーに対しては次の動作をします。
| 打鍵 | 出力 | 
|---|---|
| y 単打 | ら | 
| 左親指シフトと y の同時打鍵 | ぱ | 
| 右親指シフトと y の同時打鍵 | よ | 
便宜的に「左親指シフト」を {L}、「右親指シフト」を {R} という特殊キーにすると、ローマ字変換テーブルは次のようになります。 {!} はタイムアウト特殊キーです。
| 入力 | 出力 | 次の入力 | 
|---|---|---|
| y | ら | |
| ら{!} | ら | |
| ら{L} | ぱ | |
| {L}y | ぱ | |
| ら{R} | よ | |
| {R}y | よ | |
| {!} | ||
| {L}{!} | ||
| {R}{!} | 
最初の 6 行が y に対する設定で、最後の 3 行は y だけではなく全体に対してのタイムアウト特殊キーに関連する設定です。
テーブルの全体像は GitHub のコミットから確認できます。このコミットでは、左親指シフトキーに F18 を、右親指シフトキーに F19 を使用しています。
使用感
実際に親指シフトで入力されている方に試していただいたところ『荒削りだが親指シフトで入力できている。同時判定の時間を調整するともっとよくなりそう』というコメントをいただきました。
まとめ
Keyboard Input Hackathon というよい機会に恵まれましたので、Mozc を少しいじるとこういうこともできるようになります、という実験的な機能をいくつか作ってみました。
参加者の方々と意見交換や新しいことを教えてもらうことができまして、大変刺激的で有意義な 2 日間でした。参加者、運営、協賛のみなさま、どうもありがとうございました。
参照
Discussion