ヨン様と呼ばないで!

アクセスカウンタ

help リーダーに追加 RSS マウスボタンチャタリング対策(Windows限定)

<<   作成日時 : 2008/05/18 01:34   >>

トラックバック 1 / コメント 0

俺は前からマウスにLogicool G7を使っている。
反応・手への馴染み具合・重量などで大変気に入っているマウスなんだが、ひとつだけ重大な問題がある。

しばらく使用しているとチャタリングが発生するのだ。

どうやら、G7に限らずロジクールマウスでは結構発生しているようなのだ。
実は今使っているG7も、チャタリング発生でサポートに交換してもらった2台目だったりする。
しかし最近、その2台目もついにへたってきた。
また交換か・・・と思ったが、2ちゃんのロジスレを見ていると、どうも今サポートに出すと代替品としてG9が送られてくるようなのだ。
ワイヤレスから既に離れられない身体になっているだけに、こんなもんを送ってこられても困る。
既にG7は販売していないようで、これは困った。
ついでに言うと、その他のワイヤレスマウスを試用してみてもしっくりこないのだ。
握り心地とか、ホイールの感触(クリック・回転)とかがどれも最悪。
そんな訳でG7を延命することにした。
俺は一応ソフト屋なので、ソフトウェアでの解決を目指す。
とりあえずWindows上でどうにか出来ればよし。

ということで、キャンセルツールを作ってみた。
別にロジクールマウス専用でも何でもなくて、マウスなら何でも対応出来る(はず)。
ホントは自分のブログ領域にアップ出来ればいいんだが、どうも画像しかアップロード出来ないらしい。
拡張子をゴニョれば可能かも知らんが、それだけで困る人も出そうだからやめた。
仕方なく、フリーのアップローダを使用。
1年前のファイルとかも余裕で残ってるアップローダなので、そんなに不都合ない・・・かな。

2008.06.05変更
ベクターにて正式版が公開されました

2008.06.20追加
1.1正式版が公開されました

注意書きはだいたいReadmeに書いてあるので、そちらを参照願いたい。
追記としては、VC++2008のランタイムが必要なのでインストールしてもらうことくらいか。
ランタイムは同梱してあるのでそれを使えばいい。

以下は中身のお話をちょっと。
使うだけの人には関係ない話なので、スルーしても構わない。

さて、Windows上でマウスのチャタリングをどうにかするとなると、、やはりここはマウスのイベントを拾ってごにょごにょするしかない。
最初はマウスメッセージを拾おうと思ったが、既にダブルクリックイベントが存在しており、それはつまりチャタリングによって発生したダブルクリックなのか正当なダブルクリックか判断出来ないということで意味がない。
そんな訳で、 SetWindowsHookEx で WH_MOUSE_LL を指定してマウスの低レベルメッセージをフックすることにした。
SetWindowsHookEx に WH_MOUSE_LL を指定すると、登録した LowLevelMouseProc プロシジャでは WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE、WM_MOUSEWHEEL、WM_RBUTTONDOWN、WM_RBUTTONUP が拾えるらしい。
となると、今回は左ボタンでチャタリングが起きているので WM_LBUTTONDOWN と WM_LBUTTONUP を処理すればいいということになる。
該当部分はこんな感じ。

グローバルフック登録

SetWindowsHookEx(WH_MOUSE_LL,(HOOKPROC)fncDblClkCancel,hDllHnd,0);


ちなみに、通常グローバルフックを登録したかったら DLL にしないといかんのだが、WH_MOUSE_LL は処理が特殊なせいか Exe型式でもいいらしい。
DLL として作っちゃった後に知ったよこんちくしょう。
ついでに、.Net Framework でも処理できる数少ないグローバルフックらしい。
まあ今回は MSDN にある LowLevelMouseProc の解説で

>>引用開始

このフックプロシージャは、次のレジストリハイブ内の LowLevelHooksTimeout 値よりも短い時間のうちに、メッセージを処理するべきです。

HKEY_CURRENT_USER\Control Panel\Desktop

この値の単位は、ミリ秒(ms;1,000 分の 1 秒)です。この時間内にこのフックプロシージャが制御を返さなかった場合、システムはメッセージを次のフックへ渡します。

引用終了<<

こんなことが書いてあるので、処理速度の面から .Net は使わないことにした。
どうせ Win32API を使うんだから、C++でいいやとか。
(ちなみに VC++ Express Editionを使ってるので MFC が使えないというのもある)

話が大幅に逸れた。
んでまあ、登録した LowLevelMouseProc でメッセージループをこしらえて WM_LBUTTONDOWN と WM_LBUTTONUP を処理すればいい訳だ。
イベント発生ごとにタイムスタンプを取得して、差分を取って基準値以下だったら return TRUE すればメッセージは破棄される。
結局ここで一番重要なのは、どう差分を取って破棄するかの判断方法となる。
実際今もこれ!という判断を決めかねていて、現在の実装も完璧ではなかったりする。
チャタリングの発生状況によっては、WM_LBUTTONUP だけ捨てられてしまってドラッグ状態になってしまうことが稀にあり、ここが現在の優先課題となっている。
とりあえず判定方法を変更したバージョンもひとつ出来たので、自PCにて現在検証している。
副作用がないようなら公開しよう。

後はタイムスタンプの取得方法だなぁ。
現在は GetTickCount を使っているが、マルチメディアタイマーを使ったほうがいいかも知れない。
これは今後の様子を見て判断することとしよう。

そんな訳で、今後の課題を列挙してみる。
・チャタリングかどうかの判断方法をさらに検討
・タイマの精度を上げるか否か
・現在は左クリックだけだが、右クリックにも対応した方がいいかも知れない
・(おまけ)アイコンを作らないと今のままではみっともない

実はこの課題で一番難しいのはアイコンかもしれない。
ううう・・・。

設定テーマ

関連テーマ 一覧

月別リンク

トラックバック(1件)

タイトル (本文) ブログ名/日時
続 ChatteringCanceler
チャタリングキャンセラ、更新しますた。 ...続きを見る
ヨン様と呼ばないで!
2008/05/19 20:48

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
URL(任意)
本 文