こんにちは、びしょ〜じょです。 これはWORDIAN Advent Calendar 2018の2日目の記事です。

昨年大好評を博したWORDIAN Advent Calendarが今年もやってきました。編集部員、OBOG、または自分を編集部員だと思っている人などが記事を書きます。記事の内容はいつも通り自由。ただし、いつも通り学類長チェックは通るように努力しましょう。WORD編集部のサイト: https://www.word-ac.net/

12月2日といえば、翌3日は冴草きいちゃんの誕生日ですね!!!!!!!!!!! めでたいですね。 何度でも言うぞ。


さて今回はWORD部員協賛のもと、Lily58というキーボードを作りました。

※先行販売としての販売は終了致しました。以下のページにて後継モデルのLily58 Proの販売をしています。https://liliums.booth.pm/items/1175324 この商品ははんだ付けを必要とする組み立て式のキットです。 先行販売のベータ版のため予期せぬ不具合などが発生する可能性があります。また、今後販売予定の正式版と仕様が変更になる箇所が出る場合があります。御理解の上ご購入下さい。

材料あつめ

上記のセットに加え、キースイッチとキーキャップを58個(とUSBケーブルとTRSケーブルを)揃える必要があります。

WORD編集部室には3x3で全色異なるキースイッチのサンプルがあるので、お手元が寂しくなるとつい手を動かしてしまうW部員達には重宝されている。 カチカチしまくった結果、緑軸が良いな〜と思ったので緑軸にしようとしたものの、ちょうどどこを探しても8000個から仕入れ可能みたいなものしかなかった。 仕方がないので、遊舎工房でKailhのロープロ白軸を買った。

ロープロファイルスイッチです。 赤軸:スムーズなリニア軸 茶軸:クリック感のあるタクタイル軸 白軸:カチカチ感のあるクリッキー軸 Red Pro:軽くてスムーズなリニア軸Pink:さらに軽くてスムーズなリニア軸赤軸タイプ:リニア 押下圧:約45g±10gf 動作圧:約50g±10gf ストローク:3.0mm±0.5mm 接点:1.5mm±0.5mm PCBマウント(5ピン) 型番:CPG135001D01 メーカープロダクトページ データシート赤軸茶軸タイプ:タクタイル 押下圧:約45g±15gf 動作圧:約60g±10gf ストローク:3.0mm±0.5mm 接点:1.5mm±0.5mm PCBマウント(5ピン) 型番:CPG135001D02 メーカープロダクトページ データシート茶軸白軸タイプ:クリッキー 押下圧:約50g±10gf 動作圧:約60g±10gf ストローク:3.0mm±0.5mm 接点:1.5mm±0.5mm PCBマウント(5ピン) 型番:CPG135001D03 メーカープロダクトページ データシート白軸Red Proタイプ:リニア 動作圧:約35gf ストローク:3.0mm±0.5mm 接点:1.5mm±0.5mm PCBマウント(5ピン)Pinkタイプ:リニア動作圧:約20gfストローク:3.0mm±0.5mm接点:1.5mm±0.5mmPCBマウント(5ピン)データシート     Pink

カチカチとクリック感があり、青軸のようにうるさいのでパソコンカタカタオタク演ってる感がでて良いかな〜というのが選定理由だ。

作る

3月の引越しにつき祖父からもらったり実家からパチってきた激古はんだごてを全部捨ててしまったため、部員の@rizaudo氏にはんだごてを借り、ついでに編集部室で作業をおこなう。

ビルドガイドにしたがって作っていく。

pro micro事件1

が…

ヘ タ ク ソ1

トーストによるハンダクラックは無事失敗。 部室にあったポンコツハンダ吸い取り器や、部員のハジョン氏にハンダ吸い取り線を借りるも難航。 rizaudo氏や部室を常時警備している@akkkix氏の協力のもとハンダを吸いまくるも取れる気配がない。 @NTSC_J氏にも部室にあるものよりも使えるハンダ吸い取り器を持ってきてもらい、交代しながらハンダを吸っていく。

日が変わり、そして―

およそ5時間経過し、pro microを取り出すことに成功した。 作業員がこの時間で各々バイトをして発生した金で諸々買い直したほうが黒字だし早かったね、という話をした。 たしかにこの時点で人件費が材料費を上回ってしまっている。

くぅ〜疲れましたw これにてlily58完成です! とはいかず…。

pro micro事件2

基板に全部くっつけたのでファームウェア書き込んでおわりや!! というところで片方に全然書き込めない。 オーブンで焼いたほうは特定のキー列だけ入力を受け付けたり受け付けなかったりする。

後者の問題はpro microを剥がしたときにランドが1つお亡くなりになったことに起因すると推理し、rizaudo氏がハンダを盛りまくることで導通してくれた。 謝謝茄子。

問題は前者である。 pro microを使う他の自作キーボードを作ってるブログなどを見てみると、なんかpro microを非対称(?)に付ける必要があるっぽいな…???

(作ってる時には説明なかった)pro microを取り付ける部分はたしかになんか書いてありますねぇ!!

恐怖のハンダ吸いが再び始まり―

やばい1 ピンヘッダをなんとかしようとするrizaudoとakkkix

オワッ…

仕方がないのでハードウェア的に問題ない半分を完成させた。

早速代打を注文し、激戦の翌々日に届き、ネタが割れてしまえば爆速で完成。

tips

ロープロファイルだとアクリル板を止めるネジの頭にキーキャップが当たるので、キーキャップをちょっと削る必要がある(図2)。

削る2 削ったキーキャップ

そういえば昔WORDの記事でThinkPadのキートップを無刻印にすべくヤスリで削りまくった記憶がある。 今回はカッターでゴリゴリ削ってしまっているが、コチラのほうがはるかに作業時間が短い。


ハードウェアの実装は18時間くらいかかってしまった。 ご協力大変感謝いたします。

qmk firmware

xmodmapとはなんだったのか

まずはこちらをご覧ください。

settings/settingfiles/dots/.xmodmap

例えばキーボードの3を押すと3が入力され、Shiftも一緒に押すと#が入力されたりする。 Shiftのように、一緒におすとキーの入力が変わるのを修飾キーと呼びます。 他にもCtrlも修飾キー。 そしてアクセント記号付き文字を入力するためのAltGrというキーも存在しますが、概ね皆さんが使ってるキーボードには備わってません。 xmodmapによってキーマップを変更し、AltGrが使えるようになります。

AltGrが使えるとどうなる? 修飾ない状態、Shift修飾状態、AltGr修飾状態、AltGr + Shift修飾状態と1つのキー入力で最大4状態もたせる、つまり1つのキーと2つの修飾キーによって4通りの入力をおこなうことができる

上記のキーマップでは無変換AltGrにしてhjklで←↓↑→を入力できるようにしてます。 これはVの者にとっては非常に素晴らしいですね。

困る点

X11アプリケーションなのでX Window Systemが動いてないといけない。 なのでWindowsとかXのない状況では諦めざるを得ない。

もう一つ重大な問題としては、キーコードに対するマッピングでしかないということである。 詳細はウィキピージャ見てください。 なにかアプリケーションでキー入力を受け付けるとき、文字コードではなくキーコードを受け付けている場合非常に困る。

そこでファームウェア

qmk_firmwareは名前の通りファームウェアでして、こいつを使うことでキースイッチの入力に対応するキーコードをプログラムすることができる。

keyboards/以下に様々なキーボードのいろいろが突っ込まれてて正気の沙汰ではないですね。 サブモジュールって知ってますか?

qmkにはレイヤという概念があり、上記のAltGrのような事を、レイヤを切り替えることによって実現している。 このレイヤはユーザによっていっぱい作れるので、様々なレイヤを定義、しよう。

そしてボクのキーマップはこんな感じになった。

https://github.com/Nymphium/qmk_firmware/blob/nymphium/keyboards/lily58/keymaps/nymphium/keymap.c

キーマップのレイヤごとにAAを書くというのが習慣らしい。 たしかに分かりやすい(実際の設定と一致してれば)。

/* DEFAULT
 * ,-----------------------------------------.                    ,-----------------------------------------.
 * | ESC  |   1  |   2  |   3  |   4  |   5  |                    |   6  |   7  |   8  |   9  |   0  |      |
 * |------+------+------+------+------+------|                    |------+------+------+------+------+------|
 * | Tab  |   Q  |   W  |   E  |   R  |   T  |                    |   Y  |   U  |   I  |   O  |  P   |      |
 * |------+------+------+------+------+------|                    |------+------+------+------+------+------|
 * |Enter |   A  |   S  |   D  |   F  |   G  |-------.    ,-------|   H  |   J  |   K  |   L  |Muhen |      |
 * |------+------+------+------+------+------|  Y    |    |   B   |------+------+------+------+------+------|
 * |LShift|   Z  |   X  |   C  |   V  |   B  |-------|    |-------|   N  |   M  |      |      |      |MOUSE |
 * `-----------------------------------------/       /     \      \-----------------------------------------'
 *                   |Super | LAlt |LOWER | / Space /       \ BSPC \  | Ctrl |MOUSE |Wdeflt|
 *                   |      |      |      |/       /         \      \ |      |      |      |
 *                   `----------------------------'           '------''--------------------'
 */

レイヤごとにキーコードを割り当てられる。 これはデフォルトレイヤーで次が上記のxmodmapのキーマップにおけるAltGrを押した状態になる。

プログラム3. LOWERレイヤ
/* LOWER
 * ,-----------------------------------------.                    ,-----------------------------------------.
 * |      | F1  |  F2  |  F3  |  F4  |  F5   |                    |      |  [   |   ]  | F12  |      |      |
 * |------+-----+------+------+------+-------|                    |------+------+------+------+------+------|
 * |      |  @  |  +   | ESC  |  ;   |  ^    |                    |      |  .   |  ,   | HOME | END  |      |
 * |------+-----+------+------+------+-------|                    |------+------+------+------+------+------|
 * |      |  -  |   %  |  \   |  /   |  '    |-------.    ,-------| Left | Down |  Up  |Right |Henkan|      |
 * |------+-----+------+------+------+-------|       |    |       |------+------+------+------+------+------|
 * |      | F6  |  F7  |  F8  |  F9  | F10   |-------|    |-------| F11  | PgDn | PgUp |      |      |      |
 * `-----------------------------------------/       /     \      \-----------------------------------------'
 *                   |      |      |      | /       /       \Delete\  |      |      |      |
 *                   |      |      |      |/       /         \      \ |      |      |      |
 *                   `----------------------------'           '------''--------------------'
 */

qmkはマウスのエミュレーションができる。 これはAAを用意してないんで実際の実装になっており、LAYOUTマクロに渡されているのはそれぞれキーコードに対応する。 _______は1つ前のレイヤのキーコードを参照する。

[_MOUSE] = LAYOUT( \
  _______, _______, _______, _______, _______, _______,                   _______, _______, _______, _______, _______, _______, \
  _______, _______, _______, _______, _______, _______,                   _______, _______, _______, _______, _______, _______, \
  _______, _______, _______, _______, _______, _______,                   KC_MS_L, KC_MS_D, KC_MS_U, KC_MS_R, _______, _______, \
  _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
                             KC_BTN1, KC_BTN3, KC_BTN2, WHEEL,   _______, _______, _______, _______ \
),

キー入力処理

キー入力をprocess_record_userという関数で処理することができる。 レイヤ切り替えはcustom_keycodeというenumで新しく追加したレイヤ切り替え専用のキーコードの入力をprocess_record_userで処理する(プログラム4)。

プログラム4. process_record_user
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {
    // ......

    case LOWER:
      if (record->event.pressed) {
        layer_on(_LOWER);
        update_tri_layer(_LOWER, _SHIFT, _LSHIFT);
      } else {
        layer_off(_LOWER);
        update_tri_layer(_LOWER, _SHIFT, _LSHIFT);
      }
      return false;
      break;

    case KC_LSFT:
      if (record->event.pressed) {
        register_code(KC_LSFT);

        layer_on(_SHIFT);
        update_tri_layer(_LOWER, _SHIFT, _LSHIFT);
      } else {
        layer_off(_SHIFT);
        update_tri_layer(_LOWER, _SHIFT, _LSHIFT);
        unregister_code(KC_LSFT);
      }
      return false;
      break;

    // ......

    case KC_GRV:
    case KC_EQL:
    case KC_ASTR:
      unregister_code(KC_LSFT);
      return true;
  }

  return true;
}

keycodeは文字通りキーコード、recordは入力してるときの状態を表し、record->event.pressedでキーを押下したかどうかのブールを取れる。 関数の中を見てみると、keycodeでswitchして入力内容で分岐する。

LOWERレイヤへの切り替えは、layer_on(_LOWER)layer_off(_LOWER)のあたりでおこなっている。 LOWER+Shiftの修飾では第3のレイヤ_LSHIFTになる。

KC_LSFTというキーコードがShiftにあたる。 Shift+0を押すと?が出て欲しいなど、一部Shiftによる修飾で送出される文字を変更したかったがお手軽な方法が一見してなさそうだった。 そのため、Shift用に新たにレイヤを追加した。 また一部キーはShift修飾を外さないと意図した入力がおこなわれないため、unregister_code(KC_LSFT)Shiftの修飾を取り消している。

process_record_userの戻り値は長押しキーリピートするかどうかである。

使ってみての所感

白軸カチャカチャして楽しい。 慣れるとだいぶ快適だし、Windowsでも使えるようにちょっとした工夫もしているためWindowsでも快適な入力ができる。 ウィンドウマネージャが変更できてフォントも綺麗に表示されてWSLがちゃんと動いてアレしてコレしたらWindowsでも快適に開発できそうですね!

ハードウェア的なところとしては概ね満足ですが、キーボードが格子状なのは慣れの問題なのか、なかなか打ちづらい。 あとパームレストがないと親指がキートップのエッジのせいでちょっと痛くなる。 というか上の行がちょっと打ちづらい? ともかくパームレストは遭ったほうが良いなこれは。


これでボクがArchを使ってから愛用してきた秘伝の.xmodmapをファームウェアレベルでエミュレーションできたんじゃないでしょうか。 とはいえキーボードを持ち運ぶのはだるいので、基本的には在宅ワークするときやお家でツイッタ〜するときのみ活躍します。

他にも状態のトグルなどちょっとした知見がコードに溜まってるので、qmk_firmwareを使ってなにかする人は上記のソースを見てみてください。


  1. ビルドガイドがボクの失敗を見たためかどうか、失敗したポイントについて丁寧な解説が加えられている。みなさんは私の屍を超えて失敗レスに作ることができます。