Raspberry Pi Picoでマクロパッドを作る

#作った目的
身内でDiscordを使ってAmong Usをやってるんですが、
マイクミュート等をコマンド入力で対応しており、毎回打つのめんどくせぇな？
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/3f4eb41b-e952-8a62-be09-7c3c61c7c86a.png">
って事でマクロパッドを作ることにしました。
(諸事情により自動ミュートbotは使ってない)

#元記事
https://www.tomshardware.com/how-to/raspberry-pi-pico-powered-stream-deck

当初はProMicroと[QMK Firmware](https://docs.qmk.fm/#/)でやろうと思ってたんですが、
なんかRaspberry Pi Picoでお手軽に出来るっぽかったのでやってみました。

#部品調達

- Raspberry Pi Pico x1([遊舎工房](https://shop.yushakobo.jp/products/raspberry-pi-pico?_pos=1&_sid=3394183d1&_ss=r)で購入)
- Cherry MX互換キースイッチ x6 (余ってたGateron赤軸)
- キーキャップ x6 (余ってたry
- 適当な電子工作用ワイヤー (あm
- ケース(3Dプリンターで出力)

仕事用にもう一つ作りたかったんですが、Picoが1回の購入で1枚のみという購入制限があったので、とりあえず一つだけ作ることに。

#Raspberry Pi Picoのセットアップ
CircuitPythonのHIDライブラリを使用してるらしく、CircuitPythonが使えるようにセットアップします。
##UF2ファイルのダウンロード
[CircuitPython公式サイト](https://circuitpython.org/board/raspberry_pi_pico/)からPico用のUF2ファイルをダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/67387c6e-812b-ab85-7eb9-0f8a295d2060.png)
で、ここで注意点が一つ。
親切に言語がJAPANESEになってるかもしれませんが、ENGLISH(US)を選びましょう。(ここで躓いた)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/cb498457-8901-ed96-bad8-ea51f92ea649.png)
理由はよく分かりませんがJAPANESEだと動きません。

##UF2ファイルの書き込み
Pico本体に付いている白いボタンがBOOTSELボタンです。(画像右上)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/166298b8-d3f3-7575-40dc-07621d27280f.png)
BOOTSELボタンを押しながらUSBケーブルでパソコンと接続すると書き込みモードで起動します。
接続されたらBOOTSELボタンから指を放して大丈夫です。
無事接続されるとPicoが「RPI-RP2」というストレージとして出ているはずなので、
RPI-RP2の直下に先ほどダウンロードしたUF2ファイルをコピーします。
するとPicoが勝手に再起動して「CIRCUITPY」という名前のストレージが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/790a31ff-d592-6dae-7e01-07d8c87a5622.png)

これでCircuitPythonの導入は完了です。

##カスタムコードの追加
Picoをマクロパッドとして動作させるためのカスタムコードを追加しています。
まずはGitHubの[PiPicoMacroKeys](https://github.com/novaspirit/PiPicoMacroKeys)からZipファイルをダウンロード。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/13ddbf28-fe1f-d43f-ab31-b6322182055d.png)
Zipファイルの中身をコピー&上書きします。
Picoを接続しなおすとマクロパッドとして動作します。

#マクロの設定方法
マクロの設定は「CIRCUITPY」直下のcode.pyにあります。
デフォルトは以下の通り。
whileの中に記述してあり、それぞれCtrl+F7～F12に相当します。

```python
while True:
    if btn1.value:
        keyboard.send(Keycode.CONTROL, Keycode.F7)
        time.sleep(0.1)
    if btn2.value:
        keyboard.send(Keycode.CONTROL, Keycode.F8)
        time.sleep(0.1)
    if btn3.value:
        keyboard.send(Keycode.CONTROL, Keycode.F9)
        time.sleep(0.1)
    if btn4.value:
        keyboard.send(Keycode.CONTROL, Keycode.F10)
        time.sleep(0.1)
    if btn5.value:
        keyboard.send(Keycode.CONTROL, Keycode.F11)
        time.sleep(0.1)
    if btn6.value:
        keyboard.send(Keycode.CONTROL, Keycode.F12)
        time.sleep(0.1)
    time.sleep(0.1)
```

これを好みの内容に書き換えていくわけですが、
各キーの定義は`/lib/adafruit_hid/keycode.py`の中にあるので参考にします。
<details><summary>keycode.py</summary><div>

```python
class Keycode:
    """USB HID Keycode constants.
    This list is modeled after the names for USB keycodes defined in
    https://usb.org/sites/default/files/hut1_21_0.pdf#page=83.
    This list does not include every single code, but does include all the keys on
    a regular PC or Mac keyboard.
    Remember that keycodes are the names for key *positions* on a US keyboard, and may
    not correspond to the character that you mean to send if you want to emulate non-US keyboard.
    For instance, on a French keyboard (AZERTY instead of QWERTY),
    the keycode for 'q' is used to indicate an 'a'. Likewise, 'y' represents 'z' on
    a German keyboard. This is historical: the idea was that the keycaps could be changed
    without changing the keycodes sent, so that different firmware was not needed for
    different variations of a keyboard.
    """

    # pylint: disable-msg=invalid-name
    A = 0x04
    """``a`` and ``A``"""
    B = 0x05
    """``b`` and ``B``"""
    C = 0x06
    """``c`` and ``C``"""
    D = 0x07
    """``d`` and ``D``"""
    E = 0x08
    """``e`` and ``E``"""
    F = 0x09
    """``f`` and ``F``"""
    G = 0x0A
    """``g`` and ``G``"""
    H = 0x0B
    """``h`` and ``H``"""
    I = 0x0C
    """``i`` and ``I``"""
    J = 0x0D
    """``j`` and ``J``"""
    K = 0x0E
    """``k`` and ``K``"""
    L = 0x0F
    """``l`` and ``L``"""
    M = 0x10
    """``m`` and ``M``"""
    N = 0x11
    """``n`` and ``N``"""
    O = 0x12
    """``o`` and ``O``"""
    P = 0x13
    """``p`` and ``P``"""
    Q = 0x14
    """``q`` and ``Q``"""
    R = 0x15
    """``r`` and ``R``"""
    S = 0x16
    """``s`` and ``S``"""
    T = 0x17
    """``t`` and ``T``"""
    U = 0x18
    """``u`` and ``U``"""
    V = 0x19
    """``v`` and ``V``"""
    W = 0x1A
    """``w`` and ``W``"""
    X = 0x1B
    """``x`` and ``X``"""
    Y = 0x1C
    """``y`` and ``Y``"""
    Z = 0x1D
    """``z`` and ``Z``"""

    ONE = 0x1E
    """``1`` and ``!``"""
    TWO = 0x1F
    """``2`` and ``@``"""
    THREE = 0x20
    """``3`` and ``#``"""
    FOUR = 0x21
    """``4`` and ``$``"""
    FIVE = 0x22
    """``5`` and ``%``"""
    SIX = 0x23
    """``6`` and ``^``"""
    SEVEN = 0x24
    """``7`` and ``&``"""
    EIGHT = 0x25
    """``8`` and ``*``"""
    NINE = 0x26
    """``9`` and ``(``"""
    ZERO = 0x27
    """``0`` and ``)``"""
    ENTER = 0x28
    """Enter (Return)"""
    RETURN = ENTER
    """Alias for ``ENTER``"""
    ESCAPE = 0x29
    """Escape"""
    BACKSPACE = 0x2A
    """Delete backward (Backspace)"""
    TAB = 0x2B
    """Tab and Backtab"""
    SPACEBAR = 0x2C
    """Spacebar"""
    SPACE = SPACEBAR
    """Alias for SPACEBAR"""
    MINUS = 0x2D
    """``-` and ``_``"""
    EQUALS = 0x2E
    """``=` and ``+``"""
    LEFT_BRACKET = 0x2F
    """``[`` and ``{``"""
    RIGHT_BRACKET = 0x30
    """``]`` and ``}``"""
    BACKSLASH = 0x31
    r"""``\`` and ``|``"""
    POUND = 0x32
    """``#`` and ``~`` (Non-US keyboard)"""
    SEMICOLON = 0x33
    """``;`` and ``:``"""
    QUOTE = 0x34
    """``'`` and ``"``"""
    GRAVE_ACCENT = 0x35
    r""":literal:`\`` and ``~``"""
    COMMA = 0x36
    """``,`` and ``<``"""
    PERIOD = 0x37
    """``.`` and ``>``"""
    FORWARD_SLASH = 0x38
    """``/`` and ``?``"""

    CAPS_LOCK = 0x39
    """Caps Lock"""

    F1 = 0x3A
    """Function key F1"""
    F2 = 0x3B
    """Function key F2"""
    F3 = 0x3C
    """Function key F3"""
    F4 = 0x3D
    """Function key F4"""
    F5 = 0x3E
    """Function key F5"""
    F6 = 0x3F
    """Function key F6"""
    F7 = 0x40
    """Function key F7"""
    F8 = 0x41
    """Function key F8"""
    F9 = 0x42
    """Function key F9"""
    F10 = 0x43
    """Function key F10"""
    F11 = 0x44
    """Function key F11"""
    F12 = 0x45
    """Function key F12"""

    PRINT_SCREEN = 0x46
    """Print Screen (SysRq)"""
    SCROLL_LOCK = 0x47
    """Scroll Lock"""
    PAUSE = 0x48
    """Pause (Break)"""

    INSERT = 0x49
    """Insert"""
    HOME = 0x4A
    """Home (often moves to beginning of line)"""
    PAGE_UP = 0x4B
    """Go back one page"""
    DELETE = 0x4C
    """Delete forward"""
    END = 0x4D
    """End (often moves to end of line)"""
    PAGE_DOWN = 0x4E
    """Go forward one page"""

    RIGHT_ARROW = 0x4F
    """Move the cursor right"""
    LEFT_ARROW = 0x50
    """Move the cursor left"""
    DOWN_ARROW = 0x51
    """Move the cursor down"""
    UP_ARROW = 0x52
    """Move the cursor up"""

    KEYPAD_NUMLOCK = 0x53
    """Num Lock (Clear on Mac)"""
    KEYPAD_FORWARD_SLASH = 0x54
    """Keypad ``/``"""
    KEYPAD_ASTERISK = 0x55
    """Keypad ``*``"""
    KEYPAD_MINUS = 0x56
    """Keyapd ``-``"""
    KEYPAD_PLUS = 0x57
    """Keypad ``+``"""
    KEYPAD_ENTER = 0x58
    """Keypad Enter"""
    KEYPAD_ONE = 0x59
    """Keypad ``1`` and End"""
    KEYPAD_TWO = 0x5A
    """Keypad ``2`` and Down Arrow"""
    KEYPAD_THREE = 0x5B
    """Keypad ``3`` and PgDn"""
    KEYPAD_FOUR = 0x5C
    """Keypad ``4`` and Left Arrow"""
    KEYPAD_FIVE = 0x5D
    """Keypad ``5``"""
    KEYPAD_SIX = 0x5E
    """Keypad ``6`` and Right Arrow"""
    KEYPAD_SEVEN = 0x5F
    """Keypad ``7`` and Home"""
    KEYPAD_EIGHT = 0x60
    """Keypad ``8`` and Up Arrow"""
    KEYPAD_NINE = 0x61
    """Keypad ``9`` and PgUp"""
    KEYPAD_ZERO = 0x62
    """Keypad ``0`` and Ins"""
    KEYPAD_PERIOD = 0x63
    """Keypad ``.`` and Del"""
    KEYPAD_BACKSLASH = 0x64
    """Keypad ``\\`` and ``|`` (Non-US)"""

    APPLICATION = 0x65
    """Application: also known as the Menu key (Windows)"""
    POWER = 0x66
    """Power (Mac)"""
    KEYPAD_EQUALS = 0x67
    """Keypad ``=`` (Mac)"""
    F13 = 0x68
    """Function key F13 (Mac)"""
    F14 = 0x69
    """Function key F14 (Mac)"""
    F15 = 0x6A
    """Function key F15 (Mac)"""
    F16 = 0x6B
    """Function key F16 (Mac)"""
    F17 = 0x6C
    """Function key F17 (Mac)"""
    F18 = 0x6D
    """Function key F18 (Mac)"""
    F19 = 0x6E
    """Function key F19 (Mac)"""

    LEFT_CONTROL = 0xE0
    """Control modifier left of the spacebar"""
    CONTROL = LEFT_CONTROL
    """Alias for LEFT_CONTROL"""
    LEFT_SHIFT = 0xE1
    """Shift modifier left of the spacebar"""
    SHIFT = LEFT_SHIFT
    """Alias for LEFT_SHIFT"""
    LEFT_ALT = 0xE2
    """Alt modifier left of the spacebar"""
    ALT = LEFT_ALT
    """Alias for LEFT_ALT; Alt is also known as Option (Mac)"""
    OPTION = ALT
    """Labeled as Option on some Mac keyboards"""
    LEFT_GUI = 0xE3
    """GUI modifier left of the spacebar"""
    GUI = LEFT_GUI
    """Alias for LEFT_GUI; GUI is also known as the Windows key, Command (Mac), or Meta"""
    WINDOWS = GUI
    """Labeled with a Windows logo on Windows keyboards"""
    COMMAND = GUI
    """Labeled as Command on Mac keyboards, with a clover glyph"""
    RIGHT_CONTROL = 0xE4
    """Control modifier right of the spacebar"""
    RIGHT_SHIFT = 0xE5
    """Shift modifier right of the spacebar"""
    RIGHT_ALT = 0xE6
    """Alt modifier right of the spacebar"""
    RIGHT_GUI = 0xE7
    """GUI modifier right of the spacebar"""

    # pylint: enable-msg=invalid-name
    @classmethod
    def modifier_bit(cls, keycode):
        """Return the modifer bit to be set in an HID keycode report if this is a
        modifier key; otherwise return 0."""
        return (
            1 << (keycode - 0xE0) if cls.LEFT_CONTROL <= keycode <= cls.RIGHT_GUI else 0
        )
```
</div></details>
他にマウスクリックとかも出来るっぽい。試してないけど。
Among Us専用マクロパッドとして以下の様にしました。

```code.py
    while True:
    if btn1.value:
        keyboard.send(Keycode.PERIOD, Keycode.M, Keycode.ENTER)
        time.sleep(0.1)
    if btn2.value:
        keyboard.send(Keycode.PERIOD, Keycode.U, Keycode.M, Keycode.ENTER)
        time.sleep(0.1)
    if btn3.value:
        keyboard.send(Keycode.CONTROL, Keycode.SHIFT, Keycode.M)
        time.sleep(0.1)
    if btn4.value:
        keyboard.send(Keycode.PERIOD, Keycode.D, Keycode.ENTER)
        time.sleep(0.1)
    if btn5.value:
        keyboard.send(Keycode.PERIOD, Keycode.U, Keycode.D, Keycode.ENTER)
        time.sleep(0.1)
    if btn6.value:
        keyboard.send(Keycode.PERIOD, Keycode.U, Keycode.D, Keycode.M, Keycode.E, Keycode.ENTER)
        time.sleep(0.1)
    time.sleep(0.1)
```
#ケースの用意
実は一番面倒な所かもしれないケースの用意。
私は自分の3Dプリンター(Ender-3 V2)で出力しました。
3Dデータは[こちら](https://www.thingiverse.com/thing:4812223)から。
3Dプリンターが無い場合は、[DMM.make](https://make.dmm.com/print/)あたりの代行サービスを使うか、アクリルカットして作るか、頑張って手作りするしかないですね。
スイッチ固定用基板として[SU120](https://talpkeyboard.net/?category_id=5e83f0a42a9a422dab65796d)とか[無限の可能性](https://royal-keyboard-works.square.site/shop/3)を使うとちょっと楽かも。
ちなみに、元のデータだとコネクタの部分が狭くて手持ちのケーブルでは挿さりませんでした。
なので開口部をケース底面まで広げて出力してます。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/65233186-1607-b7e1-f673-3df9738a8fba.png"><img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/e251073f-512e-3e10-20f4-10fd7ffb0536.png">
開口部を広げたらいい感じに↓
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/a4c2ff42-898d-04a1-dcfa-6711a033aa31.png"><img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/98c737da-cd51-3170-6cb1-08de0e3c4446.png">
組み立てたらキースイッチの端子がPicoと接触しまくったので、絶縁処理をするかケースを厚めに作り直した方が良いかもしれない。

#配線
配線手順は[元記事](https://www.tomshardware.com/how-to/raspberry-pi-pico-powered-stream-deck)を見てください。(写真撮ってなかった)
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/1f293b5d-f5b6-8247-239c-b475123b3d8b.png">

#完成
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514873/ca623cad-f74b-af54-c3af-aff8460e57bb.png">
割とサクサクっと出来ちゃいましたね。
QMK Firmwareと違ってファームウェアのビルドとかが要らないのでお手軽。