HHKB Professional BT を 有線QMKキーボードに改造した話


# &#30446;&#27425;

1.  [HHKB Professional BT を 有線QMKキーボードに改造した話](#org76064c3)
    1.  [免責事項](#org33daaff)
    2.  [概要](#org9f8900a)
    3.  [背景](#orgb6b4df4)
    4.  [分解](#org5abd8ee)
    5.  [信号の解析](#org3ea2192)
    6.  [キースキャンの手順](#orgc61271b)
    7.  [コントローラの設計](#org30a4832)
    8.  [QMKの準備](#orgcd88ef6)
    9.  [組み立て](#orgf82a67d)
    10. [VIA対応](#org3e6d62f)
    11. [感想など](#org38d62e2)



<a id="org76064c3"></a>

# HHKB Professional BT を 有線QMKキーボードに改造した話


<a id="org33daaff"></a>

## 免責事項

-   改造は自己責任でおねがいします。
-   記事の内容の一切について著者は責任を負いませんのでご了承ねがいます。


<a id="org9f8900a"></a>

## 概要

HHKB Professional BT のコントローラを自作し、Bluetooth機能をなくし普通の有線キーボードにするとともに、ファームウェアにQMKを採用し自由なカスタマイズができるようにしました。

いわば [HHKB Alt Controller](https://geekhack.org/index.php?topic=71517.0) のHHKB Professional BT版です。


<a id="orgb6b4df4"></a>

## 背景

私は HHKB Professional BT の日本語配列モデル PD-KB620B（以下単にHHKB BT） を3年ほど使っています。

これはBluetoothキーボードなのですが、私は電池を抜き常時PCと給電用USBケーブルで繋いで使っていました。
（なお、HHKB BTにはUSBコネクタがありますが、これはあくまで電池に代わる電源としてUSBを使うためのもので、USBでPCとつないでも（普通の意味での）有線キーボードにはなりません）

そのうち、突然Bluetooth接続が切れる症状に悩まされることになりました（その際チャタリングしたようにキーが連続で入力される）。もう改造してだいぶたっているので詳しくは覚えていませんが、そこそこな頻度で発生していた気がします。

どうにかできないかなと調べていた折、 [HHKB Alt Controller](https://geekhack.org/index.php?topic=71517.0) や [QMK](https://qmk.fm/) の存在を知りました。これにならってコントローラを自作し、もはや使わないBluetooth機能を捨てて有線化してしまおうと思い立ち、取り組みはじめました。

ちなみに、私はいまのところHHKB BTのコントローラを改造（交換）した事例を他に見つけられていません（まあ需要もなさそうです）。


<a id="org5abd8ee"></a>

## 分解

本体を分解すると分かるのですが、キー側と下側に分解できます（裏面のネジを外せば簡単に開きます）。以下に図をのせます（写真じゃなくてすみません）

    
      キー側
        ,--------------------------------,
       / Q W E R T Y U I O P            /
      /   A S D F G H J K L            /
     /     Z X C V B N M              /
    `--------------------------------'
    
    
      下側
                    _________
        ,----------'--電池---`-----------,
       / |______________________________/|
      / /                   ,-----,    / |
     / /                   /__P1_/    / /
    |--------------------------------| /
    `________________________________|/

下側は箱のようになっており、基板 (P1) が1枚あります。DIPスイッチやUSB・電池ボックスからの線がついています。
キー側は裏返すと、それ自体でかい基板になっていて、さらにその上に小さな基板が載っています。

      キー側（裏側。キーがくっついている）
        ,--------------------------------,
       /                     ,-----,    /
      /                     /__P3_/    /
     /   P2                           /
    |--------------------------------|
     ~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^
    
      横からみるとこういうかんじ
                                           ,---- P2とP3はコネクタでくっついている
                                          /
              P3 ->                   ---vv---
              P2 -> ---------------------^^------
      キートップ -> `-^-^-^-^-^-^-^-^-^-^-^-^-^-'

P1とP3はコネクタでくっついているので容易に外せます。P2とP3は、ネジや両面テープに加え、はめ込むタイプの基板対基板コネクタでつながっています（引っ張れば抜けます）。使われているのはおそらくヒロセ電機の DF12 シリーズ、20ピンで基板間寸法が3mmのやつです。P2側にプラグ（凸）が、P3側にレセプタクル（凹）がついています。

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-left" />

<col  class="org-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">基板</th>
<th scope="col" class="org-left">用途（推測）</th>
</tr>
</thead>

<tbody>
<tr>
<td class="org-left">P1</td>
<td class="org-left">電源、DIPスイッチ</td>
</tr>


<tr>
<td class="org-left">P2</td>
<td class="org-left">キースイッチ</td>
</tr>


<tr>
<td class="org-left">P3</td>
<td class="org-left">コントローラ</td>
</tr>
</tbody>
</table>

というかんじです。なので、このうちP2はそのままP3だけ自作コントローラに交換します。P1も使いません（ので背面のDIPスイッチはなくなります）。
自作コントローラを作るためには、P2とP3の間でやりとりされる信号を解析する必要があります。


<a id="org3ea2192"></a>

## 信号の解析

有線のHHKBの解析はすでに[先行事例](https://github.com/tmk/tmk_keyboard/tree/master/keyboard/hhkb/doc)があります。これと大きくは変わらないだろうと踏んでいましたが、HHKB BTはコネクタ形状やピンの数が違うので、確認しないことにはどうにもならなそうでした。

こうしたことは初めてなので道具をそろえるところからですが、とりあえず安価でチャンネル数の多いロジックアナライザ (Kingst LA1010) を購入しました。
コネクタに悪戦苦闘しながらも、なんとか信号を引っ張りだし、動作中のHHKB BTの信号をLA1010で確認することができました。

![HHKBの基板から20本近い線を引き回して信号を引っ張り出している](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2673161/f9363190-3cb1-78e1-0484-8689d3e3a1d5.png)
（図: 信号を引っ張り出すようす）

![パソコン上でソフトウェアを使って信号を表示している](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2673161/9d30c5d8-b108-18fa-e04c-fb78a3c07f3c.png)
（図: パソコンの画面）

先行事例を参考に、いろんなキーを押下しながら試してみた結果、以下のように推測しました。

    
     10  9  8  7  6  5  4  3  2  1
    ,------------------------------,
    |                              |    ^ キーボードの上（数字があるほう）
    |      P2側のプラグ（凸）      |    |
    |                              |    v キーボードの下（スペースバーがあるほう）
    `------------------------------'
     11 12 13 14 15 16 17 18 19 20
    
    
     1  2  3  4  5  6  7  8  9  10
    ,------------------------------,
    |                              |    ^ キーボードの上（数字があるほう）
    |   P3側のレセプタクル（凹）   |    |
    |                              |    v キーボードの下（スペースバーがあるほう）
    `------------------------------'
     20 19 18 17 16 15 14 13 12 11

コントローラは、スキャン用の信号をメイン基板に送り（出力）、メイン基板より結果を受け取ります（入力）。

（「マイコンピン」は私用メモです）

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-right" />

<col  class="org-left" />

<col  class="org-left" />

<col  class="org-left" />

<col  class="org-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-right">番号</th>
<th scope="col" class="org-left">用途</th>
<th scope="col" class="org-left">コントローラの…</th>
<th scope="col" class="org-left">マイコンピン</th>
<th scope="col" class="org-left">備考</th>
</tr>
</thead>

<tbody>
<tr>
<td class="org-right">1</td>
<td class="org-left">Vcc (3.3V)</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">2</td>
<td class="org-left">Vcc (3.3V)</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">3</td>
<td class="org-left">LED1（青）</td>
<td class="org-left">出力</td>
<td class="org-left">B12</td>
<td class="org-left">LEDを点灯させるときHにします</td>
</tr>


<tr>
<td class="org-right">4</td>
<td class="org-left">LED2（オレンジ）</td>
<td class="org-left">出力</td>
<td class="org-left">B13</td>
<td class="org-left">LEDを点灯させるときHにします</td>
</tr>


<tr>
<td class="org-right">5</td>
<td class="org-left">key</td>
<td class="org-left"><b>入力</b></td>
<td class="org-left">B8</td>
<td class="org-left">スキャンの結果入力があるとHになります</td>
</tr>


<tr>
<td class="org-right">6</td>
<td class="org-left">prev</td>
<td class="org-left">出力</td>
<td class="org-left">B7</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">7</td>
<td class="org-left">scan</td>
<td class="org-left">出力</td>
<td class="org-left">B6</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">8</td>
<td class="org-left">wake</td>
<td class="org-left">出力</td>
<td class="org-left">B14</td>
<td class="org-left">キースキャン中はH。3.6ms H, 12.4ms L</td>
</tr>


<tr>
<td class="org-right">9</td>
<td class="org-left">GND</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">10</td>
<td class="org-left">GND</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">11</td>
<td class="org-left">row (bit0)</td>
<td class="org-left">出力</td>
<td class="org-left">B10</td>
<td class="org-left">スキャンするrowのLSBを指定します</td>
</tr>


<tr>
<td class="org-right">12</td>
<td class="org-left">row (bit1)</td>
<td class="org-left">出力</td>
<td class="org-left">B1</td>
<td class="org-left">スキャンするrowのLSBから1つ目のビットを指定します</td>
</tr>


<tr>
<td class="org-right">13</td>
<td class="org-left">row (bit2)</td>
<td class="org-left">出力</td>
<td class="org-left">B0</td>
<td class="org-left">スキャンするrowのLSBから2つ目のビットを指定します</td>
</tr>


<tr>
<td class="org-right">14</td>
<td class="org-left">row (bit3)</td>
<td class="org-left">出力</td>
<td class="org-left">A3</td>
<td class="org-left">スキャンするrowのLSBから3つ目のビットを指定します</td>
</tr>


<tr>
<td class="org-right">15</td>
<td class="org-left">~row (bit3)</td>
<td class="org-left">出力</td>
<td class="org-left">A2</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">16</td>
<td class="org-left">column0</td>
<td class="org-left">出力</td>
<td class="org-left">A1</td>
<td class="org-left">column0をスキャンするときLにします</td>
</tr>


<tr>
<td class="org-right">17</td>
<td class="org-left">column1</td>
<td class="org-left">出力</td>
<td class="org-left">A0</td>
<td class="org-left">column1をスキャンするときLにします</td>
</tr>


<tr>
<td class="org-right">18</td>
<td class="org-left">column2</td>
<td class="org-left">出力</td>
<td class="org-left">C15</td>
<td class="org-left">column2をスキャンするときLにします</td>
</tr>


<tr>
<td class="org-right">19</td>
<td class="org-left">column3</td>
<td class="org-left">出力</td>
<td class="org-left">C14</td>
<td class="org-left">column3をスキャンするときLにします</td>
</tr>


<tr>
<td class="org-right">20</td>
<td class="org-left">column4</td>
<td class="org-left">出力</td>
<td class="org-left">B9</td>
<td class="org-left">column4をスキャンするときLにします</td>
</tr>
</tbody>
</table>

rowとcolumnはキーを特定する数字です。rowはキーボードの列の選択（QAZの列、WSXの列…に対応）、columnはキーボードの段の選択（数字の段、QWERTYの段、ASDFの段…に対応）です。ただし数字の順番は不規則なので、下記図および表を参照ください。

    実際のキー配置にならった、キーボードのキーとrow/columnの数字の対応
    （<column><row>で表示。rowは16進数表記）
    
    14, 16, 17, 15, 13, 10, 11, 12, 1E, 1C, 1A, 19, 18, 1D, 3D
    24,  26, 27, 25, 23, 20, 21, 22, 2E, 2C, 2A, 29, 28
    04,   06, 07, 05, 03, 00, 01, 02, 0E, 0C, 0A, 09, 08,   3F
    34,     36, 37, 35, 33, 30, 31, 32, 3E, 3C, 3A, 39, 38, 3B
    44,  46, 47, 45, 43,   40,    42, 4E, 4C, 4A,   49, 48, 4B

キーボードのキーとrow/columnの数字（表）

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-right" />

<col  class="org-left" />

<col  class="org-right" />

<col  class="org-left" />

<col  class="org-left" />

<col  class="org-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-right">row</th>
<th scope="col" class="org-left">column 0</th>
<th scope="col" class="org-right">column 1</th>
<th scope="col" class="org-left">column 2</th>
<th scope="col" class="org-left">column 3</th>
<th scope="col" class="org-left">column 4</th>
</tr>
</thead>

<tbody>
<tr>
<td class="org-right">0</td>
<td class="org-left">G</td>
<td class="org-right">5</td>
<td class="org-left">T</td>
<td class="org-left">B</td>
<td class="org-left">Space</td>
</tr>


<tr>
<td class="org-right">1</td>
<td class="org-left">H</td>
<td class="org-right">6</td>
<td class="org-left">Y</td>
<td class="org-left">N</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">2</td>
<td class="org-left">J</td>
<td class="org-right">7</td>
<td class="org-left">U</td>
<td class="org-left">M</td>
<td class="org-left">Henkan</td>
</tr>


<tr>
<td class="org-right">3</td>
<td class="org-left">F</td>
<td class="org-right">4</td>
<td class="org-left">R</td>
<td class="org-left">V</td>
<td class="org-left">Muhenkan</td>
</tr>


<tr>
<td class="org-right">4</td>
<td class="org-left">LControl</td>
<td class="org-right">Esc</td>
<td class="org-left">Tab</td>
<td class="org-left">LShift</td>
<td class="org-left">LFn</td>
</tr>


<tr>
<td class="org-right">5</td>
<td class="org-left">D</td>
<td class="org-right">3</td>
<td class="org-left">E</td>
<td class="org-left">C</td>
<td class="org-left">LAlt</td>
</tr>


<tr>
<td class="org-right">6</td>
<td class="org-left">A</td>
<td class="org-right">1</td>
<td class="org-left">Q</td>
<td class="org-left">Z</td>
<td class="org-left">Zenkaku/Hankaku</td>
</tr>


<tr>
<td class="org-right">7</td>
<td class="org-left">S</td>
<td class="org-right">2</td>
<td class="org-left">W</td>
<td class="org-left">X</td>
<td class="org-left">Super</td>
</tr>


<tr>
<td class="org-right">8</td>
<td class="org-left">]</td>
<td class="org-right">^</td>
<td class="org-left">[</td>
<td class="org-left">Up</td>
<td class="org-left">Down</td>
</tr>


<tr>
<td class="org-right">9</td>
<td class="org-left">:</td>
<td class="org-right">-</td>
<td class="org-left">@</td>
<td class="org-left">\</td>
<td class="org-left">Left</td>
</tr>


<tr>
<td class="org-right">A</td>
<td class="org-left">;</td>
<td class="org-right">0</td>
<td class="org-left">P</td>
<td class="org-left">/</td>
<td class="org-left">RFn</td>
</tr>


<tr>
<td class="org-right">B</td>
<td class="org-left">&#xa0;</td>
<td class="org-right">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">RShift</td>
<td class="org-left">Right</td>
</tr>


<tr>
<td class="org-right">C</td>
<td class="org-left">L</td>
<td class="org-right">9</td>
<td class="org-left">O</td>
<td class="org-left">.</td>
<td class="org-left">RAlt</td>
</tr>


<tr>
<td class="org-right">D</td>
<td class="org-left">&#xa0;</td>
<td class="org-right">¥</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">BS</td>
<td class="org-left">&#xa0;</td>
</tr>


<tr>
<td class="org-right">E</td>
<td class="org-left">K</td>
<td class="org-right">8</td>
<td class="org-left">I</td>
<td class="org-left">,</td>
<td class="org-left">Kana</td>
</tr>


<tr>
<td class="org-right">F</td>
<td class="org-left">&#xa0;</td>
<td class="org-right">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">Enter</td>
<td class="org-left">&#xa0;</td>
</tr>
</tbody>
</table>


<a id="orgc61271b"></a>

## キースキャンの手順

（秒数の数字はロジックアナライザに表示された数値をそのまま記載しています）

1回のスキャン（全てのキーの入力チェック）には3.6msほどかかり、スキャンの間は12.5msだけ間隔があります。

1.  wakeとrowの選択
    
               wake: __~~~~~~~~~~~~~~~~__ H for 3.6ms
         row (bit0): ~~_~_~_~_~_~_~_~_~~~
         row (bit1): ~~__~~__~~__~~__~~~~
         row (bit2): ~~____~~~~____~~~~~~
         row (bit3): ~~________~~~~~~~~~~
        ~row (bit3): __~~~~~~~~__________
                row: **0123456789ABCDEF**
    
    一連のスキャン処理中はwakeがHになります。
    各rowに対応する時間間隔は等しくありません。そのrowに含まれるキーの数に依存します。キーが5つないrow（row: 1, B, D, F）では、スキャンがスキップされる分短くなります。

2.  colの選択（実際には次の 3. スキャン と前後します）
    
            row: *0000011112222233333...BBCCCCCDDEEEEEF*
        column0: ~_~~~~_~~~_~~~~_~~~~...~~_~~~~~~_~~~~~~ L for 7us
        column1: ~~_~~~~_~~~_~~~~_~~~...~~~_~~~_~~_~~~~~
        column2: ~~~_~~~~_~~~_~~~~_~~...~~~~_~~~~~~_~~~~
        column3: ~~~~_~~~~_~~~_~~~~_~..._~~~~_~~_~~~_~_~
        column4: ~~~~~_~~~~~~~~_~~~~_...~_~~~~_~~~~~~_~~
    
    キーが5つないrow（row: 1, B, D, F）では、キーが存在しないcolumnが飛ばされます。

3.  スキャン
    
        columnX: ~~~~~~~_____~~ L for 7us
           prev: __~~~~~~~~~___ H for 12.5us （もしこのキーが直前に押下されていれば（？））
           scan: ~~~~~~~~__~~~~ L for 3us
            key: __________~___ H for 812.5ns （もし押下されていれば）
    
    -   columnX は 2. colの選択 の column0 から column4 のいずれかです。
    -   prevは[先行事例](https://github.com/tmk/tmk_keyboard/tree/master/keyboard/hhkb/doc)でいうhysに対応するものだと思います。そちらでは "Not sure this is needed" と書かれています。Hになる条件を含めちゃんと調べてないですが、動いてはいます。


<a id="org30a4832"></a>

## コントローラの設計

キースキャンの流れがわかったところで、自作コントローラのありかたを考えます。

-   3.3V駆動であること
-   本体におさまること
-   スキャンに必要なピンが確保できること
-   QMKが動作すること（AVRかARM）

あたりを考慮して、今回使ったのは、WeAct の通称 Black Pill とよばれるSTM32F411がのったボードです。なんとなくARMのボードにしてみました。

当然Black Pillは、HHKB BT本体内部に固定できるようなネジ穴はありませんし、ヒロセのコネクタにもつながりません。そこで、コネクタとBlack Pillをつなぎ、またHHKB BT内部に固定できるような基板を作ることにします。[できた基板](https://github.com/8544/qmk_firmware/blob/hhkb-bt-mod-public/keyboards/hhkb/jp_bt/hhkb-bt.kicad_pcb)が下図のものです（お作法等分かっていない素人が作った基板ですが、とりあえず動いてはいます。ただし寸法はガバ）。

![KiCadの3Dビューで設計した基板を表示している](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2673161/59d76d2e-c902-4ed6-e569-d970153cedbb.png)

ただし基板といってもたいしたことはありません。Black PillのピンとHHKB BTにつながるコネクタを接続しているだけです。オプションとして、HHKB BTにもともと載っているLEDを点灯させたかったのでトランジスタが2つ、あと音を鳴らすためのブザーがありますが、それだけです。

なお、この基板はちゃんと計測せずに作ったため、ネジ穴の位置がHHKB本体とまったく合いませんでした（コネクタの位置決めにも左右されます）。もし参考にされる方がいらっしゃれば、少なくともこの基板データはアテにしないほうがいいです。私はやすりで基板を削ってどうにかしました。


<a id="orgcd88ef6"></a>

## QMKの準備

すでにQMKは WeAct の Black Pill に対応していました。よって、keyboards以下にコードを書くだけで動作しました。コードはほとんど設定ですが、キーマトリックススキャン部分だけはまともに書く必要があります。ここは、すでにQMKのソースコードにある有線のAlt Controllerの実装が参考になります。

<https://github.com/8544/qmk_firmware/blob/hhkb-bt-mod-public/keyboards/hhkb/jp_bt/matrix.c>

工夫としては、精度よくwaitするために `wait_us_arm` を使っています。あとは実際に動作させながら、ロジックアナライザで確認した信号と同じようになるように定数を調整しました。この調整が上手くいかないと、激しくチャタリングします。

この実装では、対応するキーのないrow/columnのスキャンもやってしまっています。これは本物ではスキップされています。そのため、この実装だと本物よりスキャンにかかる時間がちょっと長いです（4.4msほどかかるので、本物より0.8msほど長い）。


<a id="orgf82a67d"></a>

## 組み立て

![HHKBの基板に接続された自作コントローラ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2673161/31040b39-95d9-d638-f321-6edf800abe51.png)
（組み込む図。2つあるのは試作1号（上）と2号（下））


基板にコネクタ (`DF12(3.0)-20DP-0.5V(86)`)、トランジスタ（オプション、 `DTC123JKA` ）、ブザー（オプション）をはんだづけします。このコネクタのはんだづけが初心者の私には相当難しく、何度も失敗しました…。

ブザーはコントローラの基板上に直接実装してしまうと、フタが閉まらないか、あるいは本体の基板とコネクタで繋げなくなります。適当に線を伸ばして、もはやデッドスペースとなった電池ボックスのあたりに収めました。

基板とBlack Pillは、スルーホールにすずめっき線を通してはんだづけします。これだとBlack Pillを着脱できませんが、とりあえずはこれで…。

コントローラをHHKB本体に収めるには、Black PillとPCに接続するためのUSBケーブルをどうにかする必要があります。ちゃんとやるのであれば、もともとHHKB BTにあるMicro USBコネクタを活用するべきなのでしょうが、電池ボックスの跡地からケーブルをそのまま出しています。フタを常時外すことになるので、見た目はイマイチです。

あとはQMKをmakeして、ST-Link等でフラッシュすれば動作するようになります。

    $ make hhkb/jp_bt:default:st-flash

ブザーやLEDを使うにはQMKで適切に設定する必要があります。ブザーはオーディオを有効にし、ピンを指定すれば動きます。LEDは、光らせたい場面でBlack Pillの対応するピンをHにすれば光ります。

    writePinHigh(LED_BLUE_PIN);


<a id="org3e6d62f"></a>

## VIA対応

VIAに対応するにはEEPROMが必要ですが、Black PillにはEEPROMがありません。
なので、後でEEPROMが載せられるよう基板の裏には穴を空けておき（Black Pillはこの位置にパッドがある）、思いたったときに実装できるようにしておきました。

…と思っていたのですが、いつのまにQMKの側でフラッシュを利用したEEPROMエミュレーションに対応していました(<http://github.com/qmk/qmk_firmware/pull/14195>)。 これを使うことで別途チップをのせることなくVIA対応もできました。Black Pillだと、デフォルトでは8KBほど使えるようです。容量に余裕があるのでレイヤー数を増やしてあります。

VIA対応版は下記でビルド&フラッシュできます。

    $ make hhkb/jp_bt:via:st-flash

あとは[JSON](https://github.com/8544/qmk_firmware/blob/hhkb-bt-mod-public/keyboards/hhkb/jp_bt/keymaps/via/hhkb_bt.json)をVIAで開けば使えます。
![VIAでHHKB BTのキーマップを編集する画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2673161/f5364f28-9ff0-2e98-aefe-1d19f56ee927.png)

<a id="org38d62e2"></a>

## 感想など

音を鳴らすのはすぐ飽きてしまって、いまは無効にしています。LEDはレイヤーのインジケータとして使ってます。LEDを見て状況を判断するわけではないので、ほぼ飾りですが。

QMKの設定としては、レイヤー1にDvorakを <https://vultaire.net/software/dvorak_jp106/index.php> の流儀で定義しています。ハードウェア側でDvorakにできると、OS側での設定が不要で非常によいです（これだけなら最近のHHKBでもキーリマップでできそうですが）。ほか、Fnのキーコンビネーション（PgDown/PgUpまわり）を純正から変更したり、CtrlのMod Tapを無変換・変換に設定したり、マクロを登録したりして利用しています。

VIAは最近使いはじめましたが、フラッシュする手間が省けて便利です。