BLE Micro Pro で eeconfig_update_user が使えなかった件
Posted on Nov 16, 2019
最近、Vue + Vuetify デビューしたんですが、あれ、良いですね。React (私が触ってたのは React Native だけど)を前回触った時に苦労したのは UI の部分で、結局いろんな野良ライブラリを使わないといけなくて、API が違ったり、React 更新したら動かなくなったりで、いろいろ困ったんですが、Vuetify みたいに UI の部分がある程度準備されているのは非常に助かりますね。数日でデモ的なものが作れてしまう。Vuetify お勧めしてくれたスーパーエンジニアには、Vuex も見てみ、って言われてるので、それももうそろそろ着手しようかな。
という Vue すごいぜ!sイントロを無視し、また今回もキーボードの話。Vue の話は、そのうち、、、って書いても、仕方ないか。ま、いいや。
Windows と Mac を一つのキーボードで使う
今の会社はリモート OK なので、最近は家から仕事することが多いです。で、一つのディスプレイに、Thinkpad と Macbook を両方つないで、切り替えながら作業してるんですが、キーボードは無線接続の自作キーボード 一つでのみ。キーボードかあら接続先を切り替えるだけで、どちらの環境を操作できるので、非常に便利。ですが、切り替えるたびに、キーボードのレイアウト設定を変えないといけないのが、微妙にめんどくさい。主に変更しないといけないのは下記の2点。
- コピーとかペーストのショートカットキー: Mac は OS キーだけど、Windows は Ctrl キー
- 言語の切り替えキー: Mac の言語切り替えに使うキーは、Windows の IME では選択・カスタマイズできない(OS には認識されてるけど)
ま、よくある悩みだと思います。
今までは、キーボードにレイアウトを変更する(デフォルトレイヤーを変更する)キーを割り振り、接続先を切り替えるごとに手動で変更してました。ま、1キー押すだけなんだけど、めんどくさい(笑)
「QMK の 永続メモリ使って、キーボードにどの接続先がどの OS なのか覚えさせればいけるよね」とは思ってたんですが、こっちはこっちでめんどくさくってずっと放置。
で、今回ちょっとやってみました。
EEPROM
QMK Firmware のマニュアルにありますが、eeconfig_init_user
、eeconfig_update_user
、eeconfig_read_useer
あたりのメソッドをくしればいける模様。
サンプルもあるので、それに従って実装。C 言語は勉強したことないので見様見真似。あと、メソッド名がダサいとか、設計がダサいとか、そういうのは、目を瞑ってください(笑)。夜中の二時くらいにボーッとしながら実装したので。
# 保存する情報の構造体
typedef union {
uint32_t raw;
struct {
bool keeb1_is_mac;
bool keeb2_is_mac;
bool keeb3_is_mac;
};
} user_config_t;
# 今使ってるキーボードの設定
uint8_t current_keeb;
bool is_mac;
user_config_t user_config;
# 初期化
void eeconfig_init_user(void) {
user_config.raw = 0;
user_config.keeb1_is_mac = true;
user_config.keeb2_is_mac = true;
user_config.keeb3_is_mac = true;
eeconfig_update_user(user_config.raw);
}
# 立ち上げたときによむもの
void keyboard_post_init_user(void) {
user_config.raw = eeconfig_read_user();
current_keeb = 1;
is_mac = user_config.keeb1_is_mac;
}
# メソッド名が酷い
void update_os() {
switch (current_keeb) {
case 1:
user_config.keeb1_is_mac = is_mac;
break;
case 2:
user_config.keeb2_is_mac = is_mac;
break;
case 3:
user_config.keeb3_is_mac = is_mac;
break;
}
}
# レイヤー切り替えを行ったら、それをメモリに保存
void change_keymap(bool to_mac) {
if (to_mac) {
set_single_persistent_default_layer(_MAC);
is_mac = true;
} else {
set_single_persistent_default_layer(_WIN);
is_mac = false;
}
update_os();
eeconfig_update_user(user_config.raw);
}
# レイヤー切り替えないといけないかのチェック
bool is_change_required() {
switch (current_keeb) {
case 1:
return (user_config.keeb1_is_mac != is_mac);
break;
case 2:
return (user_config.keeb2_is_mac != is_mac);
break;
case 3:
return (user_config.keeb3_is_mac != is_mac);
break;
}
return false;
}
# 接続先デバイスを変えた際に、設定を確認し、必要に応じてレイヤー変更
void switch_device(uint8_t num) {
current_keeb = num;
if (is_change_required()) {
change_keymap(!is_mac);
}
restart_advertising_id(num);
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
switch (keycode) {
case MAC:
change_keymap(true);
return false;
case WIN:
change_keymap(false);
return false;
case AD_WO_L:
restart_advertising_wo_whitelist();
return false;
# 中略
case ADV_ID0:
restart_advertising_id(0);
return false;
case ADV_ID1:
switch_device(1);
return false;
case ADV_ID2:
switch_device(2);
return false;
case ADV_ID3:
switch_device(3);
return false;
# 中略
}
}
return true;
};
eeconfig 未実装
で、いざファームを焼こうとしたところ、
implicit declaration of function "'eeconfig_update_user'"
というエラー。で調べたところわかったことは、sekigon 氏 の nrf52 ブランチには、まだ上記の機能が実装されてない、ってこと。興味のある方は、対象の箇所のレポジトリはっときます。
- qmk_firmware/tmk_core/common/eeconfig.h @ qmk
- qmk_firmware/tmk_core/common/eeconfig.c @ qmk
- qmk_firmware/tmk_core/common/eeconfig.h @ sekigon
- qmk_firmware/tmk_core/common/eeconfig.c @ sekigon
本家の変更履歴みると、どうやら、eeconfig_*_user の機能が追加されたのは1年くらい前。すごい最近。
変更履歴見ると、上記の2ファイルさえいじればいけそう、ってのはわかったんですが、とりあえず修正。この変更を加えれば、たぶん BLE Micro Pro でも eeconfig_*_user が使えるようになると思う。多分。
ま、プルリクすればいいんですが、qmk_firmware のソースコード真面目に読んだことないし、C 言語勉強したことないしで、品質的にあれなので、今回は断念。いやだって、eeconfig_init_quantum
とか、なんのために存在するのか正直よくわからんし。quantum
フォルダもないしてるかよくわからんし。
ということで、無事実装終わり。キーボードの接続先を変更するのと合わせて、キーボードのレイヤーを変更してくれるようになりました。これで、OS 行ったり来たりしても、違和感なく作業できるはず。非常に地味ですが、便利。
今回の実装、bluetooth 接続だからできることなので、USB 接続だと、何らかの方法で OS を判定しないといけませんね。ま、そっちの方が汎用性のある実装にはなりそうですけど。
comments powered by Disqus