40%キーボードを使用している場合、raise,lower 同時押しで adjust とする設定はよく使われていると思われる。QMK Firmware での設定方法を3つ記載する。
前提
レイヤーは以下の4つとし、それぞれ記載の通りとする。
- base … デフォルトレイヤー
- lower … デフォルトレイヤーからアクティブにできる
- raise … デフォルトレイヤーからアクティブにできる
- adjust … lower,raise レイヤーからアクティブにできる
レイヤーキーのみで実装する方法
レイヤーキーはホールド状態でアクティブになる LT,MO を使用する。この記事ではより簡易的な MO で説明する。
- MO(layer) … ホールド状態で layer をアクティブにする。
- LT(layer, kc) … ホールド状態で layer をアクティブにする。タップで kc を送信する。
base レイヤーに MO(lower) や MO(raise) を設定する。また lower,raise レイヤーには MO(adjust) を設定する。最もシンプルで、プログラムが苦手な人にも実装しやすい。
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BASE ] = LAYOUT( MO(_LOWER) , MO(_RAISE ) ),
[_LOWER ] = LAYOUT( XXXXXXXX , MO(_ADJUST) ),
[_RAISE ] = LAYOUT( MO(_ADJUST) , XXXXXXXX ),
[_ADJUST] = LAYOUT( XXXXXXXX , XXXXXXXX ),
};
レイヤーキーの詳細は QMK Firmware のドキュメントを参照。
サンプルを用意した。
レイヤーキー + update_tri_layer
以下のように lower,raise のカスタムキーコードを設定する。
enum custom_keycodes {
C_LOWER = SAFE_RANGE,
C_RAISE,
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BASE ] = LAYOUT( C_LOWER , C_RAISE ),
[_LOWER ] = LAYOUT( XXXXXXXX , C_RAISE ),
[_RAISE ] = LAYOUT( C_LOWER , XXXXXXXX ),
[_ADJUST] = LAYOUT( XXXXXXXX , XXXXXXXX ),
};
カスタムキーコードを MO(lower) の代わりに C_LOWER としてキーマップに設定する。process_record_user 関数でカスタムキーコードに対する処理を実装し、layer_on,layer_off と一緒に update_tri_layer を記述する。
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case C_LOWER:
if (record->event.pressed) {
layer_on(_LOWER);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_LOWER);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
case C_RAISE:
if (record->event.pressed) {
layer_on(_RAISE);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_RAISE);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
default:
break;
}
return true;
}
この方法で実装すると以下のような動きになる。
- C_LOWER をホールド。lower レイヤーがアクティブになる。
- C_RAISE をホールド。( lower,raise の掛け合わせで) adjust レイヤーになる。
- C_RAISE を離す。lower レイヤーがアクティブになる。
- C_RAISE をホールド。( lower,raise の掛け合わせで) adjust レイヤーになる。
- C_LOWER を離す。raise レイヤーがアクティブになる。
上記の挙動は MO,LT で実装する方法では出来ない、より直感的な操作になる。
update_tri_layer の詳細は QMK Firmware のドキュメントを参照。
サンプルを用意した。
レイヤーキー + update_tri_layer_state
update_tri_layer と類似した機能。layer_on,layer_off で layer_state_set_user が呼び出されるため、その中で update_tri_layer_state を実装する。
layer_state_t layer_state_set_user(layer_state_t state) {
return update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case C_LOWER:
if (record->event.pressed) {
layer_on(_LOWER);
} else {
layer_off(_LOWER);
}
return false;
break;
case C_RAISE:
if (record->event.pressed) {
layer_on(_RAISE);
} else {
layer_off(_RAISE);
}
return false;
break;
default:
break;
}
return true;
}
簡易的に実装する場合は update_tri_layer_state、細かい制御をしたい場合は update_tri_layer と使い分けすると良さそうだ。
update_tri_layer_state の詳細は QMK Firmware のドキュメントを参照。
サンプルを用意した。
まとめ
enum custom_keycodes {
C_LOWER = SAFE_RANGE,
C_RAISE,
C_ADJUST,
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BASE ] = LAYOUT( C_LOWER , C_RAISE ),
[_LOWER ] = LAYOUT( XXXXXXXX , C_ADJUST ),
[_RAISE ] = LAYOUT( C_ADJUST , XXXXXXXX ),
[_ADJUST] = LAYOUT( XXXXXXXX , XXXXXXXX ),
};
case C_ADJUST:
if (record->event.pressed) {
layer_on(_ADJUST);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_ADJUST);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
私は正しく理解しない状態でこの実装を行い、半年以上も直感的でない操作にモヤモヤしていた。改めてドキュメントに目を通してみると答えはそこに書かれていたのだ。ドキュメントは偉大である。