見出し画像

Planckであそぼ。①(Rotary Encoder編)

はじめに

一日で一番手に触れているものはキーボードという思い込みから、不便さを克服することにより得られる快楽を毎日満喫するために小さなキーボードの導入を思い立ち、2022年12月にClaw44の購入を決意。猛烈なトレーニングによりColumn Staggered 40%キーボードにも慣れてきて、外出先でも使えるように持ち運び用として2023年3月にPlanckのGBに参加。プログラミングと自作キーボードの知識ゼロから始めた自作キーボード素人によるPlanckカスタマイズの奮闘記を綴っていきたいと思います。

Planckとは

Planckは一体型40%の4行×12列のOrtholinear(格子配列)のキーボードで、Planckの開発者は修行僧が普段お世話になっているQMK Firmware の開発者でもあるJack Humbert 氏であり、自作キーボードの修行僧にとってみれば神的存在である同氏の傑作で修行僧のマストアイテムといえる。もともとは、同氏の設立したOLKBで販売されていたが現在はDropで販売されている。現在のバージョンはv7で、猫山王が購入したのもv7。

以前は派生形のPlanck EZがZSAから販売されていた。猫山王が普段から師として一方的に崇めているBen Vallack 氏のE-learningでPlanck EZを推していたので、猫山王もPlanck EZかOLKB Planckか迷いに迷った。お値段とOLKB Planckの最新モデルv7が発売されるとあってOLKB Planck v7を購入した。ちなみにPlanck EZは2023年7月のお別れ会を最後に終売となってしまった。Planck EZは独自のキーマップ変更ツールOryxを利用することになるが、タップダンスの設定もできるので当時衝撃を受けたのを記憶している。

縦横綺麗にキーが配列されているPlanckは世界的に大人気なキーボードである。おそらくその理由は、Jack Humbert 氏が開発者であるということ、また40%とコンパクトであるもののキーマップを煮詰めることで普段使いからプログラミングまで十分にこなすことができるということ、Ortholinear(格子配列)によって指の動きが自然になるということかなと妄想したりしている。Ortholinear(格子配列)の40%キーボードであれば選択肢は豊富にあるものの、最下段のセンターが2uではなく、1u×2というのは意外と少なかったりする。以下、猫山王調べの40%Ortholinear(格子配列)キーボード。

Ortholinear(格子配列)の40%キーボード
・Planck EZ
・TPS 40
・BM40
・JJ40
・CST40
・CSTC40

Ortholinear(格子配列)の40%キーボードで1u×2
・OLKB Planck
・Chosfox minipeg48
・Equals 48
・Trident44

猫山王の普段使いのキーボードはColumn StaggeredのClaw44で、普段から親指を大活躍させているので、Claw44に近い配列で持ち運び便利な40%キーボードかつ1u×2は絶対に譲れないこだわりポイントということで、Planckの導入に至った次第である。

Rotary Encoderの楽しみ方

1.ロータリーエンコーダを購入してキーボードにはんだ付けしよう
Planck v7はDropのサイトにある通り、ロータリーエンコーダを取り付けることができる。取り付ける場所は左右それぞれの端の列で、取り付け可能な最大数は"8"と完全に一線を超えてた変態かつ狂気の沙汰ともいえる数のロータリーエンコーダをサポートしている。そのため、ルクル回転殺法とポチポチ連打拳の暗殺拳の絶対王を目指している修行僧は迷わず最大数"8"のロータリーエンコーダを搭載することをお勧めする。ちなみに猫山王はバンビちゃん仕様で、左下に1つ右下に1つの合計2つのロータリーエンコーダを搭載している。

ロータリーエンコーダのはんだ付けはサクッと差し込んでピンをはんだ付けするればいいだけのお手軽簡単修行である。猫山王がアリさんマークのAliExpressで購入したロータリーエンコーダとノブのリンクを参考までに貼っておく。

お勧めはプッシュスイッチ付きロータリーエンコーダで、軸については個人的には耐久性のある金属軸ではなく、耐久性の期待できない樹脂の軸をお勧めする。これは、せっかくハンサムでカッコいいノブを購入したとしても、キーボードに搭載したときにロータリーエンコーダの軸が長すぎてノッポな見た目で視覚的に明らかに不細工になってしまった場合に金属軸は美容整形のオペによる修正に非常に困難かつ難易度の高い修行を伴う。一方で、樹脂の軸であれば、見た目命の自作キーボードにおいてノブの位置をいい塩梅にするためのオペがヤスリやニッパーでいとも簡単にできてしまう。このオペはロータリーエンコーダをPCBにはんだ付けする前にするのがいいであろう。

2.ロータリーエンコーダに命を吹き込もう
Planck v7はロータリーエンコーダをサポートしているとはいえ、PCBにはんだ付けするだけでは、単なるお飾りで暗殺拳のデバイスとして全く機能しない。ロータリーエンコーダに命を吹き込むために変更が必要なファイルは、keymapsフォルダ下のkeymap.cファイルである。ファイルを書き換える方法については、猫山王の設定を参考にひとつひとつ解説していきたいと思います。

3.keymap.cファイルの内容を書き換えよう
Planck v7はロータリーエンコーダをサポートしているとはいえENCODER_MAP_ENABLEに対応していない残念仕様である。このことはVIA/Remap/Vial等のキーマップ変更ツールのGUI上で、ロータリーエンコーダのクルクル回転殺法の技の変更が一切できないことを意味する。すなわち、クルクル回転殺法の技を変更したい場合には毎回ソースコードを書き換えてコンパイルするという修行をいとわない、いわば究極の不便さからくる快楽を好む賢者仕様の強制労働を強いられる。猫山王もソースコードの呪文を色々と書き換えてENCODER_MAP_ENABLEを使えるようにできるかチャレンジしてみたが、そもそもロータリーエンコーダの挙動に割り当てられているPINが"B12"と"B13"の2つしかないので、根本的にENCODER_MAP_ENABLEには対応していないのだろうという妄想に達した。Planck v7でENCODER_MAP_ENABLEの対応を可能とする裏技をご存じの修行僧はこの裏技を是非教えて下さい。

ENCODER_MAP_ENABLEに対応していないとはいえ「Claw44であそぼ。⑤(Rotary Encoder編)」で紹介した呪文を参考にすれば、Planck v7でもいとも簡単にクルクル回転殺法が使えるようになる。呪文の書き換えにおいて、readme.mdファイルで割り当てられているロータリーエンコーダの番号と、keymap.cファイルに追加する呪文のロータリーエンコーダのindex番号を対応させることに注意が必要である。つまり、左下に1つ右下に1つのロータリーエンコーダを搭載している猫山王のバンビちゃん仕様では、左下のロータリーエンコーダのindex番号は"3"となり、右下のロータリーエンコーダのindex番号は"7"となる。

以下に猫山王の8レイヤー仕様のクルクル回転殺法の呪文を記載したので参考にされたし。呪文の記載場所はキーマップの下が良いであろう。猫山王のバンビちゃん仕様のindex番号は"3"、"7"の呪文を追加すれば良いが、使用していないロータリーエンコーダのindexの呪文を"/*" と"*/"の暗号で囲むことで最大数8のロータリーエンコーダを搭載した暗殺拳の絶対王への道を残した呪文としている。なお、"case _00"の"00"の箇所については、修行僧が各自でkeymap.cファイルに定義したレイヤー名称に変更する必要がある。

/* ENCODER_ENABLEのパターン */
#ifdef ENCODER_ENABLE
bool encoder_update_user(uint8_t index, bool clockwise){

/*
if (index == 0) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
else if (index == 1) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
else if (index == 2) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
*/

if (index == 3) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_WH_L); } else { tap_code(KC_WH_R); };
break;
case _01:
if (clockwise) { tap_code(KC_LEFT); } else { tap_code(KC_RGHT); };
break;
case _02:
if (clockwise) { tap_code(KC_WH_U); } else { tap_code(KC_WH_D); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}

/*
else if (index == 4) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
else if (index == 5) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
else if (index == 6) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _01:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
*/

else if (index == 7) {
switch (get_highest_layer(layer_state)) {
case _00:
if (clockwise) { tap_code(KC_VOLU); } else { tap_code(KC_VOLD); };
break;
case _01:
if (clockwise) { tap_code(KC_VOLU); } else { tap_code(KC_VOLD); };
break;
case _02:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _03:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _04:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _05:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _06:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
case _07:
if (clockwise) { tap_code(KC_NO); } else { tap_code(KC_NO); };
break;
}
}
return false;
};
#endif

4.さあ、コンパイルしよう
ここまでくれば最後はQMK MSYSでのコンパイルである。呪文のコンパイルの成功は、暗黒世界の中で不便さを克服することにより得られる快楽を求める修行僧として極楽浄土に達したことを意味する。ただし、クルクル回転殺法とポチポチ連打拳の使い手となるためには更なる精進が必要で修業の日々に逆戻りである。

実際にRotary Encodeを利用してみて

Planckは世界的にファンの多い格子配列(ortholinear)のキーボードでロータリーエンコーダを最大8も搭載できるということで、Jack Humbert 氏はクルクル回転殺法とポチポチ連打拳の暗殺拳の使い手を自然発生的に増殖させ、キーボード界征服のための傭兵を世界中に送り込んでいるのだろう。猫山王のPlanck v7はバンビちゃん仕様であるため最前線での活躍は期待できないが、Jack Humbert 氏の意思を引き継いでこれからも暗殺拳の絶対王の修羅の国での修行に励んでいく次第であります。PlanckはENCODER_MAP_ENABLEに対応していないので、クルクル回転殺法の技の変更には毎回コンパイルが必要であるが、Jack Humbert 氏の信者であればコンパイルそのものが同氏への忠誠心への証であり、非常に重要かつ神聖な意味をもつ儀式であるといえる。そのため、Planckを保有している修行僧の間では、搭載するロータリーエンコーダの数とコンパイルの回数を競うように増やすことで不便さからくる快楽を満喫する行為としてコンパイルの修行に励む修行僧が後を絶たない。
Planckはロータリーエンコーダをサーポートしているものの、そのカスタマイズを記した文献や導きの書がほとんどないためそのカスタマイズ方法に悩まれていた修行僧も一定数いるのではと妄想している。かく言う猫山王もそういった修行僧の一人であった。暗殺拳の絶対王になるためにPlanckを購入したもののロータリーエンコーダの搭載方法が分からず、暗殺拳の絶対王への道を諦めていた修行僧にとって一助となれば幸いです。
自作キーボードは敷居が高いと思われている方にとって、一日で一番手に触れているものはキーボードということで、不便さを克服することにより得られる快楽の世界への入門のための勇気づけとなれば幸いです。

次回

さて次回もPlanckのカスタマイズの奮闘記をお届けします。世界的にファンの多い格子配列(ortholinear)のキーボードをVial化し、Vial友の会の会員をネズミ算式に一気に増加させることで、Vial教団にどっぷりと浸かってVialの普及に尽力している猫山王のVial教団内の地位をビューンと上級層の位まで飛び級させてもらおうという魂胆である。究極の自作キーボードを目指して、不便さを克服することにより得られる快楽を求める修業はまだまだ続きます。

この記事が気に入ったらサポートをしてみませんか?