1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

マウスを自動で移動させてスリープさせないアプリ(SoulMouse)

Posted at

##離席中でもWindowsをスリープさせたくない
体は離席しても、魂だけは在席してマウス操作しててほしい。
というわけで、プログラムでマウス操作させてみました。
##作ったアプリ
・カーソル移動 → スクロール → 待ち、を繰り返すアプリ
・それぞれの時間はランダム(配布版では「待ち」時間はもう少し長め)
・人がいなくても、人のぬくもりを感じるアプリになりました
GhostMouse-2.gif
##ソースコード
マウスをぷるぷる動かしてスクリーンセーバを抑制するアプリ を参考にさせていただきました。ありがとうございます。

上記ページのソースコードに、以下を追加しています。
(Wait, Move, Wheel のステート追加)

Form1.cs
const int MOUSEEVENTF_WHEEL = 0x800;
INPUT[] mInput = new INPUT[1];
Stopwatch mStopwatch = new Stopwatch();
enum EState { Wait, Move, Wheel }
EState mState = EState.Wait;
Random mRandom = new Random();
int mTargetX = 0, mTargetY = 0;

private async void autoMouseRunStart()
{
    isAppRun = true;
    int screen_width = Screen.PrimaryScreen.Bounds.Width;
    int screen_height = Screen.PrimaryScreen.Bounds.Height;
    mStopwatch.Restart();
    mInput[0].mi.dx = Cursor.Position.X * (65535 / screen_width);
    mInput[0].mi.dy = Cursor.Position.Y * (65535 / screen_height);
    mInput[0].mi.dwFlags = MOUSEEVENTF_MOVED | MOUSEEVENTF_ABSOLUTE;

    // 開始時点でマウスがPrimaryScreenに無い場合、PrimaryScreenに強制移動させる
    if (Cursor.Position.X > screen_width || Cursor.Position.Y > screen_height)
    {
        mInput[0].mi.dx = (screen_width / 2) * (65535 / screen_width);
        mInput[0].mi.dy = (screen_height / 2) * (65535 / screen_height);
        SendInput(1, mInput, Marshal.SizeOf(mInput[0]));
    }

    await Task.Run(() =>
    {
        while (isAppRun)
        {
            switch (mState)
            {
            case EState.Wait:
                // 一定時間経過したら EState.Move に移行
                if (mStopwatch.ElapsedMilliseconds > mWaitTime)
                {
                    mState = EState.Move;
                    mMoveTime = mRandom.Next(1000, 3000); // 1~3秒でマウス移動
                    mTargetX = mRandom.Next(0, screen_width);  // ランダムなX座標
                    mTargetY = mRandom.Next(0, screen_height); // ランダムなY座標
                    mInput[0].mi.dwFlags = MOUSEEVENTF_MOVED | MOUSEEVENTF_ABSOLUTE;
                    mStopwatch.Restart();
                }

                // 適当にスリープさせる
                // さもないと、CPU100%で処理してしまう
                System.Threading.Thread.Sleep(5);
                break;

            case EState.Move:
                // 一定時間経過したら EState.Wheel に移行
                if (mStopwatch.ElapsedMilliseconds > mMoveTime)
                {
                    mState = EState.Wheel;
                    mWheelTime = mRandom.Next(100, 800); // 0.1~0.8秒でマウスホイール
                    mInput[0].mi.dwFlags = MOUSEEVENTF_WHEEL;
                    mInput[0].mi.mouseData = mRandom.Next(-1, 2);
                    mStopwatch.Restart();
                }

                // カーソルを目標に追従させる
                mInput[0].mi.dx += (int)((mTargetX - Cursor.Position.X) * 0.07) * (65535 / screen_width);
                mInput[0].mi.dy += (int)((mTargetY - Cursor.Position.Y) * 0.07) * (65535 / screen_height);

                // 適当にスリープさせる
                // さもないと、カーソル移動処理が実行されすぎて移動が速くなりすぎてしまう
                System.Threading.Thread.Sleep(5);

                break;

            case EState.Wheel:
                // 一定時間経過したら EState.Wait に移行
                if (mStopwatch.ElapsedMilliseconds > mWheelTime)
                {
                    mState = EState.Wait;
                    mWaitTime = mRandom.Next(10000, 30000); // 10~300秒でマウス停止
                    mInput[0].mi.dwFlags = 0;
                    mStopwatch.Restart();
                }

                // マウスホイールではスリープさせない
                // スリープさせると滑らかなスクロールにならなかった
                //System.Threading.Thread.Sleep(1);

                break;
            }

            // イベントの実行
            // Cursor.Position への代入や、SetCursorPos での座標セットではスリープ状態になってしまうので SendInput を使用
            SendInput(1, mInput, Marshal.SizeOf(mInput[0]));
        }
    });
}

// 機能停止
private void autoMouseRunStop()
{
    isAppRun = false;
    mState = EState.Wait;
    mTargetX = mTargetY = 0;
    mWaitTime = mMoveTime = mWheelTime = 2000;
}

マウスホイール時に Thread.Sleep するとスクロールがガクガクしていました。
よって、EState.Wheel では Thread.Sleep していません。
CPU速度に依存するコードになっているので、高性能PCでは Thread.Sleep する必要があるかもしれません。

プロジェクトは以下にあります。

##アプリを使用してみる

  1. こちら の「Download SoulMouse.zip」からダウンロード
  2. zip を展開
  3. SoulMouse.exe を実行するとタスクトレイに登場(灰色矢印アイコン)
  4. 「CTRL + SHIT + S」で開始(カーソルが自動で動き出す)
  5. 「CTRL + SHIT + D」で停止
  6. タスクトレイのアイコンを右クリック「終了」でタスクトレイから削除

・よくPCスリープになってしまう人は是非
・テレワーク監視はスリープ時間チェックから行われることが多い
・Webカメラを定期送信するなどの本気の監視には対応できないですが
・いずれにせよ、用法・用量を守って正しくお使いください

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?