Mod Tapの使い方

長押しでシフトなどの修飾キー、タップで通常のキーを入力できるのがMod Tap。

keymap定義の中でLSFT_T(KC_SPC)のように使う。

KC_SPCの部分には通常のキーコードしか指定できない。

他の修飾キーは公式ドキュメントに一覧がある。

process_record_user

通常と違う処理をしたい場合はprocess_record_user()を使う。

引数で渡されたkeycodeが目当てのものをif文かswitch文で捕捉して、実行したい処理を書く。

process_record_user()内でtrueを返すと通常の処理が実行される。falseを返すと通常の処理は実行されない。

本題の解説

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
	...
	switch(keycode) {
		...
		// MOD TAPのキーコードを捕捉
		case LSFT_T(KC_SPC):
		// 長押しの場合はtap.countが0
		// タップの場合は1以上
		if(record->tap.count > 0) {
			// タップの場合にしたい処理を書く。
			
			// タップの場合にしたい処理はもうおこなった。
			// falseを返すと通常の処理は実行されない。
			return false;
		}
		// 長押しの場合は通常通り修飾キーになってほしい。
		// trueを返すと通常の処理が実行される。
		return true;
		...
	}
	...
}

タップでシフト側の文字を送る例

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
	...
	switch(keycode) {
		...
		// MOD TAPのキーコードを捕捉
		// タップ側のキーコードは最後の8ビット以外は#defineマクロの展開のときに捨てられるのでJP_QUOTはKC_7と同じ扱いになってしまっている。
		case RGUI_T(JP_QUOT):
		// 長押しの場合はtap.countが0
		// タップの場合は1以上
		if(record->tap.count > 0) {
			// 押されたときの処理
			if(record->event.pressed) {
				add_mods(MOD_LSFT);
				register_code(KC_7);
			}
			// 離されたときの処理
			else {
				unregister_code(KC_7);
				del_mods(MOD_LSFT);
			}
			return false;
		}
		// 長押しの場合は通常通り修飾キーになってほしい。
		// trueを返すと通常の処理が実行される。
		return true;
		...
	}
	...
}

関連する部分のソースコードを読む助け

公式のGithubリポジトリ

MOD TAPの#defineマクロ定義はqmk_firmware/quantum/quantum_keycode.hの終わりの方にあるLT(), MT(), MODの種類_T()

MOD TAPの実際の処理を行っている部分はqmk_firmware/tmk_core/common/action_tapping.cにある。

この記事で通常のキーコードと書いているのはqmk_firmware/tmk_core/common/keycode.hで定義されている0xFFまでのキーコード。

qmk_firmware/tmk_core/common/action.cprocess_record()からqmk_firmware/quantum/quantum.cprocess_record_quantum(), process_record_kb(), process_record_user()と呼ばれていく。

process_record_quantum()の中で、キーを処理してbool値を返すさまざまな関数を論理積の短絡評価(&&)でつなげている。論理積はすべてがtrueならtrue、1つでもfalseならfalse。短絡評価は全体のbool値が確定した段階で残りの処理を省略する。結局どこかでfalseが出るまで処理を続けて、falseが出たら終了ということになる。

process_record_user()にはweak属性が指定されている。weak属性がある関数は他の場所にも同じ名前の関数があればそちらに置き換えられる。各自のkeymapファイルで置き換えることを想定されている。