フューチャー技術ブログ

最高の持ち歩きキーボード考

フューチャー夏の自由研究連載2021の3日目です。

はじめに

はじめまして。TIGの大野です。2021年4月新卒入社です。

夏の自由研究連載の2日目「Sesame3にICカード施錠/解錠機能を実装してみた with Golang & Python」を投稿された宮永さんの同期です。

現在所属するプロジェクトでの私の主な業務の1つは、お客様先へ出張して会議に出席し、議事録を取ることです。せっかくなら、出張先でもお気に入りのキーボードで楽しく議事録を取りたいですよね。

そこで、この記事では、出張のお供にぴったりな「最高の持ち歩きキーボード」を考察・製作していきたいと思います!

設計方針

製作を始める前に、まずは「最高の持ち歩きキーボード」に必要な条件を整理してみます。

携帯性

やはり「持ち歩き」キーボードですから、携帯性は不可欠でしょう。具体的には、以下のような条件が考えられます。

  • コンパクトであること
    最低でも、A4サイズの鞄にすっぽり入るくらいのサイズ感でないと論外です。分割キーボードという選択肢もありますが、左右を接続するTRRSケーブルを持ち歩くのが億劫だったため、今回は一枚板の60%キーボードを採用します。本当は40%キーボードに挑戦しようかと思ったのですが、議事録を取るという目的がある以上、数字キーは欲しいなと思い、諦めました……。
  • 軽いこと
    あんまり重たいと持ち歩く気をなくしてしまいます。かといって、あまりに軽いと打鍵の衝撃でキーボードが動いてしまうので、いい塩梅の重さが必要です。感覚としては、500mlペットボトル1本分=約500gくらいの重さだと良いかなと思っています。
  • 頑丈であること
    持ち運ぶものですから、気軽に鞄に放り込めるような頑丈さもほしいところです。わざわざキーボード用の外袋を用意するのは面倒なので、キーボード自体に蓋があるとなお良いです。

ちなみに、分割キーボードのビルドに関しては、過去に「キーボードを組み立ててみた話」という記事が公開されています。キーボードの分割にご興味のある方は、ぜひご覧ください!

静音性

持ち歩いて使う以上、必然的に人のいる場で使う機会が多くなることが予想されます。真面目な会議をしている場で、私の打鍵音が響き渡る……なんて事態は避けたいので、ある程度の静音性も必須です。

目安としては、ノートPC付属のキーボード以下くらいの静音性は欲しいところです。

Coolさ

これが一番大事です。
今回のコンセプトはずばり、どこに出しても恥ずかしくない、「ナチュラル&ボタニカルな大人のキーボード」です。疲れたときにふと手元を見るとふわりと癒やしてくれるような、目にも心にも優しいキーボードを目指します。

部品選定

前項で決めた設計方針に基づいて、パーツを決めていきます。パーツのほとんどは、遊舎工房KBDFANSで購入しました。

キーボードを作るのに必要なパーツは、大きく以下のものがあります。

キーボードパーツ

(1) ケース
PCBを収めるケースです。PCBの規格にあったものを選びます。一番外側の、見た目に大きく関わるパーツの1つです。今回は、軽くて丈夫、おまけに蓋までついていて持ち歩きにぴったりなウォールナット製のケースを採用します。また、打鍵時にケース内で音が反響してしまうのを緩和するスポンジも追加します。

(2)プレート
キースイッチをはめ込むための穴が空いたプレートです。キースイッチのグラつきを抑えます。これも、PCBの規格にあったものを選びます。真鍮製の方が音が良いという意見がありますが、お財布事情によりアルミ製です。

(3)PCB(プリント基板)&コントローラ
キーボードの核となる、回路を収めた基板です。キースイッチ、USBインタフェース、Nキーロールオーバー時の回路の誤動作を防止するダイオード、キーボードを光らせるLED、そしてPCと通信するためのコントローラなどを実装します。今回は、最初からキースイッチ以外のパーツがすべて実装されているDZ60というPCBを使用します。実装されているUSBインタフェースがType-CなのもGoodです。

(4)キースイッチ
キーボードの主役、キースイッチです。私は普段、FEKER Like Holy Pandaというタクタイル軸を愛用しているのですが、この軸の魅力はなんといっても、ハイヒールで石畳を歩くときのようなコツコツとした硬質な打鍵音です。自宅で使う分には大変良いのですが、会議の場では顰蹙を買うこと間違いなしです。そこで、今回はNovelKeys Cream Switchというリニア軸に挑戦してみます。サクサクとした打鍵感、ブレのない軸、そしてこの優しいクリーム色がお気に入りです。

(5)キーキャップ
キースイッチに被せるキャップです。ケース同様、見た目に大きく関わるパーツの1つです。また、指ざわりや打鍵音に影響するため、その材質も重要なポイントです。今回は、静音性を意識して比較的打鍵音が低めのPBT素材のものを選びました。PBT特有のざらざらとした質感が高級感を演出します。

(6)スタビライザー
スペースキーやエンターキーなど、長いキーを支えるためのパーツです。作成したいキー配列に合わせて、必要数用意します。PCBにネジ止めするタイプと爪で引っ掛けるタイプがあり、前者のほうが静音性が高いのですが、お財布と相談して今回は爪で引っ掛けるタイプのものを使用します。その代わり、スタビライザーとPCBが接する面に布テープを貼ることで反響音を緩和してあげます。

組み立て

パーツを集め終えたら、あとはPCBにパーツをはんだづけするのみです!

と言いたいのですが、まずはキースイッチとスタビライザーをルブしていきます。「ルブ」とは、パーツに潤滑油を塗ることで、これをするとしないで、打鍵のスムーズさや静音性が大きく変わってきます。80個ほどのパーツを一つひとつ分解して潤滑油を塗っていく大変な作業ですが、頑張って塗ります。

今回は、スプリングにKrytox GPL 105を、ステムとボトムハウジング(写真中クリーム色のパーツ)にKrytox GPL 205 Grade 0を使用しました。

ステムとボトムハウジング

ルブし終えたら、いよいよはんだづけするのみです。

多様なキー配列を実現するため、PCBにはたくさんのキースイッチ用スルーホールが空いています。自分の作りたい配列をよく確認し、どこにはんだづけするか、間違えないように気をつけて実装していきます。

はんだ付け

はんだづけを終えたら残りのパーツを取り付けていき、組み立て完了です!
ぱっきり割れたスペースバーがキュートです。

完成したキーボード

ファームウェア作成

DZ60の場合は、最初からファームウェアが書き込まれているため、このままでもキーボードとして使えます。しかし、自作キーボードの醍醐味はやはり自分でキーマップをカスタムすることです。ということで、これからオリジナルのファームウェアを作成していきます。

とはいえ、1からファームウェアを自作するのはとても大変です。そこで、自作キーボードでは、QMK Firmwareというオープンソースファームウェアの利用が一般的です。

頒布されている自作キーボードのDIYキットやPCBの多くは、QMKのGitリポジトリ上で専用のファームウェアが公開されています。DZ60もQMK上でファームウェアが公開されているため、今回はそちらを利用します。

DZ60のファームウェア構成は以下のようになっています。

qmk_firmware/keyboards/dz60/
config.h
dz60.c
dz60.h
info.json
readme.md
rules.mk
keymaps
└─ <キーマップ名>
└─ keymap.c

ピンの割当といったkeymaps以外の共通定義はそのまますべてお借りし、keymapsにオリジナルのキーマップ定義を追加するという方法で、ファームウェアを作成していきます。

実際に作成したキーマップのkurumiがこちらです!

keymaps/kurumi/keymap.c
#include QMK_KEYBOARD_H

/* keymap layer name */
enum keymap_layer {
_BL,
_FL,
};

/* custom keycode name */
enum custom_keycoads{
M_HNZN,
};

#define ______ KC_TRNS

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

/* BASE Layer
* ,-----------------------------------------------------------------------------------------.
* | Esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bkspc |
* |-----------------------------------------------------------------------------------------+
* | Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ |
* |-----------------------------------------------------------------------------------------+
* | HNZN | A | S | D | F | G | H | J | K | L | ; | ' | Enter |
* |-----------------------------------------------------------------------------------------+
* | Shift | Z | X | C | V | B | N | M | , | . | / | ` ~ | U | Del |
* |-----------------------------------------------------------------------------------------+
* | Ctrl | Win | Alt | Space | _FN | Space | Alt | Ctrl | L | D | R |
* `-----------------------------------------------------------------------------------------'
*/

[_BL] = LAYOUT_directional(
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, ______, KC_BSPC,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
M_HNZN, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_GRV, KC_UP, KC_DEL,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO(_FL), KC_SPC, KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RIGHT
),

/* FN Layer
* ,-----------------------------------------------------------------------------------------.
* |Reset| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | |
* |-----------------------------------------------------------------------------------------+
* | | | | Esc | | | | | Ins | | Psc | | | |
* |-----------------------------------------------------------------------------------------+
* | | App | | Del | | | L | D | U | R | | | |
* |-----------------------------------------------------------------------------------------+
* | | | | | | | HM | End | | | | | | |
* |-----------------------------------------------------------------------------------------+
* | Ctrl | Win | Alt | | _BS | | Alt | Ctrl | | | |
* `-----------------------------------------------------------------------------------------'
*/

[_FL] = LAYOUT_directional(
RESET, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, ______, ______,
______, ______, ______, KC_ESC, ______, ______, ______, ______, KC_INS, ______, KC_PSCR, ______, ______, ______,
______, KC_APP, ______, KC_DEL, ______, ______, KC_LEFT, KC_DOWN, KC_UP, KC_RIGHT,______, ______, ______,
______, ______, ______, ______, ______, ______, KC_HOME, KC_END, ______, ______, ______, ______, ______, ______,
KC_LCTL, KC_LGUI, KC_LALT, ______, ______, ______, KC_RALT, KC_RCTL, ______, ______, ______
),
};

/* result of process_record_user */
#define PROCESS_OVERRIDE_BEHAVIOR (false)
#define PROCESS_USUAL_BEHAVIOR (true)

bool process_record_user(uint16_t keycode, keyrecord_t *record) {

switch (keycode) {

case M_HNZN: {
if(record->event.pressed){
SEND_STRING(SS_LALT("`"));
}
return PROCESS_OVERRIDE_BEHAVIOR;
} break;

default: {
} break;

}

return PROCESS_USUAL_BEHAVIOR;

}

キーマップ作成に際し、工夫したポイントは次の2つです。

親指の位置にレイヤーキー

なにせ60%キーボード、キーの数が足りないので、足りないキーを仮想的に補うレイヤー機能を使う必要があります。今回の場合は、MO(_FL)キーを用意し、このキーを押している間だけ入力レイヤーがファンクションレイヤーに切り替わるという手法を取りました。

ここで重要なのが、どのキーにMO(_FL)キーを割り当てるかという点です。キー割り当てが比較的空いているのはベースレイヤーの右下のあたりですが、レイヤー切り替えのたびに右手の小指が攣りそうになるので却下です。

そこで、今回はスペースバーを真っ2つに割り、ど真ん中にレイヤーキーを配置してみました。ホームポジションに指を置いた際、ちょうど右手親指が右スペースキーとレイヤーキーの間に来るようになっており、自然なキータッチでレイヤーキーを押下できます。もちろん左手親指からもすぐ近くなので、押したいキーに合わせて押下する手を変えることも簡単です。

普通のキー配列ではサボりがちな親指をうまく有効活用できたかなと思います。

US配列で半角/全角キーを再現

US配列の大きな欠点は、半角/全角キーがないことです。Alt+~キーで半角/全角を切り替えられますが、頻繁に使う半角/全角切り替えを1キーでできないのは、耐えがたいことです。

そこで、こちらの記事を参考にM_HNZNというマクロを作成し、CapsLockキーに割り当てることで、無事1タップでの半角/全角切り替えを実現しました。マクロは、キー入力検知時に毎回呼び出される関数process_record_user内で以下のように定義しています。

keymaps/kurumi/keymap.c
case M_HNZN: {
if(record->event.pressed){
SEND_STRING(SS_LALT("`"));
}
return PROCESS_OVERRIDE_BEHAVIOR;
} break;

M_HNZNキー押下時、元々定義されたキーコードの送信をキャンセルし、左Alt+~キーコードを送信するという処理です。今回はごくシンプルな構成ですが、やろうと思えばキーのタップや長押しなど、様々なキー入力の状態に合わせてマクロを組むことができます。時間を見つけて色々試して見ようと思います。

「要らない子」と言われて久しいCapsLockキーの救済も兼ねた一石二鳥のマクロでした。

ファームウェア書き込み

いよいよファームウェアを書き込んでいきます。

なお、QMK ProjectにはQMK ConfiguratorQMK Toolboxといったファームウェア作成・書き込みのための便利なツールも存在するのですが、今回はMSYS2上に構築したQMK環境でビルドしていきます。環境構築の詳細は公式ドキュメントをご参照ください(なお、以下のビルド手順は、2021/08/25時点の公式ドキュメントで紹介されている手順より古いものですので、ご注意ください)。

まずはQMK Firmwareをインストールしたディレクトリまで移動し、さきほど作成したキーマップのkurumiを指定してファームウェアをコンパイルします。

make dz60:kurumi

問題なければ、hexファイルが出力されます。続いて以下のコマンドを実行し、ファームウェアを書き込みます。dfuはブートローダーの種類を指定するオプションです。DZ60に搭載されているブートローダーはatmel-dfuなので、dfuを指定しています。

make dz60:kurumi:dfu

途中でブートローダーの起動を求められるので、キーボートを接続し、リセットボタンを押下して起動します。

dfu-programmer: no device present.
ERROR: Bootloader not found. Trying again in 5s.
Bootloader Version: 0x00 (0)
Erasing flash... Success
Checking memory from 0x0 to 0x6FFF... Empty.
0% 100% Programming 0x5B80 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
0% 100% Reading 0x7000 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
Validating... Success
0x5B80 bytes written into 0x7000 bytes memory (81.70%).

このように表示されれば、書き込み成功です!

これで本当に完成です! やったー!!

使ってみて

先日初めての出張があったので、早速使ってみました。

最初に立てた設計方針に照らし合わせてキーボードを評価していきます。

  • 携帯性:★★☆☆☆
    • 縦横の大きさは許容範囲ですが、蓋付きのケースにしたことで約5cmの分厚さになってしまいました。バッグの中での主張が激しいです。
    • そこそこ重いです。量ったら、約700gでした。電車など、座っての移動であれば問題ありませんが、「持ち歩き」となると重さが気になります。
  • 静音性:★★★★☆
    • やはり静音モデルのキーボードには負けますが、十分な静音性を確保できました。打鍵音はするのですが、「コトコト」といった感じで音が低いので、会議室ではあまり目立ちません。
  • Coolさ:★★★★★
    • 見た目は大満足です! MA Profileという丸みを帯びた特徴的な形のキーキャップが、ウォールナット製のケースと相まってタイプライターのような趣を醸し出しています。
    • 実は、ケースの蓋がちょうどよいパームレストになります。機能美です。
キーボードを中心としたデスク画像

反省点もありますが、なんだかんだで愛着の湧く、良いキーボードができました。キーマップなどは、これから使っていく中でどんどん改良していきたいと思います。

最後に

せっかく作ったキーボードですが、新型コロナウィルスの感染拡大を受け、しばらく出張停止になったことでさっそく活躍機会がなくなってしまいました……。自由に歩きまわることのできる生活が早く帰ってくることを切に願うばかりです。

それまでは、ステイホームでタイピング練習を頑張ります!

フューチャー夏の自由研究連載2021、次の記事は真野さんによる「フォワードプロキシ」です。