モドタップの挙動を修正する

デフォルトのモドタップの問題

デフォルトのモドタップには以下の問題があります

  • レイヤーの切り替え(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するようにしないとだめです

,

Related posts

このブログの今後について

⊏'ꣲ'|
キーボードについてあらかた書いてしまったので、
今後はキーボードとは関係ない記事が増えていくと思います
ホールドでレイヤー1、タップしてから再度ホールドでレイヤー2とか、
普段はホールドでレイヤ切り替えだけど、そのままタブ押したときだけAltになるとか
ちまちま変なことやっているけれど、汎用的ではないしGitHubにあるソースを見てください

SWAP HANDSのススメ

スワップハンドすごい
スワップハンドすごい
分割キーボードなのに片手で全キー入力できる
マイクラでマウス構えながら/spawnできるし
頬杖付きながら簡単な文字入力なら行える
みんなスワップハンド導入すべき
自分はお行儀よくキーボードの正面に座って両手で操作している割合は多くないです
ゲームしながら絵を描きながらお菓子を食べながら…そんなときは大抵片手操作です
分割じゃないキーボードを使っていたときは、よく片手でプログラミングしてました
(もちろん両手を使ったほうが速い)
分割では距離がね…うn…
そんなわけで片手で入力できないのは自分的にはありえないので早速Re42にスワップハンドを導入しました
普通のキーボードの片手タイピングに比べ、速度はかなり落ちますがホームポジションから動かないで済むようになったのは悪くなかったです
配置検討
画像
色々試した結果、上図のようになりました
スワップハンド中は最上段が
左:DEL Y U I O P 右: Q W E R T ESC
になります
スワップハンド中のタブとクォートについては別レイヤーにトグルSH_TGを配置して誤魔化します(この記事では割愛)
実装
公式に書いてある通り
rules.mkにSWAP_HANDS_ENABLEを定義し、
keymap.cにマッピングを定義します
マッピングの配列にセットする順序についてはキーボード名のヘッダファイルRe42.hに定義されているLAYOUTマクロを確認します
Re42は前半が左手、後半が右手となっているようなので、スワップハンドではコレを逆にします

rules.mk
SWAP_HANDS_ENABLE =...

SHIFT+JP_XXXをUS配列に対応させる

JP_XXXとShfitキーとの組み合わせがおかしい
keymap.cでkeymap_jp.hをincludeしてKC_XXXの代わりにJP_XXXを使えば、
日本語キーボードと認識された状態でも目的の記号を入力するようにできるみたいです
ですが、例えばSHIFT+JP_2を押しても@じゃなくて"になってしまう
SHIFT+JP_QUOTにいたっては"じゃなくて'のままです
どうしたものか
(さらに…)

QMK firmwareでタップ数をカウントアップして表示する

OLEDで何かできないか
まずはファームの勉強を兼ねてOLEDで何かできないか考えたところ
タップ数をカウントアップして表示するのが難易度低そうで良さそうかな
と思い実行してみました(c経験ほぼ0)
グローバル変数にタップ数保持して、ぷりんとえふ?とかいうの使えばいいんでしょ!
それくらい解っちゃうんだから!
printfが使えない!
だめでした
printfを使うためにstdio.hをincludeしたらhexファイルのサイズが大きくなりすぎてエラーになってしまいました…
できました
ちょっと考えてprintfやitoa無しでできました
パズルみたいでたのしいですね
itoaの実装方法はググればいくらでも出てきますが、
表示するだけなら最初から文字列で持つ方が単純でよさそうでした
(WPMを自力で算出するとかなら話は別ですが…)
まず、keymap.cの適当なところに以下を追加します
char tap_count = "00000";
void countup_taps(void) {
for (int i = 4;...

Re42で遊ぶ

Re42 !
九嶋さん(@kushima8)にRe42(とRe40)のテスト版を提供いただいたので、ファームをあれこれいじって遊んでいます
ありがてぇありがてぇ
遊んでいるうちにQMK Firmwareについて色々知見が溜まってきたので、
時間ができたときにこのブログに書いていこうかなと思います
(さらに…)

Latest posts

このブログの今後について

⊏'ꣲ'|
キーボードについてあらかた書いてしまったので、
今後はキーボードとは関係ない記事が増えていくと思います
ホールドでレイヤー1、タップしてから再度ホールドでレイヤー2とか、
普段はホールドでレイヤ切り替えだけど、そのままタブ押したときだけAltになるとか
ちまちま変なことやっているけれど、汎用的ではないしGitHubにあるソースを見てください

SWAP HANDSのススメ

スワップハンドすごい
スワップハンドすごい
分割キーボードなのに片手で全キー入力できる
マイクラでマウス構えながら/spawnできるし
頬杖付きながら簡単な文字入力なら行える
みんなスワップハンド導入すべき
自分はお行儀よくキーボードの正面に座って両手で操作している割合は多くないです
ゲームしながら絵を描きながらお菓子を食べながら…そんなときは大抵片手操作です
分割じゃないキーボードを使っていたときは、よく片手でプログラミングしてました
(もちろん両手を使ったほうが速い)
分割では距離がね…うn…
そんなわけで片手で入力できないのは自分的にはありえないので早速Re42にスワップハンドを導入しました
普通のキーボードの片手タイピングに比べ、速度はかなり落ちますがホームポジションから動かないで済むようになったのは悪くなかったです
配置検討
画像
色々試した結果、上図のようになりました
スワップハンド中は最上段が
左:DEL Y U I O P 右: Q W E R T ESC
になります
スワップハンド中のタブとクォートについては別レイヤーにトグルSH_TGを配置して誤魔化します(この記事では割愛)
実装
公式に書いてある通り
rules.mkにSWAP_HANDS_ENABLEを定義し、
keymap.cにマッピングを定義します
マッピングの配列にセットする順序についてはキーボード名のヘッダファイルRe42.hに定義されているLAYOUTマクロを確認します
Re42は前半が左手、後半が右手となっているようなので、スワップハンドではコレを逆にします

rules.mk
SWAP_HANDS_ENABLE =...

SHIFT+JP_XXXをUS配列に対応させる

JP_XXXとShfitキーとの組み合わせがおかしい
keymap.cでkeymap_jp.hをincludeしてKC_XXXの代わりにJP_XXXを使えば、
日本語キーボードと認識された状態でも目的の記号を入力するようにできるみたいです
ですが、例えばSHIFT+JP_2を押しても@じゃなくて"になってしまう
SHIFT+JP_QUOTにいたっては"じゃなくて'のままです
どうしたものか
(さらに…)

Leave a Comment

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です