未知の階層に挑戦Tri-Layers

今回は、翻訳が全く働かないため、手探りでの投稿になる。

結論はOLKB用に開発したと思われる`update_tri_layer`関数についてだ。

様式：[update_tri_layer(x, y, z)](#update_tri_layer関数)
挙動1：Xレイヤー変更キーでX階層のレイヤーを使う。
挙動2：Yレイヤー変更キーでY階層のレイヤーを使う。
挙動3：Xレイヤー変更キー押下かつ、Yレイヤー変更キー押下により、Zレイヤー変更が行われることで、Z階層のレイヤーを使うことができる。

結論：少ないキー数のキーボードで有用な機能だと結論づけられる。
要は、2つのキーを同時押しすることで、今までにない階層の操作ができるため、滅多に使わないキーを割り当てることで、キーの節約になる。
例えば、ディスプレイの明度や音量の大小変更などは、1度変更してしまえば、次に使うまで固定のままだろう。
LEDの光量もしかり。
CD-ROMドライブの排出などもしかり。
過去に投稿した[Feature Mouse keys](930b87629c907a0aa787)や[Feature Bootmagic](83f1552733870914e097)などのように、そのときだけ使うキーコードを設定するのが吉だろう。

以下、本題。

# update_tri_layer_state関数
上記とは別の様式が存在する。
それが、以下だ。

関数：`update_tri_layer_state(state, x, y, z)`

使い方は、以下の通り。

# 3層目の利用方法
以下のコードを組み込むことで利用ができる。

```c:keymap.c
uint32_t layer_state_set_user(uint32_t state) {
	return update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
}
```

`_LOWER`キーコード：_LOWER階層を操作する。
`_RAISE`キーコード：_RAISE階層を操作する。
上記2種類の同時押し：_ADJUST階層を操作する。

さして難しいことはない。

## 応用
上記だけでは`_ADJUST`レイヤーのみしか使えない。
ゆえに、以下の方法で、三つ目の階層を複数用意できる。
（なぜ上書きされない？一つ目の`state`が二つ目の処理で上書きされて機能しないと思うのだが・・・）

```c:keymap.c
uint32_t layer_state_set_user(uint32_t state) {
	state = update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
	state = update_tri_layer_state(state, _RAISE, _SYMB, _SPECIAL);
	return state;
}
```

今回で言えば、`_ADJUST`のほかに、`_SPECIAL`レイヤーが用意され、拡張性がさらに増した。
覚えられるか、使いこなせるかは別問題だが。。。

## 制限？
よく理解できない箇所に遭遇した。

```c:keymap.c
state = update_tri_layer_state(state, _LAYERa, _LAYERb, _LAYERz);
state = update_tri_layer_state(state, _LAYERa, _LAYERd, _LAYERz);
```

上記の設定は出来ないようだ。
困った。


## 不可解
しかし、それとは別に、公式ページの解説が難しい。
本当にこの使い方で合っているのか分からないからだ。
実際に使えるのだから合っているのだが、複雑なコーディングをしなければ使えない説明があり、違いが分からないため、疑心暗鬼になっている。

下記の関数と異なる点は、レイヤー変更するたびにこの関数が呼ばれると言うこと。
頻繁な呼び出しが発生するようだ。
















# [update_tri_layer](https://docs.qmk.fm/#/ref_functions)関数
冒頭での説明をここで解説する。

```c:keymap.c
enum custom_layers {
	_QWERTY = 0,
	_LOWER,
	_RAISE,
	_ADJUST
};

enum custom_keycodes {
	QWERTY = SAFE_RANGE,
	LOWER,
	RAISE,
	ADJUST
};

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
	switch (keycode) {
		case LOWER:
			if (record->event.pressed) {
				layer_on(_LOWER);
				update_tri_layer(_LOWER, _RAISE, _ADJUST);
			} else {
				layer_off(_LOWER);
				update_tri_layer(_LOWER, _RAISE, _ADJUST);
			}
			return false;
			break;
		case RAISE:
			if (record->event.pressed) {
				layer_on(_RAISE);
				update_tri_layer(_LOWER, _RAISE, _ADJUST);
			} else {
				layer_off(_RAISE);
				update_tri_layer(_LOWER, _RAISE, _ADJUST);
			}
			return false;
			break;
	}
	return true;
}

```

やっていることは、上記の[update_tri_layer_state関数](#update_tri_layer_state関数)と同じことだろう。

こちらのほうが拡張性は高いが、[既存の関数](#注意点その2)との相性はよろしくない(矛盾した表現に感じる)。






## 注意点　その1
[update_tri_layer_state関数](#update_tri_layer_state関数)と[update_tri_layer関数](#update_tri_layer関数)を同時に使う場合、理解不能な挙動をする。

私の場合は、`KC_C`がレイヤー変更キーに変わってしまった。
最初理解できずに、ハンダ付けに問題があるのだと思い、付け直してしまった。
そのせいで、付け直したハンダ部分が汚くなってしまった。
無念だ。
私の轍を踏まないでか。

もしかしたら勘違いかもしれないが、一応注意しておいてくれたら幸いだ。
もししたらではなく、本当に勘違いだろう。しかし、後日もう一度検証して、本当に勘違い(間違い)だったら削除する。



## 注意点　その2
上記とは違う勘違いした挙動だ。
`update_tri_layer_state` 単体で動かしたのだが、旨く動いてくれなかった。
そのため、引数に問題があるとばかり思っていたのだが、違った。
通常のキーマップ側に問題があった。

第2引数(上記例で言う_LOWER)と第3引数(上記例で言う_RAISE)のレイヤー指定をするとき、_LOWERからみた_RAISE側のキー配置の場所に独自のキーコードが設定されていた場合、もしくは、_RAISEからみた側のキー配置の場所に独自のキーコードが設定されていたとき、うまい具合にupdate_tri_layer_state関数が動いてくれない。
要は、レイヤーを変更した先でも継承(KC_TRANS or KC_TRNS or _______)しておかなければ動かないと言うこと。

独自のキーコードを設定していた場合競合するのだろう。全く気づかず、_ADJUSTレイヤーに代わってくれなかったため、かなり焦った。


## 注意点　その3
かなり重要な注意点だ。
ちょっと試した感じでは、[レイヤー移動関数](3e7e02d025f261bf6134#switching-and-toggling-layers)と組み合わせられないようだ。
大変残念だ。

たとえば、`LT(_LOWER, KC_A)`の場合の **_LOWER** を今回のキーで置き換えたとしよう。
置き換え後：LT(LOWER, KC_A)
その結果：`LOWER`レイヤーには遷移せず、全く動かない無効キーとなる。
原因：カスタムキーコードのため、LT関数などでは認識しない。

この原因に気づくまで時間が掛かってしまった。
ちょっとだけ関わらない期間が発生するだけで忘れるとは・・・。

対策：[update_tri_layer_state関数](#update_tri_layer_state関数)を使う。

デメリットしかないのかと言えば、そんなわけない。
メリットがなければ、こんな関数最初から作られていないはずだからな。
そのメリットは、LED点灯や音を出すことを一緒くたに合わせられることにある。
例えば以下のようにする(必要最小限のコードのみ)。

```c:keymap.c
case LOWER:
	if (record->event.pressed) {
		layer_on(_LOWER);
		red_led_on(); // ←これ。
		update_tri_layer(_LOWER, _RAISE, _ADJUST);
	} else {
		layer_off(_LOWER);
		red_led_off();
		update_tri_layer(_LOWER, _RAISE, _ADJUST);
	}
	return false;
	break;
```

私は、レイヤー移動だけでなく、単体キーとの組み合わせ(LT関数など)で使いたいため、こっちの関数(update_tri_layer)を使うことはないだろう。



















# 感想
悪くない関数だと思う。
普段使わないキーコードを設定するのに便利なため、今後活用すると思う。


全く翻訳サイトが役立たずで、それを読解する力もなかったが、それでも読み取っていただけたなら幸いだ。
（process_record_user関数ではなく、`layer_state_set_user`関数での利用がだめらしいのも理解できなかった箇所だ）



以上。