Edited at
ErgoDoxDay 12

macOSとWindowsで仲良くやっていくためのレイヤー設定

More than 1 year has passed since last update.

この投稿は :calendar: 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. カスタムキーコードを作る

レイヤー切り替え用のキーを設定します。


keymap.c

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.カスタムキーコードをレイヤーに割り当てる


keymap.c

  RESET,      MAC,        WIN,        _______,    _______,    _______,    _______,

_______, _______, _______, _______, _______, QWERTY, _______,
_______, _______, _______, _______, _______, QWDR, _______,
_______, _______, _______, _______, GAME, _______,

好きなところに配置しましょう。

自分の場合、設定系の入力は2段構えでレイヤー移動した先のコンフィグ用レイヤーに割り当ててます。


4.カスタムキー入力ハンドラ

カスタムキーコードの入力をどこで処理するかというとprocess_record_userというところです。


keymap.c

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.レイヤーについて

レイヤーについては公式のドキュメントで解説されています。


keymap.md

    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.初期レイヤー設定


keymap.c

void matrix_init_user(void) {

persistant_default_layer_set(1UL<<L_MAC);
layer_move(L_QWDR);
};

キーボード接続時にはmatrix_init_userが呼ばれるので、ここで任意の初期レイヤーを設定することが可能です。


7.まとめ

冒頭にも書いたんですが、レイヤー切り替えだけならDFとかTOだけでも大丈夫です。ただ、カスタムキーコードを使ったやり方だと他の処理もいろいろできるのでまとめてみました。


その他::warning:レイヤー変更時の修飾キーのスタックを防ぐ

レイヤー設定の話とは違いますが、ついでに書いておきます。

レイヤー切り替えと修飾キーを使っていると、たまにホールド状態が戻らずに修飾キーの入力がスタックするケースがあります。


スタックする例


  • レイヤー0にShiftが割り当てられている

  • 同じキーがレイヤー1ではAが割り当てられている

  • Shiftをホールドする

  • そのままレイヤー1に移動

  • Shiftキーを離す

  • レイヤー0に戻る

こうするとShiftキーが解除されず、押しっぱなしの状態になります。なぜかというと、レイヤー1で離したときにはShiftではなくAキーをリリースしたことになるので解除されないわけです。


解決法

これはconfig.h

#define PREVENT_STUCK_MODIFIERS

というオプションをつけることで防ぐことができます。

このへんの話はちょっと前のreadmeに書いてあったのですが、最近肥大化してきてdocWikiのほうにまとめ直されているようで、こちらに記載が移動してました。