一瞬でマウス感度を切り替えるプログラムを書いてみた

アプリ

資料作成や画像編集などをしていると、1ピクセルだけずらすなどの細かいマウスさばきが要求される時ってありますよね?
マウス感度を簡単に切り替えられるようになったらみんな幸せになるかなと思ってプログラムを書いてみました。

ランチャーソフトやショートカットキーで実行できるようなEXEを作ろう

速度計のイメージ起動すると現在の速度を検知し、自動で「遅い→普通→速い→」の3種類の速度切替をするソフトを作ればよいと思いました。
そしていちいちEXEファイルをクリックするのなんかやってられないッ!
自分はMouseGestureL.ahkというマウスジェスチャーソフトを使い倒しているので「右クリック+左クリック+ボタンを離す」というジェスチャーに作ったEXEを登録すればよいと考えました。

マウスジェスチャーは苦手・・・という方はWindowsの機能を使ってEXEを起動するショートカットキーを新たに作成すればよいと思います。

レジストリを書き換えればいいだけかな?という考えは甘かった

悩むイメージWindowsXP以降では、¥HKEY_CURRENT_USER¥Control Panel¥Mouseにある4つのレジストリキーがマウス設定の鍵を握っているらしいです。
MouseSensitivity:カーソルの初速度(最大で20)
MouseSpeed:マウスを動かした速度に応じてカーソルを加速させる機能の有無
SmoothMouseXCurve:加速直線のX軸の値
SmoothMouseYCurve:加速直線のy軸の値

そこでさっそくレジストリエディタでMouseSensitivityを変更したけれど、カーソルには何も変化がない!
それもそのはず、レジストリはあくまで一時的なメモにしか過ぎず一度サインアウトまたは再起動しないとレジストリの値は適用されないらしいのです。へぇ~。
再起動しなきゃマウス感度が変更できないなんてそんなバカな話はない。きっと他に方法があるはず・・・

WIN32APIを.NET Frameworkでちょっと強引に呼び出す事にした

無理やり呼び出してみたどうやらマウスの速度を変更するといったOSを直接操作するような事はWindowsと共に歩み続けたふか~い歴史があるWIN32APIという手段を使うとよいそうです。

しかしWIN32APIを使うにはC言語やC++といった言語を使わなくてはならない・・・サッパリ分からないから困ったなぁと思っていたところ、ちょっと強引だけど.NET Frameworkを使っても呼び出せる事が分かったのでVisual Studioを使ってやってみる事にしました。

MouseSensitivityChangerのソース

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ConsoleApp1
{
    class MouseSensitivityChangeProgram
    {
        [DllImport("user32.dll")]
        extern static bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
        private const uint SPI_GETMOUSESPEED = 112;
        private const uint SPI_SETMOUSESPEED = 113;
        private const uint SPIF_UPDATEINIFILE = 1;
        private const uint SPIF_SENDCHANGE = 2;

        unsafe static void Main(string[] args)
        {
            uint mouseSpeed;
            uint level1 = 3;
            uint level2 = 10;
            uint level3 = 20;

            if (level1 >= 1 & level2 >= 1 & level3 >= 1 & level1 <= 20 & level2 <= 20 & level3 <= 20)
            {
                SystemParametersInfo(SPI_GETMOUSESPEED, 0, new IntPtr((void*)&mouseSpeed), 0);

                if (mouseSpeed < level2)
                {
                    SystemParametersInfo(SPI_SETMOUSESPEED, 0, new IntPtr(level2), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
                }
                else if (mouseSpeed < level3) { SystemParametersInfo(SPI_SETMOUSESPEED, 0, new IntPtr(level3), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); } else if (mouseSpeed >= level3)
                {
                    SystemParametersInfo(SPI_SETMOUSESPEED, 0, new IntPtr(level1), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
                }
            }
            else
            {
                MessageBox.Show("速度レベルは1~20の範囲で設定をして下さい。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

気を付けた事

SystemParametersInfo(SPI_GETMOUSESPEED, 0, new IntPtr((void*)&mouseSpeed), 0);

現在のMouseSensitivityを検知して3つ目の引数のpvParamに代入するWIN32APIの機能。地味な機能だけどpvParamは参照渡しにしなきゃいけないためややこしい。参照渡しの処理はunsafeじゃないとできないらしいのでメソッドをunsafeにし、VisualStudioでunsafeのビルドを許可しています。

SystemParametersInfo(SPI_SETMOUSESPEED, 0, new IntPtr(level2), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);

レジストリのMouseSensitivityを3つ目の引数のpvParamに変更してくれる上、変更した事をWindowsに伝えてくれる今回のメインウェポンとなるWIN32APIの機能。

[DllImport("user32.dll")]
        extern static bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
        private const uint SPI_GETMOUSESPEED = 112;
        private const uint SPI_SETMOUSESPEED = 113;
        private const uint SPIF_UPDATEINIFILE = 1;
        private const uint SPIF_SENDCHANGE = 2;

上記2つの機能は.NET Frameworkは当然知らないので教えてあげる必要がある。
SystemParametersInfoの機能があるDLLファイル名を調べて、インポートさせ、extern修飾子で関数の実体が外部にあることを教えた。(データ型は対応するC#の型に変換する必要がある)
SPI_GETMOUSESPEEDやSPIF_UPDATEINIFILEは定数なのですが、当然その定数も知らないので頑張って調べて教えてあげる必要がありました。

Sensitivityの3段階の値をもしiniファイルとかXMLとかで外部で設定する事になった時、20以上の値が来たらメッセージボックスでエラーを出すようにしておきました。

自作なんて非効率?

二匹のペンギンの画像プロジェクトをビルドしてランチャーソフトにEXEファイルを登録して・・・簡単な操作で一瞬でマウス感度が切り替わるようになりました!

WIN32APIとかの知識は一切なかったのですが、ネット上に情報はたくさん散らばっていたので「こんなのがあったらいいよね」という気持ちだけで実際に使えるプログラムが作れてしまいました。
デバイスのブラックボックス化がどんどん進む世の中で自作なんて非効率だと言われるかもしれませんが、自分にぴったり合うものは自分にしか作れないし、自分が必要とするものは誰かにとってもすごく必要なものでもあると思うのでアプリやバッチを自作する事は効率化にとっては大事な事だと思います。