zmk に変更したので、今は使っていません。記録のために残しておきます。
sweep 無線化に従い、arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" arch -x86_64 brew install qmk/qmk/qmk
ロゼッタ版の brew を入れる必要があるみたい。 arm 版の brew を置き換えるので注意。
sweep
sweep というキーボードを使っています。
右と左の設定
参考: https://github.com/qmk/qmk_firmware/tree/master/keyboards/ferris/sweep
左の promicro に繋げた状態で、 reset を 1 秒ショートさせるとブートロードモードになるので
make CONVERT_TO=kb2040 ferris/sweep:default:uf2-split-left
を実行する。右も同じ
デフォルトキーマッピングの設定
参考: https://joshajohnson.com/sea-picro/#documentation
同じくブートロードモードになってる状態で、
qmk flash -c -kb ferris/sweep -km default -e CONVERT_TO=promicro_rp2040
qmk list-keyboards
とすると、対応するキーボードのリストが出てくる。
この時点で普通の qwerty は使える状態になった。おそらくhttps://config.qmk.fm/#/ferris/sweep/LAYOUT_split_3x5_2 で確認できるもの。
キーマップの定義
旅行中に firmware が破損したのか、左右と上下が反転したような挙動を確認した。usbc どうしを繋げたのが悪かったのか、それとも何かがショートしたのかわからないけど帰ってから、firmware を re flash した。
なかなか EEPROM のリセットがうまくいかなかったのか、元に戻せないでいたけど、下記のコマンドで解決&復活した。
cd ~/qmk_firmware # for left make CONVERT_TO=promicro_rp2040 ferris/sweep:yasushisakai:uf2-split-left # for right make CONVERT_TO=promicro_rp2040 ferris/sweep:yasushisakai:uf2-split-right
リセットは毎度のピンセットでやった。これだといいのは、ドラッグ&ドロップしなくてもいいところで、コマンドラインで全てか解決すると、d&d だと表示されない、ログが出るからいい。
とはいえ、ipad しか持って行ってない状態で今回みたいなことがあると困る。
デフォルトのキーボードとキーマップを設定しておく。
# qmk config user.keyboard=ferris/sweep # qmk config user.keymap=yasushisakai
https://docs.qmk.fm/#/newbs_building_firmware?id=building-your-first-firmware
qmk new-keymap
ほんとは、 meh
を設定したいけど、また今度。
~/qmk_firmware/keyboards/ferris/keymaps/yasushisakai
ができる。
keymap.c
が出てくると思いきや、 keymap.json
が出てきた。c で追記する関数があるので、
qmk json2c keymap.json > keymap.c
として、cに書き直す。 一応これでコンパイルが通るか確認した。
そのまま
qmk compile -e CONVERT_TO=promicro_rp2040
すればいいんだと思う。
keymap.c
- header
#include QMK_KEYBOARD_H /* THIS FILE WAS GENERATED! * * * This file was generated by emacs org-mode tangle function. * see https://yasushisakai.com/qmk.html for details */ /* tap dance codes */ enum { CT_CLN, CT_Q_ESC, CT_Z_TAB, CT_R_LPRN, CT_T_RPRN, CT_I_LBRC, CT_O_RBRC, CT_P_MINUS, CT_SCLN_EQ, CT_SLSH_QUOT, CT_MEH_TO1, CT_MEH_TO2 };
- meta programming keymap
TRANS = 'KC_TRNS' def kc(key): return f'KC_{key.upper()}' def render_layers(layers): output = "" meat = ",\n".join([render_layer(i, layer) for i, layer in enumerate(layers)]) return meat def render_layer(i, layer): output = f' [{i}] = LAYOUT_split_3x5_2(' meat = ", ".join(layer) output += meat; output += ")" return output base = [ 'TD(CT_Q_ESC)', kc('w'), kc('e'), 'TD(CT_R_LPRN)', 'TD(CT_T_RPRN)', kc('y'), kc('u'), 'TD(CT_I_LBRC)', 'TD(CT_O_RBRC)', 'TD(CT_P_MINUS)', kc('a'), 'CTL_T(KC_S)', 'ALT_T(KC_D)', 'SFT_T(KC_F)', 'GUI_T(KC_G)', 'RGUI_T(KC_H)', 'RSFT_T(KC_J)', 'ALT_T(KC_K)', 'RCTL_T(KC_L)', 'TD(CT_SCLN_EQ)', 'TD(CT_Z_TAB)', kc('x'), kc('c'), kc('v'), kc('b'), kc('n'), kc('m'), kc('comma'), kc('dot'), 'TD(CT_SLSH_QUOT)', kc('spc'), kc('ent'), 'CT_MEH_TO1', kc('bspc') ] numbers = [ kc('esc'), kc('7'), kc('8'), kc('9'), kc('0'), TRANS, TRANS, kc('lbrc'), kc('rbrc'), kc('bsls'), kc('tab'), 'CTL_T(KC_4)', 'ALT_T(KC_5)', 'SFT_T(KC_6)', 'GUI_T(KC_MINS)', 'RGUI_T(KC_LEFT)', 'RSFT_T(KC_DOWN)', 'ALT_T(KC_UP)', 'RCTL_T(KC_RIGHT)', kc('quot'), kc('grv'), kc('1'), kc('2'), kc('3'), kc('eql'), TRANS, TRANS, kc('lbrc'), kc('rbrc'), kc('slsh'), 'TO(0)', TRANS, 'CT_MEH_TO2', TRANS ] functions = [ TRANS, kc('f7'), kc('f8'), kc('f9'), kc('f10'), TRANS, kc('btn1'), kc('wh_d'), kc('btn2'), kc('volu'), TRANS, kc('f4'), kc('f5'), kc('f6'), kc('f11'), kc('ms_l'), kc('ms_d'), kc('ms_u'), kc('ms_r'), kc('mute'), TRANS, kc('f1'), kc('f2'), kc('f3'), kc('f12'), TRANS, TRANS, kc('wh_u'), TRANS, kc('vold'), 'TO(0)', TRANS, TRANS, TRANS ] layers = [base, numbers, functions]; layer_part = '#+begin_src c :tangle /Users/yasushi/qmk_firmware/keyboards/ferris/keymaps/yasushisakai/keymap.c\n' layer_part += 'const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\n' layer_part += render_layers(layers) layer_part += '\n};' # the last bracket to close the root object return layer_part
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [0] = LAYOUT_split_3x5_2(TD(CT_Q_ESC), KC_W, KC_E, TD(CT_R_LPRN), TD(CT_T_RPRN), KC_Y, KC_U, TD(CT_I_LBRC), TD(CT_O_RBRC), TD(CT_P_MINUS), KC_A, CTL_T(KC_S), ALT_T(KC_D), SFT_T(KC_F), GUI_T(KC_G), RGUI_T(KC_H), RSFT_T(KC_J), ALT_T(KC_K), RCTL_T(KC_L), TD(CT_SCLN_EQ), TD(CT_Z_TAB), KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMMA, KC_DOT, TD(CT_SLSH_QUOT), KC_SPC, KC_ENT, TO(1), KC_BSPC), [1] = LAYOUT_split_3x5_2(KC_ESC, KC_7, KC_8, KC_9, KC_0, KC_TRNS, KC_TRNS, KC_LBRC, KC_RBRC, KC_BSLS, KC_TAB, CTL_T(KC_4), ALT_T(KC_5), SFT_T(KC_6), GUI_T(KC_MINS), RGUI_T(KC_LEFT), RSFT_T(KC_DOWN), ALT_T(KC_UP), RCTL_T(KC_RIGHT), KC_QUOT, KC_GRV, KC_1, KC_2, KC_3, KC_EQL, KC_TRNS, KC_TRNS, KC_LBRC, KC_RBRC, KC_SLSH, TO(0), KC_TRNS, TO(2), KC_TRNS), [2] = LAYOUT_split_3x5_2(KC_TRNS, KC_F7, KC_F8, KC_F9, KC_F10, KC_TRNS, KC_BTN1, KC_WH_D, KC_BTN2, KC_VOLU, KC_TRNS, KC_F4, KC_F5, KC_F6, KC_F11, KC_MS_L, KC_MS_D, KC_MS_U, KC_MS_R, KC_VOLD, KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F12, KC_TRNS, KC_TRNS, KC_WH_U, KC_TRNS, KC_MUTE, TO(0), KC_TRNS, KC_TRNS, KC_TRNS) };
- footer (tap hold)
/quantum
フォルダの中にほとんど入ってたけど、必要そうなものを抜粋。/* tap_dance_action_t */ typedef struct { tap_dance_state_t state; struct { tap_dance_user_fn_t on_each_tap; tap_dance_user_fn_t on_dance_finished; tap_dance_user_fn_t on_reset; } fn; void *user_data; } tap_dance_action_t; typedef struct { uint16_t interrupting_keycode; uint8_t count; uint8_t weak_mods; # ifndef NO_ACTION_ONESHOT uint8_t oneshot_mods; # endif bool pressed : 1; bool finished : 1; bool interrupted : 1; } tap_dance_state_t; /* Key event container for recording */ typedef struct { keyevent_t event; #ifndef NO_ACTION_TAPPING tap_t tap; #endif #ifdef COMBO_ENABLE uint16_t keycode; #endif } keyrecord_t; /* key event */ typedef struct { keypos_t key; bool pressed; uint16_t time; } keyevent_t; # define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset) \ { .fn = {user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset}, .user_data = NULL, }
#if defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = { }; #endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE) ////////// TAP_HOLD typedef struct { uint16_t tap; uint16_t hold; uint16_t held; } tap_dance_tap_hold_t; bool process_record_user(uint16_t keycode, keyrecord_t *record) { tap_dance_action_t *action; switch (keycode) { case TD(CT_CLN): // list all tap dance keycodes with tap-hold configurations case TD(CT_Q_ESC): case TD(CT_Z_TAB): case TD(CT_R_LPRN): case TD(CT_T_RPRN): case TD(CT_I_LBRC): case TD(CT_O_RBRC): case TD(CT_SLSH_QUOT): case TD(CT_P_MINUS): case TD(CT_SCLN_EQ): action = &tap_dance_actions[TD_INDEX(keycode)]; if (!record->event.pressed && action->state.count && !action->state.finished) { tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data; tap_code16(tap_hold->tap); } } return true; } /// The second function, on_dance_finished_fn(), is called when the tap dance is interrupted or ends because TAPPING_TERM milliseconds have passed since the last tap. void tap_dance_tap_hold_finished(tap_dance_state_t *state, void *user_data) { tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; if (state->pressed) { if (state->count == 1 #ifndef PERMISSIVE_HOLD && !state->interrupted #endif ) { register_code16(tap_hold->hold); tap_hold->held = tap_hold->hold; } else { register_code16(tap_hold->tap); tap_hold->held = tap_hold->tap; } } } // After on_dance_finished_fn() was called or would have been called, but no sooner than when the tap dance key is released, on_dance_reset_fn() is called. It is possible to end a tap dance immediately, skipping on_dance_finished_fn(), but not on_dance_reset_fn, by calling reset_tap_dance(state). void tap_dance_tap_hold_reset(tap_dance_state_t *state, void *user_data) { tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; if (tap_hold->held) { unregister_code16(tap_hold->held); tap_hold->held = 0; } } #define ACTION_TAP_DANCE_TAP_HOLD(tap, hold) \ { .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), } #define ACTION_TAP_TOGGLE_MEH_HOLD(tap, hold) \ { .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), } tap_dance_action_t tap_dance_actions[] = { [CT_CLN] = ACTION_TAP_DANCE_TAP_HOLD(KC_COLN, KC_SCLN), [CT_Q_ESC] = ACTION_TAP_DANCE_TAP_HOLD(KC_Q, KC_ESC), [CT_Z_TAB] = ACTION_TAP_DANCE_TAP_HOLD(KC_Z, KC_TAB), [CT_R_LPRN] = ACTION_TAP_DANCE_TAP_HOLD(KC_R, KC_LPRN), [CT_T_RPRN] = ACTION_TAP_DANCE_TAP_HOLD(KC_T, KC_RPRN), [CT_I_LBRC] = ACTION_TAP_DANCE_TAP_HOLD(KC_I, KC_LBRC), [CT_O_RBRC] = ACTION_TAP_DANCE_TAP_HOLD(KC_O, KC_RBRC), [CT_P_MINUS] = ACTION_TAP_DANCE_TAP_HOLD(KC_P, KC_MINS), [CT_SCLN_EQ] = ACTION_TAP_DANCE_TAP_HOLD(KC_SCLN, KC_EQL), [CT_SLSH_QUOT] = ACTION_TAP_DANCE_TAP_HOLD(KC_SLSH, KC_QUOT), [CT_MEH_TO1] = ACTION_TAP_DANCE_TAP_HOLD(KC_MEH, TO(1)), [CT_MEH_TO2] = ACTION_TAP_DANCE_TAP_HOLD(KC_MEH, TO(2)), };