見出し画像

GK61 proの親指シフトキーボード化

自作キーボードでQMK firmwareにnicolaを実装して親指シフトキーボードにしている事例は知っていましたが、すでにB割れUSキーボードのGK68とhoboNicolaアダプターで不自由してなかったし、何より費用がかかるので興味が湧きませんでした。 ところが昨年(2023年)、SKYLOONGからQMK/VIA対応のキーボード GK61 pro が発売されました。 GK68に較べるとカーソルキーやDELキーが無いのがやや不満ですが、価格も1万くらいなので親指ネタとしては面白い…くらいの感覚で購入してみました。



1. ATmega32u4のnicola実装例

自作キーボードではMCUにATmega32u4が多く使われていて、nicola実装例としては@sadaoikebeさんのXD60キットで親指シフトキーボードを作るが有名です。 今回はこの実装をパクって…いや参考にオリジナルのレポジトリに修正をくわえました。 MCUはST32F103ですので、他のARM系の32bit MCUでも同じように実装できると思います。

2. SKYLOONG GK61 proの親指シフト化

qmk_firmwawreのレポジトリをForkして変更を加えます。 具体的には \keyboards\skyloong\gk61\pro_48\keymaps\defaultをコピーして\nicola に名前を変えます。keymap.c でキーマップとnicolaモード切替えを入れ、nicola.c で状態遷移とローマ字変換を行います。 具体的にはソースコードで確認してください。

keymap.c

process_record_user( ) はキーボードのイベント毎に呼ばれるユーザ定義です。 前半ではMS-IMEをon/offするキーコードを送出します。

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        // 英数キー(Caps Lock)、nicola mode オフ
        case KC_CAPS_LOCK:
            if (record->event.pressed)
                send_string(SS_LSFT(SS_TAP(X_CAPS_LOCK)));
            return false;
        // 英数モードのとき左親指キー(F14)で、nicola mode オン
        case KC_F14:
            if (record->event.pressed)
                send_string(SS_TAP(X_F14));
            return false;
    }

後半では nicola_mode( ) で入力モードか修飾モードかを確認し、nicola状態遷移図に従ってキーコードを process_nicola( ) で親指シフトのコードに変換します。

     // NICOLA親指シフト
    bool a = true;
    if (nicola_state()) {
        nicola_mode(keycode, record);
        a = process_nicola(keycode, record);
    }
    if (a == false)
        return false;
    return true;
}

nicolaモードのon/offは後述するWidowsアプリ observe_ime からの通知されるNumLockを使います。 これを実装するため led_update_kb( ) を使います。 この関数はキーボードのLEDが変化したときに呼ばれます。

 bool led_update_kb(led_t led_state) {
    bool res = led_update_user(led_state);
    if(res) {
        if (led_state.num_lock)
            nicola_on();
        else
            nicola_off();
    }
    return res;
}

matrix_scan_user( ) はキースキャンのたびに呼ばれる関数で、timer_tick( ) を呼び出してキープレスタイマーのタイムアウトをチェックします。 キースキャンは1秒間に1000回とGK61 proの説明にありますので、タイマーの分解能はだいたい1msだと思います。 タイマー割込みを使わないため、直接レジスタをいじる必要がありません。

void matrix_scan_user(void) {
    uint32_t now = timer_read32();
    timer_tick(now);    // drive nicola state-machine.
}

親指キーの間にあるホイールの設定は encoder_map で指定します。以下は回転方向によってBackspaceとDeleteに割り当てた場合です。 デフォルトの設定は2クリックですが、info.joson 内の設定で変えられます。

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
    [_QWERTY] = { ENCODER_CCW_CW(KC_BSPC, KC_DEL) },
    [_NICOLA] = { ENCODER_CCW_CW(KC_BSPC, KC_DEL) },
    [_FUNC] =   { ENCODER_CCW_CW(_______, _______) }
};
#endif

レイヤー毎のLED設定は rgb_matrix_indicators_advanced_user( ) で行いました。nicolaモードのときは左右の親指キーを点灯しています。

レイヤー毎のLED設定

nicola.c

状態遷移はNICOLA規格に従って一部コードを変えています。操作感は特に変わっていません。状態遷移図についは以下の記事を参照して下さい。

タイマー関連はMCUが違うので変えています。キープレスタイマーのタイムアウト監視は前述のようにキースキャンのたびに呼ばれます。 タイムアウトした場合は、状態によってコードを送出して状態遷移を初期状態に戻します。

static uint32_t event_time = 0;

void timer_tick(uint32_t now) {
    if (event_time != 0 && (now > event_time)) {
        event_time = 0;
        keypress_timer_expired();
    }
}

キープレスタイマーの設定は状態遷移の中で行います。 現在の時間+タイムアウト時間 をevent_time に設定するだけです。 通常のキーは150ms、親指シフトキーは250msにしています。

    //keypress_timer_start(TIMEOUT_THRESHOLD * 16);
    event_time = curr_time + TIMEOUT_THRESHOLD;
    
    //keypress_timer_start(TIMEOUT_THRESHOLD * 16);
    event_time = curr_time + TIMEOUT_OYA_THRESHOLD;

親指シフトキーの単押しと長押しの打ち分けは以下のとおりです。 250msのタイムアウト前に親指シフトキーがリリースされは場合は、通常の親指キーに割り当てられたコードを送出します。

void nicola_o_type(void) {
    if(nicola_o_key == NG_SHFTL)
        send_string(SS_TAP(X_F14)); 
    else if(nicola_o_key == NG_SHFTR)
        send_string(SS_TAP(X_SPACE)); 
}

タイムアウトした場合はTABキー、F15(変換)キーのコードを送出します。

void nicola_o_TO_type(void) {
    if(nicola_o_key == NG_SHFTL)
        send_string(SS_TAP(X_TAB)); 
    else if(nicola_o_key == NG_SHFTR)
        send_string(SS_TAP(X_F15)); 
}

キー配列

キー配列は最終的に以下のようにしました。 FNキーは多用するので右親指キーの隣に移動しました。カーソルキーもよく使うので、右下の修飾キーに割り当てています。本来の機能はFNレイヤーに移しています。

親指キーの単独打鍵は短押しと長押しで機能が異なります。左親指キーの単押し(250ms以下)でIMEオフ、長押しでTAB(候補選択)にしています。 右親指キーは単押しでSPACE、長押しでF15(変換)になります。

中央のノブは用途に迷うところです。現状は反時計回りでBackspace、時計回りでDeleteにしています。押すとESCキーです。

【ソースコード】の利用はあくまでも自己責任で行って下さい。

3. ファームウエアの書き込み

QMKファームウエアのビルド環境の作り方はネットにいろいろ載っています。 私はWindows11にMsys2をインストールしてMSYS2 MINGW64でビルド、VSCodeでコードの編集をしています。

ビルドはQMKファームウエアのディレクトリに移動して、以下のmakeコマンドで書き込みまで進みます(:flashが無ければビルドのみ)。

$ make skyloong/gk61/pro_48:nicola:flash
MSYS2 MINGW64の起動とビルド

GK61 proはUSBを差し込んだ一瞬だけBootloaderモードになるので、書き込みのために特に操作は必要ありません。 単純にUSBの挿抜で済みます。 ビルドが終わってたら書き込み先のBootloaderを探しますから、キーボードのUSBを差し込みます。

ビルド完了とDFUデバイス待ち

USBを差し込むとFlashメモリへ書き込みがはじまります。 ほぼ一瞬で終わりますので静かに待ちます。 何度も書き込みをしていますが、まだ失敗したことはあません。

書き込み完了

最後にもう一度USBを挿抜するとキーボードか使えるようになります。
なお、ビルドしたファームウエアをそのまま使用する場合、QMKのビルド環境を作らずにQMK Toolboxで書き込むことが出来ます。

4. Windows PCの設定

4.1 MS-IMEの設定

MS-IMEは日本語モードでキーボード・レイアウトはUSキーボードです。キーボードはローマ字に変換してPCに出力します。 USキーボードには無変換/変換キーを受け付けませんから、代わりにF14/F15を使用します。 これを無変換/変換キー相当の動作にするには「以前のバージョン」のMS-IMEにする必要があります。 この変更のしかたはネットにいろいろ書いていますので検索してください。

F14とF15キーの追加

詳細設定→全般にある「直接入力モードを使用しない(U)」にチェックを入れておきます。

直接入力モードの設定

また、Japanist2003などを使用していた場合は、色設定をATOKにしておくと変換時の違和感が少ないです。

4.2 Observe IMEの設定

本キーボードはhoboNicolaで使用している"observe_ime"を使うことを想定しています。 Windowsのアプリ毎のIME状態がキーボードに反映されるので、いわゆるモードずれを気にする必要がありません。 入手先は情報元に記載しています。

  • F14でMS-IMEは"IME on"、CAPSLOCKで"IME off"に切り替える。

  • "observe_ime"はIMEの状態からキーボードにNum Lockで通知する。

  • キーボードではNum Lockの状態に従ってNicolaモードをon/offする。

※この機能を利用しない場合は\pro_48\config,hの#define USE_OBSERVE_IMEをコメントアウトして下さい。

"observe_ime"はスタートアップに入れておいて、以下のように設定しておきます。

observe_imeの設定

5. 情報元


この記事が気に入ったらサポートをしてみませんか?