Capslock?そいつなら1x年前にCtrlに置き換えたよ
私は日頃、キーボードのCapslockキーをCtrlキーにremapして使用しています。
最近はUSB切り替え器を使っていて、一組のマウスとキーボードをPCやRaspberry Piなど複数の機材で使用する機会も増えました。
機材ごとに都度キー設定するのは面倒だし、やんごとない理由でキー設定できない機材もあるし できればキーボード側でremapさせたいと思っていました。
ここで「自作キーボードつくるよ!」となるのが現在は主流でしょうが、私の場合は10年以上使い続けている今のキーボードに満足しているのでそのまま使用したいところです。
ということで、今回は既存キーボードをremapできるように手を加える方向で考えてみました。
紆余曲折(+オチ)があったのですが、結論だけまとめずに失敗含めてここに残しておこうと思います。
キーボードとPCの間にremapするなにかを挟む
キーボードで押されたキーをremapしたキーに置き換えてPCに伝えることが目標となります。
今回はRaspberry Piを使って、remapさせることにしました。
イメージ
Keyboard --> Raspberry Pi ---(USB OTG)--> USBハブ --> USB切り替え器 --> PCやRaspberry Pi
↑ココ
Raspberry Piに接続したキーボードをremapする…ちょうどピッタリのものを見つけました。
https://github.com/viggofalster/kiri
そこらへんに転がってるRaspberry Piに導入すれば簡単にできそうですね!さくっと作ってみましょう(フラグ)
自宅に転がっていたRaspberry Pi Zero Wを使って試してみることにしました。
で、さっそくキーボードを接続して…動かない。
そう、Raspberry Pi ZeroのUSBポートは以下の2つなのです。
- 電源供給専用
- USBデバイスを接続 / USB OTG(排他)
排他!
USBキーボード繋げたらPCにつなげるポートがありません。
おとなしくRaspberry Pi 4Bを購入することにしました。
Raspberry Pi 4Bが届いたところで作業再開です。
microSDカードはZero Wで設定したものをそのまま使用します。
ケースはThingiverseに公開されていたモデルを3Dプリントしました。
www.thingiverse.com
USBハブの電力ではRaspberry Piが動いてくれないので、信号と電源でケーブルを分けます。
USB-C Data/Power Splitterthepihut.com
Splitterのケースはいい感じに3Dプリントします。
基盤自体のデータはGrabCADで公開されていました。
grabcad.com
あとはconfig.py
を設定して… 動きました。
満足感に浸りながらキーボードを使います。
そして気づきます。
「無変換」「変換」「¥」「\」キーが効かない!
失敗3 キーが効くぞ!(Windowsのみ)
動作確認に使っていたWindows PCで効かないキーのキーコードを確認しました。
www2d.biglobe.ne.jp
たとえば「¥」キーはキーコードが 89
。
次は kiri.py
がキーボードとしてどのキーコードを出してるか確認してみましょう。
a
キー
[2022-03-04 14:44:00,247|root|INFO] Writing report to output: 00:00:04:00:00:00:00:00
¥
キー
[2022-03-04 14:44:03,320|root|INFO] Writing report to output: 00:00:c2:8b:00:00:00:00:00
…桁、長くね?
知らないキーコード c2
があるし、桁数変わってますね。
89
はUTF-8にすると 0xC2
0x89
になる。これが原因ですね。
コード全体を直す気がないので、 応急処置しました。
diff --git a/kiri.py b/kiri.py
index 9106237..629fb3d 100644
--- a/kiri.py
+++ b/kiri.py
@@ -131,9 +131,9 @@ class Kiri:
self.update_state()
def write_report(self, report: str):
- self.log.debug('Writing report to output: %s', ":".join("{:02x}".format(c) for c in report.encode('utf-8')))
+ self.log.info('Writing report to output: %s', ":".join("{:02x}".format(c) for c in report.encode('latin-1')))
with open('/dev/hidg0', 'rb+') as fd:
- fd.write(report.encode())
+ fd.write(report.encode('latin-1'))
@staticmethod
def set_bit(value, bit):
無事Windowsで「無変換」「変換」「¥」「\」キーが効くようになりました!
さっそく普段使っているUbuntuのデスクトップマシンに接続してみましょう。
…やっぱり効かない。
コードの問題は解決したはずなのに効かない。
さきほどはコード kiri.py
を疑いましたが、コードが悪いのか切り分けが必要ですね。
コードやキーボードを使わず、Raspberry Pi上で直接 /dev/hidg0
に流し込んでみます。
a
echo -ne "\0\0\x4\0\0\0\0\0" > /dev/hidg0
echo -ne "\0\0\0\0\0\0\0\0" > /dev/hidg0
\
echo -ne "\0\0\x89\0\0\0\0\0" > /dev/hidg0
echo -ne "\0\0\0\0\0\0\0\0" > /dev/hidg0
a
しか効きませんね。
疑うべきはコードではなく…キーボードとして正しく認識されていない?という点です。
こんな例もあります。HIDクラスのディスクリプタの内容は正しいのでしょうか?
jtakao.web.fc2.com
キーボードを直接つないだときと、Raspberry Piをつないだときで比較してみました。
まず、直接キーボードを接続した場合。
$ lsusb
Bus 003 Device 006: ID 04d9:2011 Holtek Semiconductor, Inc. Keyboard [Diatec Filco Majestouch 1]
$ sudo usbhid-dump -e descriptor -a 003:006
003:006:000:DESCRIPTOR 1646550972.361890
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01
05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06
75 08 26 FF 00 05 07 19 00 29 91 81 00 C0
内容を見やすくしてくれるサービスがありました。
eleccelerator.com
0x03, 0x06, 0x00, 0x05, 0x01, // Unknown (bTag: 0x00, bType: 0x00)
0x09, 0x06, // Usage (0x06)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x03, // Usage Maximum (Scroll Lock)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x91, // Usage Maximum (0x91)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
// 65 bytes
次にRaspberry Piです。
$ lsusb
Bus 003 Device 005: ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
$ sudo usbhid-dump -e descriptor -a 003:005
003:005:000:DESCRIPTOR 1646550112.843986
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
75 01 95 08 81 02 95 01 75 08 81 03 95 05 75 01
05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 06
75 08 15 00 25 65 05 07 19 00 29 E7 81 00 C0
0x03, 0x05, 0x00, 0x05, 0x01, // Unknown (bTag: 0x00, bType: 0x00)
0x09, 0x06, // Usage (0x06)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0xE7, // Usage Maximum (0xE7)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
// 66 bytes
Logical Maximum
の値が違いますね。
キーボード
0x26, 0xFF, 0x00, // Logical Maximum (255)
Raspberry Pi
0x25, 0x65, // Logical Maximum (101)
細かな違いを分析するのも面倒なので キーボードと同じディスクリプタを喋らせてしまいましょう。
kiri_usb
を修正します。
diff --git a/kiri_usb b/kiri_usb
index 848c52b..8b2f2c8 100755
--- a/kiri_usb
+++ b/kiri_usb
@@ -22,7 +22,7 @@ echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
# usb descriptor equivalent to keybrd.hid seen with https://www.usb.org/document-library/hid-descriptor-tool
-echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
+echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x01\\x95\\x03\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x03\\x91\\x02\\x95\\x05\\x75\\x01\\x91\\x01\\x95\\x06\\x75\\x08\\x26\\xff\\x00\\x05\\x07\\x19\\x00\\x29\\x91\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
# End functions
ついにUbuntuでもキーが使えるようになりました!
結論
これ買えばよかった…(あとから教えていただきました)
booth.pm