Open8

KillerWhaleKB ファームウェアカスタマイズ

KounotoriKounotori

前提

  • ファームウェアのベースは 0.23.9.1
  • レイヤー 0 のキーマップ
    レイヤー 0 のキーマップ
    • アルファベットキーは大西配列
    • ホームポジションを1行奥にずらしている
      • 数字キーの行を無くし、その分天面ユニットの一番下の行の内側 2, 3 個のキーを親指キーとして他な記号キーにしている
  • 側面ユニット・追加ユニットを持ち上げるような形でテンティングしており、側面ユニットの外側のキーは母指球で押す形
  • Google 日本語入力の設定
    • キー設定は「MS-IME」
    • ローマ字テーブルに zt, zn, zr, zs で ←↓↑→ を入力できるよう追加

各レイヤーの役割

  • 1-3: 未使用 (今のところは)
  • 4 (LOWER): テンキーレイヤー
    • ホームポジションを1行ずらしていることで無くなっている数字キー行の分は、右手側にテンキーのように (0を除く) 数字キーを並べている
      テンキーレイヤー
  • 5 (UPPER): Control レイヤー
    • Mac の Control キーを (よく使う組み合わせのショートカットキーについて) Windows でも再現するためのレイヤー
    • Mac では Control キーがあるので使わない
  • 6 (UTIL): 矢印キーとファンクションキーレイヤー
    • 左手の iauo に ←↓↑→ キーを配置
    • テンキーレイヤーと同じ数字の位置にファンクションキーを配置
  • 7: マウスレイヤー
  • 8-9: 設定レイヤー (デフォルトのまま)
    • トグルスイッチの左で 8・右で 9 に入るようにしている
KounotoriKounotori

QMK 0.24.0 以降に入る修正の適用

オートマウスレイヤー切替の閾値機能

この機能がないと、本体を打鍵する程度の微細な振動がトラックボールに伝わっただけでも切り替わってしまう。これでは不便すぎて使えない。
この機能が入ると微細な振動ではレイヤーが切り替わらなくなる。

設定の名前は AUTO_MOUSE_THRESHOLD で、デフォルトは 10。
config.hdef ine AUTO_MOUSE_THRESHOLD 20 と書くことで変更可能。

やること

PR#21398 の差分をそのまま適用

右が Master の際に右トラックボールの CPI が変更できないバグ修正

PR#23391 の差分をそのまま適用

KounotoriKounotori

手元の VSCode のスタイル設定によってファイルを開くだけでスタイルに沿わない部分が勝手に修正されて差分がでまくる件の対応

手元の VSCode の設定上、行末のスペースを勝手に消したり EOF に改行を入れたりするようにしている。

KillerWhaleKB のファームウェアには、ソース内に EOF 改行がなかったり、行末に空白があったりする箇所が多く、それが勝手に直されてしまい差分に出てしまう。
ファームウェア改造にあたりそれは余計なので抑制する。

やること

.vscode/settings.json に次を追加

  • "files.insertFinalNewline": false
  • "files.trimTrailingWhitespace": false
KounotoriKounotori

HOLD_ON_OTHER_KEY_PRESS をデフォルトオフに

これは、Hold/Tap のキーを押した状態で別のキーを押下すると、まだ Tapping term の時間が経過していなくても別のキーを押下した時点で Hold 扱いとするオプション。
配布されている KillerWhale のファームウェアでは、これが常時有効になるようになっている。

アルファベットキーのような高速打鍵しがちなキーを Tap/Hold にした場合、これは邪魔になってしまうため切っておく。
この機能はそれが役に立つ条件を満たしたキーでのみ個別に有効化したい。

やること

info.jsontapping キーごと削除

KounotoriKounotori

デフォルト値などの変更

  • RGB レイヤーをデフォルト ON
    • common_killerwhale.ceeconfig_init_kb()kw_config.rgb_layer = true;
  • Master の OLED には現在のレイヤーではなく Stats を表示
    • common_killerwhale.ceeconfig_init_kb()kw_config.oled_mode = false;
  • Slow モードのカーソルが遅すぎるので少し早く
    • lib/common_killerwhale.hCPI_SLOW を 400 に
  • オートマウスレイヤー切替が戻るのが早すぎるのでもう少し遅く
    • config.hAUTO_MOUSE_TIME を 500 に
KounotoriKounotori

マウスレイヤーと Control 再現レイヤー以外はキーを割り当てしているところを発光させるとなんかいい感じかもと思いそのようにしている。

各 LED の番号を頑張って調べた:
LED 番号表

やること

lib/add_rgblayers.c

  • lower_layer[] = RGBLIGHT_LAYER_SEGMENTS( {42, 4, HSV_BLUE}, {50, 3, HSV_BLUE}, {55, 4, HSV_BLUE} );
  • upper_layer[] = RGBLIGHT_LAYER_SEGMENTS( {41, 1, HSV_PURPLE} );
  • util_layer[] = RGBLIGHT_LAYER_SEGMENTS( {17, 3, HSV_CORAL}, {23, 1, HSV_CORAL}, {43, 4, HSV_CORAL}, {49, 4, HSV_CORAL}, {55, 4, HSV_CORAL} );
  • mouse_layer[] = RGBLIGHT_LAYER_SEGMENTS( {54, 1, HSV_AZURE} );
KounotoriKounotori

Mac と日本語配列設定の Windows で同じキーマップ設定で使えるようにする

Windows で日本語配列設定している場合、Remap 上で割り当てた記号と実際に入力されるキーが異なるものがある。
たとえば、ˋ~半角/全角 として扱われてしまうので、それを意図するキーには \| を割り当てる必要がある。また、\|ˋ~ として扱われてしまうので、それを意図するキーには ¥ (INTERNATIONAL3) を割り当てる必要がある。

おれはプライベートでは Windows 、仕事では Mac なので、この違いのせいで、Windows 用のキーマップ・Mac 用のキーマップ、と2種類を用意して、左右の Raspberry Pi Pico のどちらがどちら用かを決めておいて書き込まないといけない。

これは非常に面倒臭いので、Mac 用であることを前提としたキーマップをベースとし、それがそのまま Windows でもいい感じに使えるようにしたい。

やること

keymaps/via/keymap.c

  • #include "os_detection.h を追加
  • process_record_user() を追加し、Wlndows の場合は特定のキーが入力された場合にはそれを無視し、代わりに指定したキーを入力した扱いにするような処理を追加する
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if (detected_host_os() == OS_MACOS || detected_host_os() == OS_IOS) {
        return true; // Mac では今のところ手を加えるものはない
    }

    switch (keycode) {
        case LT(LOWER, KC_GRAVE):
            if (!record->tap.count) {
                return true; // Hold の場合はそのまま処理
            }

            // Tap の場合は日本語配列設定の Windows でキーコードと入力されるキーを一致させる
            if (record->event.pressed) {
                register_code(KC_BACKSLASH);
            } else {
                unregister_code(KC_BACKSLASH);
            }
            return false; // Skip all further processing of this key
        case LCTL_T(KC_SPACE):
            if (record->tap.count) {
                return true; // Tap の場合はそのまま処理
            }

            // Hold の場合は Control 再現レイヤー扱いにする
            if (record->event.pressed) {
                layer_on(UPPER);
            } else {
                layer_off(UPPER);
            }
            return false;
        case KC_BACKSLASH:
            if (record->event.pressed) {
                register_code(KC_INTERNATIONAL_3); // 日本語配列設定の Windows でキーコードと入力されるキーを一致させる
            } else {
                unregister_code(KC_INTERNATIONAL_3);
            }
            return false;
        case KC_MISSION_CONTROL:
            if (record->event.pressed) {
                register_code(KC_LWIN);
                register_code(KC_TAB);
            } else {
                unregister_code(KC_TAB);
                unregister_code(KC_LWIN);
            }
            return false;
        case KC_LAUNCHPAD:
            if (record->event.pressed) {
                register_code(KC_LWIN);
            } else {
                unregister_code(KC_LWIN);
            }
            return false;
        default:
            return true; // Process all other keycodes normally
    }
}

説明

この関数そのものについては QMK のドキュメントを参照

Mac 判定
  • detected_host_os() == OS_MACOS || detected_host_os() == OS_IOS が真なら Mac
  • detected_host_os() を使うために os_detection.hinclude が必要
Hold/Tap のキーに割り込み処理を入れる

たとえば、ˋ~ = KC_GRAVE は通常は先述の通り日本語配列設定の Windows だと 半角/全角 キーとして扱われてしまうので、実際に ˋ~ が入力されるキーコードに置換したいとする。

もし ˋ~ のキーが Tap/Hold ではない単独のキーだった場合、

case KC_GRAVE:
    if (record->event.pressed) {
        register_code(KC_BACKSLASH);
    } else {
        unregister_code(KC_BACKSLASH);
    }
    return false;

とするだけで良い。

しかし「Tap で ˋ~ キー (KC_GRAVE)、Hold でレイヤー 4 キー」というキーにしている場合、そのキーを入力した際に process_record_user()keycode 引数は LT(4, KC_GRAVE) になるため、case KC_GRAVE では拾えず case LT(4, KC_GRAVE) とする必要がある。

また、割り込み処理の内容自体にも注意が必要。
上記の単独キーの場合と同じ割り込み処理を書いてしまうと、Hold してもレイヤーキーにならず単独キーと同じ動作になってしまう。

record->tap.countが truthy な値なら Tap 、Falsey な値なら Hold としてみなすことができる。

Hold の挙動はそのままで Tap の挙動を変える
if (!record->tap.count) {
    return true; // Hold の場合はそのまま処理
}

// Tap のキーコードを別に差し替え
if (record->event.pressed) {
    register_code(KC_BACKSLASH);
} else {
    unregister_code(KC_BACKSLASH);
}
return false;
Tap の挙動はそのままで、Hold の挙動を変える

前提に書いたように、Mac における Control キーを Windows でも (ざっくりとでいいので) 使いたかったので、レイヤー 5 を Windows 用の Control 再現レイヤーとして用意している。

キーマップ設定では「Tap で Space、Hold で Control」としているキーがある。
これを Windows では「Tap で Space、Hold で Layer(5)」となるようにしたい。

このような場合は以下のようにする。

if (record->tap.count) {
    return true; // Tap の場合はそのまま処理
}

// Hold の場合はレイヤー5扱いにする
if (record->event.pressed) {
    layer_on(5);
} else {
    layer_off(5);
}
return false;

その他

  • Mission Control キーは Mac でのみ有効だが、仮想デスクトップの表示やカレントの仮想デスクトップ上のウィンドウ一覧がでるというのは、Windows では Win + Tab キーの挙動と一致するのでそのように差し替えている
  • Launch Pad はなんとなく Windows では Windows キーに相当するような感じがあるのでそのように差し替え

KillerWhale 独自キーの挙動調整

lib/add_keycodes.c をいじる。

スクリーンショット

Captcha という、範囲選択をしたスクリーンショットを Mac なら Mac の、Windows なら Windows のショートカットキーを入力してくれる独自追加キーがある。

大変ありがたいのだが、Mac で使うと取ったスクショはいちいち写真アプリ的なのが開いてその中にスクショが表示される。
Windows ではクリップボードにスクショが入るので挙動が異なる。

Mac でも Control キーも入力していればクリップボード行きになるのだが、個人的にはクリップボード行きで問題ないケースが多く、Windows でも Mac でも同じ操作で同じことが起こってほしいので、
Captcha キーは Mac では Control も含めたスクショのショートカットキーを入力するようにする。

case CAPTCHA:
    if (record->event.pressed) {
        if (detected_host_os() == OS_MACOS || detected_host_os() == OS_IOS){
            register_code(KC_LSFT);
            register_code(KC_LGUI);
            register_code(KC_LCTL); // これ
            tap_code(KC_4);
            unregister_code(KC_LCTL); // これ
            unregister_code(KC_LGUI);
            unregister_code(KC_LSFT);
        } else {
KounotoriKounotori

Hold/Tap の挙動調整

Tap を優先すべきキーについて

アルファベットキーは、指を離す前に次のキーを押して高速打鍵することが記号キーなどと比べると圧倒的に多い。
これを踏まえると、よく使うアルファベットのキーを Tap/Hold とする場合、優先すべきは Hold ではなく Tap だと思われる。

「大西配列」(ホームポジションにローマ字入力において頻出するキーが配置されているキー配列) ではなおのこと、ホームポジションのキーに Tap/Hold を用いる場合には Tap を優先する必要性が大きくなる。

Tap/Hold の判定に影響する設定は幾つもあるが、Tap を優先させたい場合には、主に以下がポイントになると考えられる

  • Tapping term
    → Hold と見なす押下継続時間の閾値。これより小さい時間の入力なら Tap になる
    • Tap を優先したければ、デフォルト値の 200 より大きい値にすると良い
  • hold_on_other_key_press
    → Tapping term 以下の押下時間でも、Tap/Hold を押下中に別のキーも押下した瞬間、直ちに Hold として扱う
    • Tap 優先には自明に不要。デフォルトオフにしていれば特に設定しない
  • Permissive Hold
    hold_on_other_key_press の、Tap/Hold を押下したまま、別のキーを押下しさらに離すまでした場合に直ちに Hold 扱いとするバージョン
    • これを有効にするかは好みだと思う
    • こちらも hold_on_other_key_press もオフだと、Hold として使うには必ず Tapping term の時間押しっぱなしする必要が出てしまう
    • アルファベットキーを優先はしつつも、Hold でレイヤーを切り替えてその先のキーを早めに入力したいようなケースでは、有効化しておくと良さそうに思う

やること

Tapping termPermissive Hold を指定したキーでのみ有効化する

uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        case LT(UTIL, KC_E):
            return 300;
        default:
            return TAPPING_TERM;
    }
}

bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        case LT(UTIL, KC_E):
            return true;
        default:
            return false;
    }
}

Hold を優先すべきキーについて

このスクラップの前提にも書いたが、おれの場合はデフォルトのレイヤーには数字キーが無いため、別のレイヤーに配置する必要がある。

そのレイヤーに移るのを Tap/Hold で行う場合、Tap 優先だと数字や Shift と組み合わせた記号の入力が素早くできない問題が生じてしまう。
ある程度素早く入力できるようにしたいキーがあるレイヤーがあり、そのレイヤーへの移動を、頻繁には使わないキーの Tap/Hold で行う場合には、Hold を優先すると良いと思われる。

Hold を優先させたい場合、hold_on_other_key_press を有効にするのが良い。

やること

bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        case LT(4, KC_GRAVE):
        case LCTL_T(KC_SPACE):
            return true;
        default:
            return false;
    }
}