【スポンサーリンク】

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

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

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

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

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

ErgoDoxの組み立て作業

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

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

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

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

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

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

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

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

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

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

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

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

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

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

キーマップを変更する

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

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のファームウェアの書換えできました。

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配列の環境での事例と違っていたようです。

ErgoDoxキーマッピングで記号をどこにするかで迷った

次に ErgoDoxは JISキーボード として使う上での問題点に、記号・のキーが足りない、ということがあります。
右手の最右列をどう使うか、だいぶ試行錯誤しました。

最右列を操作キーにする場合

第一案では、最右列を Enter や BackSpace に使おうと思ったのですが、うまくいきませんでした。

しかし、親指シフトの入力で、コロンの位置に Backspace を配置していたので、一つ右にずらすとBackSpaceをしたくなるのです。

ただ、通常の英数入力の時はその位置でEnterをしたくなったりと、うまくいきませんでした。

結局、EnterとBackSpaceは右手の親指の位置になりました。
もともとある記号をそのまま、続きで最右列に配置しました。

キー配列ができた

ErgoDox でもやっと親指シフトでの入力ができるようになりました。
クセのないキーマップにしたら、だいぶ慣れてきました。

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

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

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

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

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

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

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

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

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

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

QRコードを読み込むと、関連記事を確認できます。
自作キーボードのErgoDoxを作ってみた
【スポンサーリンク】
タイトルとURLをコピーしました