C#のグローバルフック及びマウスカールの制御についての質問です。

プログラムの作成は Microsoft Visual C# 2010 Express で行っております。
プログラムの内容はグローバルフックを用いてマウスカーソルの移動を検知し、
マウスカーソルが移動した際に移動前の座標と移動後の座標から移動距離を割り出して、
プログラム内で指定した角度分回転した座標へマウスカーソルを移動するというものです。
そこで問題があります。グローバルフックを使わずにフォーム内でのマウスカーソルの移動だけを
検知して、同じ処理を行った場合は正確に動作するのですが、
グローバルフックを使うとマウスカーソルの位置補正の挙動がおかしくなり、正常に動作しません。
原因と解決策をお聴きしたいです。
プログラミングの初心者ですので、質問の内容がわかりづらいとは思いますが回答よろしくお願いします。

プログラムのソースコードは文字制限のため私のブログに載せています。以下のURLとなっております。
http://d.hatena.ne.jp/kamonabe178/

わかりやすく、早く回答していただいた方には500ptお支払いします。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2011/11/04 13:01:28
  • 終了:2011/11/10 13:30:09

ベストアンサー

id:heke2mee No.1

heke2mee回答回数162ベストアンサー獲得回数432011/11/07 00:47:33

ポイント500pt

取得した座標がスクリーン座標になっていて、セットしようと

している座標をクライアント座標に変換してないからじゃないかな

(細かくソース見てないので間違ってたらすみません)

こちらに説明があるので参考にしてください

http://www.atmarkit.co.jp/fdotnet/dotnettips/377screentoclient/screentoclient.html

  • id:kamonabe178
    heke2meeさん回答ありがとうございます。
    スクリーン座標とクライアント座標が存在しており使い分けないといけないということはわかったのですが補正後にカーソルを移動するべき座標自体はしっかりと算出されています。
    Cursor.Positionでカーソルを移動する際(した際)に本来移動すべき座標ではない場所にカーソルが何度か移動し、角度の補正がかかっていない場所へカーソルが戻ってしまうという現象が起きています。

    お手数おかけしますが、可能でした一度プログラムを実行していただけたらよりわかりやすいと思います。
  • id:cx20
    回答ではないですが、はてなダイアリーにソースコードを載せる場合、
    「はてな記法」の「シンタックス・ハイライト」機能を使うとキーワードが色分けされて少し見やすくなります。

    ■ 入力したプログラムコードを色付けするスーパーpre記法 シンタックス・ハイライトの実装について - はてなダイアリー日記
    http://d.hatena.ne.jp/hatenadiary/20061215/1166155734

    <C# のソースコードを「シンタックス・ハイライト」で表示する例>
    >|cs|
    using System;

    namespace HelloWorld
    {
      class Hello
      {
        static void Main()
        {
          Console.WriteLine("Hello, C# World!");
        }
      }
    }
    ||<
  • id:kamonabe178
    cx20さんありがとうございます。
    早速使わせていただきました。
  • id:kamonabe178
    プログラムの内容がわかりづらいかと思いますので補足させていただきます。
    まず、
    x, y; 移動前のカーソルの座標
    x0, y0; 角度補正後のカーソルの座標
    xm, ym; 移動後のカーソルの座標
    xd, yd; カーソル移動前と移動後の差
    xmax, ymax; //ディスプレイ上の最大座標
    angle //補正する角度
    rad //angleをラジアンに変換した値
    というように値と格納しており、
    マウスカーソルが移動した際に
    移動前のカーソルの座標(x,y)を原点とし、移動後の座標(xm,ym)に対してangleに設定した値の分だけ
    回転した座標、つまり角度補正後のカーソルの座標(x0,y0)へカーソルを移動させるという処理を行い、
    マウスカーソルに角度の補正をかけたように見せているという内容になっています。

    各変数の値を表示してみたところ、角度補正後の座標(x0,y0)まで正確に算出されており、
    マウスカーソルをプログラムにより移動する(Cursor.Position)の処理がうまくいっていない状態です。

    グローバルフックを使わずにフォーム内のマウスイベントしか取得できないプログラム(ブログに追加しました)だと角度補正さます。
  • id:heke2mee
    MouseHookProcの中でSetCursorPos(APIです)を呼んでみたけど駄目だったので
    フックしたのをフォームに投げたでけですが、こんな感じでいいのかな?

    ブログのサンプルではFomStopwatch_FormClosingになってるけど
    Form1のクローズタイミングで呼ぶんですよね?

    私のソースではFom3になってます


    public partial class Form3 : Form
    {
    static MouseHookAPI.HookProcedureDelegate mouse_proc;

    [DllImport("User32.dll", EntryPoint = "PostMessage")]
    public static extern int PostMessage(int hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    int x, y; //移動前のカーソルの位置
    int x0, y0; //角度補正後のカーソルの位置
    double xm, ym; //移動後のカーソルの位置
    double xd, yd; //カーソル移動前と移動後の差
    double angle, rad;
    Point pos;
    int xmax, ymax; //ディスプレイ上の最大座標

    public Form3()
    {
    InitializeComponent();
    }

    private void Form3_Load(object sender, EventArgs e)
    {
    using (Process process = Process.GetCurrentProcess())
    using (ProcessModule module = process.MainModule)
    {
    MouseHookInfo.hHook = MouseHookAPI.SetWindowsHookEx(
    MouseHookInfo.WH_MOUSE_LL,
    mouse_proc = new MouseHookAPI.HookProcedureDelegate(MouseHookProc),
    MouseHookAPI.GetModuleHandle(module.ModuleName),
    0);
    }
    if (MouseHookInfo.hHook == IntPtr.Zero)
    MessageBox.Show("SetWindowsHookEx Failed.");

    xmax = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
    ymax = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;

    x = Cursor.Position.X;
    y = Cursor.Position.Y;
    }



    private void Form3_FormClosing(object sender, FormClosingEventArgs e)
    {
    if (MouseHookAPI.UnhookWindowsHookEx(MouseHookInfo.hHook) == false)
    MessageBox.Show("UnhookWindowsHookEx Failed.");
    }

    public IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
    if (nCode >= 0)
    {
    MouseHookInfo.MouseHookStruct MyMouseHookStruct = (MouseHookInfo.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookInfo.MouseHookStruct));
    switch ((int)wParam)
    {
    case MouseHookInfo.WM_LBUTTONDOWN:
    {
    break;
    }
    case MouseHookInfo.WM_LBUTTONUP:
    {
    break;
    }
    case MouseHookInfo.WM_MOUSEMOVE://マウス移動
    {
    PostMessage((int)this.Handle, MouseHookInfo.WM_MOUSEMOVE, wParam, lParam);
    break;
    }
    }
    }
    return MouseHookAPI.CallNextHookEx(MouseHookInfo.hHook, nCode, wParam, lParam);
    }

    private void Form3_MouseMove(object sender, MouseEventArgs e)
    {
    xm = Cursor.Position.X;
    ym = Cursor.Position.Y;

    angle = 90;

    rad = Math.PI * angle / 180;

    xd = xm - x;
    yd = ym - y;

    x0 = (int)(x + (xd * Math.Cos(rad) - yd * Math.Sin(rad)));
    y0 = (int)(y + (xd * Math.Sin(rad) + yd * Math.Cos(rad)));

    pos = new Point(x0, y0);

    Cursor.Position = pos;

    //x = Cursor.Position.X;
    //y = Cursor.Position.Y;

    x = pos.X;
    y = pos.Y;
    }


    }
  • id:kamonabe178
    再度回答ありがとうございます。
    試してみたのですが処理が実行されませんでした。
    (private void Form3_MouseMove(object sender, MouseEventArgs e)に入れてない?)
    私が何かミスしてしまってるのでしょうけど
    注意事項などはありましたか?

    ベストアンサーについては
    heke2meeさんにさせていただきます。
    すばやく丁寧に回答していただきありがとうございました。
  • id:heke2mee
    http://www1.axfc.net/uploader/Sc/so/291150.zip
    こちらにプロジェクトファイルを置いておきます。

    パスワードはポイントメッセージで送信しておきますね

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません