2014/05/13

LinuxでTrackballで左右同時押しスクロール

Kensington Slimbladeの左クリックのスイッチが壊れたので、今回は違うのを試してみようと思ってKensington Orbit Wireless Mobile Trackballを購入した(Slimbladeは機会があればハンダゴテで修理したいと思う)。
本機にはセンサースクロールがあるが、使い勝手があまりよろしくない。例えばWindowsとかの環境だと、トラックボールを使う場合は左右ボタン同時押し+ボール回転でスクロールするようにするのが一般的らしい。少し調べた限りでは、Linuxにおいては例えばLogicoolのTrackman Marble TM-150rとかの場合、ボタンの一つ(例えば左小ボタンなど)をスクロール用に割り当てる方法が一般的なようであった。

2ボタントラックボールでボールでスクロールをする場合どのようにすればいいかについて色々試してみたため、忘れないようメモしておく。

xorg.confでできるボタン設定について(evdev使用):
Option "Emulate3Buttons" "true/false"
Button 1,Button 3の同時押しでButton 2にできる。

Option "EmulateThirdButton" "true/false"
Button 1の長押し(EmulateThirdButtonTimeout)で任意のボタン(EmulateThirdButtonButton)にできる。

Option "EmulateWheel" "true/false"
任意のボタン(EmulateWheelButton)を押しながらのボール操作でスクロールできる。ただしそのボタンはEmulateされたボタンであってはならない。
例えば、
Option "Emulate3Buttons" "true" ← Button 2を1,3同時押しでエミュレートする
Option "EmulateWheel"  "true"
Option "EmulateWheelButton" "2"
の場合、「"EmulateWheelButton' "2"」 は無効である。これが一番やりたいんだが。


解決策1. 右ボタンをスクロール用に割り当てる。

xorg.conf -----
  Option     "ButtonMapping" "1 3 2 4 5 6 7 8"
 Option     "EmulateThirdButton" "true"
 Option     "EmulateThirdButtonTimeout" "400"
 Option     "EmulateThirdButtonButton" "2"
 Option     "EmulateThirdButtonMoveThreshold" "1"
 Option     "EmulateWheel"       "true"
 Option     "EmulateWheelButton" "3"
 Option     "EmulateWheelTimeout" "250"
 Option     "YAxisMapping"  "4 5"
 Option     "XAxisMapping"  "6 7"
-----

右ボタンをスクロール用にしてしまうと、副作用として右クリックドラッグができなくなる。自分の場合、右クリックドラッグが必要であった。
EmulateThirdButtonとEmulate3Buttonsは同時に使用できないか(ソースちょっと見たが、あんまり詳しく読んでないw)?そのためButtonMappingで右ボタンを中クリック(Button 2)にする。"EmulateWheelButton" "3"の3は物理的な右ボタンを意味するので、右ボタンをスクロール用にする。こうすると右クリックに相当するものが必要になるので、左ボタン長押しで右クリックを出すようにする。"EmulateThirdButtonButton" "2"でButtonMappingの2番目、すなわちButton 3とする。
この設定なら、400ms以上左ボタンを長押しすれば右クリックが出せる。EmulateThirdButtonMoveThreshold (1px)以上ポインタを動かせば、左クリックドラッグ扱いとなる。

左ボタン→左クリック
左ボタン長押し→右クリック
右ボタン→中クリック
右ボタン+ボール操作→スクロール

となる。長押しに慣れれば結構便利かもしれないとは思った。


解決策2. やっぱり左右同時押しでスクロールしたい。

EmulateWheelButtonがEmulateされたボタンであってはならない、というのが制約である。ソースコード修正が必要となった。これを書いている時点で、gentooではxf86-input-evdev-2.8.2が最新っぽかったのでこれをget。/src/emuMB.c がMiddle Button Emulationをしている。むずかしいステートマシンになっているようで、ここの理解はあきらめたw。。。ただ、EvdevMBEmuFilterEvent()関数で、EvdevQueueButtonEventでエミュレートボタンをQueueしていることでボタンをエミュレートしていた。ここにEmulateWheelを行うEvdevWheelEmuFilterButton()をhookすればいいかもしれない。EvdevQueueButtonEvent()に投げる引数をそのまま投げることにした。

myemu.patch -----
diff -ur xf86-input-evdev-2.8.2/src/emuMB.c xf86-input-evdev-2.8.2-my/src/emuMB.c
--- xf86-input-evdev-2.8.2/src/emuMB.c 2013-08-29 14:10:43.000000000 +0900
+++ xf86-input-evdev-2.8.2-my/src/emuMB.c 2014-05-12 23:07:32.939481119 +0900
@@ -237,12 +237,14 @@
 
     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][0]) != 0)
     {
-        EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ if (!EvdevWheelEmuFilterButton(pInfo, abs(id), (id >= 0)))
+     EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
         ret = TRUE;
     }
     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][1]) != 0)
     {
-        EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ if (!EvdevWheelEmuFilterButton(pInfo, abs(id), (id >= 0)))
+     EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
         ret = TRUE;
     }
-----

xorg.conf -----
 Option     "Emulate3Buttons"       "true"
 Option     "Emulate3Timeout"       "100"
 Option     "EmulateWheel"       "true"
 Option     "EmulateWheelButton" "2"
 Option     "EmulateWheelTimeout" "250"
 Option     "YAxisMapping"  "4 5"
 Option     "XAxisMapping"  "6 7"
-----

ソースをくまなく読んだわけではないし、あまり深く考えてもいないが、これでなんとかいけてる(かもしれない)。引数は理論的にこれで正しいか、他の修正は本当に必要ないのか、等の質問には全く答えられないが、とりあえず下記のように動くようになった。

左ボタン→左クリック
右ボタン→右クリック
左右ボタン同時押し→中クリック
左右ボタン同時押し+ボール操作→スクロール

中クリックドラッグができないのは仕様ということになるか。
この方法だとやっぱ便利だわ。