ZMKのオートマウスレイヤーを極める
オートマウスレイヤーとは
オートマウスレイヤーとは、「マウスカーソルを動かすと、自動的に一定時間マウスレイヤーが有効になる機能」 のことです。
自動マウスレイヤー、または略してAMLと呼ばれる場合もあります。
AMLを利用することで、Keyballシリーズのようなトラックボール付きキーボードにおいて、デフォルトレイヤーのキー数を節約しつつ、キー入力とマウス操作をスムーズに切り替えることが可能になります。
この記事では、Keyball/QMKのAMLにあるような
- 非マウスキーを押したらマウスレイヤーを抜ける
- マウスキーを押したらタイムアウトを延長する
- マウスキーを押すまでマウスレイヤーに留まる[1]
などの機能をZMKで設定する方法を解説します。
ZMKにおけるオートマウスレイヤー
ZMKのオートマウスレイヤーには
- zmk-pmw3610-driver[2] で実装されているもの
- Input Processor を使用したもの
の2種類が存在します。
zmk-pmw3610-driverのAML機能は非常にシンプルで、QMKにあるような、
- 非マウスキーを押したらマウスレイヤーを抜ける
- マウスキーを押したらタイムアウトを延長する
という機能はありません。
Input ProcessorによるAMLは、pmw3610-driverのAMLより新しくできたもので、より汎用的かつ高機能であり、設定すれば上記の機能も使用可能になります。
今から新しく設定するなら、Input Processorを使用することを推奨します。
設定方法
PMW3610 Driverのオートマウスレイヤー
&trackball
にautomouse-layer
を設定します。
この例では、トラボを動かすとレイヤー5が有効になります。
&spi0 {
status = "okay";
compatible = ...
trackball: trackball@0 {
status = "okay";
compatible = "pixart,pmw3610";
...
+ automouse-layer = <5>;
};
};
タイムアウトの長さを変えるには、CONFIG_PMW3610_AUTOMOUSE_TIMEOUT_MS
を設定します。
CONFIG_PMW3610_AUTOMOUSE_TIMEOUT_MS=700
Input Processorを使用したオートマウスレイヤー
&trackball
に対してinput-listener
を追加し、zip_temp_layer
というInput Processorを適用します。
この例では、トラボ使用後10秒間、レイヤー5が有効になります。
#include <input/processors.dtsi>
/ {
trackball_listener {
compatible = "zmk,input-listener";
device = <&trackball>;
input-processors = <&zip_temp_layer 5 10000>;
};
};
非マウスキーを押したらタイムアウトに関係なくマウスレイヤーを抜ける
Input Processorを使用したAMLでは、excluded-positions
を設定すると、その位置のキー以外を押したときにAMLが解除されます。
設定例
この例では、トラボ使用後10秒間、レイヤー5が有効になります。
ただし、excluded-positions
以外のキーを押すとAMLが解除されます。ここではroBaのJ
, K
, ;
, Ctrl
の位置をexcluded-positions
に設定しています。
#include <input/processors.dtsi>
&zip_temp_layer {
excluded-positions = <
18 // J
19 // K
21 // ;
34 // Ctrl
>;
};
/ {
trackball_listener {
compatible = "zmk,input-listener";
device = <&trackball>;
input-processors = <&zip_temp_layer 5 10000>;
};
};
マウスキーを押したらタイムアウトを延長する
&mkp
(マウスキー押下)に対してInput Processorを設定することで、マウスキーを押したらタイムアウトを延長できます。
設定例
.keymap
ファイルに以下を追記すると、クリックしたときに10秒間AMLが延長されます。
#include <input/processors.dtsi>
&mkp_input_listener {
input-processors = <&zip_temp_layer 5 10000>;
};
マウスキーを押すまでマウスレイヤーに留まる
マウスキーを押すまでマウスレイヤーに留まる場合でも、ダブルクリックの猶予を与えるために、クリック後一定時間待つ必要があります。
そのため、実は「マウスキーを押すまでマウスレイヤーに留まる」機能は「マウスキーを押したらタイムアウトを延長する」と同じ実装で、タイムアウトの長さが違うだけです。
設定例
.keymap
ファイルに以下を追記すると、クリックした後250ミリ秒後にAMLが解除されます。
#include <input/processors.dtsi>
&mkp_input_listener {
input-processors = <&zip_temp_layer 5 250>;
};
また、AML自体のタイムアウトは長めにしておきましょう。
CONFIG_PMW3610_AUTOMOUSE_TIMEOUT_MS=100000
または、Input Processorを使用している場合:
#include <input/processors.dtsi>
/ {
trackball_listener {
compatible = "zmk,input-listener";
device = <&trackball>;
input-processors = <&zip_temp_layer 5 100000>;
};
};
キー入力中のオートマウスレイヤー誤爆防止
キー入力中、振動や意図せずトラボに触れてしまうことが原因でAMLが発動し、マウスクリックが誤爆することがあります。
これの対策として、Input Processorを使用したAMLでは、require-prior-idle-ms
というプロパティを設定することで、キー入力から一定時間はAMLを発動しないようにできます。
設定例
#include <input/processors.dtsi>
&zip_temp_layer {
require-prior-idle-ms = <200>;
};
/ {
trackball_listener {
compatible = "zmk,input-listener";
device = <&trackball>;
input-processors = <&zip_temp_layer 5 10000>;
};
};
Shift+クリックの動作改善
ShiftキーをZキーのMod Tap(&mt LEFT_SHIFT Z
)にしているような場合、上記のInput Processorを使用したAMLでは、
「マウスカーソルを動かす → Shiftを押す → クリックする」
という操作によりテキストを選択しようとすると、Shiftを押した段階でAMLが解除され、クリックのつもりがキー入力になってしまいます。
必ずShiftを押した後にマウスカーソルを動かすようにすれば対処できますが、少し面倒です。
excluded-positions
に設定する手もありますが、それだとZを入力したときにAMLが解除されず、誤爆の原因になります。
これは、タップ時のみAML解除するbehaviorを定義することで解決できます。
設定方法
- レイヤーを無効化するbehavior
tog_off
[3]を定義する - AMLを解除するマクロ
exit_AML
を作る - キー押下後にAMLを解除するマクロ
kp_exit_AML
を作る - ホールド時は
kp
、タップ時はkp_exit_AML
を使うhold-tap behaviormt_exit_AML_on_tap
を定義する -
mt_exit_AML_on_tap
をmt
の代わりに使う - そのキーの位置を
excluded-positions
に入れる
これによりホールド時はAMLを解除せず、タップ時のみAMLを解除するという動作が可能になります。
#define MOUSE 5
/{
macros {
exit_AML: exit_AML {
compatible = "zmk,behavior-macro";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <0>;
bindings = <&tog_off MOUSE>;
label = "exit_AML";
};
kp_exit_AML: kp_exit_AML {
compatible = "zmk,behavior-macro-one-param";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <1>;
bindings = <¯o_param_1to1 &kp MACRO_PLACEHOLDER &exit_AML>;
label = "KP_exit_AML";
};
};
behaviors {
tog_off: toggle_layer_off {
compatible = "zmk,behavior-toggle-layer";
#binding-cells = <1>;
display-name = "Toggle Layer Off";
toggle-mode = "off";
};
mt_exit_AML_on_tap: mt_exit_AML_on_tap {
compatible = "zmk,behavior-hold-tap";
label = "MT_exit_AML_ON_TAP";
bindings = <&kp>, <&kp_exit_AML>;
#binding-cells = <2>;
tapping-term-ms = <200>;
flavor = "balanced";
quick-tap-ms = <200>;
};
};
}
オマケ: マクロで再現する方法
キー入力中のAML誤爆防止以外は、Input Processorを使わなくても、pmw3610-driverのAML+マクロで再現できます。
今あえてInput Processorを使わずにpmw3610-driverのAML+マクロで頑張る理由は特にありませんが、過去にInput Processorの不具合でフリーズすることがあった(現在は修正済み)ため、そういった場合の代替手段として使用できました。
ZMKは一見融通が利かないように見えて、実は大抵のことはマクロ+レイヤー移動で解決できてしまいます。ZMKのそういうところの面白さや魅力を感じていただければ幸いです。
設定方法
exit_AML
を仕込んだkp
、mt
、mo
、lt
を作り、代わりに使います。
タイムアウトに関連する動作はSticky Layer(sl
)を組み合わせることで作れます。
このmt
/lt
ではキータップ+長押しで連打が効かなくなりますが、hold時のみAML解除するものを使うと回避できます。
「マウスキーを押したらタイムアウトを延長する」「マウスキーを押すまでマウスレイヤーに留まる」には、mkp_exit_AML
を使います。
#define MOUSE 5
/{
macros {
exit_AML: exit_AML {
compatible = "zmk,behavior-macro";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <0>;
bindings = <&tog_off MOUSE>;
label = "exit_AML";
};
kp_exit_AML: kp_exit_AML {
compatible = "zmk,behavior-macro-one-param";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <1>;
bindings = <¯o_param_1to1 &kp MACRO_PLACEHOLDER &exit_AML>;
label = "KP_exit_AML";
};
mod_exit_AML: mod_exit_AML {
compatible = "zmk,behavior-macro-one-param";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <1>;
bindings =
<¯o_press>,
<¯o_param_1to1 &kp MACRO_PLACEHOLDER>,
<¯o_tap>,
<&exit_AML>,
<¯o_pause_for_release>,
<¯o_release>,
<¯o_param_1to1 &kp MACRO_PLACEHOLDER>;
label = "MOD_exit_AML";
};
mo_exit_AML: mo_exit_AML {
compatible = "zmk,behavior-macro-one-param";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <1>;
bindings =
<¯o_press>,
<¯o_param_1to1 &mo MACRO_PLACEHOLDER>,
<¯o_tap>,
<&exit_AML>,
<¯o_pause_for_release>,
<¯o_release>,
<¯o_param_1to1 &mo MACRO_PLACEHOLDER>,
<¯o_tap>;
label = "MO_exit_AML";
};
mkp_exit_AML: mkp_exit_AML {
compatible = "zmk,behavior-macro-one-param";
#binding-cells = <1>;
bindings =
<¯o_press>,
<¯o_param_1to1 &mkp MACRO_PLACEHOLDER>,
<¯o_pause_for_release>,
<¯o_release>,
<¯o_param_1to1 &mkp MACRO_PLACEHOLDER>,
<¯o_tap>,
<&sl_250 MOUSE>;
label = "MKP_EXIT_AML";
};
};
behaviors {
sl_250: sl_250 {
compatible = "zmk,behavior-sticky-key";
label = "SL_250";
bindings = <&mo>;
#binding-cells = <1>;
release-after-ms = <250>;
};
tog_off: toggle_layer_off {
compatible = "zmk,behavior-toggle-layer";
#binding-cells = <1>;
display-name = "Toggle Layer Off";
toggle-mode = "off";
};
lt_exit_AML: lt_exit_AML {
compatible = "zmk,behavior-hold-tap";
label = "LT_exit_AML";
bindings = <&mo_exit_AML>, <&kp_exit_AML>;
#binding-cells = <2>;
tapping-term-ms = <200>;
quick-tap-ms = <200>;
flavor = "balanced";
};
lt_exit_AML_on_hold: lt_exit_AML_on_hold {
compatible = "zmk,behavior-hold-tap";
label = "LT_exit_AML_ON_HOLD";
bindings = <&mo_exit_AML>, <&kp>;
#binding-cells = <2>;
tapping-term-ms = <200>;
quick-tap-ms = <200>;
flavor = "balanced";
};
mt_exit_AML: mt_exit_AML {
compatible = "zmk,behavior-hold-tap";
label = "MT_exit_AML";
bindings = <&mod_exit_AML>, <&kp_exit_AML>;
#binding-cells = <2>;
tapping-term-ms = <200>;
flavor = "balanced";
quick-tap-ms = <200>;
};
mt_exit_AML_on_tap: mt_exit_AML_on_tap {
compatible = "zmk,behavior-hold-tap";
label = "MT_exit_AML_ON_TAP";
bindings = <&kp>, <&kp_exit_AML>;
#binding-cells = <2>;
tapping-term-ms = <200>;
flavor = "balanced";
quick-tap-ms = <200>;
};
};
}
この記事はroBaで書きました。
-
zmk-pmw3610-driverはZMKでPMW3610を使用するためのドライバーです。PMW3610はマウスセンサーで、roBaやmoNa2といった多くのZMKトラボ付きキーボードで採用されています。zmk-pmw3610-driverにはいくつか派生(fork)があり、badjeff氏のフォークなどでは、Input ProcessorでAMLが可能になったので、AML機能が削除されています。 ↩︎
-
ZMKの公式ドキュメントに記載されているものです。これらを標準搭載しようというPRがあるので、これがマージされれば自分で定義しなくても使えるようになります。 ↩︎
Discussion
roBaish、Zonkeyを愛用していて、キー入力中のトラックボール誤爆に困っていたので、こちらの記事がめちゃくちゃ参考になりました。
本当にありがとうございました!