モドタップの挙動を修正する
Index
デフォルトのモドタップの問題
デフォルトのモドタップには以下の問題があります
- レイヤーの切り替え(LT(kc))にIGNORE_MOD_TAP_INTERRUPTが効かない
素早く入力したときに想定通り入力できないというあれです - 別レイヤーにMT(kc)を配置した場合、レイヤーを切り替えるとホールドも解除されてしまう
例えばデフォルトレイヤーのみにA~Z、LOWERレイヤーにGUI_T(kc)を配置してWin+R
をタップしようとして
LOWERホールド
→GUI_T(kc)ホールド
→LOWER解除
→R
と入力した場合、Win
は就職されずに単にR
になってしまいます - タップダンスで細かく色々できそうだけどなんか書きにくそう(個人の感想)
先人
こちらの方も同じ問題にぶちあたって解決したようです
http://akakyouryuu.com/blog/qmk-firmware%E3%81%AEtap-hold%E3%81%AE%E5%8B%95%E4%BD%9C%E3%82%92%E6%94%B9%E5%96%84%E3%81%99%E3%82%8B/
それはそれとして
上記記事を見つける前に自前で実装してしまったので、メモっておきます
ソースコード
config.h
#define TAPPING_TERM 200
keymap.c(もしくはヘッダファイルも作って別ファイルへ)
#include QMK_KEYBOARD_H
#include "fix_tap_hold.h"
tap_state_t tap_state;
static struct {
uint16_t keycode;
uint16_t time;
} last_pressed = {0, 0};
static void process_tap_state(uint16_t keycode, keyrecord_t *record) {
bool in_tapping_term = (record->event.time - last_pressed.time) <= TAPPING_TERM;
bool is_same_keycode = keycode == last_pressed.keycode;
if (record->event.pressed) {
last_pressed.keycode = keycode;
last_pressed.time = record->event.time;
tap_state = (is_same_keycode && in_tapping_term) ? DOUBLE_HOLD : SINGLE_HOLD;
} else if (is_same_keycode && tap_state != DOUBLE_HOLD){
tap_state = in_tapping_term ? SINGLE_TAP : LONG_TAP;
} else {
tap_state = KEYUP;
}
}
static uint8_t quick_MT_mod = 0;
static void process_quick_MT(void) {
if (quick_MT_mod && tap_state == SINGLE_HOLD) {
register_mods(quick_MT_mod);
quick_MT_mod = 0;
}
}
bool quick_MT(uint16_t mod_key, uint16_t keycode) {
if (tap_state != SINGLE_HOLD) {
quick_MT_mod = 0;
unregister_mods(MOD_BIT(mod_key));
}
switch (tap_state) {
// register mod_key when another key is pressed in process_quick_MT.
case SINGLE_HOLD: quick_MT_mod = MOD_BIT(mod_key); break;
case DOUBLE_HOLD: register_code16(keycode); break;
case SINGLE_TAP: tap_code16(keycode); break;
case LONG_TAP: tap_code16(mod_key); break;
default: unregister_code16(keycode);
}
return false;
}
bool quick_LT(uint8_t layer, uint16_t keycode) {
if (tap_state != SINGLE_HOLD) {
layer_off(layer);
}
switch (tap_state) {
case SINGLE_HOLD: layer_on(layer); break;
case DOUBLE_HOLD: register_code16(keycode); break;
case SINGLE_TAP: tap_code16(keycode); break;
default: unregister_code16(keycode); break;
}
return false;
}
void process_fix_tap_hold(uint16_t keycode, keyrecord_t *record) {
process_tap_state(keycode, record);
process_quick_MT();
}
使い方
process_record_user
にてprocess_fix_tap_hold
を実行すれば、
タップのホールドの状態を以下の通りtapstate
の値で取得できます
tapstate | 意味 |
---|---|
SINGLE_HOLD | キーを押している |
SINGLE_TAP | 割り込みなしでキーを押して離した |
LONG_TAP | 割り込みなしでキーを押して離した(TAPPING_TERMミリ秒以上) |
DOUBLE_HOLD | 一度タップしTAPPING_TEAM以内に同じキーを再度ホールド中 |
KEYUP | 上記以外の状態 |
MT(kc)
とLT(kc)
の代わりはquick_MT(kc)
とquick_LT(kc)
です
関数名はいまいち
組み込み例
keymap.c
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
process_fix_tap_hold(keycode, record);
switch (keycode) {
// 例: DELを長押ししたらINS、タップした後に再ホールドDEL押しっぱなし
case KC_DEL:
switch (tapstate) {
case SINGLE_TAP: tap_code(KC_DEL); break;
case LONG_TAP: tap_code(KC_INS); break;
case DOUBLE_HOLD: register_code(KC_DEL); break;
default: unregister_code(KC_DEL);
}
return false;
// 例: ホールドで1番レイヤー、タップでEnter、タップ後ホールドでEnter押しっぱなし
case KC_ENT: return quick_LT(1, KC_ENT);
// 例: ホールドでLGUI、タップでESC、ロングタップでLGUIタップ、タップ後ホールドでESC押しっぱなし
case KC_ESC: return quick_MT(KC_LGUI, KC_ESC);
}
}
追記
quick_MTですが、これだとmod+マウスクリックができないです
ちゃんとやるにはタイマーを使用して一定時間押しっぱなしならmodをregisterするようにしないとだめです
Leave a Comment