ほぼNICOLA化プログラム hoboNicolaのページ

概要

hoboNicolaは、USBキーボードやPS/2キーボード(JIS配列)とPCやスマホなどのデバイスの間に接続することで、ふつうのキーボードをあたかもNICOLAキーボード(親指シフトキーボード)のように入力できるようにするためのアダプタシステムです。

また、改造したキーボードの中に組み込み、キーボードのスキャンや同時打鍵処理、配列変換やUSBインタフェースのコントロールを行うことで、キーボード単独でほぼNICOLAなキーボードを実現できます。

USB hoboNicola
USB hoboNicola
ps/2 hoboNicola
ps/2 hoboNicola

NICOLAキーボードに必要な同時打鍵処理や文字図形配列の生成には、ATmega32u4を使ったArduinoまたはArduinoコンパチブルボード(SparkFun Pro Microまたはそのコピーボード)を用います。

USBキーボードを接続するためには、Pro Microにmini USB Host Shield を接続します。PS/2キーボードの場合は、mini DINコネクタを直接Pro Microに接続します。今のところ、両者を一度に接続するようにはなっておらず、使いたいキーボードのいずれかに合わせて構成する必要があります。

USB版

SparkFun Pro Micro相当品(+3.3V, 8MHz版)と若干の加工をほどこしたCircuits@Homeのmini USB Host Shield (miniUHS)相当品でのみ動作を確認しています。Pro Microについてはこちらの投稿を、miniUHSとその加工方法についてはこちらの投稿を参照のこと。

※ 追記 Circuit@Homeの回路図は残念ながらリンク切れになっています。商品については、amazonやaliexpressから入手可能です。

PS/2版

PS/2キーボード自体の電源や通信用の接続のためには+5V動作するマイコンが必要なので、SparkFun Pro Micro相当品(+5V, 16MHz版)を使っています。PS/2キーボードからのケーブルを接続するためのmini DIN 9ピンのソケット、ソケットとマイコンのI/O端子を直接接続する回路が必要になります。回路などの諸情報は、こちらの投稿を参照

ASkeyboard版

1988年製のASkeyboardという親指シフトキーボードの内部を改造し、USBの親指シフトキーボードとして使えるようにしました。キーボードの基板にPro Micro 5V,16MHz版を接続し、USB版やPS/2版と同じ同時打鍵ロジックを組み込んで実現しています。
USB版やPS/2版では、キーボードのスキャンやコード生成は既製のキーボードが行っているのに対し、ASkeyboard版ではその部分から実装してあるので、例えば自作のキーボードや他のキーボードを改造してhoboNicolaを利用する際の参考にできると思います。

XD87キーボード版

1.5版から、XD87 PCBを用いた自作キーボードに対応するプログラムも公開しました。XD87 PCBにの概要、回路、制御方法などについては、ブログの投稿を参照してください。


このページには以下を記載しています。

  • ビルドに必要な開発環境とライブラリ
  • hoboNicola一式のソフトウェアの概略説明
  • IME状態を通知するプログラムについて(Windows版)

hoboNicolaのダウンロードはこちらから。

開発環境、ライブラリ

hoboNicola一式は、Arduino IDEにインストール可能なライブラリ形式になっており、Arduino IDE 1.8.15版でビルドと確認を行っています。アダプタやキーボードなどの実装用のスケッチは、ライブラリのスケッチ例(examples)としてzipファイル内に格納しているので、そのままIDEに読み込んでビルドすることが可能です。

開発環境や必須ライブラリの導入方法については、別のページにまとめました。hoboNICOLAアダプタのプログラムのビルド方法 を参照してください。

Microsoft VisualStudio 2017 Community版

Windowsでの快適な入力のため、日本語入力IMEの状態をハードウェアに通知するためのソフトウェアを用意しました。そのビルドにはVS2017を使っています。

このページの最後のあたりで、操作用のアイコンをインジケータ領域に表示するようにしたプログラム(observe_ime)をダウンロードできるようにしました。仕組みについてはソース・ファイルを参照のこと。

hoboNicolaを構成するファイル

アダプタ用およびキーボード用のプログラムは、メインスケッチやハードウェア依存部分が異なるがその他は共通になっています。PS/2版ではUHSライブラリの代わりに、hoboNicolaライブラリ用に作成したps2_kbdクラスを使い、ASkeyboard版では、ASkeyboardクラスを使います。

hoboNicolaの構成

hoboNicola1.5版について

hoboNicola1.5版は、ファイル構成やクラス構成を変更しています。そのため、以下に記した1.2版までの内容とは若干異なっていますのでご注意ください。1.5版については、こちらの投稿を参照してくたさい。

USB版のメインスケッチ usb_hobo_nicola.ino

UHSライブラリのキーボード処理用インスタンス(HidKeyboard)とほぼNICOLA化の実装のNicolaKeyboardクラスのインスタンス(hobo_nicola)を保持し、これらの間の仲立ちを行います。

ほぼNICOLA化しようとするキーボードに対する押下やリリース操作は、HidKeyboardに渡したKeyboardEventクラスのメンバ関数(OnKeyDown() , OnKeyUp(), OnControlKeysChanged())に通知されてきます。スケッチ内では、これらのメンバ関数が受けた通知内容を、ほぼそのままhobo_nicolaに渡します。

hobo_nicola側でキーボードイベントの通知を受け取る key_press(), key_release()はNicolaKeyboardクラス内に、修飾キーの変化を受け取るmodifier_change() は基本クラスのBaseKeyboardクラス内に実装しています。

メインループ(loop())内で hobo_nicola.idle(); とすることで、hobo_nicola側に、いろいろな処理を実行するタイミングを与えています。

usb_hobo_nicola.inoは、ライブラリのexamples/usb_hobo_nicola ディレクトリに格納しています。

PS/2キーボード版のメインスケッチ ps2_hobo_nicola.ino

USB版とほぼ同様な構成になっており、PS/2キーボードとのインタフェースを行うps2_kbdクラスのインスタンス(ps2)と、NicolaKeyboardクラスのインスタンス(hobo_nicola)を保持し、これらの間の仲立ちを行っています。

キーボードでの押下/リリース操作は、ps2_event クラスのメンバ関数(key_pressed(), key_released(), modifier_changed() )によって通知されるので、その内容をそのままhobo_nicolaにわたしています。PS/2キーボードのスキャンコードからHID Usage IDへの変換はps2_kbdクラスの内部で完了しており、PS/2キーボードが発生するリピートも抑止しています。

メインループ(loop())内で hobo_nicola.idle(); とすることで、hobo_nicola側に、いろいろな処理を実行するタイミングを与えています。

ps/2_hobo_nicola.inoは、ライブラリのexamples/usb_hobo_nicola ディレクトリに格納しています。

HIDキーボードを実装した BaseKeyboardクラス(1.2版まで)

Arduinoに付属するKeyboardクラスを参考に、ATmega32u4をHIDキーボードに見せるための実装を記述してあります。

まず、コンストラクタでHIDクラスに対してHIDレポートデスクプリタテーブルの登録とLEDレポート時のコールバック関数の登録を行います。LEDレポート用のコールバック関数の登録は、HIDライブラリが修正済の場合にのみ有効です。

このクラスは、キーの押下やリリースといった情報をPC側にレポートする(インプットレポート)機能と、現在の修飾キーの押下状況を維持する機能、そして、asciiコードで表現された文字や記号を、HID Usage ID(生キーコード)に変換してレポートする機能などを備えています。

ほぼNICOLA化するNicolaKeyboardクラス

生キーコードから内部コードへの変換

キーの押下/リリース時には、UHSライブラリやps2_kbdライブラリからキーボード(またはライブラリ)が発生したHID Usage ID(生キーコード)を受け取ります。まず、これを処理しやすいように内部コード(nid)に変換しています。そのキーがNICOLA配列内ならば変換し、そうでなければ配列外のキー(各種機能キー、テンキーなど)と判断して変換せずそのままHIDクラスに渡します。

変換テーブル(hid_to_nid[])や変換のための関数(convert_keycode())はnicola_table.cpp に置き、配慮が必要なコードについてはnicola_table.h 内に定義しています。

ほぼNICOLA配列
生キーコード。クリックすると大きくなります。

今回の実装では、親指左を無変換、親指右を変換としています。これらのコード変換も convert_keycode()内で行っているので、親指キーを変えたいなら修正することができます。
なお、1.11版からは実行時に空白キーも左右いずれかの親指キーとして設定できるようになりました(空白キーを設定した場合も、無変換/変換キーの機能は変わりません)。

ScrLock LEDがオンならほぼNICOLA化

現在のプログラムは、ホストデバイス側(PCなど)と通信するHIDクラスから渡されたキーボードLED情報のうちのScrLock LEDビットを使ってほぼNICOLA動作するかどうかを判断しています。ScrLock LEDが点灯中(ScrLockがロック中)ならNICOLAモードとして動作し、そうでないなら何もせずにそのままPCにキーコードを流します。
BaseKeyboardクラスでは、ScrLock LEDの状態をPro MicroのRXLEDにも反映するようにしているので、NICOLAモード中はRXLEDが点灯します。

key_press(), key_release(), modifier_pressed()

メインスケッチの仲立ちを経てキーボードから上がってくるキーコードやイベントはこれらの関数が処理します。NICOLAモードのとき、生キーコードが内部コードに変換できて、同時打鍵を伴う範囲のキーで、CtrlやAltが押されていないなら、同時打鍵ステートマシンに入力するためにnicola_state() を呼び出します。

配列内だが同時打鍵を伴わないキー

今のところ、右手小指近辺に配置したBSキーとESCキーをさしています。pre_convert(); でキーコードが得られれば、同時打鍵を伴わないキーとして、ステートマシンの入力とせず出力(インプットレポートとして送信)します。

同時打鍵処理

同時打鍵処理については伝統的な実装をなるべく忠実に再現しています。詳しくは、NicolaKeyboardクラスの同時打鍵ステートマシンの説明 を参照してください。

ASkeyboardには専用の親指キーがあるので、1.2.1版ではそのための対応を追加してあります。

output() と get_output_data() と出力文字列

ステートマシンからの出力を、ホストデバイスに送信するためのコード(HID Usage ID)に変換し、あたかもキーボードから入力されたかのように送信(インプットレポート)します。

同時打鍵が成立時や単独打鍵時など、場合に応じてnicola_table.cppにPROGMEMデータとしておいたテーブルを、内部コードに基づいて参照します。単独打鍵なら output_single[], 親指左同時打鍵なら output_left[], 親指右同時打鍵なら output_right[]を使います。また、Shiftキーが押されていたならば、output_shift[] を使います。

これらのテーブルの要素は、やはりPROGMEMデータとしておいた出力文字列のアドレスになっており、get_output_data() が対象文字列のアドレス、または、出力が割り当てられていない内部コードを表す0を返します。

出力文字列を生キーコード列で表現すると読みにくいので、ASCII文字列で記述しており、出力時に生キーコードに置換して出力しています(send_PGM_string())。

出力文字列の変更について

ブログの投稿としても書きましたが、特殊な記号を一発で出すためには、出力文字列のローマ字シーケンスを変更し、IME側にローマ字定義を追加すればよいでしょう。Shiftキーを押したときの出力文字列はほとんど空いている(empty_str[] PROGMEM = “”;)ので、”z;”とか”zx”とか適当に試してみることができます。

出力文字列の変数名は、以下の配列図でキーの位置を表す記号に基づいています。

ほぼNICOLA配列
ほぼNICOLA配列。クリックすると大きくなります。

なるべくシンプルな実装目指しているので、PCなどのホスト側から出力文字列を変更する機能(配列を変更する機能)を追加する予定はありません。変更したい場合は、nicolatable.cpp  内の配列を書き換えることになります。

NICOLAモード時のShiftキー押下中のキー割り当て

1.11版より、NICOLAモードのときにShiftキーを押したまま入力できるキーを追加しました。従来は、半濁音と一部の記号のみでした。

追加した割当は以下のとおりです。

  •  ”/”キー : “?”記号
  •  ”D”キー : ←(左矢印)
  •  ”F”キー : ↓(下矢印)
  •  ”J”キー : ↑(上矢印)
  •  ”K”キー : →(→矢印)
  •  ”N”キー : Delete
  •  ”M”キー : Enter

これらの多くは、IME候補リストからの選択や文書編集をホームポジションで行うことを意図したものです。
キー割り当てはnicola_table.cpp内の定義を編集してフラッシュに書けば変更したり追加することができます。

動作オプションの設定

いくつかのオプション機能について、フラッシュを書き換えることなく、キーボードとしての動作中に動作を許可/禁止できるようにしました。以下のオプションがあります。

  •  1 : 空白キーを左親指キーにする。
  •  2 : 空白キーを右親指キーにする(1と2はいずれかのみ有効)
  •  3 : 空白キーの親指キー設定を解除。
    (空白キーを親指キーとして追加した場合も、無変換と変換キーは左右の親指キーのまま)。
  •  5 : リピート動作を許可/禁止する
    (NICOLAモードのみで、英数字はふつうにリピートする)。
  •  7 : 英数キーを押したとき、ScrLockをオフにする。
  •  8 : ひらがなキーを押したとき、ScrLockをオンにする。
  • 9  : 半角/全角キーを押したとき、ScrLock をトグルする。
  •  0 : 即時文字出力動作を有効/無効。
  •  \ : 設定内容の表示。

これらの設定は、NICOLAモード時に左親指+Pauseキーの同時打鍵によって開始する設定モードで行います。設定モードに入ると、Pro MicroのLEDが約1Hzで点滅します。

上記のオプションの有効/無効の切替えは、各オプションの先頭に書いた数字キーを押下します(キーボード上段のキー)。設定が完了すると、設定モードを終了します。何もせずに設定モードを終了する際には、Pauseキーを単独で押下します。

設定モード中に¥キーを押すと、その時点での設定内容をキーボードからの入力として出力します。大量の文字を一気に送るので、メモ帳など軽いエディタを開いてから表示するようにしてください。

設定内容は、Pro MicroのEEPROMに記憶するので、電源を切っても覚えています。

即時文字出力動作

聖人さんが開発し公開中の親指の友 Mk-2 キーボードドライバ  が備えている、文字キー出力零遅延モード に倣った機能です。具体的な動作や、同時打鍵ステートマシンへの組み込みについては、NicolaKeyboardクラスの同時打鍵ステートマシンの説明 を参照してください。

文字キーを押下した瞬間に画面に文字がでるので、NICOLA(親指シフト)キーボードに慣れている人ほど新鮮かもしれません。親指と文字の同時打鍵によって表示される文字については、親指キーを先にうつことが多い人にはほとんど違和感はなく、文字キー先行が多い人には、一瞬表示された文字が本来の文字に化けていくのが見えて、これはこれで面白いと思います。

今のところ、facebookの投稿フィールドでは即時出力後に次の文字を打つと、最初の文字が消えるという現象があります。なにかfacebook のJavaScript と相性のようなものがあるのでしょう。

Windows用のIME状態通知プログラム

NICOLAモードとして動作するためには、ScrLock LEDが点灯している必要がありますが、ホストデバイス側のIMEと状態が一致していないと無意味なローマ字列が出力されてしまいます。そのため、IMEが有効で「かな・カナ・カナ」のとき、Windows APIのSendInput() を使ってScrLockをオン(ロック状態)にし、IMEが上記以外ならばオフ(アンロック状態)にするためのプログラムがあると、入力のストレスを大きく軽減できます。そのためにobserve_ime というプログラムを用意しました。

NicolaKeyboardクラスではキーボードのLEDの状態を見てほぼNICOLAするかどうか決めているが、 LEDが存在しないキーボード(今使っているのがそう)であっても問題なく動作します。そういうキーボードのScrLockを押した場合も、PCからPro MicroにLEDを点けろ、または、消せという指示は出るようになっているためです。

このプログラムの詳細については、ダウンロードしたzipファイルに含まれている readme.txtを参照してください。

IME状態をLEDに反映するプログラムがなくても、ScrLockキーの操作や、以下に示すオプション機能によりほぼNICOLAキーボードとして使うことはできます。

注意点
  1. アダプタがNICOLAモードのとき、Windows Explorer のコンテキストメニュー(右クリックメニュー)を開いても、アダプタはNICOLAモードのままです。このため、ショートカットの文字が期待どおりには入力できません。IMEがオフになってくれればいいのですが、Explorerではそうなりません。
    次善の方法として、Ctrlキーを押しながらショートカットキーを入力するとうまくいきます。
  2. アプリケーションによっては、IME の状態が正しく把握できないものがあるようです。MS-IMEではダメだがGoogle日本語入力ならばオーケーというケースもありました。特に対応はありません。
英数キー/ひらがなキーによるScrLockや半角/全角キーに同期したScrLock操作

オプションとして用意したこれらの機能は、IME状態通知プログラムが使えないとき、ホストデバイス側のIME状態とhoboNicolaのNICOLAモードとの関係を、キーボード操作だけで一致させることができると期待して用意しました。

  • ひらがなキーを押したときに、IMEが日本語文字モードとなり、hoboNicolaはNICOLAモードになる。
  • 英数キーを押したときにIMEが英数文字モードとなり、hoboNicolaも非NICOLAモードになる。
  • 半角/全角キーを押したとき、noboNicolaの動作モードも同時に切り替える。

といった動作を期待しています。

改版履歴

変更してリリースすることがあれば、その内容を記載していきます。

  • 2021/8/10  1.5.0版
    ファイル構成やクラス構成を変更しました。このバージョンでの変更内容については、こちらの投稿を参照してください。
  • 2018/12/8  1.21版
    • USBキーボードに改造したASkeyboard用のライブラリファイルを追加し、他のファイルについても修正を行った。
    • 専用の親指キーをもつASkeyboardへの対応のため、 同時打鍵ステートマシンを若干変更した。共用親指キーが前提の、usb版やPS/2版への影響はありません。
    • ESP32を使ったBluetooth版のため、全体的な構成変更を行った。ESP32版用のライブラリファイルは入っているが暫定的なもの。
    • observe_imeの実行中にWindowsがスリープ(サスペンド)しスリープから復帰したとき、ScrLock をオフにするようにした。アダプタがNICOLAモードのままスリープして復帰したとき、復帰時にNICOLAモードに戻るため、サインイン画面でのパスワード入力が正しく行えなかったため。
  • 2018/11/1  1.11版
    • Arduinoのライブラリ形式に変更し、hoboNicolaLibrary111.zip としました。
    • USBキーボードのLEDをホスト側と同期するように修正。
    • PS/2キーボード用のps2_kbdクラスを追加。
    • NICOLAモード時のShiftキー押下中のキー割り当てを追加。
    • オプション設定を行うための、設定モードを追加。
    • 即時文字出力(零遅延出力)動作を選択可能に。
    • 空白キーを左右いずれかの親指キーとして割当可能に。
    • 文字単独や同時打鍵時のリピート出力動作を選択可能に。
    • 即時文字出力やリピートの関係で、同時打鍵ステートマシンを変更。
    • 英数キーでScrLock(NICOLAモード)をオフ、ひらがなキーでオンにするオプションを追加(IME状態の通知ができないときに使う)。
    • PS/2キーボードで、Alt + PrintScreenやると全く違うスキャンコード(0x84)が上がってくるのね。これにも対応。
  • 2018/10/9 初版(1.00版)リリース。