エンドゲームに近づいたのか?

キーボード #2 Advent Calendar 2020 - Adventar 6日目の記事です。

昨日はTakeshi Nishioさんの自キ活1年目で出来たものと、総当たりマトリクスのご紹介(ダイジェスト版) | 勢いだけでやるページ on GitHubでした。

明日はF_YUUCHIさんの2020年にやったこと/できなかったこと&これからの話 - ゆーちログです。

2020年の自作キーボード活動

2019年、自作キーボードについては、いろいろやりつくした感があったけれど、こうやってまとめてみると、まったくやりつくしてなかったと言わざるをえない。 今年もキーレイアウト遊びをふくめていろいろ試してみた。 2020年は、エンドゲームに近づいたのか?

今年作ったキーボード

  • Caravelle

積んでいるキーボード

  • SPACE65:CyberVoyager
  • NumATTACK16

設計したキーボード

  • X68 Treadstone配列風の68キー一体型
  • Gullwing エルゴノミック配列一体型BLEキーボード
  • 742BLE Ortholinear7x4分割BLEキーボード
  • 742 Ortholinear7x4分割キーボード

配列

742キーボード

さて、アドカレ記事の本題として742キーボードの設計制作過程を5ステップに分けて振り返ってみたいと思います。 7行4列で左右2あるので、プロジェクト名を742と名付けてそのまま今に至ります。

Phase 1 Plan and Define Program

2018年に自キ入門してから、 いろいろな配列を試してみて、 Ortholinearが自分に一番あうことは、だいたいわかってきました。 自作キーボードらしいcolumn staggeredも最初は大好きでしたが、 どのキーも満遍なく押しやすい、キー位置を把握しやすく、アルペジオしやすいのはOrtholinearだと思います。 一方、一体型のOrtholinearは手が意外と窮屈で、Ortholinearなら左右分割が ベストだと思っています。

キー数は40%でもなんとかはなるのですが、もうすこし多い50キーくらいあると安心というのが、今の感覚です。 これまで、Ortholinearは何個も作りましたが、親指1Uは指が迷う、押し間違えることが多かったので、2Uにしたら非常に安定しました。 親指2Uが、今年最大の発見かもしれません。

2018年時点で、HelixやErgo42というほぼ自分のエンドゲームに近いキーボードがあったのですが、 それに気づくだけの知識と経験を得るのに2年かかったということでしょう。 沼は深いです。

実はCaravelleをベースに、いきなり742のBLE版を最初につくって、これはエンドゲームか、と思ったのですが、 BLEは複数端末とのペアリング切り替えが安定しなかったし、最初は快調だったのに、数か月すると動作も安定しなくなってきました。 QMK薙刀式も、nrf用QMKで動作するには、それなりに変更が必要で、機能に制限もあり、有線版と同時にメンテしていくのは得策ではないと思いました。 私にはBLEは難易度が高すぎたようです。 そこで、この有線版742キーボードをつくります。 チップを全部PCBに実装するのはあこがれますが、BLEで苦労したので、今回はPro Microでかたくいきます。 Pro MicroやケーブルのレイアウトはErgo42を踏襲させていただきました。

英字配列は自作のColevrak配列です。 これはキーキャップにColevrakキットという、Dvorak配列とColemak配列の両方に対応できるキーキャップがありますが、 そのキーキャップと標準のQWERTYキットの範囲でできる英語専用の配列を目指しています。 配列屋さんからすると、そんなしばり意味ないと思いますが、 自キ勢のこだわりとして導入してみました。

かな配列は、もちろん、QMK薙刀式かな入力を搭載します。 今回はじめてOLEDを載せてみました。 QMK薙刀式はキーボード内で、英字入力とかなと入力のモードを切り替えるので、ここには入力モードの表示をやろうと思っていました。

だいたい仕様がきまりました。

Phase 2 Product Design and Development

設計に入ります。

ケースとプレートは3Dプリンタでつくるのが安くて手っ取り早いので、最近の定番です。 3D CADとの親和性は高いし、 すばやく試行錯誤でき、自宅で作れるメリットは大きいです。 3Dプリンターでつくるプレートもやわらかくて好きです。 Ortholinearなんでキーレイアウトの設計はほぼなしです。 Column Staggeredなんかだと、KLEで悩むんですが。

各部品のレイアウトが決まったら、最初にKiCADでPCBの設計に入ります。 この段階でケースの2Dレイアウトはおおむねやっておきます。

f:id:eswai:20201130061459p:plain

そして、KiCADでPCB設計、KiCADからSTEP形式でPCBをエクスポート、Fusion360へインポートしてケースを設計し、不具合をまたKiCADへフィードバックする、というサイクルを2、3周して設計をすすめます。 設計というのは、手戻りなく一発で決めよう、と思わないほうがいいと思っています。 CADは清書ツールじゃなくて、思考ツールですから。 さらに3Dプリンタモックアップを作成し、実際にキースイッチやキーキャップもつけてみて、レイアウトやデザインの確認をします。

f:id:eswai:20201130010651p:plain

OLEDはケースと隙間なく取り付けたかったので、ケースのパネルにはめ込んでから、取り付けるようにしました。

f:id:eswai:20201130010702p:plain

だいたい納得できたら、PCBをオーダーするタイミングです。 PCBは安くて速いJLCPCBを使いました。 1週間から10日くらいで到着するので、文句なしです。 PCBを待つ間に、もう1回モックアップをつくって寸法を調整しました。

薙刀式ロゴについては作者の大岡さんに使用許可をいただきました。権利は大岡さんに帰属します。 動画では英数と漢字で表示していましたが、直感的でないので、その後ABCと表示するように変更しました。

Phase 3 Process Design and Development

製造プロセスの設計も大切です。

PCBは上述のように外注しますので、プロセスというと3Dプリンタでケースを作るのと、はんだ付け、組み立てが、自宅製造プロセスです。

特に組み立てできるのかは、よく考えておかないといけません。 OLEDを先にPCBに取り付けると、ケースにひっかかって組み込めないこととがわかったので、 OLEDは最後にとりつけるように設計しなおしました。 おかげで、上記のようにOLEDをケースにピッタリつけることもできました。

ケースには60mmくらい橋渡しになる形状があり、3Dプリンタでサポートが必要な形状ですが、 サポート除去はめんどうですし、除去跡も美しくありません。 やってみると空中ブリッジ印刷で問題なくできたので、最終的にサポートはまったく不要でした。 ここは個人的に満足度の高いポイントです。

3DプリントケースのTipsとして、ケース底面の角などアンダーになるところは角Rではなく面取り、面取りは45度よりすこし大きめの角度にするときれいに印刷できます。 ねじ穴はインサートをはんだごてでいれるのが一般的ですが、最近はねじでセルフタッピングしてます。 外形2mmの六角形の穴をあけておけばM2ねじがいい感じで入ります。 頻繁につけ外ししないから、これでいいや、という感じです。

f:id:eswai:20201130010655p:plain

Phase 4 Product and Process Validation

実際に作って動作検証します。

PCB待ちのあいだにケースを3Dプリントします。 左右1セットの印刷に12時間くらいかかりました。

実際に組み立ててみると、モックアップまで作っているので大きな間違いはなかったのですが、OLEDの表示範囲が上下対称ではなかったので、左右対称の窓をあけると表示がきれてしまうことがわかりました。

OLEDの表示はすこし苦労しました。 だいたいglcdfont.cの一部にロゴをいれて、文字列としてロゴを表示するというのが一般的なようですが、同じようにやっても、うまくいったりいかなかったり。

キースイッチはKailh Box Silent Pinkを使ってみました。 がたつきが少なく、標準で比較的軽いのでこれも好きです。 スペース、エンター、レイヤーキーなど同時押しするキーは、25gに交換しました。

2Uキーにはスタビをつけてみましたが、25gのスプリングだとスタビが重くてキーが持ち上がりませんでした。 これは失敗。

Phase 5 Feedback, Assessment and Corrective Action

問題の修正にうつります。

OLEDの表示位置問題ですが、本来はPCBを直したいところですが、ケースを非対称に変更して、とりあえず修正しました。 3Dプリンターなので、不具合はすぐに直せます。 CADで悩むより、つくって試すほうが早い時もありますね。

OLEDの表示は、すこし富豪的ですが、画面サイズとおなじ128x32ドットの画像を3枚(かな、ABC、薙刀式ロゴ)用意して、 oled_write_raw_P関数で表示するというのが一番シンプルで思い通りに動作しました。

スタビはなしでつかうことにしました。 そもそもスプリングが軽いので、スタビなしでも問題はないんです。

成果物をこちらにおいておきます。

f:id:eswai:20201202220011j:plain

まとめ

ことしも自作キーボードをエンジョイしました。 しばらく742で満足できそうな気がします。 これはハード面でも、ソフト面でも、エンドゲームに近づいたのではないかという気もしています。 しかし、だいたい頂上が見えてからがつらいのは、ご存じのとおりです。 2021年も、また一歩エンドゲームにちかづけるように精進したいと思います。

最後に、本記事はもちろん742キーボードと薙刀式で書きました。

f:id:eswai:20201203202542j:plain

本家DvorakJ薙刀式で後置シフトを有効にする

新JISの定義をみてやったらできたのでメモしておきます。 なぜこれで後置シフトできるのかは、理解できていません。 後置シフトと認識される時間はかなり短いようです。 親指シフトになれていて、前置きシフトになれないとお悩みの方はお試しください。 もちろん、後置シフトが有効になるとロールオーバーはやりにくくなるので、ご注意ください。

29行目あたりのシフトの定義を変更します。

/* シフトキー */
{S}   | +space

99行目あたりに以下を追加します。

({S}{S}[
{!}|@|{#}|$|%    |{^}  |&        |* |( |) |_ |{+}|@@@|
  |ね|り|め|+{←}|+{→}|さ       |よ|え|ゆ|『|』|
せ|ぬ|に|ま|ち   |や   |の       |も|わ|つ|" |~ |
ほ|ひ|を|、|み   |お   |。{Enter}|む|ふ|れ|!|
{Space} |
]

2020年版QMKで自作キーボードを薙刀式へ拡張する

昨年薙刀式を自作キーボードに導入する方法を記載しましたが、その後だいぶ変更されているので、最新版に基づいて書き直してみました。よりシンプルになりましたが、相変わらずkeymapを自分で編集できる人向けです。親指シフトは更新していませんし、より優れた実装があるので、そちらをお使いください。

github.com

追記

OS切り替えにも対応した最終形V13uを作りました。移植方法はほとんど同じです。 github.com

まずnaginata_v13.cとnaginata.hを自分のキーマップのあるフォルダにコピーします。

修正する箇所を説明していきます。基本的には// 薙刀式で囲まれた部分を自分のconfig.h、keymap.c、rules.mkに追加していきます。

rules.mk

naginata_v13.cがコンパイル対象になるようにrules.mkにSRC +=naginata_v13.cを追加します。 また編集モードを使うにはUNICODE_ENABLEも有効にしてください。コンボは薙刀式オンオフでは使わなくなりました。 ファームウェアサイズがオーバーしてしまう場合はEXTRAFLAGS += -fltoをつけると最適化されてサイズが小さくなるので試してみてください。

UNICODE_ENABLE = yes
SRC +=    naginata_v13.c
EXTRAFLAGS += -flto
config.h

config.h の// 薙刀式で囲まれた部分を自分のconfig.cに追加します。OS(WindowsMacLinux)に応じてコメントの有効無効を切り替えてください。

#define NAGINATA_TATEGAKI
// #define NAGINATA_YOKOGAKI

#define NAGINATA_EDIT_WIN // JP106
#define UNICODE_SELECTED_MODES UC_WINC

// #define NAGINATA_EDIT_MAC // US101
// Macはunicode入力を使わない
// #define MAC_LIVE_CONVERSION // Macでライブ変換をオンにしている場合

// #define NAGINATA_EDIT_LINUX
// #define UNICODE_SELECTED_MODES UC_LNX

// #define NAGINATA_KOUCHI_SHIFT // シフトを後置でも有効にする
keymap.c

ここからはkeymap.cを編集していきます。同様にconfig.hの// 薙刀式で囲まれた部分を適切な位置にコピペしていきますが、自分のキーボードに合わせた編集が必要です。

ヘッダをインクルードして薙刀式のキーレイアウトを定義するキーを導入します。

#include "naginata.h"
NGKEYS naginata_keys;

薙刀式入力モードがオンの時、NAGINATAレイヤーに切り替わります。NAGINATAレイヤーはデフォルトレイヤーとLOWER, RAISEなどのレイヤーの間に作っておけば、かな入力中もこれらのレイヤーを使えます。

enum keymap_layers {
  _QWERTY,
// 薙刀式
  _NAGINATA, // 薙刀式入力レイヤー
// 薙刀式
  _LOWER,
  _RAISE,
};

薙刀式用のキーを追加したので、独自のキーはSAFE_RANGEではなくNG_SAFE_RANGEから開始してください。

enum custom_keycodes {
  EISU = NG_SAFE_RANGE,
  KANA2,
  LCTOGL, // Macのライブ変換対応オンオフ
};

NAGINATAレイヤーを定義します。通常のKCなんとかと言うキーコードではなく、薙刀式入力で使うキーにはNG_で始まるキーコードを使います。ここではデフォルトレイヤーにかかわらず、QWERTYでキー配置を定義してください。KCコードを使えば、かなに変換されることなく入力されるので、例えばKC_SLSHとNG_SLSHを同じレイヤーに置いて、記号入力とかな入力を使い分けることが可能です。

  [_NAGINATA] = LAYOUT(
    _______,NG_Q   ,NG_W   ,NG_E   ,NG_R   ,NG_T   ,                NG_Y   ,NG_U   ,NG_I   ,NG_O   ,NG_P   ,_______, \
    _______,NG_A   ,NG_S   ,NG_D   ,NG_F   ,NG_G   ,                NG_H   ,NG_J   ,NG_K   ,NG_L   ,NG_SCLN,_______, \
    _______,NG_Z   ,NG_X   ,NG_C   ,NG_V   ,NG_B   ,                NG_N   ,NG_M   ,NG_COMM,NG_DOT ,NG_SLSH,_______, \
                                    _______,NG_SHFT,_______,_______,NG_SHFT,_______
  ),

初期設定として、_NAGINATAレイヤーが薙刀式のためのレイヤーであることを設定します。薙刀式を有効にするキー、無効にするキーもここで定義します。 QWERTYならそのまま、DVORAKやCOLEMAKならそれに応じて変更してください。

void matrix_init_user(void) {
  // 薙刀式
  uint16_t ngonkeys[] = {KC_H, KC_J};
  uint16_t ngoffkeys[] = {KC_F, KC_G};
  set_naginata(_NAGINATA, ngonkeys, ngoffkeys);
  // 薙刀式
}

キー一発でかな入力をオンオフしたければ、キーを定義してnaginata_onまたはnaginata_offを呼び出してください。なくても可。

    case EISU:
      if (record->event.pressed) {
        // 薙刀式
        naginata_off();
        // 薙刀式
      }
      return false;
      break;
    case KANA2:
      if (record->event.pressed) {
        // 薙刀式
        naginata_on();
        // 薙刀式
      }
      return false;
      break;

薙刀式の変換処理はprocess_record_user関数で行なっています。この関数はキーが押された時と、キーを離した時に呼び出されます。ここでnaginata_v13.c の関数を呼び出しています。process record user関数の最後、return trueの前に追加してください。関数がない場合は、追加してください。

  // 薙刀式
    if (!process_naginata(keycode, record))
      return false;
  // 薙刀式

  return true;

OLED表示に対応しました。OLED_DRIVER_ENABLEがyesの場合は、以下が有効になり、入力モードや薙刀式ロゴが表示されます。

// 薙刀式 OLED表示
#ifdef OLED_DRIVER_ENABLE
以下省略

f:id:eswai:20201128224743j:plain
OLED

マツコの知らない世界

祝、自作キーボードの立役者ぺかそさん、びあっこさんのテレビ初出場。

番組中で「マツコの知らない世界は毎週火曜日よる8時57分から放送中」をタイプすると、左手23回、右手42回になるという。 これは他の配列も試してみるしかない。

このような短い文章で、配列の比較をするのは、それぞれの配列の特徴を正確に表しているとは言えないかもしれない。 あくまでテレビの内容の延長ということで、ご理解ください。

まず、例文をかな文字列に変換すると「まつこのしらないせかいはまいしゅうかようびよる8じ57ふんからほうそうちゅう」で38文字になる。 ローマ字入力すると「matukonosiranaisekaihamaishuukayoubiyoru8ji57funkarahousouchuu」で62打鍵になると思うのだが、ぺかそさんはsiをshiとか入力するのだろうか。

左右打鍵の比率はQWERTYほど悪いものはない。QWERTYローマ字入力が悪すぎるだけである。

押したキーの数を比較すると、ローマ字入力の62キーに対して、単打入力が多いJISかなは42キーですむが、キーが広範囲に散らばり、ホームポジションでの打鍵は19%しかない。 飛鳥、新下駄、薙刀式などの名高いかな配列は同レベルの47, 48キー。ホームポジションでの打鍵は60%前後で、特に飛鳥は77%と際立っている。

同時押しを1アクションと数えると、飛鳥や親指シフトは文字数と同じ38アクションで入力できる。 新下駄、薙刀式は拗音拡張があるので、しゅ、ちゅ、を1アクションで入力でき、合計で36アクションとカナ文字数よりもすくない数になる。 音の数(モーラ)と同じ数で、入力が文字と直結する大きな利点である。 JISかな、新JISは濁点が別なので少し多め。

EucalynやけいならべはQWERTYローマ字に比べれば大幅に改善しているが、 ローマ字入力に変わりはないため、カナ入力のように打鍵数は減っていない。 親指シフトも飛鳥、新下駄、薙刀式らと比べると、ベストとは言えないのは各所で語られる通り。

たかだか38文字の入力であるが、評判通りの結果になっているのではないだろうか。

配列 左手 右手 合計 アクション数 ホームポジション
QWERTY 22 40 62 62 31%
Eucalyn 34 28 62 62 55%
けいならべ 23 35 58 58 50%
新JIS 28 21 49 40 63%
JISかな 24 18 42 40 19%
親指シフト 22 27 49 38 55%
飛鳥 21 27 48 38 77%
新下駄 23 25 48 36 63%
薙刀 20 27 47 36 57%

USキーボードをJIS設定で使う

解決する課題

  • US配列のキーキャップ通りに入力したい
  • 変換、無変換キーも使いたい

自作キーボードの悩みの一つに、キーキャップはUS配列だが、OSは日本語配列と認識するため、キーキャップの表示通りに入力できない、というのがある。

OSの設定をUSキーボードにすればいい、と思うかもしれないが、そうすると変換、無変換キーコードが認識されないという別の問題が生じる。 IMEオンオフのために、この2キーは生かしたい。

また、#include "keymap_jp.h"することで、JP_なんとかキーコードを使ってキーマップをつくれば、単押しのキー入力はキーキャップと入力が一致するものの、シフトキーを押しながら入力する記号が一致しない。

私は、シフトをレイヤーキーにして、シフトキーをおして入力する文字をそのレイヤーに定義しており、だいたいは問題なく使えるが、シフトキーはレイヤー切り替えキーでありシフトキーではないため、単押しでシフトキーとしては機能しない。

解決策

github.com

キー入力のたびに、キーコードを変換して送り出す。 シフトキーを押しているかどうかと、変換後の文字がシフトキーを押して出力するキーかどうかは一致しないことがあるため、その点も含めてキー操作を変換する必要がある。 キーマップはKC_キーコードのまま定義することができる。

使い方はtwpair_on_jis.c, twpair_on_jis.hをコピーして、以下の3ヶ所を修正する。

rules.mkに追加

SRC +=  twpair_on_jis.c

keymap.cに以下を追加

#include "twpair_on_jis.h"
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  if (!twpair_on_jis(keycode, record))
    return false;

  return true;
}

性能比較

メインマシンの性能がどれくらいパワーアップしたのか確認しておく。参考に買ったかもしれないiMacもいれて。

CPU

まずはCPU 、これは自分で計測したのではなくデータベースの値を適当に持ってきて比較。7年たってざっくり性能は2倍にしかなっていない。iMacに踏み切れなかったのは、ベンチマークをみると大して性能上がってない、という理由だったので、2倍には満足しておく。仮にRyzen 5 2600だったらiMac並みだったようなので、3600のシングルコアは満足できる。

Machine CPU Geekbench 5 Single-Core Geekbench 5 Multi-Core UserBenchmark
MacBook Pro (15-inch Retina Late 2013) Core i7-4750HQ 4 cores, 8 threads 745 3109 51.2%
7万円台PC Ryzen 5 3600 6 cores, 12 threads 1200 6485 87.7%
参考iMac (27-inch Retina Early 2019) Intel Core i5-8500 6 cores 996 4719 80.9%

GPU

GPUはさすがに大躍進。統合GPUなんで比較にはならない。iMacは同じRadeon、上位モデルということで少し上。

Machine GPU UserBenchmark
MacBook Pro (15-inch Retina Late 2013) Intel Iris Pro Graphics 5200 4.86%
7万円台PC Radeon RX580 8GB 56.7%
参考iMac (27-inch Retina Early 2019) Radeon Pro 570X 4GB 48.5% (RX570)

Monitor

さすが、Macはかたくなに200ppi以上を維持していて、同等のモニターは入手困難だ。

Machine Size PPI
MacBook Pro (15-inch Retina Late 2013) 15.4inch, 2880x1800 220ppi
7万円台PC DELL UP2720Q 27inch, 3840 × 2160 163ppi
参考iMac (27-inch Retina Early 2019) 27inch, 5120 x 2880 218ppi

7万円代PC

某5万円代PCの企画にのせられて、どうしてもやってみたくなり購入してしまったので、メモ。スーツケースに入れて持ち帰らないといけないので、ケースなし。Ryzen 5 2600は迷っているうちに売り切れたので、3600にアップグレードした。ここにWindowsを追加して9万円と少しと言うのがトータルの出費。主な用途はFusion 360Blender、KiCAD、3Dプリンタのスライサーなど。 自宅に帰ったら、ケースとモニターを買う予定。モニターは悩みそう。

思い起こせばiMac 27inchを買おう、買おうと思っていたが、これに変化したかんじ。随分コスパがいい感じだが、その分モニターはいいのを買わないと、Retina慣れした目には期待はずれになりかねない。