カーソル (Cursors)

マウス、ペンそれにトラックボールなどのカーソル (マウスポインタ) を制御する方法について解説します。

カーソルの位置

BOOL GetCursorPos(
  LPPOINT lpPoint   // カーソルの位置
  );
GetCursorPos 関数 | MSDN

現在のマウスポインタの位置を、スクリーン座標で取得できます。

カーソルの移動

BOOL SetCursorPos(
  int X,  // 水平位置
  int Y   // 垂直位置
  );
SetCursorPos 関数 | MSDN

マウスポインタを、スクリーン座標の指定の位置へ移動できます。これは後述するSendInput()でも可能であり、それには次のようにします。

void Move(int x, int y)
{
    const double ScaleX = 0xffff / GetSystemMetrics(SM_CXSCREEN);
    const double ScaleY = 0xffff / GetSystemMetrics(SM_CYSCREEN);

    INPUT input = {};
    input.type = INPUT_MOUSE;
    input.mi.dx = (LONG)(x * ScaleX);
    input.mi.dy = (LONG)(y * ScaleY);
    input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;

    SendInput(1, &input, sizeof(INPUT));
}

クリック

クリックはSendInput()で行えます。

UINT WINAPI SendInput(
  _In_ UINT    nInputs, // pInputsの要素数
  _In_ LPINPUT pInputs, // マウスまたはキーボード入力の内容
  _In_ int     cbSize   // INPUT構造体のバイト数
  );
SendInput function (Windows) | MSDN

入力方法を指定するpInputsは、次のINPUT構造体で定義します。

typedef struct tagINPUT {
  DWORD type;
  union {
    MOUSEINPUT    mi;
    KEYBDINPUT    ki;
    HARDWAREINPUT hi;
  };
  } INPUT, *PINPUT;
INPUT structure (Windows) | MSDN

入力方法をマウスとするにはtypeをINPUT_MOUSEとし、その入力内容はmiにMOUSEINPUT共用体で指定します。

typedef struct tagMOUSEINPUT {
  LONG      dx;
  LONG      dy;
  DWORD     mouseData;
  DWORD     dwFlags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
  } MOUSEINPUT, *PMOUSEINPUT;
MOUSEINPUT structure (Windows) | MSDN

これらを用いて、たとえば現在の位置から右へ100ピクセル移動した位置をクリックするならば、次のようにします。

INPUT input = {};
input.type = INPUT_MOUSE;
input.mi.dx = 100;
input.mi.dy = 0;
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;

SendInput(1, &input, sizeof(INPUT));

INPUT構造体の定義時に初期化すれば、これは次のように簡潔に記述できます。

INPUT input = { INPUT_MOUSE, 100, 0, 0, MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP };
SendInput(1, &input, sizeof(INPUT));

ダブルクリック

たとえば現在の位置でダブルクリックするならば、次のように同じ位置で2度クリックします。

INPUT input[] = { {}, {} };
input[0].type       = input[1].type       = INPUT_MOUSE;
input[0].mi.dwFlags = input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;

SendInput(sizeof(input) / sizeof(input[0]), input, sizeof(INPUT));

カーソルの形状

HCURSOR WINAPI LoadCursor(
  _In_opt_ HINSTANCE hInstance,
  _In_     LPCTSTR   lpCursorName
  );
LoadCursor function (Windows) | MSDN
HCURSOR WINAPI SetCursor(
  _In_opt_ HCURSOR hCursor
  );
SetCursor function (Windows) | MSDN
SetCursor(LoadCursor(NULL, IDC_HAND));

SetCursor()は、アプリケーション上での現在のカーソルを変更します。これをアプリケーション外にも適用させるには、SetSystemCursor()でシステムのカーソルを変更します。

BOOL WINAPI SetSystemCursor(
  _In_ HCURSOR hcur,
  _In_ DWORD   id
  );
SetSystemCursor function (Windows) | MSDN SetSystemCursor 関数 | MSDN

SetSystemCursor()に渡すhcurは、カーソル変更後に破棄されます。よって破棄されては困るリソースは、コピーを渡すようにします。

HCURSOR cursor = LoadCursor(NULL, IDC_CROSS);
SetSystemCursor(CopyCursor(cursor), OCR_NORMAL);

なおシステムカーソルの変更はアプリケーション終了後も維持されるため、明示的に元に戻さねばなりません。

// カーソルを保存する
HCURSOR normalCursor = CopyCursor(LoadCursor(NULL, IDC_ARROW));


// カーソルを変更する
SetSystemCursor(CopyCursor(LoadCursor(NULL, IDC_HAND)), OCR_NORMAL);

// 一時的に戻す
SetSystemCursor(CopyCursor(normalCursor), OCR_NORMAL);

// カーソルを変更する
SetSystemCursor(CopyCursor(LoadCursor(NULL, IDC_CROSS)), OCR_NORMAL);


// 元に戻す
SetSystemCursor(normalCursor, OCR_NORMAL);

参考

参考書

Microsoft Learnから検索