内蔵キーボードのキーマップ改変準備

Date: 2022/06/03 (initial publish), 2022/08/23 (last update)

Source: jp/note-00053.md

Previous Post Top Next Post

TOC

キーボード状況

USB接続の自作外付けキーボードでは、キーマップがQMKを使うとキーマップ改変が自由に構成でき、HOME ROW MOD等を使うと動きの少ない手や指にやさしいタイピングができます。

PC内蔵のキーボードででも、同じようにキーマップ改変ができないかと言う気になり色々調査しました。

interception-toolsを利用すれば、evdevのデーターをフィルター処理しキーマップを改変できそうです。 ただevdevのデーターの実際に使用されている慣習や制約、また異常時の対応法など不明点もあります。 単なるキーの置き換え以上の適当な先行例が見当たりません。

公式のプラグインのDual Function Keysには、HOME ROW MODが上手く動作しないともかかれています。どうも状況は簡単ではないようです。

実際の状況や解決策が分かりにくいので、まず読みやすいPythonのchorded_keymapを見ました。この中のプログラムをベースにデーターダンプするユーティリティーを作り、更にもう一度出力をオプションでコントロール出きるように、最初から書き直し実状調査をしました。あとから考えるとほぼ同じ機能のコマンドevtestがあるんですが、この経験をしたことで少し実態が分かりました。

本体付属キーボード(i8042)

やっつけで書いたログをstdoutに吐き出すこの解析用のmanglekbdプログラムの出力(時間は差分表示)は、本体付属の英語キーボードだと以下です。

$ sudo intercept /dev/input/by-path/platform-i8042-serio-0-event-kbd | python3 ~/bin/manglekbd -s u
0.024794	MSC,SCAN,0x1c	KEY,ENTER,↑	SYN,REPORT,0	
0.486209	MSC,SCAN,0x2a	KEY,LEFTSHIFT,↓	SYN,REPORT,0	
0.161347	MSC,SCAN,0x1e	KEY,A,↓	SYN,REPORT,0	A
0.082717	MSC,SCAN,0x1e	KEY,A,↑	SYN,REPORT,0	
0.147690	MSC,SCAN,0x1f	KEY,S,↓	SYN,REPORT,0	S
0.070924	MSC,SCAN,0x1f	KEY,S,↑	SYN,REPORT,0	
0.216163	MSC,SCAN,0x20	KEY,D,↓	SYN,REPORT,0	D
0.085756	MSC,SCAN,0x20	KEY,D,↑	SYN,REPORT,0	
0.212290	MSC,SCAN,0x21	KEY,F,↓	SYN,REPORT,0	F
0.103219	MSC,SCAN,0x21	KEY,F,↑	SYN,REPORT,0	
0.220644	MSC,SCAN,0x22	KEY,G,↓	SYN,REPORT,0	G
0.096932	MSC,SCAN,0x22	KEY,G,↑	SYN,REPORT,0	
0.205199	MSC,SCAN,0x2a	KEY,LEFTSHIFT,↑	SYN,REPORT,0	
0.687972	MSC,SCAN,0x34	KEY,DOT,↓	SYN,REPORT,0	.
0.251521	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.029991	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.030303	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.032326	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.030289	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.029097	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.029683	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.032301	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	
0.030361	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	.
0.030282	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	.
0.028590	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	.
0.029813	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	.
0.030434	MSC,SCAN,0x34	KEY,DOT,→	SYN,REPORT,0	.
0.014303	MSC,SCAN,0x34	KEY,DOT,↑	SYN,REPORT,0	
1.000906	MSC,SCAN,0x39	KEY,SPACE,↓	SYN,REPORT,0	 
0.077423	MSC,SCAN,0x39	KEY,SPACE,↑	SYN,REPORT,0	
0.367762	MSC,SCAN,0x39	KEY,SPACE,↓	SYN,REPORT,0	 
0.077315	MSC,SCAN,0x39	KEY,SPACE,↑	SYN,REPORT,0	
1.240154	MSC,SCAN,0x2a	KEY,LEFTSHIFT,↓	SYN,REPORT,0	
0.082025	MSC,SCAN,0x2a	KEY,LEFTSHIFT,↑	SYN,REPORT,0	
0.149037	MSC,SCAN,0x1e	KEY,A,↓	SYN,REPORT,0	a
0.091403	MSC,SCAN,0x1e	KEY,A,↑	SYN,REPORT,0	
0.083278	MSC,SCAN,0x1f	KEY,S,↓	SYN,REPORT,0	s
0.113698	MSC,SCAN,0x1f	KEY,S,↑	SYN,REPORT,0	
0.231215	MSC,SCAN,0x20	KEY,D,↓	SYN,REPORT,0	d
...

USB外付けキーボード(QMK)

manglekbdプログラムの出力(時間は差分表示)は、USB外付けキーボード(QMK)だと以下です。

$ sudo intercept /dev/input/by-id/usb-osamuaoki_cgc56-if01-event-kbd | python3 ~/bin/manglekbd -s u
0.751624	MSC,SCAN,0x700e1	KEY,LEFTSHIFT,↓	SYN,REPORT,0
0.277636	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039919	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039829	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040182	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.043845	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040168	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040073	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039748	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040206	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040087	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039937	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039980	KEY,LEFTSHIFT,→	SYN,REPORT,1	MSC,SCAN,0x700e1	KEY,LEFTSHIFT,↑	SYN,REPORT,0
0.336394	MSC,SCAN,0x700e0	KEY,LEFTCTRL,↓	SYN,REPORT,0
0.087998	MSC,SCAN,0x700e0	KEY,LEFTCTRL,↑	SYN,REPORT,0
0.245960	MSC,SCAN,0x70016	KEY,S,↓	SYN,REPORT,0
0.000777	MSC,SCAN,0x70016	KEY,S,↑	SYN,REPORT,0	s
0.462331	MSC,SCAN,0x70007	KEY,D,↓	SYN,REPORT,0
0.000686	MSC,SCAN,0x70007	KEY,D,↑	SYN,REPORT,0	d
0.316044	MSC,SCAN,0x700e1	KEY,LEFTSHIFT,↓	SYN,REPORT,0
0.281818	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039781	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040190	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040032	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039996	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039994	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039794	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040185	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040004	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039971	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.040058	KEY,LEFTSHIFT,→	SYN,REPORT,1
0.039995	KEY,LEFTSHIFT,→	SYN,REPORT,1	MSC,SCAN,0x700e1	KEY,LEFTSHIFT,↑	SYN,REPORT,0
0.699406	MSC,SCAN,0x7000e	KEY,K,↓	SYN,REPORT,0
0.000751	MSC,SCAN,0x7000e	KEY,K,↑	SYN,REPORT,0	k
0.099252	MSC,SCAN,0x7000e	KEY,K,↓	SYN,REPORT,0	k
0.064789	MSC,SCAN,0x7000e	KEY,K,↑	SYN,REPORT,0
0.070250	MSC,SCAN,0x7000e	KEY,K,↓	SYN,REPORT,0	k
0.257558	KEY,K,→	SYN,REPORT,1
0.043806	KEY,K,→	SYN,REPORT,1
0.040184	KEY,K,→	SYN,REPORT,1
0.039998	KEY,K,→	SYN,REPORT,1
0.040042	KEY,K,→	SYN,REPORT,1
0.039727	KEY,K,→	SYN,REPORT,1
0.040037	KEY,K,→	SYN,REPORT,1	kk
0.040171	KEY,K,→	SYN,REPORT,1	MSC,SCAN,0x7000e	KEY,K,↑	SYN,REPORT,0

気づいたことは:

これを頭に、現在出回っている、フィルターを見てみました。

HOME-ROW-MODを考えるなら、CHORDED(併せ押し)ではなく、TAP-HOLD(押しの短長)アプローチです。ただ、それもcaps2esc等は、press=HOLDで、RELEASEでタイミングが200ms以下ならTAPを出す感じです。CAPSのような端のキーならまだしも、HOME-ROW-MODでこれをするとまともにタイプできません。

TAP-HOLD時間判断はプログラム内で管理が必要かと思っていましたが、あまりフィルターで使われていないリピート(→)を上手く利用すると複雑なEVENT処理をし無くとも実現できそうな気がします。

Dual Function Keysは、基本イベント処理ループはCで書かれていて、YAML設定ファイルはC++で読み込んでいます。別にタイミングチャート図が有り参考になります。TAP-HOLDのスタートや他キーが早くPUSH・RELEASEされた際の対応はいい感じです。他にキー打鍵無い際のHOLD移行にタイマーかREPEATを使わないようなのは気になります。またこれが使うTAP-HOLDのルールーは上記のHOME-ROW-MODで問題の原因の気がします。(最近この辺改善された感もあります)

Interception plugin for vimproved input は、C++で書かれていて、汎用性は無い形でかかれていて、複雑でタイミングなど読みきれませんがレイヤー処理があります。(SPACE-fn)

interception-k2kは、基本イベント処理ループはCで書かれていて、設定ファイルはincludeファイルを使う汎用マッパーです。レイヤー機能はありません。設定ファイルがCですが、見通しがいいスタイルですね。REPEATにも対応してそうです。 (Makefileのターゲットの前提要件中に|を使ってORDER-ONLY-PREREQUISITESを規定するのははじめてみたので、ちょっとと惑いました。)

キーボードのTAP-HOLDタイミング考察

QMKで採用したホームポジションMOD用のパラメーターで確立されているのと同様の遅延処理アプローチが望ましい気がします。そう考えると、キーボードのTAP-HOLDの処理は、HOME-ROW-MODを考えるなら、端のキーの処理では充分な即時処理(immediate)タイプではなく、一見手の込んだ遅延処理(delayed)タイプが必要な気がします。

以下キータイミング図で、あるべき動作を思考実験で確認してみました。

どうも、遅延処理の全面導入と、リピートの利用、シフト等の(早期)確定後のシフト解除時にタップが出なくする、等々が必要な感じです。

単一MT キーを使用時の遅延処理有無のタイミング図

これへの対応は必要だが、リピートを使えば意外と簡単。

A: as MT(KC_SHFT, KC_A)
  S: KC_SHFT
  A: KC_A

----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓             A↑

immediate:      S↓             S↑A↓A↑
delayed:        ??               A↓A↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                        A→        A↑

immediate:      S↓                                  S↑
delayed:        ??                        S↓        S↑
----------------------------------------------------------------------------------

MTキーと普通キーを両方使用時に、普通キーに遅延処理しない際のベストケースのタイミング図

こういうことができるか考えてみたが、こうすると後から打ったキーが先に処理されるので問題山積でした。やはり次のセクションのように全てのキーを遅延処理するべきみたいですね。

A: as MT(KC_SHFT, KC_A)
  S: KC_SHFT  (後から打った他キーのリリースでもHOLDにする)
  A: KC_A
B: simple key TAP無処理の場合 (これを遅延処理するなら、次のセクションのMT(KC_CTRL, KC_B)と同じ)

----------------------------------------------------------------------------------
                <---------200ms---------> (この条件でのシフト入力は高速タイプ対策上必要)
keyboard1:      A↓             A↑
keyboard2:         B↓ B↑

immediate:      S↓ B↓ B↑       S↑       (Aタップ扱いしない処理が必要)
delayed:        ?? B↓ B↑S↓     S↑       (Aタップ扱いしない処理が必要)
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms---------> (普通キーの遅延処理が無いと、MTキーで必然の逆順問題発生)
keyboard1:      A↓             A↑
keyboard2:                B↓             B↑

immediate:      S↓        B↓   S↑A↓A↑    B↑    (逆順出力問題+シフト問題:HOME-ROW-MODで問題)
delayed:        ??        B↓   A↓A↑      B↑    (逆順出力問題)
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:         B↓ B↑

immediate:      S↓ B↓ B↑                            S↑
delayed:        ?? B↓ S↓B↑                          S↑  (シフト欠落問題)
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→            A↑
keyboard2:                          B↓         B↑

immediate:      S↓                  B↓         B↑     S↑
delayed:        ??                  B↓  S↓     B↑     S↑  (シフト欠落問題)
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→            A↑
keyboard2:                                   B↓  B↑

immediate:      S↓                           B↓  B↑   S↑
delayed:        ??                      S↓   B↓  B↑   S↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:                                   B↓          B↑

immediate:      S↓                           B↓     S↑   B↑
delayed:        ??                      S↓   B↓     S↑   B↑
----------------------------------------------------------------------------------

MTキー同士の組み合わせ使用時のタイミング図(遅延処理有りのMTと普通キーとの組み合わせも含む)

どうもこれが望ましい処理ですね。これには遅延処理の待ちリストが必要かな。

A: as MT(KC_SHFT, KC_A)
  S: KC_SHFT
  A: KC_A
B: as MT(KC_CTRL, KC_B)
  C: KC_CTRL
  B: KC_B
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓             A↑
keyboard2:         B↓ B↑

immediate:      S↓    B↓B↑     S↑       (Aタップ扱いしない処理が必要)
delayed:        ?? ** S↓B↓B↑   S↑       (Aタップ扱いしない処理が必要)
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms---------> (逆順はMTキー同士では発生しない)
keyboard1:      A↓             A↑
keyboard2:                B↓             B↑

immediate:      S↓        **   S↑A↓A↑    B↓B↑ (シフト問題なし)
delayed:        ??        **   A↓A↑      B↓B↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:         B↓ B↑

immediate:      S↓    B↓B↑                          S↑
delayed:        ?? ** S↓B↓B↑                        S↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:                          B↓         B↑

immediate:      S↓                             B↓B↑ S↑
delayed:        ??                  **  S↓     B↓B↑ S↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→            A↑
keyboard2:                                   B↓  B↑

immediate:      S↓                               B↓B↑ S↑
delayed:        ??                      S↓       B↓B↑ S↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:                                   B↓            B↑

immediate:      S↓                                         B↓S↑B↑
delayed:        ??                      S↓   **            B↓S↑B↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
                                     <---------200ms--------->
keyboard1:      A↓                      A→          A↑
keyboard2:                          B↓                       B→        B↑

immediate:      S↓                  ??              S↑       C↓        C↑
delayed:        ??                  **  S↓          S↑       C↓        C↑
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
                <---------200ms--------->
                                     <---------200ms--------->
keyboard1:      A↓                      A→                       A→           A↑
keyboard2:                          B↓                       B→        B↑

immediate:      S↓                  ??                       C↓        C↑     S↑
delayed:        ??                  **  S↓                   C↓        C↑     S↑
----------------------------------------------------------------------------------

フィルタープログラムの考察

フィルタープログラム作成時に必要な配慮点をを列記します。

フィルター機能の設定法の考察

evdevデーターのフィルター機能の設定法を考えました。

試作中のフィルター evmk

systemdのjournalへのログ出力ができるようにした、改良版のフィルター・ログ用のプログラムevmkを試作中です。

Previous Post Top Next Post