海外サイトに注文した自作キーボードキット ErgoDox を組み立てました。
未経験者にとっては はんだ付けに苦労しましたが、意外と3時間ほどで組み立てられました。
ただし、キー配列のファームウェアを作るのは大変でした。
キーコードの定数を配列にしたC言語のソースコードをコンパイルして、キーボード内のマイコンに書き込むのですが、なかなか思ったキーコードを見つけられず試行錯誤しました。
1. ErgoDoxの組み立て作業
夏ごろに届いていた ErgoDox(自作 分割キーボード) をようやく開封しました。
組み立ての作業そのものは、だいたい3時間ぐらいでできました。
大変なのは、キースイッチの「はんだ付け」。
はんだ付けは高校の授業以来で、まったく不慣れです。
しかし、それでも何とかつながるんですね。
1-1. ErgoDoxは片手単体では動かない
途中、片手分だけが完成したので、動くか試したのですが、まったく反応しません。
途中のはんだ付けが失敗して、回路を痛めたかと かなり心配しました。
約3万円が無駄になると ショックが大きいです。
それでも、そのまま作業を続けて、両手ともキーボードを完成させます。
そろったところでつないだら、ちゃんと動いたのでほっと一安心。
1-2. ガジェットの組み立ても「エンターテイメント」
ひさびさに子どもと一緒にガジェットを組み立てて、ワクワクしました。
この体験だけでも、3万円のうちの5,000円ぐらいの価値はあるかも。
1-3. 親指シフトとローマ字入力で混乱
やっと完成して、試し打ちをしているのですが、まだ全然なれませんね。
初期配列では無変換キーがなかったので、親指シフトの入力では使いにくいです。
私の場合は普段は親指シフトで打っていることもあり、とりあえずキーマップまでは手が回らず、デフォルトのまま入力しています。
職場では普通にローマ字変換しているのに異様に混乱して全然打てません。
直交するキー並びなのか、FとJに突起がないからなのか、頭がなかなか親指シフトからローマ字入力に切り替わりません。
特に、「い」と「ん」や「、」「。」のうち間違えが多発しています。
こんなに入力で混乱するのは、親指シフトを始めた時を思い出します。
2. キーマップを変更する
キーマップの変更には Cの開発環境が必要です。
続けて作業するのは、ちょっと気力が必要です。
2-1. qmkでのコンパイルはちょっと難しい
qmkでのコンパイルの仕方が、読んでたサイト情報と変わってて苦戦しましたが、なんとか納得いくところまでできました。
キーマップのコンパイルやインストールには、Linux(Ubuntu)PC を引っ張り出しました。
#include QMK_KEYBOARD_H
#include "debug.h"
#include "action_layer.h"
#include "version.h"
#define BASE 0 // default layer
#define SYMB 1 // symbols
#define MDIA 2 // media keys
#define JA_CLON KC_QUOT // : and +
#define JA_AT KC_LBRC // @ and `
#define JA_HAT KC_EQL // ^ and ~
#define JA_ENUN KC_RO // \ and _ (EN mark and UNder score)
#define JA_ENVL KC_JYEN // \ and | (EN mark and Vertical Line)
#define JA_LBRC KC_RBRC // [ and {
#define JA_RBRC KC_BSLS // ] and }
#define _______ KC_TRNS
enum custom_keycodes {
PLACEHOLDER = SAFE_RANGE, // can always be here
EPRM,
VRSN,
RGB_SLD
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
// If it accepts an argument (i.e, is a function), it doesn't need KC_.
// Otherwise, it needs KC_*
[BASE] = LAYOUT_ergodox( // layer 0 : default
// left hand
KC_GRAVE, KC_1, KC_2, KC_3, KC_4, KC_5, JA_HAT,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, JA_LBRC,
KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, JA_RBRC,
KC_LCTL, KC_LGUI, KC_LALT, MO(MDIA), KC_SPC,
/* */ KC_PGUP, LCTL(KC_C),
/* */ KC_WBAK,
/* */ KC_SPC, KC_PGDN, LCTL(KC_V),
// right hand
KC_ESC , KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
KC_DEL, KC_Y, KC_U, KC_I, KC_O, KC_P, JA_AT,
/* */ KC_H, KC_J, KC_K, KC_L, KC_SCLN, JA_CLON,
KC_BSPC, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, JA_ENUN,
/* */ KC_HENK, MO(MDIA), KC_DOWN, KC_UP, JA_ENVL,
/* */ KC_LEFT, KC_RGHT,
/* */ KC_UP,
/* */ KC_DOWN, KC_BSPC, KC_ENT
),
// SYMBOLS
[SYMB] = LAYOUT_ergodox(
// left hand
VRSN, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______,
_______,KC_EXLM,KC_AT, KC_LCBR,KC_RCBR,KC_PIPE,_______,
_______,KC_HASH,KC_DLR, KC_LPRN,KC_RPRN,KC_GRV,
_______,KC_PERC,KC_CIRC,KC_LBRC,KC_RBRC,KC_TILD,_______,
EPRM,_______,_______,_______,_______,
RGB_MOD,_______,
_______,
RGB_VAD,RGB_VAI,_______,
// right hand
_______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
_______, KC_UP, KC_7, KC_8, KC_9, KC_ASTR, KC_F12,
KC_DOWN, KC_4, KC_5, KC_6, KC_PLUS, _______,
_______, KC_AMPR, KC_1, KC_2, KC_3, KC_BSLS, _______,
_______,KC_DOT, KC_0, KC_EQL, _______,
RGB_TOG, RGB_SLD,
_______,
_______, RGB_HUD, RGB_HUI
),
// MEDIA AND MOUSE
[MDIA] = LAYOUT_ergodox(
RESET, _______, _______, _______, _______, _______, _______,
_______, _______, _______, KC_UP , _______, _______, _______,
_______, _______, KC_LEFT, KC_DOWN, KC_RGHT, _______,
_______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, KC_BTN1, KC_BTN2,
_______, _______,
_______,
_______, _______, _______,
// right hand
_______, _______, _______, _______, _______, _______, _______,
_______, _______, KC_BTN1, KC_MS_U, KC_BTN2, _______, _______,
_______, KC_MS_L, KC_MS_D, KC_MS_R, _______, KC_MPLY,
_______, _______, _______, KC_MPRV, KC_MNXT, _______, _______,
KC_VOLU, KC_VOLD, KC_MUTE, _______, _______,
_______, _______,
_______,
_______, _______, KC_WBAK
),
};
const uint16_t PROGMEM fn_actions[] = {
[1] = ACTION_LAYER_TAP_TOGGLE(SYMB) // FN1 - Momentary Layer 1 (Symbols)
};
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
{
// MACRODOWN only works in this function
switch(id) {
case 0:
if (record->event.pressed) {
SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION);
}
break;
case 1:
if (record->event.pressed) { // For resetting EEPROM
eeconfig_init();
}
break;
case 2:
if (record->event.pressed) {
return MACRO( D(LALT), T(GRAVE), U(LALT), END);
}
break;
}
return MACRO_NONE;
};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
// dynamically generate these.
case EPRM:
if (record->event.pressed) {
eeconfig_init();
}
return false;
break;
case VRSN:
if (record->event.pressed) {
SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION);
}
return false;
break;
case RGB_SLD:
if (record->event.pressed) {
#ifdef RGBLIGHT_ENABLE
rgblight_mode(1);
#endif
}
return false;
break;
}
return true;
}
// Runs just one time when the keyboard initializes.
void matrix_init_user(void) {
#ifdef RGBLIGHT_COLOR_LAYER_0
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_0);
#endif
};
// Runs constantly in the background, in a loop.
void matrix_scan_user(void) {
};
// Runs whenever there is a layer state change.
uint32_t layer_state_set_user(uint32_t state) {
ergodox_board_led_off();
ergodox_right_led_1_off();
ergodox_right_led_2_off();
ergodox_right_led_3_off();
uint8_t layer = biton32(state);
switch (layer) {
case 0:
#ifdef RGBLIGHT_COLOR_LAYER_0
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_0);
#else
#ifdef RGBLIGHT_ENABLE
rgblight_init();
#endif
#endif
break;
case 1:
ergodox_right_led_1_on();
#ifdef RGBLIGHT_COLOR_LAYER_1
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_1);
#endif
break;
case 2:
ergodox_right_led_2_on();
#ifdef RGBLIGHT_COLOR_LAYER_2
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_2);
#endif
break;
case 3:
ergodox_right_led_3_on();
#ifdef RGBLIGHT_COLOR_LAYER_3
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_3);
#endif
break;
case 4:
ergodox_right_led_1_on();
ergodox_right_led_2_on();
#ifdef RGBLIGHT_COLOR_LAYER_4
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_4);
#endif
break;
case 5:
ergodox_right_led_1_on();
ergodox_right_led_3_on();
#ifdef RGBLIGHT_COLOR_LAYER_5
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_5);
#endif
break;
case 6:
ergodox_right_led_2_on();
ergodox_right_led_3_on();
#ifdef RGBLIGHT_COLOR_LAYER_6
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_6);
#endif
break;
case 7:
ergodox_right_led_1_on();
ergodox_right_led_2_on();
ergodox_right_led_3_on();
#ifdef RGBLIGHT_COLOR_LAYER_7
rgblight_setrgb(RGBLIGHT_COLOR_LAYER_7);
#endif
break;
default:
break;
}
return state;
};
ErgoDoxのファームウェアの書換えできました。
2-2. ErgoDoxで「半角・全角」キーのキーコード
keymap.cは、ergodox_ezのフォルダ内でコンパイルしました。
一番の難関は「半角・全角」キーでキーコードをいくつか試してやっと希望する動作に行きつきました。
私の環境では Windowsでも LinuxでもErgoDoxを「JISキーボード」として認識していたので、なかなかうまくいかなかったようです。
ダメだったキーコードは
KC_LANG1, KC_LANG2
うまくいったのは
KC_GRAVE
USキーボードの「`(Grave)」は スキャンコード の1番で、これが JISキーボードでの半角全角キーに相当するようです。
なので、ErgoDoxのキーコードを探すには、
まず JISキーボードのスキャンコードを調べ、それに対応するUSキーボードのキーを調べます。
そして、そのキーのキーコードを keymap.c で配置していくことになります。
このあたりが Macのような US配列の環境での事例と違っていたようです。
2-3. ErgoDoxキーマッピングで記号をどこにするかで迷った
次に ErgoDoxは JISキーボード として使う上での問題点に、記号・のキーが足りない、ということがあります。
右手の最右列をどう使うか、だいぶ試行錯誤しました。
2-4. 最右列を操作キーにする場合
第一案では、最右列を Enter や BackSpace に使おうと思ったのですが、うまくいきませんでした。
しかし、親指シフトの入力で、コロンの位置に Backspace を配置していたので、一つ右にずらすとBackSpaceをしたくなるのです。
ただ、通常の英数入力の時はその位置でEnterをしたくなったりと、うまくいきませんでした。
結局、EnterとBackSpaceは右手の親指の位置になりました。
もともとある記号をそのまま、続きで最右列に配置しました。
3. キー配列ができた
ErgoDox でもやっと親指シフトでの入力ができるようになりました。
クセのないキーマップにしたら、だいぶ慣れてきました。
肩が広がるので、なんかリラックスできる気がします(プラシーボ?)。
いろいろ試してみて、こんなキーマップに落ち着いています。
ポイントは、なるべく通常のパソコンのキー配置と違いを少なくして、あまり親指のキーを多用しないで済むようにしていることです。
3-1. 親指シフトと ErgoDox は相性が悪い?
いろいろ試行錯誤してみて、そもそも ErgoDoxと親指シフトは相性が悪いのかもしれません。
じっさいに触ってみて思ったんですが、親指シフトはもともとシフトに親指を使っているので、これ以上親指のボタンを増やしても負荷が大きいからです。
親指シフトで日本語入力していると、ふだんは親指は、VとMの下にあります。
なので、あんまり親指エリアを有効に活用できていないんですよね。
これなら、(見た目のカッコよさをかんがえなければ)もっと「ふつうの分割キーボード」でもよかったのかもしれないです。
でも、ErgoDoxは、見た目がかっこいいから、やっぱりいいんですよね。
純粋にメカデザインとしては ErgoDox は面白いので、何とか打ちこなしていきたいと思います。
キーマップをいろいろ考えても、実際に手で触ってみると なかなか頭で考えた通りにはいきません。人間工学って奥深いんだなと思いました。
こちらもどうぞ。