• 作成:
  • 更新:

Linux(X11)でキーボードのチャタリングをGnomeなどのアクセシビリティツールを使わずに抑止するにはxkbsetを使う

ソフトウェアでチャタリングを解決

Alienware m17に買い換えてGentoo LinuxをBtrfs on dm-cryptでインストールしてNVIDIAのGPUを有効にして起動しました - ncaq で述べているように, C-mが意図せず2回押される問題に悩まされています.

「キーボード チャタリング」で検索するとソフトウェアから対処する方法があることを知りました.

人間の意図する連打速度ではない連打を無効化して押さなかったことにするアプローチのようです.

Windowsだとccchattttterというソフトウェアが普及しているようですね. ゲーミングキーボードでのチャタリングの直し方、防止するための対策方法 – DPQP

LinuxだとKbdkbdrateコマンドで設定することが出来ると思ったのですが, システムアプリなので最初からGentooに入っていました. でもこれCLIでLinuxのコンソール用の設定じゃないですか. そもそもこれは自動繰り返しの設定であって連続で押された場合の制御ではない.

Xorg でのキーボード設定 - ArchWiki によるとxsetで設定可能? と思ったのですがこれも自動繰り返しですね…

arch linux - Fix keyboard chattering/bouncing on the software side - Unix & Linux Stack Exchange ではやっぱり自動繰り返しについて述べられていますがその下の XkbSetBounceKeysDelay(3) では確かにそういった設定が出来ると思ったら, えっこれC言語の関数? コマンドラインは無いんですか?

CinnamonとかGnome系ではGUIからこの設定が出来るみたいですけど.

bounce · Search · GitLab 見てもbounceを取得するコードは書かれてても設定するコードはない… あー構造体でまとめて設定してるのかな. サーチしてもすぐは出てきませんが.

eix xkbで出てくるツールにbounceを設定するコードが無いことをざっと見たのでこれはこれ以上調べるより自分で書いた方がまだ速いと判断したので書くことにしようとしたのですが, mark7/keybounce-detect: Utility to detect "bouncing" keyboard keys を見つけて, xkbset bouncekeysで設定できることを知りました. 確かにxkbset bouncekeysすると連続してキーが押せなくなります.

xkbsetは見つけていたのですがあまりにサイトが古すぎていたので調べる気が失せていました. 調べるべきでしたね…

xkbset bouncekeys 50ぐらいで丁度よい感じでしょうか. ゲームする時に連打が抑制されてしまいますが, このラップトップでゲームはせず, ゲームは基本デスクトップPCでするので問題はありません. 解除したい時もxkbset -bouncekeysを実行するだけですしね.

XkbSetBounceKeysDelayは何故かヘッダファイルが無かったので自前で呼び出し宣言とか書くのが面倒くさいので, 設定するCLIがあって良かったです.

xkeysnailが一部動かなくなる

これにて解決… と思ったらxkeysnailが一部効かなくなりました. とりあえずxkeysnailを再起動したら動くようになりました. 一部干渉するようですがxkbsetを先に起動させていれば問題ないようです.

ただXMonadの問題なのか何の問題なのかわかりませんが, ウィンドウマネージャを完全初期化する前に起動すると効かないようなので, sleepによる場当たり的対処を行いました.

sleepする秒数は自分の環境に合わせてください.

spawn "sleep 10 && xkbset bouncekeys 50 && systemctl --user restart xkeysnail"

で起動を遅らせて, xkeysnailもそれに合わせて遅らせる必要があるようです.

AutoStartでやれば良いのかもしれませんが, まあXMonadで完結するのでこれで.

定期的に無効化されてしまうのでservice化してtimerで動かす

ただこの方法にも問題があることが発覚して, どうも設定が何かの拍子に戻ってしまうんですよね. lockとかで戻ってしまうならわかるのですが.

特にXに関係する動作を行っていないのにxkbset qで確認したら Bounce-Keys = OnからBounce-Keys = Offに戻ってしまっていることがよくあって, 完全に謎です.

エスパーすると何かのプログラムがXkbAccessXNotifyEvent構造体でXの設定を行う時にデフォルト設定で設定を行ってしまっていて, その時に戻ってしまっていると予想します.

仕方がないので, timerで1時間毎に設定することにしました. 1時間の周期内では設定無効化されるおそれがありますが無いよりはマシなので.

xkbset-bouncekeys

#!/usr/bin/env zsh

if xkbset q|rg 'Bounce-Keys = Off'; then
    xkbset bouncekeys 50
    systemctl --user restart xkeysnail
else
    echo "Bounce-Keys On"
    return
fi

xkbset-bouncekeys.service

[Unit]
Description=xkbset bouncekeys

[Service]
ExecStart=/home/ncaq/.rc/xkbset-bouncekeys
Type=oneshot

[Install]
WantedBy=graphical.target

xkbset-bouncekeys.timer

[Timer]
OnUnitActiveSec=1h

[Install]
WantedBy=timers.target

systemdのCondition系にcommandを条件にするものが無いか探したのですが, 存在しなかったので仕方なくシェルスクリプトを書いています.

XMonadの設定もsystemdを使うものに変更です.

spawn "sleep 10 && systemctl --user restart xkbset-bouncekeys"

ダメでした

どうもxkeysnailにはxkbsetの設定を無効にしてしまう問題があるようでこれで解決はしません. xkeysnailを起動した後にxkbsetを起動するとxkeysnailが狂うのでどちらの順番で起動しても問題です.

xkeysnailにpull requestを作ろうかと思ったのですが原因不明でした. とりあえずissueだけ建てておきました.

xkeysnail reset xkbset config · Issue #49 · mooz/xkeysnail

xkeysnailのキーシーケンスが効かなくなる理由はMetaキーが連続押しとして排除されてる感じですかね? xkeysnailがxkbsetの設定した値を無効化してしまう理由は不明です. ストレス値としてはチャタリングの方がSlackで定義したキーシーケンスが使えないものより大きいので, ひとまずラップトップではxkeysnailの一部キーマップを諦めることにしました.