天高工房

キーキャップに印字して遊んだり電子工作して遊んだりしたことを書くかもしれません。

emojiキーボードを実現する

emojiキーボードを実現するために色々罠があったのでまとめます。

経緯

昇華印刷のネタとしてemojiがあったので「じゃあemojiを直接入力できるキーボードを作ろう!」と考えました。

動画では一見うまくいっているように見えます。Windows10向けではうまくいきました*1

ソフトウェアエンジニアにはMacLinuxが多いので、一応対応させてみるかーと確認をしてみると、unicode直接吐きだせるって話だったので楽勝だと思ってたら全然そんなことなかったのです。

QMKとunicode

公式ドキュメントのunicode関連は以下にまとめられています。

github.com

準備

rule.mk

末尾に以下を追加します。

UNICODEMAP_ENABLE = yes

keymap.c

process_unicode.h をインクルードさせます。

unicode_map 配列を定義して、キーコードとしてX(XXXX) を呼びます。XXXXはunicode_mapの呼び出したい記号のindexです。

emojiのunicode_mapを提供している人もいますが、hexのサイズが大きくなるので最小限だけにするのがよいかと思います。

また、今回は数が少ないので直接インデックスを指定していますが、enumでemoji名の定数を定義してindexとして割り当てるのがミスの原因にならなくてよいかもしれません。

最後にmatrix_init_user内でset_unicode_input_modeを呼びます。引数はOS別です(Windows, MaxOSX, Linux)。

サンプル

const uint32_t PROGMEM unicode_map[]=
{
    0x1f37a,//beer
    0x1f423,//hatching chick
    0x1f498,//heart with arrow
    0x1f607,//innocent
    0x1f647,//bow
    0x1f914,//thinking face
    0x1f644,//rolling eye
    0x1f363, //sushi
    0x1f4b8,//money with wings
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = 
    {
        {X(0),X(1),X(2),X(3)},
        {X(4),X(5),X(6),X(8)}
    }
};

void matrix_init_user(void) {
    set_unicode_input_mode(UC_WINC);

}

問題たち

OSごとに入力スタイルが違う

OSごとに受け取れる方法が違います。

set_unicode_input_modeは3種類のOSに分けられます。Windows, MacOSX, Linuxです。いずれかに設定するとほかのOSでは動作しません。

OSの中でも設定によって入力スタイルが違う

OSで用意されている機能があっても、実用に耐えないため代替策が用意されていることがあります。

例えばWindowsデフォルトはレジストリキーを書き換えた上でAltキーを押してから入力するスタイルです*2。現状、多くのWindowsアプリケーションではAltはメニュー展開キーのため、多くのアプリケーションでうまく動かすことが難しいです。そのため非推奨の方法となっています。

そのため代替策として、WinComposeという入力補助の外部ツールをインストールし、WinComposeの入力スタイルを送信するという方法が用意されており*3, 推奨方法とされています。

MacOSXではデフォルトでUnicodeを受ける手段が用意されているため一見簡単なように見えます。しかし、実際はIMEを日本語でも英語でもなくUnicodeに設定しなければならないため、IMEにこだわりがない、IMEが変わっても入力内容に変更がない人間にしか常用は難しいです。 また、受けられるのは0xffffまでなのでサロゲートペアとして送り付けるようになっています。そのため、一部非対応ソフトウェアでは正しく動作しません。

MacOSXの代替手段もAltキーを使うスタイルのため、利用に堪えないことが考えられます。

Linuxは確認していません。

これらの理由により、テキストエリアに直接emojiを入力する方法で常用に足るのはWindowsでWinComposeを併用するスタイルだけになってしまうでしょう。

QMKの機能としては用意されていませんが、OS側で特定の入力をUnicodeとして解釈するソフトウェアを用意し、そのソフトウェア向けのマクロを送り込むような記述をすることで入力は不可能ではないかと思います。

コロンスタイルの入力方式でも完璧じゃない

テキストエリアに直接emojiを入力する方法は全てのOSで共通にすることができないため、使いたいPCのOSが混在していると利用が難しいことがわかりました。

今現在、emojiを頻繁に使うアプリケーション上での入力スタイルは2種類あります。IMEが支援してくれるタイプとslackなどで採用されているemoji名をコロンで挟む方式*4です。

このうち、コロンスタイルはすべてアスキー文字で構成されていますので、どのOSでも確実に受け取ってくれます。

QMKにはキーをたたいた時に文字列を送信する機能*5がありますので、実現するのは難しくなさそうです。

しかし、実際には3種類の問題がありました。

キーボードスタイル

JISとANSIで同じキーコードで表示される文字が違う問題です。基本的にキーコードはANSIの位置で決まっています。

JISではコロンは単独キーで存在しますが、ANSIではセミコロンの裏です。その位置にはANSIではクォートがあります。そのためJISのコロンのキーコードはKC_QUATです。また、コロン単独としてKC_COLONというキーコードも用意されていますが、これはJISではプラスとして認識されます。

キーボードの種類は少なくともWindowsでは全体で一種類しか設定できませんでした。

これによって、普段使っているキーボードのスタイル(主に記号の組み合わせ)によって正しく入力できないケースが発生することがわかりました。

アプリケーションごとの名前の違い

私はよく🤔thinking_faceを使います。Slack, tweetdeck, emojipediaなどではthinking faceと表記されています。

しかし、discordではthinkingなのです。discordでは表情系からfaceが省略されているのです*6

どちらかしか使わないのであれば問題ないですが、どちらも使う場合は問題です。

:thinkingでとめてコロンで閉じないことで入力候補を絞り込む程度にとどめる運用で何とかしています。

非対応アプリケーションの場合

コロンスタイルでのemoji入力を受け付けていないアプリケーションでは当然ながらemojiに変換されず文字として入力されてしまいます。 emojiをいれるつもりが謎の文字列が連発されるので焦ります。

その他の問題

8キーしかないのでレイヤーを追加して入力できる文字を増やしたいです。しかし、8キーしかないからこそ単独のモディファイヤキーを入れたくありません。

QMKにはタップとホールドで挙動を変更することができる機能があります。例えばLT(layer, keycode)です。ホールドしている間は指定したレイヤー扱いになりますが、タップでは指定したキーコードの文字列が入力されます。

実はこのときに指定できるキーコードは0xffまでなのです。そのため、emojiは割り当てることができません。割り当ててみたら謎の文字列を吐き出すのみでした。

現在ほかの方法がないか模索中です。

先行事例・参考文献

github.com

github.com

mzp.hatenablog.com

qiita.com

qiita.com

Adding SUSHI key to my ErgoDox EZ - yhara.jp

おまけ

利用するunicodeが0xffff以下であれば、rule.mkUNICODE_ENABLE=yesを追加した上でキーコードとしてUC(0xXXXX)を当てることで使えます。

*1:WinComposeを追加導入・使用

*2:UC_WIN

*3:UC_WINC

*4::sushi:など

*5:SEND_STRING

*6:face_with_rolling_eyesなど