kbigwheelのプログラミング・ソフトウェア技術系ブログ

プログラミング・ソフトウェア技術系のことを書きます

update_tri_layer(_state)を使えばタイピングがより快適になる

わかりにくいupdate_tri_layer / update_tri_layer_state関数

update_tri_layer関数はいろんなキーマップで使用されている割にその意味がわかりにくい関数だと思う。

ちょっと調べれば、この関数がだいたいPlanckキーボード発祥で、LOWERレイヤー移動キー、RAISE移動キーを同時押ししたときにADJUSTレイヤーへ移動するためのものだということはわかる。

しかし、その詳細な使い方はかなりわかりにくい。 間違った説明や適切でない使い方が散見されることからも、よくわからずコピペしている人がかなりの割合いでいそうだ。 公式ドキュメントに専用の項目があり、それなりに説明されているものの暗黙的に前提としている知識が多く、qmkについての前提知識がない状態で読んでもほとんど理解できない。 本記事を書く上で非常に参考にさせていただいた未知の階層に挑戦Tri-Layers - Qiitaの記事ですら翻訳が役に立たず読み解けなかったと書かれている1。 例えば、応用の項目で

(なぜ上書きされない?一つ目のstateが二つ目の処理で上書きされて機能しないと思うのだが・・・)

と書かれているが、これはKeymap Overviewで書かれている用語・仕組みを理解すれば謎が解ける(端的に言うとqmkのレイヤーは複数のレイヤーが同時にONになりえて、もしそうなっている場合はレイヤー番号が一番大きなものだけが有効になるため)。

なぜupdate_tri_layerは必要なのか

update_tri_layerの最大の謎は、なぜこれが必要なのか、である。

どういう意味か。update_tri_layerは

LOWERレイヤー移動キー、RAISE移動キーを同時押ししたときにADJUSTレイヤーへ移動するためのもの

と上に書いたが、これを達成するだけなら実はupdate_tri_layerは不要だからだ。 実際、僕が今使っているtreadstone48はおろかすべてのキーマップでは使用していなかった。 というのも、画像のように MO キーをLOWERレイヤー、RAISEレイヤーそれぞれに配置するだけで十分やりたいことができるためだ(最下段のスペースの左とエンターの右のキーに注目してほしい)。

これはMOキーだけではなくLTキーでも同じだ。

では、なぜupdate_tri_layerを使うのだろう。

update_tri_layerの価値

結論から書くと、update_tri_layerを使えばレイヤー変更キー周りの体験を改善することができるからだ。

どういうことか説明する。

画像のようなMOキーのみによって同時押しレイヤーを表現している場合、

順番 押したキーの位置
(Layer 0でのキー配置基準)
押された/離されたと判定されたキー
1 初期状態(何も押していない)
2 MO(1) キーを押す Layer 0の MO(1) キー
3 MO(2) キーを押す Layer 1の MO(3) キー
4 MO(1) キーを離す Layer 3の MO(1) キー (Layer 0まで透過された結果)
5 N キーを押す Layer 3の Menu キー

以上の順番で押すとLayer3の Menu キーが押された判定になる。 これは直感的には違和感がある。押しているのは MO(2) 位置のキーと N の位置のキーなので、Layer2の N 位置にある / が入力されてほしい。 なぜこんなことになるのかの詳細はコードを見てほしいが、簡単に言うと MO(1)キーを離したとしても押しっぱなしと判定されるのは Layer 1のMO(3) で、Layer 0の MO(2) が押されていると再度判定されるわけではないためである。

先程の手順にレイヤーの変化を書き加えるとこうなる。

順番 押したキーの位置
(Layer 0でのキー配置基準)
押された/離されたと判定されたキー それによるレイヤーのON/OFF変化 有効なレイヤー 最上位レイヤー(=入力判定に使われるレイヤー)
1 初期状態(何も押していない) 0 (デフォルトレイヤー) 0
2 MO(1) キーを押す Layer 0の MO(1) キー Layer 1がON 01 1
3 MO(2) キーを押す Layer 1の MO(3) キー Layer 3がON 013 3
4 MO(1) キーを離す Layer 3の MO(1) キー (Layer 0まで透過された結果) Layer 1がOFF 03 3
5 N キーを押す Layer 3の Menu キー 03 3

これに対してupdate_tri_layer (update_tri_layer_state)ベースのキーマップはこうなる。

見ての通り、Layer1と2にあった MO(3) がTransparent(透過)キーに変更されている。これにより、Layer 1の状態で MO(2) 位置のキーを押すと MO(2) 判定になる。以下に、update_tri_layerを使ったときの挙動を書く(太字の部分が使わなかった場合との差分)。

順番 押したキーの位置
(Layer 0でのキー配置基準)
押された/離されたと判定されたキー それによるレイヤーのON/OFF変化 有効なレイヤー 最上位レイヤー(=入力判定に使われるレイヤー)
1 初期状態(何も押していない) 0 (デフォルトレイヤー) 0
2 MO(1) キーを押す Layer 0の MO(1) キー Layer 1がON 01 1
3 MO(2) キーを押す Layer 1の MO(2) キー (Layer 0まで透過された結果) Layer 2がON 012 2
update_tri_layer_stateがレイヤー1と2のONを検知してレイヤー3をONにする Layer 3がON 0123 3
4 MO(1) キーを離す Layer 3の MO(1) キー (Layer 0まで透過された結果) Layer 1がOFF 023 3
update_tri_layer_stateがレイヤー1のOFFを検知してレイヤー3をONにする Layer 3がOFF 01 1
5 N キーを押す Layer 1の Menu キー 01 1

このように、言うなれば M(1) キーと M(2) キーの状態を独立して直交して扱えるため、より直感的な動作が可能になる。

果たしてこれはどの程度有効なのか

と思われるかもしれない。同時押しのレイヤー(いわゆるADJUSTレイヤー)は普段使わないものを配置しているため、上記のような状況は余り発生しないと思うだろう。しかし、実は上記のような状況はかなり簡単に発生する。

この、treadstone48で 1- というキーを入力するシーンを考える。 この場合、

  1. Layer 1でQの位置を押して 1 を入力
  2. Layer 2でSの位置を押して - を入力

となる。 このとき、理想的な打鍵順序は以下になる。

順番 押した/離したキーの位置
(Layer 0でのキー配置基準)
押されたと判定されたキー
1 MO(1) キーを押す Layer 0の MO(1) キー
2 Q キーを押す Layer 1の 1 キー
3 Q キーを離す
4 MO(1) キーを離す
5 MO(2) キーを押す Layer 0の MO(2) キー
6 S キーを押す Layer 1の - キー
7 S キーを離す
8 MO(2) キーを離す

しかし、人間はそれほど正確に動けないため、このように複雑な同時押しや順序が絡んだシークエンスは容易にミスをする。特に早く打鍵しようとするとレイヤーが切り替わるタイミングは順序が前後しやすい。上記の4と5の順番が入れ替わってしまうと、一瞬レイヤー3が有効になる。これは上の方で説明した、レイヤー3へ移動した後に片方離した状態である。

順番 押した/離したキーの位置
(Layer 0でのキー配置基準)
押されたと判定されたキー
1 MO(1) キーを押す Layer 0の MO(1) キー
2 Q キーを押す Layer 1の 1 キー
3 Q キーを離す
4 MO(2) キーを押す Layer 1の MO(3) キー
5 MO(1) キーを離す
6 S キーを押す update_tri_layerを使っていない場合: Layer 3の RGB Mode + キー
update_tri_layerを使っている 場合: Layer 1の - キー
7 S キーを離す
8 MO(2) キーを離す

実際、早く打鍵しようとすればするほどこの現象は発生してしまうため、快適かつ高速な打鍵を達成するためには update_tri_layerはとても有効ということになる。

まとめ

udpate_tri_layer(_state) の動作について詳しく見ていき、その有用性について説明した。 ただ、実際のところなくてとても不便かと言うと打鍵速度がそれほど早くなかったり、レイヤー1と2の間をコロコロ切り替わるようなことがなければそれほど困らないとも言える。 更に言うと、このupdate_tri_layerを使うには自分でファームウェアを書き換える必要があり、remapなどでは実現が難しそうに見える(未調査)。

自分が何を優先するかによって、利用するかどうかを選択しよう、というのが最終的な結論になる。


  1. この記事には感謝したい。update_tri_layerをかなり詳細に調査されており、それが僕自身のudpate_tri_layer理解につながった