最近、Vue + Vuetify デビューしたんですが、あれ、良いですね。React (私が触ってたのは React Native だけど)を前回触った時に苦労したのは UI の部分で、結局いろんな野良ライブラリを使わないといけなくて、API が違ったり、React 更新したら動かなくなったりで、いろいろ困ったんですが、Vuetify みたいに UI の部分がある程度準備されているのは非常に助かりますね。数日でデモ的なものが作れてしまう。Vuetify お勧めしてくれたスーパーエンジニアには、Vuex も見てみ、って言われてるので、それももうそろそろ着手しようかな。

という Vue すごいぜ!sイントロを無視し、また今回もキーボードの話。Vue の話は、そのうち、、、って書いても、仕方ないか。ま、いいや。

Windows と Mac を一つのキーボードで使う

今の会社はリモート OK なので、最近は家から仕事することが多いです。で、一つのディスプレイに、Thinkpad と Macbook を両方つないで、切り替えながら作業してるんですが、キーボードは無線接続の自作キーボード 一つでのみ。キーボードかあら接続先を切り替えるだけで、どちらの環境を操作できるので、非常に便利。ですが、切り替えるたびに、キーボードのレイアウト設定を変えないといけないのが、微妙にめんどくさい。主に変更しないといけないのは下記の2点。

ま、よくある悩みだと思います。

今までは、キーボードにレイアウトを変更する(デフォルトレイヤーを変更する)キーを割り振り、接続先を切り替えるごとに手動で変更してました。ま、1キー押すだけなんだけど、めんどくさい(笑)

「QMK の 永続メモリ使って、キーボードにどの接続先がどの OS なのか覚えさせればいけるよね」とは思ってたんですが、こっちはこっちでめんどくさくってずっと放置。

で、今回ちょっとやってみました。

EEPROM

QMK Firmware のマニュアルにありますが、eeconfig_init_usereeconfig_update_usereeconfig_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 ブランチには、まだ上記の機能が実装されてない、ってこと。興味のある方は、対象の箇所のレポジトリはっときます。

本家の変更履歴みると、どうやら、eeconfig_*_user の機能が追加されたのは1年くらい前。すごい最近。

変更履歴見ると、上記の2ファイルさえいじればいけそう、ってのはわかったんですが、とりあえず修正。この変更を加えれば、たぶん BLE Micro Pro でも eeconfig_*_user が使えるようになると思う。多分。

ま、プルリクすればいいんですが、qmk_firmware のソースコード真面目に読んだことないし、C 言語勉強したことないしで、品質的にあれなので、今回は断念。いやだって、eeconfig_init_quantum とか、なんのために存在するのか正直よくわからんし。quantum フォルダもないしてるかよくわからんし。


ということで、無事実装終わり。キーボードの接続先を変更するのと合わせて、キーボードのレイヤーを変更してくれるようになりました。これで、OS 行ったり来たりしても、違和感なく作業できるはず。非常に地味ですが、便利。

今回の実装、bluetooth 接続だからできることなので、USB 接続だと、何らかの方法で OS を判定しないといけませんね。ま、そっちの方が汎用性のある実装にはなりそうですけど。


comments powered by Disqus