MicroPythonで USBキーボードを作ってみた
一般に USBキーボードを作りたい場合、QMK Firmware を使う人が多いのではないでしょうか。
キーボタンを押したら該当するキーコードを送出するのなら、これが1番容易なのでしょう。
ちょっと複雑なキーコードを送出したい場合は、hid_keyboard_report という 8 byteのパケットを送出する必要があります。
マイコン向けのUSBスタック TinyUSB を使えば容易です。
でも、C言語ではなく MicroPythonで実装したいのです。
import usb_hid
MicroPythonを調査/勉強すると、下記のコードが見つかりました。
import usb_hid
keyboard = usb_hid.Device.KEYBOARD
report = bytearray(8)
keyboard.send_report(report)
そうそう、8 byte の reportを送出する、こんな実装がしたいのです。
CircuitPython が必要
今回使う RP2040-Zero には USB端子があります。
このUSB機能を使いたい場合、MicroPython ではダメで、CircuitPython を使う必要があります。
RP2040-Zero用の CircuitPython が提供されています。
CircuitPython RP2040-Zero
ここから .UF2 ファイルをダウンロードし、ファームを更新します。
Thonnyで実装できる
CircuitPythonで開発するのですから、Thonnyのインタプリタ設定を変えなきゃいけません。
CircuitPython(ジェネリック)・USBシリアルデバイス@COM10
を選んで実装していきます。
(私の環境では COM10 でしたが、環境により異なります)
import time
import usb_hid
keyboard = usb_hid.Device.KEYBOARD
def send_key(modifier, keycodes):
report = bytes([modifier, 0] + keycodes + [0] * (6 - len(keycodes)))
keyboard.send_report(report)
#=== main ===
time.sleep(10)
i = 0
while i < 3:
# 'a' を押す (0x04)
send_key(0x00, [0x04])
send_key(0x00, [0])
time.sleep(0.5)
# Shift + 'b' (0x05)
send_key(0x02, [0x05])
send_key(0x00, [0])
time.sleep(0.5)
# AとB 同時押し
send_key(0x00, [0x04, 0x05])
send_key(0x00, [0])
time.sleep(3)
i += 1
これを動かすと、起動して10秒後に a, B, ab の文字が送出されます。
3回繰り返して終了します。
電源投入時に自動実行させる code.py
電源投入時に自動実行させたいです。
このプログラムを RP2040-Zeroストレージに code.py という名前で 保存します。
これで電源投入したら 本プログラムが自動起動されます。
デバイス初期化は boot.py
電源投入時に PC側を見ると RP2040-Zero のストレージ、CDC(USBシリアル)が有効になっています。
でも、今回作ったのは USBキーボードであり、これらは見えないで欲しいです。
マイコン起動時に、ストレージ, CDCを無効にしてみます。
boot.py に以下のように書くと、起動時にストレージ, CDCが非表示になります。
import storage
import usb_cdc
usb_cdc.disable()
storage.disable_usb_drive()
このプログラムを RP2040-Zero ストレージに boot.py という名前で保存します。
※boot.py は "BOM無し UTF8ファイル" で保存すること
(ブートエラーになって実行に失敗した原因を調べたら BOMがあった為でした)
boot.py を無効にする
ストレージ, CDCが無効になっているので、プログラムの差し替える手段がありません。
そんなときは、MicroPythonのブートローダーを消すしかない。
まず、以下の .uf2 を入手します。
flash_nuke.uf2 を入手します。
まずはこれで Firmwareを上書きします。
次に CircuitPythonの Firmwareを再インストールします。
再起動すると、ストレージ/CDCが元の状態に戻っています。
boot.py を更新する
ストレージ/CDCが無効になると、プログラムの差し替えができなくなります。
マイコン起動時に、無効にする/しないを切替えできるようにしました。
具体的には、GP2に押しボタンスイッチをつなぎ、これを押しながらマイコン起動した場合は デバイスを無効にしない、にしました。
ついでに、今回 使わない HID_MOUSE や MIDIデバイスも無効にします。
また何かと使う ストレージは常に有効にしました。
import storage
import usb_cdc
import usb_midi
import usb_hid
import board, digitalio
button = digitalio.DigitalInOut(board.GP2)
button.pull = digitalio.Pull.UP
pressed = not button.value
if not pressed:
usb_midi.disable()
usb_cdc.disable()
# storage.disable_usb_drive()
usb_hid.enable( (usb_hid.Device.KEYBOARD, ) )
else:
pass
で、完成
これで、Pythonで 自作キーボードを作れることが判りました。
Pythonなので、上位プログラムを作るのは容易ですね。
押しボタンはもとより、センサーに反応してキー送出するなど、特別なマイコン制御キーボードを いろいろ作れますね。