TapDanceの設定(その2・Shiftキーを組み合わせる)
TapDanceは Basic Keycodes に列挙されているキーしか指定できない仕様のため(や:のように、Shiftキーと組み合わせてタイプする文字を入力するには工夫が必要になる。 Shiftキーと組み合わせる文字を入力する場合、TapDanceの挙動を細かく指定できるACTION_TAP_DANCE_FN_ADVANCED関数やACTION_TAP_DANCE_FN_ADVANCED_TIME関数(qmk_firmware/quantum/process_keycode/process_tap_dance.hで定義)を使う。
2つの関数の違いは、4番目の引数でTAPPING_TERMの時間を個別に指定できるか否かだけなので、共通部分を解説する。
ACTION_TAP_DANCE_FN_ADVANCED関数の引数は、次の3つである。
on_each_tap_fn
TapDanceに指定したキーを押す度に実行される関数を指定する。
on_dance_finished_fn
config.hで指定したTAPPING_TERMの時間が経過するか、連打の途中でTapDanceを設定していないキーが押された(interrupt)場合に実行される関数を指定する。
on_dance_reset_fn
on_dance_finished_fnが実行された後に実行される関数を指定する。TapDanceの処理はここに指定した関数でリセットする。
3つの引数に指定した関数には、qk_tap_dance_state_t型(qmk_firmware/quantum/process_keycode/process_tap_dance.hで定義)のstate変数を引数に指定できる。qk_tap_dance_state_t型の定義は次のとおりで、キーの連打回数や、連打中に別のキーが押されたか判定するフラグなど、TapDanceの挙動を細かく制御するために必要な変数が揃っている。
code:process_tap_dance.h
typedef struct
{
uint8_t count; //同じキーを連続して押した回数が格納される
uint8_t oneshot_mods;
uint8_t weak_mods;
uint16_t keycode; //押したキーのキーコードが格納される
uint16_t interrupting_keycode;
uint16_t timer;
bool interrupted; //連打の途中で別のキーが押されたらTrueになる
bool pressed; //押しっぱなしの時にtrueになる
bool finished;
} qk_tap_dance_state_t;
なお、3つの関数の実行されるタイミングをパターン別に示すと次のような感じである。
TAPPING_TERMで指定した時間内にキー連打
キータイプ
|
| on_each_tap_fn関数を実行
|
キータイプ
|
| on_each_tap_fn関数を実行
|
(TAPPING_TERMで指定した時間が経過)
|
| on_dance_finished_fn関数を実行
| 続いてon_dance_reset_fn関数実行
|
処理完了
2回目のキーを押す前にTAPPING_TERMで指定した時間が経過
キータイプ
|
| on_each_tap_fn関数を実行
|
(TAPPING_TERMで指定した時間が経過)
|
| on_dance_finished_fn関数を実行
| 続いてon_dance_reset_fn関数実行
|
処理完了
2回目のキーを押す前に別のキーを押下
キータイプ
|
| on_each_tap_fn関数を実行
|
別のキーをタイプ
|
| on_dance_finished_fn関数を実行
| 続いてon_dance_reset_fn関数実行
|
処理完了
TAPPING_TERMで指定した時間内にキーを連打してさらに別のキーを押下
キータイプ
|
| on_each_tap_fn関数を実行
|
キータイプ
|
| on_each_tap_fn関数を実行
|
別のキーをタイプ
|
| すぐにon_dance_finished_fn関数を実行
| 続いてon_dance_reset_fn関数実行
|
処理完了
具体的な設定方法
ここでは、上で説明した「タップで.、2連打で,を入力する」設定に続けて、次の設定を行う。
タップすると[、2連打すると(を入力する
タップすると;、2連打すると:を入力する
まず、keymap.cに専用のキーコードを定義する。
code:keymap.c
enum {
TD_PERIOD_COMMA = 0, //先ほど定義したキーコード
TD_LBRC_LPRN,
TD_SCLN_COLN
};
それから、ACTION_TAP_DANCE_FN_ADVANCED関数の2番目と3番目の引数に指定する関数を定義する。
なお、C言語で関数を定義するには事前に関数の宣言を行う必要があるが、dance_cln_finishedとdance_cln_reset関数については、宣言不要で定義できる。
code:keymap.c
void dance_cln_finished (qk_tap_dance_state_t *state, void *user_data) {
switch (state->keycode) {
case TD(TD_LBRC_LPRN):
if (state->count == 1) {
register_code (KC_LBRC);
} else if (state->count == 2) {
register_code (KC_LSFT);
register_code (KC_9);
}
break;
case TD(TD_SCLN_COLN):
if (state->count == 1) {
register_code (KC_SCLN);
} else if (state->count == 2) {
register_code (KC_LSFT);
register_code (KC_SCLN);
}
break;
}
}
void dance_cln_reset (qk_tap_dance_state_t *state, void *user_data) {
switch (state->keycode) {
case TD(TD_LBRC_LPRN):
if (state->count == 1) {
unregister_code (KC_LBRC);
} else if (state->count == 2) {
unregister_code (KC_LSFT);
unregister_code (KC_9);
}
break;
case TD(TD_SCLN_COLN):
if (state->count == 1) {
unregister_code (KC_SCLN);
} else if (state->count == 2) {
unregister_code (KC_LSFT);
unregister_code (KC_SCLN);
}
break;
}
}
どちらの関数にも、少し前で説明したqk_tap_dance_state_t型の変数*stateを引数に指定したうえで、switch(state->keycode)で押されたキーを判定してcase文で処理を振り分けている。なお、キー判定にあたっては、独自設定のキーコードが使える。
それから、if (state->count == 1)で、この関数が実行されるまでに同じキーが何回押されたか判定して処理を振り分けている。
register_codeとunregister_codeは、それぞれ引数に指定されたキーコードを押す(KeyDown)動作と離す(KeyUp)動作を実現する関数なので、dance_cln_finished関数にregister_code()を、TapDanceの処理をリセットするdance_cln_reset()関数にunregister_codeを指定している。
そして、Shiftキーと組み合わせて入力するキーを指定するときは、次のように指定する。register_code(KC_LPRN)と1行で指定することはできない。
code:keymap.c
register_code(KC_LSFT)
register_code(KC_9)
そして、上記で設定した関数を独自設定のキーコードに割り当てる。
code:keymap.c
qk_tap_dance_action_t tap_dance_actions[] = {
TD_LBRC_LPRN = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset), TD_SCLN_COLN = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset) };
最後に、TD_LBRC_LPRNとTD_SCLN_COLNのキーコードをキーマップで割り当てれば、キーを一回押したときは[、二連打したときは)を入力するという動作を実現できる。キーマップへの割り当て方は上で説明したとおりである。
キーボードタイプのタイミングと文字入力の時間差
上記の設定を行うと、[でも(でも、割り当てたキーを叩いてから文字が入力されるまでに時間差があると感じるはずである。一方、割り当てたキーをタイプしてから素早くAキーをタイプしたときは、時間差無しで[aが入力されると感じるはずである。
その理由は、実際のキー入力処理を行うdance_cln_finishedとdance_cln_reset関数が、2連打後にTAPPING_TERMで設定した時間が経過してから実行されるためである。一方、割り当てキーをタイプしてから素早く別のキーを押した場合、dance_cln_finished関数とdance_cln_reset関数は別のキーを押した直後に実行されるため、時間差なく文字入力が行われる。
この時間差を解消する方法は次の2つである。
TAPPING_TERMの時間を短くする。
ACTION_TAP_DANCE_FN_ADVANCEDの1番目の引数であるon_each_tap_fnを利用する
1番目の方法を採用する場合、config.hファイルの#define TAPPING_TERM 175の数値を変更すれば全てのTapDanceについて変更できる。一方、キー毎に変更したい場合、ACTION_TAP_DANCE_FN_ADVANCED_TIMEの4番目の引数に任意の時間を設定する。ただし、どちらの方法でも時間を短くするほど連打の判定がシビアになってしまう。
code:keymap.c
TRD_HENK_RAISE = ACTION_TAP_DANCE_FN_ADVANCED_TIME(each_tap, finished, reset, 200), TRD_MHEN_LOWER = ACTION_TAP_DANCE_FN_ADVANCED_TIME(each_tap, finished, reset, 180) 2番目のACTION_TAP_DANCE_FN_ADVANCEDの1番目の引数であるon_each_tap_fnを利用する方法については、次で紹介する。