しらいとブログ

ネットで検索してもなかなか出てこないIT情報を独自にまとめています

「WinMouse+」開発記録 Part1

以前からマウスの操作に違和感を感じていたので、Windowsのマウスカーソル移動処理をフックして独自の移動処理に置き換えるソフトを開発することにしました。

先に言っておくと、マウス処理のフックは非常に簡単です。
「マウス フック」で検索すればやり方もサンプルも出てきます。

問題は「マウスのセンサーに問題がある場合にどうすれば快適に使えるのか」になります。

私が使っているマウスの問題

私が使っているマウスはLogicoolのM500tです。
これは3000円以上するマウスなので安物ではないはずです。

実はこのマウス、センサーに問題があります。

これはマウスを右下に動かしたときの移動量を計測したものです。

x,y: 19, 20
x,y: 20, 21
x,y: 38, 40
x,y: 19, 20
x,y: 41, 38
x,y: 20, 19
x,y: 21, 19
x,y: 42, 40
x,y: 21, 20
x,y: 41, 41
x,y: 21, 20
x,y: 42, 41
x,y: 22, 20
x,y: 21, 20
x,y: 44, 41
x,y: 22, 21
x,y: 44, 40
x,y: 22, 21
x,y: 22, 20
x,y: 45, 42

この結果をよく見ると20くらいの値と40くらいの値が交互に出てくるのに30くらいの値は出てきませんね。まるで処理落ちが発生して2回分まとめて処理したような結果です。

ですが処理落ちは発生していませんでした。マウスのレポートレートは125Hzですが、仕様通り1秒間に125回処理されています。

おそらく、センサーの記録更新頻度とレポートレートがあっていないのでしょう。解析プログラムを作ってセンサーの記録更新レートを予測させてみましたが何度やっても175Hzになりました。

M500tは1度ボタンが壊れて新しいのを送ってもらったことがあるので、そのボタンが壊れた方でも同じ実験をしましたが、そちらでも同じ症状が発生しました。

逆に他の機種(LogicoolのG300r)でも同じ実験をしましたが、こちらにはこのような症状はありませんでした。

なのでM500t固有の症状となります。

そして、この症状はカーソルの加速処理で問題になります。

実はマウスカーソルの移動量はマウスの移動量に比例せず、速度に応じて変わるようになっています。

マウスをゆっくり動かせばカーソルの移動量は本来の移動量より少なくなり、精密な動作ができます。マウスを速く動かせば本来の移動量より多くなり、マウスを大きく動かさなくても画面の端から端まで移動できます。

この機能はコントロールパネルのマウスのプロパティで「ポインター精度を高める」にチェックを入れると有効になります。

さきほどの測定結果はこの加速処理がされていない生の値でした。

加速処理を有効にすると次のようになります。

x,y: 27, 20
x,y: 82, 56
x,y: 27, 20
x,y: 26, 18
x,y: 83, 56
x,y: 27, 20
x,y: 30, 21
x,y: 83, 56
x,y: 31, 21
x,y: 82, 56
x,y: 31, 22
x,y: 82, 56
x,y: 31, 21
x,y: 26, 17
x,y: 82, 56
x,y: 27, 21
x,y: 82, 56
x,y: 24, 19
x,y: 27, 20
x,y: 78, 52

さきほどの生の値と比べて差が激しくなりました。2倍だった差が3倍にまで広がっています。

センサーの記録が1回分のところは低速と判定され移動量が少なめになり、2回分のところは高速と判定され移動量が多めになっているからです。

こうなると加速処理の本来の特性が薄れてしまいます。これが違和感の正体でした。

ちなみに加速処理を無効にすると違和感は無くなりますが、それだと低速に設定すると画面の端から端まで移動するのにマウスを大きく動かさなければならず、高速に設定すると細かい作業がしづらくなります。

どうやって解決するのか

マウスを変えれば解決するのはわかっていますが、M500tの形状とか重さとか気に入っているのでそれは無しの方向で考えます。まあ、欲を言えばもっと解像度の高いマウスが良かったと思っています(M500tは1000DPIしかない)が、3000円以上払ったし保証もまだ残っているのでやっぱり使い続けることにします。

そういうわけでソフト側でなんとか対応しようと思います。

とりあえずフックしてみて分かったのが、カーソル移動量の変更方法は2種類あります。

1つは移動量を直接変更する方法。もう1つは移動量を0に変更しておいて、後からカーソルを動かす方法。

前者のやり方だとマウスを動かしているときにカーソルを動かすことができますが、マウスが止まっているときにカーソルを動かすことはできません。後者のやり方だとマウスが止まっていてもカーソルを動かすことができますが、マウスの移動からカーソルの移動までに遅延が生じます。

この2つで上記の症状を緩和する方法を考えなければなりません。

例えば後者のやり方なら移動平均を使って移動量を平均化することができます。その場合カーソルは慣性のついた動きになり、マウスを止めてからカーソルが止まるまでに少し時間があります。

あるいは違和感の少ない加速処理を考えて実装する方法もあります。残念ながらそのような加速処理は現時点で思いついていません。

他には加速処理を使わない方法でうまいやり方を模索することもできます。例えばショートカットキーやマウスのボタンで速度を変える方法があります。

いろいろ案を練っていますが、まだ「これだ」という案が出ていません。

他にやりたいこと

Windowsのカーソル座標の精度を内部で小数を使うことで上げられないかと考えています。厳密にいえばWindowsも加速処理では高精度な座標計算をやっているようですが、もっといいやり方があるような気がします。

小数で管理するなら閾値の計算もしなければなりません。小数を整数に丸める場合、小数点以下を切り捨てだろうと四捨五入だろうと必ず境界があります。

例えば0以上1未満は0に、1以上2未満は1に切り捨てる場合、1付近は境界になります。
この場合、0.99は0に、1.00は1になります。

つまり、カーソルが1.00付近にある場合、たった0.01のプラスマイナスでカーソルが行ったり来たりします。

この問題は小数点以下が累積しやすい高DPIマウスでよく起こります。

この問題を防ぐには閾値を設ける必要があります。

例えば閾値を±0.5にすると、カーソルが0にある場合、内部座標が1.5以上になったら1に移動します。カーソルが1にある場合は内部座標が0.5以下になったら0に移動し、2.5以上になったら2に移動します。

このやり方だと境界が移動するので高速で行ったり来たりすることが無くなります。

他には高速スクロールが使い物にならない(ホイールが勝手に動く)ので独自の高速スクロールを実装したいとか、マウスの速度切り替えも実装したいとかいくつか案があります。

とりあえずできたもの

WinMouse+_alpha01.zip
※Windows10でスタートメニュー、ストアアプリでクラッシュする不具合が発覚しました

実装した機能
加速処理4種類
小数座標(閾値の計算あり)
加速前の移動量の平均化(前回の移動量との平均)
独自の高速スクロール
低速モード

これだけの機能を実装してもコードは400行でした。

作ってて面白くなってきたのでもっと機能を増やそうと思います。