キーボード配列エミュレーション技術の説明

#１．はじめに

　キーボード配列エミュレーションとは、例えばJIS配列のキーボードに対して、デフォルトとは異なる配列で入力可能なように変換する技術のことをいいます。富士通が公式に親指シフトに対するサポート終了を明言したいま、既存のキーボードで親指シフトを実現する「キーボード配列エミュレーション」は、ますます重要です。
　自分は、紅皿(benizara)と命名したキーボード配列エミュレーションをメンテナンスしており、最近は各種配列についても色々と興味深く見させて頂いています。そして、最近は各種配列やらキーボードやらの記事に興味があり、色々と読ませて頂いています。

こちらは、ikejiさんのブログです。

https://blog.ikejima.org/make/keyboard/2018/12/23/keyboard-numa.html

　なかなか面白い纏め記事でした。このうち自分は、親指シフト派に分類されるのだと思います。以下に上記記事の一部を引用します。

>親指シフト派
親指シフトを搭載しているワープロはなくなったが、根強い人気を持っているのが親指シフト配列のキーボードだ。 日本語を入力するのに最適化されているため、日本語で文章を大量に書く人に人気だ。 思考を妨げずに入力できると言われている。 メーカーからの新作がないのに住人の努力によって維持されている沼の鏡のような沼だ。(ikejiのblogより）


こちらは井上明人さんの記事です。

https://slowinternet.jp/article/20200220/

　上記の記事では、タイパー（高速タイピング）の沼、物理的にキーボードの配列を設計・自作する沼、ソフト的にキーボードの配列を設計・自作する沼の３つが紹介されています。自分はどこに分類されるのか不明ですが、敢えていうならば配列沼の住人なのだろうと思います。

　以下、キーボード沼の住人として、備忘録を兼ねて、キーボード配列エミュレーション技術を纏めてみようと思います。

#２．Windowsにおけるキー入力とキーボード配列エミュレーション

https://docs.microsoft.com/ja-jp/windows/win32/inputdev/about-keyboard-input

こちらのWebページにキーボード入力モデルが記載されています。以下に要点を引用します。

>キーボードデバイスドライバーは、キーボードからスキャンコードを受信します。キーボードレイアウトに送信されます。キーボードレイアウトは、メッセージに変換され、アプリケーション内の適切なウィンドウにポストされます。（キーボード入力の概要より）

キーボード配列エミュレーションとは、キーボードからアプリケーションまでの間の何れかに割り込んで、スキャンコードやメッセージを書き換えるというものです。
以下、キーボードとキーボードデバイスドライバとの間をハードウエアレイヤと呼び、キーボードデバイスドライバ内部をドライバレイヤと呼び、キーボードデバイスドライバからアプリケーションまでの間をアプリケーションレイヤと呼びます。

#３．各レイヤでのキーボード配列エミュレーションの実現
##３．１．ハードウエアレイヤでのキーボード配列エミュレーションの実現
　ハードウエアレイヤで、JISキーボードの配列を親指シフト配列などにエミュレーションするものです。情報セキュリティの面から、フリーソフトウェアなどの使用が制約されている環境であっても使用可能です。ただし、その特性上、ノートパソコンに適用するのは難しいです。また、ＩＭＥのモードを検知するため、ローマ字変換モードやかな変換モードへの遷移は、 ALT-半角全角キー同時押しによるトグルではなく、遷移キーと解除キーをそれぞれ割り当てる必要があります。

###３．１．１．OyaConv

https://oyaconv.jp/

OyaConvは、高橋祥之さんが発表されている商品であり、キーボードからUSB入力を受け付けてスキャンコードを変換し、パソコン側のUSBホストコントローラに送信するというものです。USBバスパワーで動作するため電源不要です。OyaConvは、Arduino上で実現されているようです。
令和３年４月２９日に、キーボードからUSB入力を受け付けてスキャンコードを変換し、Bluetoothでパソコン側に送信するものを発表されています。
<iframe width="560" height="315" src="https://www.youtube.com/embed/4XmcZPbOFVM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


###３．１．２．かえうち

https://kaeuchi.jp/summary/

かえうちは、うぇぶしま（代表責任者・中島崇さん）が販売している商品であり、キーボードからUSB入力を受け付けてスキャンコードを変換し、パソコン側のUSBホストコントローラに送信するというものです。USBバスパワーで動作するため電源不要です。
「かえうちカスタマイズ」プログラムにより、様々な配列に対応しています。
また、「かえうちパートナー」プログラムを常駐させることにより、ＩＭＥのモード検知や記号入力補助が可能です。

###３．１．３．その他

http://sohta02.web.fc2.com/usb2bt.html

　USB2Bplusは、キーボードからUSB入力を受け付けてスキャンコードを変換し、Bluetoothでパソコン側に送信するというものです。外付け電源があれば、キーボードのワイヤレス化と同時にキーボード配列のエミュレーションも可能です。

　その他、Arduino上でNICOLA配列（≒親指シフト配列）を実現されている方がおられます。

https://okiraku-camera.tokyo/blog/?p=8131

##３．２．ドライバレイヤでのキーボード配列エミュレーションの実現
　ドライバレイヤで、JISキーボードの配列を親指シフト配列などにエミュレーションするものです。Windowsストアアプリ等でも安定して親指シフト入力を行うことが可能です。

###３．２．１．OASYSキーボードドライバ Windows 10用 (V5.0.3.0)
　富士通のFMV-KB613, FMV-BIBLO/LIFEBOOKシリーズ(親指シフトキーボードモデル)用のドライバーです。~~が、実はPS2コネクタを有するJISキーボードに適用しても動きます。FMV-KB613のキーボードの物理配線は、JISキーボードと同様だからです。但し、キーレイアウトの変更はできません。
　なお、富士通の推奨環境から外れますので自己責任でお使いください。~~

  2021年5月9日修正、このドライバは、右親指キーと左親指キーに相当するものを持っていないと動作しないようです。また、
FMV-KB613の物理配線については色々とありそうなので、再度調査して書き込みます。

https://www.fujitsu.com/jp/products/software/applications/applications/japanist/download/

この「Japanist バージョン共通(セキュリティパッチ、キーボードドライバなど)」をクリックして開くと、ドライバのダウンロードが表示されます。
以下、富士通親指シフトドライバのINFファイルのインストールセクションです。親指シフトキーボードとして認識した場合、親指シフトキーボードドライバのインストールを実行します。

```ini:F5DNOYA.INF
;*****************************************
; Install Section
;*****************************************

[Manufacturer]
%FUJITSU%=FUJITSU_KBD,NTamd64

[FUJITSU_KBD.NTamd64]
%*FJT0611.DeviceDesc%         = KB611_TYPE_Inst,ACPI\VEN_PNP&DEV_0303        ;Fujitsu 	FMV-KB611 Keyboard

```

サービスインストールセクションです。なお、ここで記載されているi8042prt.sys は、PS2用ドライバです。

```ini:F5DNOYA.INF
;*****************************************
; Service Installation section
;*****************************************

[OASYS_AddReg]
HKLM,SYSTEM\CurrentControlSet\Services\i8042prt\Parameters,OverrideKeyboardType,%REG_DWORD%,0x7
HKLM,SYSTEM\CurrentControlSet\Services\i8042prt\Parameters,OverrideKeyboardSubtype,%REG_DWORD%,0x52
HKLM,SYSTEM\CurrentControlSet\Services\i8042prt\Parameters,OverrideKeyboardIdentifier,%REG_SZ%,"FUJITSU_OYAYUBI"

[OASYS_Inst.Services]
AddService = i8042prt, 0x00000002, OASYS_TYPE_i8042prt_Service_Inst, i8042prt_EventLog_Inst ; Port Driver
AddService = kbdclass,, OASYS_kbdclass_Service_Inst, OASYS_kbdclass_EventLog_Inst            ; Class Driver

[OASYS_LayerDriverFiles]
f5dnoya.dll
f5dnjis.dll
f5dnchex.dll

[OASYS_TYPE_AddReg]
HKLM,SYSTEM\CurrentControlSet\Services\i8042prt\Parameters,"LayerDriver JPN",%REG_SZ%,"f5dnoya.dll"

[JIS_TYPE_AddReg]
HKLM,SYSTEM\CurrentControlSet\Services\i8042prt\Parameters,"LayerDriver JPN",%REG_SZ%,"f5dnjis.dll"


[OASYS_kbdclass_Service_Inst]
DisplayName    = %kbdclass.SvcDesc%
ServiceType    = %SERVICE_KERNEL_DRIVER%
StartType      = %SERVICE_SYSTEM_START%
ErrorControl   = %SERVICE_ERROR_NORMAL%
ServiceBinary  = %12%\f5dnkcls.sys
LoadOrderGroup = Keyboard Class

[OASYS_kbdclass_EventLog_Inst]
AddReg = OASYS_kbdclass_EventLog_AddReg

[OASYS_kbdclass_EventLog_AddReg]
HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\f5dnkcls.sys"
HKR,,TypesSupported,0x00010001,7

[OASYS_TYPE_i8042prt_Service_Inst]
DisplayName    = %i8042prt.SvcDesc%
ServiceType    = %SERVICE_KERNEL_DRIVER%
StartType      = %SERVICE_DEMAND_START%
ErrorControl   = %SERVICE_ERROR_NORMAL%
ServiceBinary  = %12%\i8042prt.sys
LoadOrderGroup = Keyboard Port
```

ドライバ固有の情報をレジストリに書き込むためのセクションです。

```ini:F5DNOYA.INF
; ==============================================
; KB611 (OYAYUBI)
; ==============================================
[KB611_TYPE_Inst]
CopyFiles  = OASYS_CopyFiles, OASYS_LayerDriverFiles
AddReg     = OASYS_AddReg, OASYS_TYPE_AddReg, KB611_TYPE_STYLE_AddReg
;DelReg     = OASYS_DelReg

[KB611_TYPE_STYLE_AddReg]
HKLM,SYSTEM\CurrentControlSet\Services\kbdclass\Parameters,OyayubiKeyboardType,%REG_DWORD%,0xe0000101

[KB611_TYPE_Inst.HW]
AddReg = OASYS_AddReg.HW

[KB611_TYPE_Inst.Services]
Needs = OASYS_Inst.Services

```

これは想像ですが、富士通のキーボードドライバは、i8042prt.sysからキーボードのスキャンコードを受け取ると、親指シフトキーボードのキーコードに変換して上位層に返すのではないかとおもいます。

###３．２．２．親指の友Mk-IIキーボードドライバ

https://www.vector.co.jp/soft/winnt/util/se521156.html

　聖人さん作のキーボードドライパです。なんと個人製作です。そして、USBキーボードなどでも動作します。kbdclass.sys（下位のキーボードドライバ）からの入力を受け付けてスキャンコードを変換し、アプリケーション層に引き渡すフィルタドライバであると思われます。昨年４月から署名つきドライバになったので、インストールが簡単になったのはありがたいです。
　以下に、64bitドライバのINFファイルの要部を抜粋して引用します。

```ini:kbd_oya_mk2.INF
・・・略・・・
;=====================================================================
;
; Service Installation
;
[kbf_oya_mk2.Services]
AddService = kbf_oya_mk2, , kbf_oya_mk2_Service_Inst
AddService = kbdclass, , kbdclass_Service_Inst, kbdclass_EventLog_Inst

[kbf_oya_mk2.HW]
; ｷｰﾎﾞｰﾄﾞﾎﾟｰﾄﾄﾞﾗｲﾊﾞに対する上位(後段)ﾌｨﾙﾀとしてｲﾝｽﾄｰﾙ
AddReg = kbf_oya_mk2.HW.AddReg

[kbf_oya_mk2.HW.AddReg]
HKR,,"UpperFilters",0x00010000,"kbf_oya_mk2"

[kbf_oya_mk2_Service_Inst]
DisplayName    = %kbfiltr.SvcDesc%
ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
StartType      = 3                  ; SERVICE_DEMAND_START
ErrorControl   = 0                  ; SERVICE_ERROR_IGNORE
LoadOrderGroup = Keyboard Port
ServiceBinary  = %12%\kbf_oya_mk2.sys

;---------------------------------------------------------------------
;/* ｸﾗｽﾄﾞﾗｲﾊﾞ(@memo 本当はInclude=keyboard.infとかすべきだが、どうもコロコロ構造が変わっているようで…) */
[kbdclass_Service_Inst]
DisplayName    = %kb_class.SvcDesc%
ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
StartType      = 1                  ; SERVICE_SYSTEM_START
ErrorControl   = 0x1                  ; SERVICE_ERROR_NORMAL
LoadOrderGroup = Keyboard Class
ServiceBinary  = %12%\kbdclass.sys

[kbdclass_EventLog_Inst]
AddReg = kbdclass_EventLog_AddReg

[kbdclass_EventLog_AddReg]
HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\kbdclass.sys"
HKR,,TypesSupported,0x00010001,7
・・・略・・・
```
　この親指の友Mk-IIキーボードドライバは、配列置換機能、ソフトウェアによるキーリピート機能、設定の動的変更機能、零遅延モードをサポートしています。

「零遅延モード」とはどういうものかを、ブログの記事から引用します。

https://kiyoto-y.hatenablog.com/entry/38994299

>この遅延は、親指シフトの同時打鍵ロジックの必要悪みたいなもので、「逐次打鍵(小指のシフトキーみたいな)」ではなく「同時打鍵」を実現するため、親指キーよりも文字キーが一瞬先に押されてしまったとしてもシフト操作として受け付るようになっています。つまり、文字キーが押されてもすぐに文字を確定せず、親指キーが押されないか少し待つようになっているわけです。これが、キーを押してから画面に文字が出るまでのラグとなります。
では、今回実装した機能を有効化するとどうなるかというと、なんとこの待ち時間を無くし、押された瞬間に結果を出力するようになります。当然このままでは誤打鍵が増えてしょうがないですね。そのため、後で親指キーが押されたりして出力済の内容と矛盾が生じた場合は、「BackSpaceのコードを出力して、既に出した文字入力を消す」というアクロバティックな動作を行うようにしました。（雑記帳より）

　こんな重要なことがさらっとブログに書かれているのが実に勿体ない。特許にすればいいのにと思いました。なお、零遅延モードは紅皿にも入れさせていただきました。零遅延モードに関する記事は以下です。

https://qiita.com/kenichiro_ayaki/items/0dfdd93c3844b4a7a9da


##３．３．アプリケーションレイヤでのキーボード配列エミュレーションの実現

やまぶき、DvorakJ、そして紅皿は、何れもアプリケーションレイヤにて実現されています。やまぶきとDvorakJは、ライフラボ製の親指シフト表記付きUSBライトタッチキーボードのサイトで、これらを容易にインストールするためのインストーラが提供されています。

###３．３．１．やまぶき

やまぶきは、http://yamakey.seesaa.net/ にて、yamaさんが公開されているキーボード配列エミュレータです。Windowsのフックを使って実現されていると思われます。
以下、自分が常用していたやまぶきR（ローマ字モードで動作するやまぶき）について説明します。

https://docs.microsoft.com/ja-jp/windows/win32/winmsg/about-hooks

やまぶきRの実行ファイルは、以下のように構成されています。

yamabuki_r.exe
yabuhook_r.dll
yabu_r64.exe
yabuhook_r64.dll

そして、やまぶきRのマニュアルには以下のように記載されています。

>特別なインストールは必要ありません。yamabuki_r.exeを実行してください。
　64bit環境では、さらにyabu_r64.exeが内部で呼び出されます。yabu_r64.exeは内部呼び出し専用で、単体実行はできません。yabu_r64.exeが強制終了してしまってyamabuki_r.exeだけが動いている状態では、64bitアプリに対して文字が出ません。

すると、yamabuki_r.exe は32bit実行ファイル、yabuhook_r.dllは、32bit環境におけるフックの為のdllと推定されます。そして、yabu_r64.exe は64bit実行ファイル、yabuhook_r64.dllは、64bit環境におけるフックの為のdllと推定されます。
つまり、やまぶきRは、グローバルフックを、Microsoftの公式資料とおり素直に実現しているものと思われます。

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa

microsoft公式資料にも、64bit環境と32bit環境の両方にキーフックする場合、32ビットDLLと64ビットDLLが必要である旨が記載されていてます。

>SetWindowsHookExを使用して、DLLを別のプロセスに挿入できます。32ビットDLLを64ビットプロセスに挿入することはできません。また、64ビットDLLを32ビットプロセスに挿入することもできません。アプリケーションで他のプロセスでフックを使用する必要がある場合は、32ビットアプリケーションでSetWindowsHookExを呼び出して32ビットDLLを32ビットプロセスに挿入し、64ビットアプリケーションでSetWindowsHookExを呼び出して64ビットを挿入する必要があります。 DLLを64ビットプロセスに。32ビットDLLと64ビットDLLの名前は異なる必要があります。

やまぶきR(ver.1.10.0) に同梱されている配列ファイルは以下です。
　NICOLA配列系統の各ファイル
　SKY++
　かえでレフティあすか(英かなシフト同置)
　月U9RC2
　新下駄
　飛鳥123配列系統の各ファイル
この他、配列沼の方々が、やまぶき用のさまざまな配列ファイルを発表されています。

###３．３．２．DvorakJ

DvorakJ（https://blechmusik.xii.jp/dvorakj/ ）は、blechmusikさんが公開されているキーボード配列エミュレータです。Autohotkey で記述されており、全ソースコードが公開されています。

DvorakJ （2014-06-07版）は、極めて多くのキーボード配列に対応していることが特徴です。

順にも同時にも打鍵する配列として、以下の配列ファイルを含んでいます。
　KKGon配列
　一打鍵ローマ字入力「ローナ」
　市式仮配列

順に打鍵する配列として、以下の配列ファイルを含んでいます。
　DvorakJP配列の各種ファイル
　中指NICOLA配列
　QWERTY 配列系の各種ファイル
　SKY 配列系の各種ファイル
　花配列系の各種ファイル
　月配列系の各種ファイル
　phoenixかな配列
　きゅうり改
　けいならべ
　新 JIS 配列
　叢雲配列
　和ならべ

同時に打鍵する配列として、以下の配列ファイルを含んでいます。
　蒼星（日本語入力配列）　（Dvorak系）
　NICOLA配列系の各種ファイル
　同時打鍵機能付き QWERTY 配列
　SKY 配列系の各種ファイル
　下駄配列系の各種ファイル
　色波２
　AKonT配列
　JIS かな配列
　ＯＥＡ配列（ローマ字入力時）
　Perky配列
　さら配列
　小梅配列
　新50音順配列
　新日本語入力方式
　同時打鍵版「きゅうり改」

なお、Autohotkeyとは、Windows上で動作するスクリプト言語であり、スクリプトをコンパイルして実行ファイルを作成することも可能です。但しコンパイルとは言っても、単にコメントを削除してランタイムのインタープリターを付加しているだけのようです。
（なお、Autohotkey スクリプトをコンパイルして生成した実行ファイルをバイナリエディタで見ると、後半部分にソースコードがそのまま見えます。）
DvorakJは、Autohotkeyで記述されているため、Windows10 のストアアプリにも入力可能です。おそらく、Autohotkeyは署名されたアプリケーションなのだと思います。よって、Autohotkey上で動作するスクリプトも、Windows10 のストアアプリへのメッセージをフックできるのだとおもいます。

　なお、Autohotkeyでコンパイルした実行ファイルは、32bit.dllや64bit.dllを付加しなくてもそのまま動作します。どのようにして64bit環境と32bit環境の両方にキーフックしているかは不明です。

###３．３．３．紅皿

紅皿(benizara) は、拙作のキーボード配列エミュレータです。Autohotkey で記述されており、github に全ソースコードを公開しています。

https://github.com/k-ayaki/benizara

紅皿の使用説明書はこちらです。

https://qiita.com/kenichiro_ayaki/items/03ac81a20137c3d91554

紅皿の動作仕様書はこちらです。

https://qiita.com/kenichiro_ayaki/items/9a39a5c7622c23e3ce3b

紅皿 ver.0.1.4.5が現在対応している配列は以下です。
　NICOLA配列
　NICOLA-F配列
　orzレイアウト
　親指シフト表記付きUSBライトタッチキーボード配列
　月U9完成版
　新下駄
　下駄配列
　飛鳥123
　かえでレフティあすか(英かなシフト同置)

紅皿をAutohotkeyで記述したのは、Windows10 のストアアプリにも入力可能とするためだったのですが、そのせいでWindows Defender を含む幾つかのウイルス検知ソフトウェアにウイルスまたはマルウエアとして誤検知されます。調べてみると、マルウエアのなかに、Autohotkeyで記述されたものがあるそうです。よっで、これらのウイルス検知ソフトウェアは、Autohotkeyのランタイムのインタープリターをバイナリで検知すると、マルウエアと認識するようです。

そのせいか、新バージョンを作る度にマイクロソフトにバイナリを送信して、Defender の検知から外してくれと申請する必要があります。Microsoftに対する非マルウエアファイルの申請はこちらです。

https://www.microsoft.com/en-us/wdsi/filesubmission

###３．３．４．ＩＭＥレイヤでのキーボード配列エミュレーションの実現
（令和３年９月２３日追記）

 https://www.fujitsu.com/jp/products/software/applications/applications/japanist/

　富士通からリリースされていた日本語入力ソフトウエア Japanist には、親指シフトエミュレーション機能が組み込まれています。

>標準的な 106 / 109 日本語キーボードを親指シフト配列として使用できる、エミュレーション機能を搭載。
>専用キーボードがなくても、気軽に親指シフトで入力できるようになります。

　そして、mozcでは同時打鍵機能をサポートされたそうです。これが、Google日本語入力に組み込まれるといいですね。

https://www.facebook.com/groups/oyayubishift/posts/4784775908216957/
　

#４．まとめ
　ここでは、各レイヤでのキーボード配列エミュレータと、その特徴について説明しました。キーボード配列エミュレータは、キーボード沼のなかの更にニッチな範囲なので、この情報が役立つ方は少ないかもしれません。但し、ローマ字入力のタイピング速度がキーボードの物理的限界に達した方にとって、親指シフト配列やその他の配列は、一つの解決案になるかと思います。