先日ちょっと書いた、Linuxではマウスホイールの加速ができない(ディストリビューションやデバイスによってはできるかも知れないが、僕の使っているLinux Mint Xfceにはない)件だが、できるようにする方法が見つかった。まだアイデアの実現性が確認できた(PoC)段階だが、一応使えるようになった。

はじめに書いておくが、現状でも、ウインドウサーバ(X11)の設定などでマウスホイールの加速をすることはできる。例えば、imwheelコマンドを使えばホイールの倍率を設定できる。ただ、それは今一つ実用的でない。僕も以前試してうまく行くと思ったのだが、問題があって止めた(そのことを忘れていた)。

その問題は、設定やimwheelは常に加速する(「加速」というより、「倍率」という方が正しい)ので、例えばVivaldiブラウザでタブ一覧をホイールで選ぼうとすると、1ノッチしか動かさなくても設定した倍率のノッチ分(例: 3ノッチ)動いてしまって、まともにタブが切り替えられないことだ。imwheelは設定で対象のウインドウを指定または除外できるが、Vivaldiのタブ一覧は子ウインドウではなさそうで、除外できなさそうだった(実際には子ウインドウなのだろうが、容易には分からなかった。もし分かったとしても、自分が使うすべてのアプリについて調べるのは、実用的でない)。

そのため、単なる倍率設定でなく、本当に加速する機能が必要だ。その、「本当に加速する」は以下の定義とする。

  • ホイールの回転速度(以下、速度)が速い時にホイールの変化数を増やす。
  • ホイールの速度は、ある時間内のホイールの変化数(ノッチの変化数)とする。
  • 増やす値は、例えば、ホイールの変化数にあらかじめ設定した値(加速係数)を掛けて求める。

上記の定義を実現する処理の概要を以下に示す。

  1. マウスをLinuxのウインドウサーバ(X11)(のイベントドライバevdev)が無視するように設定する。ホイールだけ無視できるなら、そうする。
  2. マウスイベントを取得する。
    • 通常のX11では、ホイールはマウスのボタン4と5に割り当てられているので、それらのイベントを取る。
  3. ホイール以外のイベントは、そのまま発生させる。
  4. ホイールのイベントは、加速処理をしてイベントを発生させる。
    • ホイールの速度は、所定の時間内に(連続して)取得できた同一イベント数から求める。イベントの有無の判定にはselectを使った。
    • ホイールの速度に比例させてホイールイベントを追加発行する。
      • 例: 2イベント発生、速度= 40イベント/s、加速係数= 0.1 → 0.1*40*2 -2= 6イベント追加

イベント処理の概略図

イベント → ホイールイベント処理プログラム → ウインドウサーバ (X11)
                 ホイールイベント: 加速処理をして出す
                 他のイベント: 何もしないで出す

次に、本方式の実現性を確認するためのテストプログラムを作成した。C言語は手間が掛かるのでPHPを用いた。この時、evdevの設定変更のたびにX11を再起動したくなかったので、上記1番のevdevがホイールを無視するように設定する処理について、evdevと並行してイベントを読めるか試したら読めたので(ただし、通常の設定ではrootの権限が要る)、実装を保留して残りの処理を実装した。また、evdevと並行動作させるため、他のイベントを発生させる必要もないから、上記3番の実装も行っていない

なお、加速処理で追加のホイールイベントを発生させる処理は、速度や負荷の点から、本来はネイティブなX11のライブラリを使うべきだが、今回は実現性の確認が主な目的なので、xdotoolコマンドで発生させた(例: xdotool click 4 (または5))。

作成したプログラムは(予想に反してw)期待どおり動いた

最初は想定していなかったのだが、この処理はウインドウサーバ(X11)の処理と並行して動作できるので、X11への変更は全く不要で、プログラムの追加だけでできた。そのため、最初は仮想環境で動作確認や修正をしようと思って準備したのだが、全然使わなかった。

以下に、本方式のデモを示す。

○ページのスクロール (ホイールを6回、速く動かした場合)

通常(ホイール加速なし)の場合 (スクロール速度は変わらず遅い)

 

本方式の場合 (スクロール速度が高速)

 

○タブの切り替え (ホイールをゆっくり動かした場合)

imwheelの倍率を有効にした場合 (複数タブ分飛んでしまう)

 

本方式の場合 (タブが正常に切り替えられる)

 

考案した方式でホイールの加速が実現できることが分かったが、現状では以下のような問題点や不足点があるので、追って改良して正式版にしたい。

  • ホイールイベントの追加数が多い場合(加速が大きい場合)、スクロールが遅い(終わるまでに時間が掛かる)。そのせいか、今一つ感触が悪い(「スムーススクロール」に似た、ぬるぬるした感じ)。 → 不具合の修正と動作・パラメタの調整で解消し、きびきび動くようになった。
    • 追加数が一定値以上の場合はホイールでなくPage Up/Downにすると良さそうだが、アプリの対応状況に依存するので、単純ではない。
    • 追加イベントの発行にxdotoolを使わなければ速くなるのか、要確認。 → xdotoolのイベント発行間隔(--delay)を指定する必要があった。
    • Windowsでの動作を調べる。
    • 設定(しきい値、加速係数など)を調整する。
  • 追加イベント発行中(スクロール中)にマウスを動かしてウインドウが切り替わると、別のウインドウにホイールイベントが行くので、思わぬ結果になる。 → スクロール開始時のアクティブウインドウにイベントを発行するようにしたが、まだ不十分な点もある。 → 上記のスクロールが遅い不具合を修正したため、ほとんど問題にならなくなった。
    • ウインドウが切り替わったらイベント発行を停めたいが、結構難しそう。
    • Windowsでの動作を調べる。
  • マウスのイベントデバイス(/dev/input/event*)を自動検出する。 → 対応した(複数のマウスがある場合は、最初のものに対応することにした)。
  • ホイールイベント発行にxdotoolでなく、ネイティブなX11のライブラリを使う。 → 対応した。
    • PHPから容易にイベントを発行できるX11ライブラリが見つからなかったため、XTestを使ったサンプル(fakeMouse)を元にして、標準入力からマウスのボタン番号などを読んで対応するイベントを送信するプログラムを作り、本プログラムとパイプで接続して、ホイールイベントを送信できるようにした。
      • 構成: 本プログラム(標準出力) → [ボタン番号] → (標準入力)マウスイベント送信プログラム → [マウスイベント] → X11
      • イベント送信プログラムはネイティブライブラリを使っているし、イベント送信のたびにプログラムを起動せずに済むので、速度や負荷は問題ないはずである。 → 何となく、スクロールがスムーズになった気がする。
  • 設定の最適化
  • その他、設定変更機能、異常対応処理や細かい機能の追加。

 

(12/15 7:51追記) 使っていて大きな問題はないが、一部のアプリ(NixNote2)でホイールを高速に動かすと誤動作(逆方向にスクロール)する。そのアプリ固有の問題なのか、イベントの出し方に何かコツがあるのかは不明だ。ただ、xdotoolでイベントを出していた時は無視されたし、他にもこれとは関係ない問題が若干あるので、NixNote2固有の問題の気がする。

 

(12/13 8:31 改良・修正結果を反映; 9:54 若干修正、デモビデオを更新; 19:13 xdotoolを止めた件などを反映)

PS. これはいくら検索しても出てこなかったので、まだ誰もやっていないと思うが、どうだろうか? 誰かは居るかな。

PS2. もし、ご入用・ご興味のある方がいらっしゃいましたら、コメントなどでお知らせ下さい。公開を検討します。

  •   0
  •   0

コメントを書く

名前    

メール 

URL