自作キーボードのErgoDoxを作ってみた

自作キーボードのErgoDoxを作ってみた

海外サイトに注文した自作キーボードキット ErgoDox を組み立てました。

未経験者にとっては はんだ付けに苦労しましたが、意外と3時間ほどで組み立てられました。

ただし、キー配列のファームウェアを作るのは大変でした。
キーコードの定数を配列にしたC言語のソースコードをコンパイルして、キーボード内のマイコンに書き込むのですが、なかなか思ったキーコードを見つけられず試行錯誤しました。

sns_share_buttons
\記事が役に立ったらシェアしてね/
【スポンサーリンク】

1. ErgoDoxの組み立て作業

夏ごろに届いていた ErgoDox(自作 分割キーボード) をようやく開封しました。

1. ErgoDoxの組み立て作業

組み立ての作業そのものは、だいたい3時間ぐらいでできました。

大変なのは、キースイッチの「はんだ付け」。
はんだ付けは高校の授業以来で、まったく不慣れです。
しかし、それでも何とかつながるんですね。

1. ErgoDoxの組み立て作業

1.1. ErgoDoxは片手単体では動かない

途中、片手分だけが完成したので、動くか試したのですが、まったく反応しません。
途中のはんだ付けが失敗して、回路を痛めたかと かなり心配しました。
約3万円が無駄になると ショックが大きいです。

それでも、そのまま作業を続けて、両手ともキーボードを完成させます。
そろったところでつないだら、ちゃんと動いたのでほっと一安心。

1.2. ガジェットの組み立ても「エンターテイメント」

ひさびさに子どもと一緒にガジェットを組み立てて、ワクワクしました。

1.2. ガジェットの組み立ても「エンターテイメント」

この体験だけでも、3万円のうちの5,000円ぐらいの価値はあるかも。

1.3. 親指シフトとローマ字入力で混乱

やっと完成して、試し打ちをしているのですが、まだ全然なれませんね。
初期配列では無変換キーがなかったので、親指シフトの入力では使いにくいです。

私の場合は普段は親指シフトで打っていることもあり、とりあえずキーマップまでは手が回らず、デフォルトのまま入力しています。

職場では普通にローマ字変換しているのに異様に混乱して全然打てません。
直交するキー並びなのか、FとJに突起がないからなのか、頭がなかなか親指シフトからローマ字入力に切り替わりません。

特に、「い」と「ん」や「、」「。」のうち間違えが多発しています。
こんなに入力で混乱するのは、親指シフトを始めた時を思い出します。

2. キーマップを変更する

キーマップの変更には Cの開発環境が必要です。
続けて作業するのは、ちょっと気力が必要です。

2. キーマップを変更する

2.1. qmkでのコンパイルはちょっと難しい

qmkでのコンパイルの仕方が、読んでたサイト情報と変わってて苦戦しましたが、なんとか納得いくところまでできました。

キーマップのコンパイルやインストールには、Linux(Ubuntu)PC を引っ張り出しました。

2.1. qmkでのコンパイルはちょっと難しい
#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. キー配列ができた

肩が広がるので、なんかリラックスできる気がします(プラシーボ?)。

いろいろ試してみて、こんなキーマップに落ち着いています。
ポイントは、なるべく通常のパソコンのキー配置と違いを少なくして、あまり親指のキーを多用しないで済むようにしていることです。

3. キー配列ができた

3.1. 親指シフトと ErgoDox は相性が悪い?

いろいろ試行錯誤してみて、そもそも ErgoDoxと親指シフトは相性が悪いのかもしれません。

じっさいに触ってみて思ったんですが、親指シフトはもともとシフトに親指を使っているので、これ以上親指のボタンを増やしても負荷が大きいからです。

親指シフトで日本語入力していると、ふだんは親指は、VとMの下にあります。

3.1. 親指シフトと ErgoDox は相性が悪い?

なので、あんまり親指エリアを有効に活用できていないんですよね。

これなら、(見た目のカッコよさをかんがえなければ)もっと「ふつうの分割キーボード」でもよかったのかもしれないです。

でも、ErgoDoxは、見た目がかっこいいから、やっぱりいいんですよね。
純粋にメカデザインとしては ErgoDox は面白いので、何とか打ちこなしていきたいと思います。

キーマップをいろいろ考えても、実際に手で触ってみると なかなか頭で考えた通りにはいきません。人間工学って奥深いんだなと思いました。

QRコードを読み込むと、関連記事を確認できます。

自作キーボードのErgoDoxを作ってみた
【スポンサーリンク】
タイトルとURLをコピーしました