leopardgeckoのブログ

Macの関連事項など

Planckキーボード:Lowerキーのダブルタップでレイヤーをロック(トグル)する。

今回はPlanckキーボードというよりはQMK Firmwareの話です。

はじめに

小型キーボードで面倒なことの一つに数値の入力があります。フルサイズのキーボードならテンキーがあるので楽ですが、Planckのようないわゆる40%サイズのキーボードの場合は何か別のキーとの同時押しで数値を入力しなければなりません。
そこで考えたのが、Lowerレイヤーをテンキー配列にしてレイヤーをロックする機能をつけることです。それだけなら前回の記事で紹介したキーマップでも実現できているのですが、今回はそれに加えてLowerキーをダブルタップしてLowerレイヤーをロック(トグル)する方法を紹介します。LowerキーをダブルタップすればPlanckがテンキーとして使えるようになるので数値の入力が格段に楽になります。以前紹介した、単押しでMacの「英数」およびWindowsの「無変換」キーとしても使える機能はそのままです。ロックされたLowerレイヤーはもう一度Lowerキーを押すとデフォルトレイヤーに戻るようにします。

考え方

QMK FirmwareのTap Dance機能を使います。ただ単にTap Danceを実装しただけでは単押し(タップ)と長押し(ホールド)の使い分けに問題が生じます。どういうわけかホールドと認識されるまでの時間が長くなってしまい、Lowerレイヤーの文字を入力したつもりでもデフォルトレイヤーの文字が入力されてしまうという誤動作が増えてしまうのです。かといってそれを避けるためにタップの時間設定である「TAPPING TERM」を短くすると、ダブルタップをものすごく速くやらないと認識されないというジレンマに陥ります。その問題点を解決するためには「PERMISSIVE HOLD」という機能を併用します。これはTAPPING TERMの設定がどうあれ修飾キーを押した後に他のキーを押すと最初に押したキーがホールドの扱いになるというものです。

やり方

Lowerレイヤーはテンキーっぽいキーマップにしておいた方がレイヤーをロックするメリットを実感できます。例えばこんな感じで。

/* Lower
 * ,-----------------------------------------------------------------------------------.
 * |      |   1  |   2  |   3  |   4  |   5  |   6  |   7  |   8  |   9  |   0  | Bksp |
 * |------+------+------+------+------+-------------+------+------+------+------+------|
 * |      |      |      |      |      |   ,  |   +  |   4  |   5  |   6  |   *  |      |
 * |------+------+------+------+------+------|------+------+------+------+------+------|
 * |      |      |      |      |      |   .  |   -  |   1  |   2  |   3  |   /  |   =  |
 * |------+------+------+------+------+------+------+------+------+------+------+------|
 * |      |      |      |      |      |             |   0  |      |      |      |      |
 * `-----------------------------------------------------------------------------------'
 */

機能面での書き方ですが、まず「config.h」ファイルに先ほどのPERMISSIVE_HOLDを有効にするために「#define PERMISSIVE_HOLD」という記述を追加します。これだけでも良いのですが、ダブルタップの誤動作を防ぐためにTAPPING_TERMを180くらいのやや短めに設定しておきます。このくらいの設定だとゆっくりめのダブルタップをすると「英数」キーのダブルタップとしても使えるので、慣れるとレイヤーロックと「英数」ダブルタップの使い分けができるようになります。

#define TAPPING_TERM 180
#define PERMISSIVE_HOLD

「rules.mk」ファイルでTap Danceを有効にします。ファイルサイズが大きくなってしまうので、マウスキーを無効にしておいた方が良いでしょう。それでもファイルがサイズオーバになってしまう場合はデバッグ用のコンソールも無効にします。

TAP_DANCE_ENABLE = yes
MOUSEKEY_ENABLE  = no
CONSOLE_ENABLE = no

次に「keymap.c」の記述です。以下はQMK Firmwareの公式ドキュメントの応用です。
最初の方にTap Danceのキーコードの設定を書きます。ここでは「TAP_L」という名前で定義しています。

// Tap Danceの設定
enum {
 X_TAP_DANCE_1 = 0,
};
#define TAP_L TD(X_TAP_DANCE_1)     // タップで「英数」「無変換」 ホールドでLower  ダブルタップでLowerレイヤーのトグル

ファイルの最後の方にTap Danceの動作を書きます。

// Tap danceの設定
enum {
  SINGLE_TAP = 1,
  SINGLE_HOLD = 2,
  DOUBLE_TAP = 3,
};

typedef struct {
  bool is_press_action;
  int state;
} tap;

int cur_dance (qk_tap_dance_state_t *state) {
  if (state->count == 1) {
    if (!state->pressed) return SINGLE_TAP;
    else return SINGLE_HOLD;
  }
  else if (state->count == 2) {
    return DOUBLE_TAP;
  }
  else return 6; //magic number. At some point this method will expand to work for more presses
}

//instanalize an instance of 'tap' for the 'x' tap dance.
static tap xtap_state = {
  .is_press_action = true,
  .state = 0
};

void x_finished_1 (qk_tap_dance_state_t *state, void *user_data) {
  xtap_state.state = cur_dance(state);
  switch (xtap_state.state) {
    case SINGLE_TAP:                     // 単押しで「英数」と「無変換」 Lowerレイヤーがトグルされている場合はレイヤーをオフにする
        if (IS_LAYER_ON(_LOWER)){
            layer_off(_LOWER);
        } else {
        register_code(KC_MHEN);
        register_code(KC_LANG2);
        }
        break;
    case SINGLE_HOLD:                   // 長押しでLowerレイヤーをオンにする
        layer_on(_LOWER);
        break;
    case DOUBLE_TAP:                    // ダブルタップでLowerレイヤーをトグル
        layer_invert(_LOWER); 
        break;
  }
}

void x_reset_1 (qk_tap_dance_state_t *state, void *user_data) {
  switch (xtap_state.state) {
    case SINGLE_TAP:  
        unregister_code(KC_LANG2);
        unregister_code(KC_MHEN); 
        break;
    case SINGLE_HOLD: 
        layer_off(_LOWER);
        break;
    case DOUBLE_TAP:  break;
  }
  xtap_state.state = 0;
}

qk_tap_dance_action_t tap_dance_actions[] = {
 [X_TAP_DANCE_1] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished_1, x_reset_1),
};

最後にkeymap.cのキーマップで設定しているLowerキーのキーコードを「TAP_L」に書き換えれば終了です。

これだけだとレイヤーがロックされているのかどうかがわかりにくいため、サウンドやLEDの併用をお勧めします。
サウンドやLEDの機能も含めたキーマップのファイルを以下で配布します。仕様は前回記事とほぼ同じで、今回紹介したTap Danceの機能が加えられています。ファームウェアのサイズの問題でマウスキーは無効にしています。仕様については前回記事を参照してください。

キーマップファイルのダウンロードはこちらから

最後に

ミニサイズのキーボードは指の動きが少なくて済むのは良いのですが、複数キーの同時押しがほぼ確実に求められる点は面倒に感じることもあります。特に数字の入力が片手でできないのは個人的に結構なストレスでした。しかしPlanckでテンキーのレイヤーを作ってレイヤーをロックできるようにしてからはその不満はほぼなくなりました。
Tap Danceはただ単に実装しただけでは動作速度での難点があり使いにくいものだったのですが、最近「PERMISSIVE_HOLD」の存在を知って加えてみたところ見事に思ったような動作になりました。ちょっとした工夫でグッと使い勝手が良くなるのもQMK Firmwareの面白いところだと思います。