hoboNicolaライブラリ1.5版とxd87対応

Pro Micro + miniUHS
Pro Micro + miniUHSの2階建て版と日本語キーボード

概要

hoboNicolaライブラリの新しいバージョン(1.5版)について。

  • usbアダプタ、PS/2アダプタ、改造したASkeyboardに加えて、xd87 PCBを使った自作キーボードに対応。
  • 2018年に公開したhoboNicolaライブラリ(1.2版)から、構成ファイルの名前やクラス名などを変更。
  • 新しい機能をいくつか追加。
  • あいかわらずArduino IDE(1.8.15版)でビルドする。

hoboNicola1.5版 ( hoboNicola150.zip) のダウンロードはこちらからできます。

ディレクトリ構成

hoboNicola150.zip  の中身は以下のようなディレクトリ構成になっている。

zipファイルを展開して都合のよいフォルダに置いてもいいし、Arduino IDEの スケッチ/ライブラリをインクルード/.ZIP形式のライブラリをインストール…  でhoboNicola150.zip を選択し、Arduinoライブラリとして組み込むこともできる。各ディレクトリに含まれているファイルについは後述する。

新しい機能

今回の実装では以下のような機能を追加した。

  • 兼用Fnキー
  • メディア制御
  • システム制御
  • シングル親指キーモード
  • US レイアウト対応
  • いくつかのキーのコード変更に対応(暫定)
  • アダプタ/キーボードの設定の変更や追加
  • XD87キーボードへの対応

兼用Fnキー

Fnキーとはキーボードの機能を拡張するために用いる、キーボードの中だけで有効な一種の修飾キーで、よくある機能拡張としては以下のようなものがある。

  • メディア再生のプレイ/ストップ、音量の上下、ミュートなどのHIDコンシューマーデバイス制御機能。
  • PCのスリープやシャットダウンなどのHIDシステム制御機能。
  • キーボードロック、LEDの光量調整、物理的に存在しないキー(F13~F20など) の入力、ブートローダーモードの開始といったキーボードの独自機能。

今回のバージョンでは、Fnキーを追加できるようにすると共に、Fnキーを押しながらキーを操作することで実現する機能をいくつか取り入れた。

ただ、アダプタに接続する日本語キーボードにはFnキーは存在しない(存在したとしてもコードは上がってこない)ので、既存のキーを兼用Fnキーとして利用できるようにした。そして、既存キーの機能をなるべく損なわないようにした。

今回の実装ではAppキーを兼用Fnキーとしている。タイムアウト時間 (約200msec) 以内にAppキーのストローク (押して離す) が完了すればオリジナルのAppキーとして機能し、タイムアウト後も押されていればFnキーになる。

兼用Fnキーのタイミング

Fnキーがオンになってタイムアウト時間以内にオフになったことを検出すれば、その時点でFnキー本来のコード(図ではApp)のオンとオフを送信する。タイムアウトした場合には、本来のキーコードの出力は行わない。

兼用Fnキーに割り当てるキーは、各実装のinoファイルで上書きできるので変更は簡単。ただ、Appキーはあまり使わないキーなのでまず弊害はないと思うのだけど、IMEを操作するキーや修飾キーなど素早い反応が求められるキーをFnキーに設定した場合、そのキーを離すまで本来の効果が得られないので、ちょっと違和感があるかもしれない。

兼用Fnキーがオンのときに使うキーの定義と機能は、各アダプタやキーボードごとのメインスケッチ(.inoファイル)に書いてあるので、都合のいいような直して使うことができる。

メディア制御

兼用Fnキーを押しながら別のキーを押すと、以下のコンシューマーデバイスのメディア制御用コードを通知できるようにした。これらは、HID Usage Table に定義されているConsumer Page (0x0c)の一部。

index Usage ID Usage Name 備考
1 0xCD Play/Pause 再生/ポーズ
2 0xCE Play/Skip
3 0xB3 Fast Forward 早送り
4 0xB4 Rewind 巻戻し
5 0xB5 Scan Next 次へ
6 0xB6 Scan Previous 前へ
7 0xB7 Stop 再生停止
8 0xE9 Volume Increment 音量アップ
9 0xEA Volume Decrement 音量ダウン
10 0xE2 Mute ミュート

音量変更やミュートについてはデスクトップグローバルに作用するが、次へ、前へ、早送り、巻き戻しなどは実行中のアプリケーション次第のようだった。Play/Pauseはだいたい有効。
一応、Windows10に付属の動画やGrooveアプリケーション、Windows Media Player、Google  Chrome上のYoutubeやamzon music などで使えることを確認した。

メディア・コントロール

Youtube の動画を見ながら音量調整をしてみると、こんな具合に表示された。

システム制御

Generic Destop Page (0x01)のシステムコントロールに含まれている機能のうち、以下の3項目を利用可能とした。

index Usage ID Usage Name 備考
1 0x81 System PowerDown シャットダウン
2 0x82 System Sleep スリープ
3 0x83 System Wakeup

このうち有効なのは、シャットダウンとスリープで、Wakeupはスリープからの復帰用と思うが、うちの環境ではどのキーを押しても復帰するので、確認できていない。

レポートデスクリプタの拡張

メディア制御およびシステム制御機能を組み込むため、従来のバージョンではキーボード用のみだったレポートデスクリプタを追加した。詳しくは hobo_nicola.cppの最後の方を見てください。

シングル親指キーモード

空白キーの大きなキーボードやUSレイアウトのキーボードをほぼNICOLA化する場合、空白キー以外のもう一つの親指キーをどうするか、あるいは、親指キー一つでどうやるかが30年ほど前からの課題と思う。

シングル親指キー(JP)

図は日本語レイアウトのキーボードをNICOLA配列にしたときの主要な図形文字部分を示しており、各キーの上側(同時打鍵時)を上段文字、下側(単独打鍵時)を下段文字と称している。上段文字の選択は親指キーとの同時打鍵で行う。

NICOLA配列ではもともと上段側に濁音になりうる文字がないので、濁音を入力する際には下段側の清音を打った後でどこかのキー (たとえば@とか) に割り当てた濁点を打つなどの方法が昔からあった。

今回は、濁音にしたい下段文字を長押しするようにしてみた。たとえば「は」を押すと画面には「は」が表示されるが、そのまま数十msec押したままにすると「ば」にすり替わるようにした。

具体的には「は」を出力した後で長押し判定タイミングまでに「は」のキーがオフにならなければ、Backspaceキーのコードを出力し、改めて「ば」を出力する。

欠点としては、文章を入力するとき、濁音に差し掛かるとちょっと入力のリズムが失われる。ただ、濁点を入力するための指の動きがないため、打鍵のポジションを堅持することはできる。

この方式は即時出力モード(零遅延モード)と同じ方法で出力文字のすり替えを行っているが、SNSのページのようにJavaScriptで制御されているHTML Formで使おうとすると、最初の文字が消えてしまうなどの副作用がでる可能性がある。

この動作モードの有効/無効は設定の4で切り替えるようにした。あくまでも親指キーが一つしか使えない場合の逃げ道です。

USレイアウトへの対応

今回の実装ではUSレイアウトに対応した(設定のU)。シングル親指キーモードはUSレイアウト時にもっぱら使うことになる。

hoboNicolaから文字を送り出すときには、その文字があたかもキーボードから入力されたかのように、HID Usage IDで表現する必要がある。たとえば、@ (ASCIIコードの0x40) という記号を出力するとき、日本語レイアウトならば0x2F を送るが、USレイアウトならば、Shiftキーオンの状態で0x1Fを送る必要がある。この0x1Fとは 2 キーのHID Usage IDである。

hoboNicolaをUS レイアウト設定にしたとき、 Windows10のUS レイアウトにしたがったコードを送信するようにした。具体的には変換テーブルをもつ char_to_hid.cpp  を参照のこと。

Windows10のキーボードレイアウトの変更について

Windows10でキーボードレイアウトの変更は、設定 >> 地域と言語 >> 言語 >>  (優先する言語の)日本語 をクリック >> オプション  をクリック >> (言語のオプション)のハードウェア キーボードレイアウトにある  レイアウトを変更する をクリックしてたどり着く、以下のような画面で行う。

キーボードレイアウトの変更

以前は違ったような気もするが、現行のWindows10 (21H1 19043.1110) ではこうなっていた。もっとも、レイアウト変更の面倒なところはいちいち再起動させられることである。

Windows10をUSレイアウトに設定すると、DOS/V日本語キーボードに追加された、無変換、変換、ひらがな、およびいくつかの記号キーは存在しないことになる。ふだん無変換キーやひらがなキーにお世話になっている身としては、IME操作がとても厄介になってしまう。

hoboNicolaアダプタの利点として、ふつうのキーボードにはないF13~F24のコードを無変換、変換、ひらがなといった日本語キーボード用のキーで発生させることができる(プログラムあるいはテーブルの変更が必要)。これに合わせてIMEを適宜カスタマイズしたりすると、USレイアウトでも不自由がなくなる。ただ、従来のMS-IMEのカスタマイズ機能は互換性のために残された「以前のバージョンの…」ということになっていて、先行きどうなるか分からない。

いくつかのキーコードの変更や入れ替え

右Altキーをひらがなキーに

私がアダプタを介して使っているUSBキーボードは、ひらがなキーと隣接するAltキーがともに小さくてよく押し間違ってしまって腹立たしいから、右Altキーをひらがなキーにしてしまえるようにした (設定A) 。

ひらがなキーAltキー

Caps(英数)キーとCtrlキーの入れ替え

よくあるキーの入れ替え機能として、Capsと左Ctrlキーの入れ替えができるようにした(設定C)

今回のバージョンから、修飾キーの処理方法を変更したので、こういった入れ替えは容易になった。実際の処理は、hoboNicola.cppのkey_event() メソッドに書いてあります。

設定の変更や追加

今回の実装ではCtrl + Fn + S  で設定モードに入るようになっている(inoファイルで変更可能)。従来の(NICOLAモードで) 親指キー + Pause の同時打鍵も有効です。

EEPROMに記憶する設定内容も以下のようにちょっと増えた。

有効になっている項目の先頭に * を表示。初期値は上記のように設定3と設定6以外は無効になっている。最後の32ビットが2つのHEX表示は、EEPROM内の設定値である。

設定番号/記号 内容 備考
1 空白キーを左親指キーとする。
2 空白キーを右親指キーとする。
3 空白キーは親指キーにしない。 無変換が左親指、変換が右親指。
4 シングル親指キーモード有効。 空白キーは右親指キーとなる。
5 NICOLAモードでのリピート許可。
6 Scroll Lock LEDとNICOLAモードを同期させるかどうか。 初期値は同期する。
7 英数(Caps)キーでNICOLAモードをオフにする。
8 ひらがなキーでNICOLAモードをオンにする。
9 半角/全角キーでNICOLAモードのオン/オフをトグルする。
0 半角/全角キーを押すとNICOLAモードをオフにする。
文字即時出力動作を有効にする。 零遅延モード。
A 右Altキーをひらがなキーにする。
C Capsキーと左Ctrlキーを入れ替える。
U US レイアウト対応とする。

Scroll Lock LEDとNICOLAモードの同期について

hoboNicolaでは、PC本体で動かす observe_imeというプログラムがアクティブなウィンドウのIME状態を検出し、「かな・カナ」入力時にはScroll Lock をかけることで、アダプタに動作モードを通知することを前提としている。通知がない場合でも、最悪ScrLockキーを叩くことでNICOLAモードをオン/オフすることもできた。

今回も従来の動作は踏襲しているが、ScrLock LEDに依存しないようにできないものかと考え、まずはLEDとNICOLAモードを同期させないようにする設定6を用意した。そして設定7~設定0 のように、特定のキーによってNICOLAモードのオン/オフを切り替えることができるようにしてみた。

これらのキー操作を有効に利用するためには、IMEの文字種切り換え操作を上記の各キーによって行えるようカスタマイズしておく必要がある。たとえば、ひらがなキーを押したときには常にIMEがオンになってひらがな入力状態になる、とか、英数キーを押したときには常に(トグルではなく) IMEがオフになるとかである。

この話は想定するキー操作と入力状態の遷移にあわせたIMEのカスタマイズが必要になってややこしいので、詳しくはそのうち。

EEPROMへの設定の記憶

設定した内容は、ArduinoのEEPROMライブラリを使ってEEPROMに記憶する (アドレス0からの16バイトを使用)。

ライブラリが使っている基本的な項目はアドレス0からの4バイトに、各実装(アダプタやキーボード)固有の項目はアドレス8からの4バイトに記憶するようにした。おのおの引き続く4バイトに設定データの反転値を保持するようにしており、読み出し時に2つの値をテストし食い違いがあれば値0を採用する。

ATmega32u4のEEPROMの寿命は書き換え10万回ということなのでおよそ困らないはずだが、何度やっても設定がちゃんと記憶されてないなんてことになったら、settings.h 内の EEPROMアドレスを変更して対処することになるだろう。

xd87対応

XD87 PCBキットを使ったほぼNICOLAキーボードのファームウェアとしてhoboNicolaライブラリを使えるようにした。実際のところ、キーボードの組立てと同時に使えるようになっていたが、ちょっと面倒になって公開が先延ばしになってました。

xd87 hoboNicola keyboard.

2021年8月現在は写真のようなピンク系のUS用キーキャップを付けているが、ふだんは日本語キーボードレイアウトで日本語キーボードとして利用している。

hoboNicola150.zipに含まれる実装では、以下のようなレイアウトになっている。

xd87 hoboNicola 200. スイッチ番号とキー割り当て

各キーの上部の番号は、XD87 PCBのキースイッチ番号(独自採番)で、詳しくは以前の投稿に書いスイッチマトリックス図などを参照のこと。

左右の親指キーは無変換と空白とし、変換キーは存在しない。ISO型のEnterキーはスタビライザーの取付けの都合で諦めた。Enterキーの下の大きい方をアンダーバーとし、個人的にあまり利用しない右Shiftキーは1Uキーとした。ふつうの日本語キーボードとの大きな相違は、左右のブラケット [ ]   がEnterキーの上で並んでいることくらいか。

DFUブートローダー

XD87版はテスト用のプログラムを作っている時点から、ATmega32u4にもともと書き込まれているDFUブートローダーを利用している。今回の実装では、L-Ctrl + R-Ctrl + Fn + B のコンビネーションによってDFUブートローダーを起動するようにした。ブートローダーモードを開始すると、ポートが初期化される関係でCaps LEDが点灯する。フラッシュメモリへの書き込みには、ATmel Flipを用いている。

xd87用のプログラムについて

xd87用のプログラムは、examples/xd87 に格納してあり、Arduino IDEでxd87.ino を開いてビルドしする。

xd87.ino

メインスケッチでは、各アダプタ用と同様にハードウェアを初期化したあと、新しく押されたキーを検出してライブラリに渡す処理を繰り返す。そのほかにxd87独自の機能としては以下のようなことをやっている。

  • RGB LEDの光量の変更とEEPROMへの保存や読み出し。
  • 兼用Fnキーと共に押すキーと機能の定義
  • ライブラリから指示されるLED (CapsLock, ScrLock)の点灯/消灯
xd87.cpp / xd87.h

XD87 PCBに載っているATmega32u4用の初期化や、スイッチマトリックスのスキャン、スキャン結果のFIFOバッファへの格納などを行う。具体的には組み立て時にいろいろやってブログに書いた内容と同様。

WS2812.cpp/WS2812.h, light_ws2812.cpp, cRGB.h

これらのファイルは light_ws2812 V2.4 のArduino版で、WS2812.h に void setOutput2(….) というメソッドを追加してある。今回の実装はArduino環境ではあるものの、直接ポートやレジスタを指定する必要があったためにメソッドを追加した。その他のファイルはオリジナルと同様。

ライブラリファイル(src内)について

hobo_nicola.cpp / hobo_nicola.h

hoboNicolaクラスの定義と実装の一部でライブラリの主要部。HIDレポートディスクリプタの設定、キーボードレポートの送信、(アダプタやマトリックススキャナからの) キー入力イベントの処理、Fnキー周りの処理などを行う。

1.5版からは修飾キーの扱い方を変更し、このモジュール内でレポート用のビットマップを生成するようにした。

nicola_state.cpp

hoboNicolaクラスの実装の一部で、親指同時打鍵ステートマシンや、入力キーのコード変換テーブル、処理後の出力文字列のテーブルなどの実装を含む。ほぼNICOLA配列の変更を行う際にはこのファイルを触ることになる。

1.5版から、空白キーのみを親指キーとして用いるシングル親指キーモードというのを追加し、ステートマシンの実装を少し変更した。

output_string.h

nicola_state.cpp 内の出力文字列テーブルには、出力用のローマ字文字列のPGMアドレスを並べるが、ローマ字文字列の定義はこのファイル内にある。

以前のバージョンでは配列の位置に基づく名前付けをしていたが、今回は並べ替えがしやすいよう数字や「音」に基づく名前付けに変更。

nicola_settings.cpp

やはりhoboNicolaクラスの実装の一部で、設定内容の表示出力や設定操作の実装を含む。

settings.h

EEPROMに保存する設定内容の定義やメソッドの定義と実装。

hid_keycode.h

キーボード用のHID Usage ID (キーコードや修飾キーのビットマスク)などに名前をつけた定義集。

char_to_hid.cpp / char_to_hid.h

プログラム内のASCIIコードの文字列を、キーボードからあがるHID Usage ID表現に変換するためのテーブルと、それを利用するための関数。

USBCore.cpp / USBCore.h

Arduinoのcoreライブラリに含まれているファイルを若干修正して取り入れた。USBCore.cppに対して以下を修正した。USBCore.h はオリジナルのまま。

  • USB_CONFIG_POWER を再定義し値を100とした。また、D_CONFIGも再定義した。アダプタとキーボードをあわせた消費電流がおよそ100mA程度に収まるようなので。
  • USBCore.cppは、Pro MicroやLeonardoの送受信LEDを操作するコードを含んでいるが、XD87ではこれらのLEDと同じポートをマトリックススキャンに用いている。そのため、送受信LED用ポートへの操作が行われないよう、TXLED, RXLED関連のマクロを再定義した。結果として、アダプタ版をビルドしたとき、LEDが忙しくまたたくこともなくなった。
HID.cpp / HID.h

ArduinoのAVR用ライブラリに含まれているファイルを若干修正して取り入れている。

  • メディア制御およびシステム制御用のレポートディスクリプタを追加しキーボード以外のレポートも送信するようにしたので、HID.h内に以下の定義を追加した。

  • 従来と同様で、ホストからのLED点灯指示がhoboNicolaライブラリに伝わるよう、通知用の関数ポインタをプログラムから設定できるようにし、点灯指示があれば通知を行うようにした。

関係する投稿など

きょうのまとめ

hoboNicolaアダプタの部品実装済基板を作られた方がいらっしゃって、PS/2版とUSB版(3.3V/8MHz版と5V/16MHz版)を譲っていただいた。完成度が高くてとても快適です。そのうち写真も追加します。

XD87キーボード版のhoboNicolaを先に作っていて自分ではこの1年以上それを使っていたのだけど、基板になったUSB版やPS/2版に触発され、各実装で使えるライブラリに仕上げた。

何か大事なことをかき忘れているような気がするので、気がついたら補筆していきます。