この投稿は ErgoDox Advent Calendar 2016 の 12日目の記事です。
課題
- macOSの
Cmdキー
はWindowsだとWinキー
になるよ - 同じ感覚で使うために
Cmd
のところはWindowsではCtrl
にしたいよ - じゃあOS毎のレイヤーを作って設定しよう
- Linuxは残念ながら使ってないので書いてません…
- 単にレイヤー設定だけなら
DF
とかTO
でいいんですが、今回はカスタムキーコードを使うやり方を書きます
やり方
1. 各OS用の差分レイヤーを作成する
macOS用
,-------------. ,---------------.
|ctl F2| | |ctl sp| ctl F3 |
,------|------|------| |------+--------+------.
| | | | | | | |
| Space| LAlt |------| |------| | |
| Cmd | | LCtrl| | | | |
`--------------------' `----------------------'
Windows用
,-------------. ,-------------.
|Alt F4| | | | |
,------|------|------| |------+------+------.
| | | | | | | |
| Space| LAlt |------| |------| | |
| LCtrl| | Win | | | | |
`--------------------' `--------------------'
一例ですが、こんな感じにOSによって変更したい部分だけのレイヤーを用意することでMacのときにはCmd
、WindowsのときにはCtrl
として設定を変えるというのが今回の趣旨です。
2. カスタムキーコードを作る
レイヤー切り替え用のキーを設定します。
enum custom_keycodes {
//--layers--
// layouts
QWERTY = SAFE_RANGE,
QWDR,
GAME,
// momentary layer
NAV,
CONF,
GAME2,
// os
MAC,
WIN,
};
最近ErgoDoxのデフォルトキーマップにも追加されていたんですが、カスタムキーコードというものを設定して使います。enumの開始行で指定しているSAFE_RANGE
というのはキーコード定義の最後で宣言されているものなので、これ以降のキーコードを使うことでカスタム専用の入力ができます。
※ただ、このキーコードの注意点としては通常キーの0x0000-0x00FF
の範囲外となるのでCTL_T(keycode)
といったアクション設定などはそのままでは利用できません。
3.カスタムキーコードをレイヤーに割り当てる
RESET, MAC, WIN, _______, _______, _______, _______,
_______, _______, _______, _______, _______, QWERTY, _______,
_______, _______, _______, _______, _______, QWDR, _______,
_______, _______, _______, _______, GAME, _______,
好きなところに配置しましょう。
自分の場合、設定系の入力は2段構えでレイヤー移動した先のコンフィグ用レイヤーに割り当ててます。
4.カスタムキー入力ハンドラ
カスタムキーコードの入力をどこで処理するかというとprocess_record_user
というところです。
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
//--layers--
//os
case MAC:
if (record->event.pressed) {
persistant_default_layer_set(1UL<<L_MAC);
}
return false;
break;
case WIN:
if (record->event.pressed) {
persistant_default_layer_set(1UL<<L_WIN);
}
return false;
break
//layout
case QWERTY:
if (record->event.pressed) {
layer_move(L_QWERTY);
}
return false;
break;
case QWDR:
if (record->event.pressed) {
layer_move(L_QWDR);
}
return false;
break;
case GAME:
if (record->event.pressed) {
layer_move(L_GAME);
}
return false;
break;
//momentary layer
case GAME2:
switch_layer(L_GAME2, record->event.pressed);
return false;
break;
case NAV:
switch_layer(L_NAV, record->event.pressed);
return false;
break;
case CONF:
switch_layer(L_CONF, record->event.pressed);
return false;
break;
}
return true;
}
ここでやっているのは主に3つです。
- OS用のレイヤー設定をdefault_layerで指定
- 文字配列をlayer_moveで指定
- ホールド時の一時的なレイヤーをlayerのオンオフで設定
5.レイヤーについて
レイヤーについては公式のドキュメントで解説されています。
Overlay feature layer
--------------------- bit|status
____________ ---+------
31 / / 31 | 0
30 /___________// -----> 30 | 1
29 /___________/ -----> 29 | 1
: : | :
: ____________ : | :
2 / / 2 | 0
,->1 /___________/ -----> 1 | 1
| 0 0 | 0
| +
`--- default_layer = 1 |
layer_state = 0x60000002 <-'
レイヤー設定は32bitの情報で管理されていて各レイヤーがオンオフの状態を持っているので、好きなレイヤーを有効にして上層から掛け合わせることができます。
- default_layer_state
- layer_state
レイヤー設定は上記2つのステートがあり、default_layerに指定されているレイヤーは常にオンになります。
今回はOS用レイヤーをdefault_layerに指定し、さらに文字配列のレイヤーをlayer_moveで排他的に選択することで、OSと文字配列レイヤーをそれぞれ選択して掛け合わせるようにしました。
レイヤー設定を変えるアクションについてはこのへんに定義されています。
6.初期レイヤー設定
void matrix_init_user(void) {
persistant_default_layer_set(1UL<<L_MAC);
layer_move(L_QWDR);
};
キーボード接続時にはmatrix_init_user
が呼ばれるので、ここで任意の初期レイヤーを設定することが可能です。
7.まとめ
冒頭にも書いたんですが、レイヤー切り替えだけならDF
とかTO
だけでも大丈夫です。ただ、カスタムキーコードを使ったやり方だと他の処理もいろいろできるのでまとめてみました。
その他:レイヤー変更時の修飾キーのスタックを防ぐ
レイヤー設定の話とは違いますが、ついでに書いておきます。
レイヤー切り替えと修飾キーを使っていると、たまにホールド状態が戻らずに修飾キーの入力がスタックするケースがあります。
スタックする例
- レイヤー0にShiftが割り当てられている
- 同じキーがレイヤー1ではAが割り当てられている
- Shiftをホールドする
- そのままレイヤー1に移動
- Shiftキーを離す
- レイヤー0に戻る
こうするとShiftキーが解除されず、押しっぱなしの状態になります。なぜかというと、レイヤー1で離したときにはShiftではなくAキーをリリースしたことになるので解除されないわけです。
解決法
これはconfig.h
に
#define PREVENT_STUCK_MODIFIERS
というオプションをつけることで防ぐことができます。
このへんの話はちょっと前のreadmeに書いてあったのですが、最近肥大化してきてdocやWikiのほうにまとめ直されているようで、こちらに記載が移動してました。