カーソルの使用
このセクションでは、次のトピックについて説明します。
カーソルの作成
次の例では、標準の砂時計カーソル用と、アプリケーションのリソース定義ファイルにリソースとして含まれるカスタム カーソル用の 2 つのカーソル ハンドルを作成します。
HINSTANCE hinst; // handle to current instance
HCURSOR hCurs1, hCurs2; // cursor handles
// Create a standard hourglass cursor.
hCurs1 = LoadCursor(NULL, IDC_WAIT);
// Create a custom cursor based on a resource.
hCurs2 = LoadCursor(hinst, MAKEINTRESOURCE(240));
アプリケーションでは、実行時にカーソルを作成するのではなく、カスタム カーソルをリソースとして実装し、 LoadCursor、 LoadCursorFromFile、または LoadImage を使用する必要があります。 カーソル リソースを使用すると、デバイスの依存を回避し、ローカライズを簡略化し、アプリケーションでカーソルデザインを共有できます。
次の例では、 CreateCursor 関数を 使用して、実行時にカスタム モノクロ カーソルを作成します。 この例は、システムがカーソル マスクを解釈する方法を示すためにここに含まれています。
HINSTANCE hinst; // handle to current instance
HCURSOR hCurs1, hCurs2; // cursor handles
HCURSOR hCurs3; // cursor handle
// Yin-shaped cursor AND mask
BYTE ANDmaskCursor[] =
{
0xFF, 0xFC, 0x3F, 0xFF, // line 1
0xFF, 0xC0, 0x1F, 0xFF, // line 2
0xFF, 0x00, 0x3F, 0xFF, // line 3
0xFE, 0x00, 0xFF, 0xFF, // line 4
0xF7, 0x01, 0xFF, 0xFF, // line 5
0xF0, 0x03, 0xFF, 0xFF, // line 6
0xF0, 0x03, 0xFF, 0xFF, // line 7
0xE0, 0x07, 0xFF, 0xFF, // line 8
0xC0, 0x07, 0xFF, 0xFF, // line 9
0xC0, 0x0F, 0xFF, 0xFF, // line 10
0x80, 0x0F, 0xFF, 0xFF, // line 11
0x80, 0x0F, 0xFF, 0xFF, // line 12
0x80, 0x07, 0xFF, 0xFF, // line 13
0x00, 0x07, 0xFF, 0xFF, // line 14
0x00, 0x03, 0xFF, 0xFF, // line 15
0x00, 0x00, 0xFF, 0xFF, // line 16
0x00, 0x00, 0x7F, 0xFF, // line 17
0x00, 0x00, 0x1F, 0xFF, // line 18
0x00, 0x00, 0x0F, 0xFF, // line 19
0x80, 0x00, 0x0F, 0xFF, // line 20
0x80, 0x00, 0x07, 0xFF, // line 21
0x80, 0x00, 0x07, 0xFF, // line 22
0xC0, 0x00, 0x07, 0xFF, // line 23
0xC0, 0x00, 0x0F, 0xFF, // line 24
0xE0, 0x00, 0x0F, 0xFF, // line 25
0xF0, 0x00, 0x1F, 0xFF, // line 26
0xF0, 0x00, 0x1F, 0xFF, // line 27
0xF8, 0x00, 0x3F, 0xFF, // line 28
0xFE, 0x00, 0x7F, 0xFF, // line 29
0xFF, 0x00, 0xFF, 0xFF, // line 30
0xFF, 0xC3, 0xFF, 0xFF, // line 31
0xFF, 0xFF, 0xFF, 0xFF // line 32
};
// Yin-shaped cursor XOR mask
BYTE XORmaskCursor[] =
{
0x00, 0x00, 0x00, 0x00, // line 1
0x00, 0x03, 0xC0, 0x00, // line 2
0x00, 0x3F, 0x00, 0x00, // line 3
0x00, 0xFE, 0x00, 0x00, // line 4
0x0E, 0xFC, 0x00, 0x00, // line 5
0x07, 0xF8, 0x00, 0x00, // line 6
0x07, 0xF8, 0x00, 0x00, // line 7
0x0F, 0xF0, 0x00, 0x00, // line 8
0x1F, 0xF0, 0x00, 0x00, // line 9
0x1F, 0xE0, 0x00, 0x00, // line 10
0x3F, 0xE0, 0x00, 0x00, // line 11
0x3F, 0xE0, 0x00, 0x00, // line 12
0x3F, 0xF0, 0x00, 0x00, // line 13
0x7F, 0xF0, 0x00, 0x00, // line 14
0x7F, 0xF8, 0x00, 0x00, // line 15
0x7F, 0xFC, 0x00, 0x00, // line 16
0x7F, 0xFF, 0x00, 0x00, // line 17
0x7F, 0xFF, 0x80, 0x00, // line 18
0x7F, 0xFF, 0xE0, 0x00, // line 19
0x3F, 0xFF, 0xE0, 0x00, // line 20
0x3F, 0xC7, 0xF0, 0x00, // line 21
0x3F, 0x83, 0xF0, 0x00, // line 22
0x1F, 0x83, 0xF0, 0x00, // line 23
0x1F, 0x83, 0xE0, 0x00, // line 24
0x0F, 0xC7, 0xE0, 0x00, // line 25
0x07, 0xFF, 0xC0, 0x00, // line 26
0x07, 0xFF, 0xC0, 0x00, // line 27
0x01, 0xFF, 0x80, 0x00, // line 28
0x00, 0xFF, 0x00, 0x00, // line 29
0x00, 0x3C, 0x00, 0x00, // line 30
0x00, 0x00, 0x00, 0x00, // line 31
0x00, 0x00, 0x00, 0x00 // line 32
};
// Create a custom cursor at run time.
hCurs3 = CreateCursor( hinst, // app. instance
19, // horizontal position of hot spot
2, // vertical position of hot spot
32, // cursor width
32, // cursor height
ANDmaskCursor, // AND mask
XORmaskCursor ); // XOR mask
カーソルを作成するために、 CreateCursor は 次の真理値テーブルを AND マスクと XOR マスクに適用します。
AND マスク | XOR マスク | 表示 |
---|---|---|
0 | 0 | Black |
0 | 1 | White |
1 | 0 | Screen |
1 | 1 | 画面の反転 |
詳細については、「 ビットマップ」を参照してください。
実行時にアルファ ブレンド カーソルまたはアイコンを作成するには、次の手順に従います。
- これらの手順に従うコード例のように BITMAPV5HEADER 構造体を完成し、ピクセルあたり 32 ビット (BPP) アルファ ブレンド DIB を定義します。
- CreateDIBSection 関数を呼び出して、完了した BITMAPV5HEADER 構造体に基づいて DIB セクションを作成します。
- アルファ ブレンド カーソルまたはアイコンに必要なビットマップとアルファ情報を使用して、DIB セクションを完了します。
- ICONINFO 構造体を完成させます。
- hbmMask フィールドに空のモノクロ ビットマップを配置し、hbmColor フィールドにアルファ ブレンド DIB セクションを配置します。
- CreateIconIndirect 関数を呼び出して、アルファ ブレンド カーソルまたはアイコンを作成します。
次のコードは、アルファ ブレンド カーソルを作成する方法を示しています。 ICONINFO 構造体の fIcon メンバーを TRUE に変更することで、同じコードを使用してアルファ ブレンド アイコンを作成できます。
HCURSOR CreateAlphaCursor(void)
{
HDC hMemDC;
DWORD dwWidth, dwHeight;
BITMAPV5HEADER bi;
HBITMAP hBitmap, hOldBitmap;
void *lpBits;
DWORD x,y;
HCURSOR hAlphaCursor = NULL;
dwWidth = 32; // width of cursor
dwHeight = 32; // height of cursor
ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = dwWidth;
bi.bV5Height = dwHeight;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
HDC hdc;
hdc = GetDC(NULL);
// Create the DIB section with an alpha channel.
hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
(void **)&lpBits, NULL, (DWORD)0);
hMemDC = CreateCompatibleDC(hdc);
ReleaseDC(NULL,hdc);
// Draw something on the DIB section.
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
PatBlt(hMemDC,0,0,dwWidth,dwHeight,WHITENESS);
SetTextColor(hMemDC,RGB(0,0,0));
SetBkMode(hMemDC,TRANSPARENT);
TextOut(hMemDC,0,9,"rgba",4);
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
// Create an empty mask bitmap.
HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL);
// Set the alpha values for each pixel in the cursor so that
// the complete cursor is semi-transparent.
DWORD *lpdwPixel;
lpdwPixel = (DWORD *)lpBits;
for (x=0;x<dwWidth;x++)
for (y=0;y<dwHeight;y++)
{
// Clear the alpha bits
*lpdwPixel &= 0x00FFFFFF;
// Set the alpha bits to 0x9F (semi-transparent)
*lpdwPixel |= 0x9F000000;
lpdwPixel++;
}
ICONINFO ii;
ii.fIcon = FALSE; // Change fIcon to TRUE to create an alpha icon
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = hMonoBitmap;
ii.hbmColor = hBitmap;
// Create the alpha cursor with the alpha DIB section.
hAlphaCursor = CreateIconIndirect(&ii);
DeleteObject(hBitmap);
DeleteObject(hMonoBitmap);
return hAlphaCursor;
}
終了する前に、 DestroyCursor 関数を使用して 、CreateCursor または CreateIconIndirect で作成したカーソルを破棄する必要があります。 他の関数によって作成されたカーソルを破棄する必要はありません。
カーソル サイズの取得
「アイコンのサイズを取得する」を参照してください。
カーソルの表示
クラス カーソル (カーソルが指しているウィンドウに関連付けられたカーソル) が自動的に表示されます。 ウィンドウ クラスの登録中にクラス カーソルを割り当てることができます。 次の例は、wc パラメーターで識別される WNDCLASS 構造体の hCursor メンバーにカーソル ハンドルを割り当てることでこれを示しています。
WNDCLASS wc;
// Fill the window class structure with parameters that
// describe the main window.
wc.style = NULL; // class style(s)
wc.lpfnWndProc = (WNDPROC) MainWndProc; // window procedure
wc.cbClsExtra = 0; // no per-class extra data
wc.cbWndExtra = 0; // no per-window extra data
wc.hInstance = hinst; // application that owns the class
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // class icon
wc.hCursor = LoadCursor(hinst, MAKEINTRESOURCE(230)); // class cursor
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // class background
wc.lpszMenuName = "GenericMenu"; // class menu
wc.lpszClassName = "GenericWClass" // class name
// Register the window class.
return RegisterClass(&wc);
ウィンドウ クラスが登録されている場合、アプリケーションのリソース定義ファイルで 230 で識別されるカーソルは、 クラスに基づくすべてのウィンドウの既定のカーソルです。
アプリケーションでは、 SetCursor 関数を使用し、別のカーソル ハンドルを指定することで、カーソルのデザインを変更できます。 ただし、カーソルが移動すると、システムはクラス カーソルを新しい場所に再描画します。 クラス カーソルが再描画されないようにするには、 WM_SETCURSOR メッセージを処理する必要があります。 カーソルが移動し、マウス入力がキャプチャされないたびに、システムはカーソルが移動しているウィンドウにこのメッセージを送信します。
WM_SETCURSORの処理中に、条件ごとに異なるカーソル を指定できます。 たとえば、次の例は、最小化されたアプリケーションのアイコンの上にカーソルが移動するたびにカーソルを表示する方法を示しています。
case WM_SETCURSOR:
// If the window is minimized, draw the hCurs3 cursor.
// If the window is not minimized, draw the default
// cursor (class cursor).
if (IsIconic(hwnd))
{
SetCursor(hCurs3);
break;
}
ウィンドウが最小化されていない場合は、クラス カーソルが表示されます。
SetClassLong 関数を使用して、クラス カーソルを置き換えることができます。 この関数は、指定したクラスのすべてのウィンドウの既定のウィンドウ設定を変更します。 次の例では、既存のクラス カーソルを カーソルに hCurs2
置き換えます。
// Change the cursor for window class represented by hwnd.
SetClassLongPtr(hwnd, // window handle
GCLP_HCURSOR, // change cursor
(LONG_PTR) hCurs2); // new cursor
詳細については、「 ウィンドウ クラス 」と「 マウス入力」を参照してください。
カーソルの閉じ込め
次の例では、カーソルをアプリケーションのウィンドウに限定し、カーソルを前のウィンドウに復元します。 この例では 、GetClipCursor 関数を使用して、カーソルを移動できる領域を記録し、 ClipCursor 関数を使用してカーソルを閉じ込め、復元します。
RECT rcClip; // new area for ClipCursor
RECT rcOldClip; // previous area for ClipCursor
// Record the area in which the cursor can move.
GetClipCursor(&rcOldClip);
// Get the dimensions of the application's window.
GetWindowRect(hwnd, &rcClip);
// Confine the cursor to the application's window.
ClipCursor(&rcClip);
//
// Process input from the confined cursor.
//
// Restore the cursor to its previous area.
ClipCursor(&rcOldClip);
システムには一度に 1 つのカーソルしか使用できないため、カーソルを閉じ込めるアプリケーションは、コントロールを別のウィンドウに再要求する前にカーソルを復元する必要があります。
カーソル関数を使用してマウストラックを作成する
次の例では、 SetCursorPos、 GetCursorPos、 CreateCursor、 LoadCursor、 および SetCursor 関数を使用して、単純なマウストラックを作成します。 また、カーソルとタイマー関数を使用して、10 秒ごとにカーソルの位置を監視します。 カーソル位置が過去 10 秒間に変更されておらず、アプリケーションのメイン ウィンドウが最小化されている場合、アプリケーションはカーソルを変更してマウストラック アイコンに移動します。
同様のマウストラックの例は、 アイコンに含まれています。 デバイスに依存する CreateCursor 関数と CreateIcon 関数ではなく、LoadCursor 関数と LoadIcon 関数を使用します。
HICON hIcon1; // icon handles
POINT ptOld; // previous cursor location
HCURSOR hCurs1; // cursor handle
// The following cursor masks are defined in a code
// example that appears earlier in this section.
// Yin-shaped cursor AND and XOR masks
BYTE ANDmaskCursor[] = ...
BYTE XORmaskCursor[] = ...
// Yang-shaped icon AND mask
BYTE ANDmaskIcon[] = {0xFF, 0xFF, 0xFF, 0xFF, // line 1
0xFF, 0xFF, 0xC3, 0xFF, // line 2
0xFF, 0xFF, 0x00, 0xFF, // line 3
0xFF, 0xFE, 0x00, 0x7F, // line 4
0xFF, 0xFC, 0x00, 0x1F, // line 5
0xFF, 0xF8, 0x00, 0x0F, // line 6
0xFF, 0xF8, 0x00, 0x0F, // line 7
0xFF, 0xF0, 0x00, 0x07, // line 8
0xFF, 0xF0, 0x00, 0x03, // line 9
0xFF, 0xE0, 0x00, 0x03, // line 10
0xFF, 0xE0, 0x00, 0x01, // line 11
0xFF, 0xE0, 0x00, 0x01, // line 12
0xFF, 0xF0, 0x00, 0x01, // line 13
0xFF, 0xF0, 0x00, 0x00, // line 14
0xFF, 0xF8, 0x00, 0x00, // line 15
0xFF, 0xFC, 0x00, 0x00, // line 16
0xFF, 0xFF, 0x00, 0x00, // line 17
0xFF, 0xFF, 0x80, 0x00, // line 18
0xFF, 0xFF, 0xE0, 0x00, // line 19
0xFF, 0xFF, 0xE0, 0x01, // line 20
0xFF, 0xFF, 0xF0, 0x01, // line 21
0xFF, 0xFF, 0xF0, 0x01, // line 22
0xFF, 0xFF, 0xF0, 0x03, // line 23
0xFF, 0xFF, 0xE0, 0x03, // line 24
0xFF, 0xFF, 0xE0, 0x07, // line 25
0xFF, 0xFF, 0xC0, 0x0F, // line 26
0xFF, 0xFF, 0xC0, 0x0F, // line 27
0xFF, 0xFF, 0x80, 0x1F, // line 28
0xFF, 0xFF, 0x00, 0x7F, // line 29
0xFF, 0xFC, 0x00, 0xFF, // line 30
0xFF, 0xF8, 0x03, 0xFF, // line 31
0xFF, 0xFC, 0x3F, 0xFF}; // line 32
// Yang-shaped icon XOR mask
BYTE XORmaskIcon[] = {0x00, 0x00, 0x00, 0x00, // line 1
0x00, 0x00, 0x00, 0x00, // line 2
0x00, 0x00, 0x00, 0x00, // line 3
0x00, 0x00, 0x00, 0x00, // line 4
0x00, 0x00, 0x00, 0x00, // line 5
0x00, 0x00, 0x00, 0x00, // line 6
0x00, 0x00, 0x00, 0x00, // line 7
0x00, 0x00, 0x38, 0x00, // line 8
0x00, 0x00, 0x7C, 0x00, // line 9
0x00, 0x00, 0x7C, 0x00, // line 10
0x00, 0x00, 0x7C, 0x00, // line 11
0x00, 0x00, 0x38, 0x00, // line 12
0x00, 0x00, 0x00, 0x00, // line 13
0x00, 0x00, 0x00, 0x00, // line 14
0x00, 0x00, 0x00, 0x00, // line 15
0x00, 0x00, 0x00, 0x00, // line 16
0x00, 0x00, 0x00, 0x00, // line 17
0x00, 0x00, 0x00, 0x00, // line 18
0x00, 0x00, 0x00, 0x00, // line 19
0x00, 0x00, 0x00, 0x00, // line 20
0x00, 0x00, 0x00, 0x00, // line 21
0x00, 0x00, 0x00, 0x00, // line 22
0x00, 0x00, 0x00, 0x00, // line 23
0x00, 0x00, 0x00, 0x00, // line 24
0x00, 0x00, 0x00, 0x00, // line 25
0x00, 0x00, 0x00, 0x00, // line 26
0x00, 0x00, 0x00, 0x00, // line 27
0x00, 0x00, 0x00, 0x00, // line 28
0x00, 0x00, 0x00, 0x00, // line 29
0x00, 0x00, 0x00, 0x00, // line 30
0x00, 0x00, 0x00, 0x00, // line 31
0x00, 0x00, 0x00, 0x00}; // line 32
hIcon1 = CreateIcon(hinst, // handle to app. instance
32, // icon width
32, // icon height
1, // number of XOR planes
1, // number of bits per pixel
ANDmaskIcon, // AND mask
XORmaskIcon); // XOR mask
hCurs1 = CreateCursor(hinst, // handle to app. instance
19, // horizontal position of hot spot
2, // vertical position of hot spot
32, // cursor width
32, // cursor height
ANDmaskCursor, // AND mask
XORmaskCursor); // XOR mask
// Fill in the window class structure.
WNDCLASS wc;
wc.hIcon = hIcon1; // class icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // class cursor
//
// Register the window class and perform
// other application initialization.
//
// Set a timer for the mousetrap.
GetCursorPos(&ptOld);
SetTimer(hwnd, IDT_CURSOR, 10000, (TIMERPROC) NULL);
LONG APIENTRY MainWndProc(
HWND hwnd, // window handle
UINT message, // type of message
UINT wParam, // additional information
LONG lParam) // additional information
{
HDC hdc; // handle to device context
POINT pt; // current cursor location
RECT rc; // minimized window location
switch (message)
{
//
// Process other messages.
//
case WM_TIMER:
// If the window is minimized, compare the
// current cursor position with the one 10
// seconds before. If the cursor position has
// not changed, move the cursor to the icon.
if (IsIconic(hwnd))
{
GetCursorPos(&pt);
if ((pt.x == ptOld.x) && (pt.y == ptOld.y))
{
GetWindowRect(hwnd, &rc);
SetCursorPos(rc.left + 20, rc.top + 4);
// Note that the additional constants
// (20 and 4) are application-specific
// values to align the yin-shaped cursor
// and the yang-shaped icon.
}
else
{
ptOld.x = pt.x;
ptOld.y = pt.y;
}
}
return 0;
case WM_SETCURSOR:
// If the window is minimized, draw hCurs1.
// If the window is not minimized, draw the
// default cursor (class cursor).
if (IsIconic(hwnd))
{
SetCursor(hCurs1);
break;
}
case WM_DESTROY:
// Destroy timer.
KillTimer(hwnd, IDT_CURSOR);
PostQuitMessage(0);
break;
}
}
キーボードを使用してカーソルを移動する
システムはマウスを必要としないため、アプリケーションはキーボードを使用してマウス操作をシミュレートできる必要があります。 次の例は、GetCursorPos 関数と SetCursorPos 関数を使用し、方向キーからの入力を処理することによってこれを実現する方法を示しています。
HCURSOR hCurs1, hCurs2; // cursor handles
POINT pt; // cursor location
RECT rc; // client area coordinates
static int repeat = 1; // repeat key counter
//
// Other declarations and initialization.
//
switch (message)
{
//
// Process other messages.
//
case WM_KEYDOWN:
if (wParam != VK_LEFT && wParam != VK_RIGHT &&
wParam != VK_UP && wParam != VK_DOWN)
{
break;
}
GetCursorPos(&pt);
// Convert screen coordinates to client coordinates.
ScreenToClient(hwnd, &pt);
switch (wParam)
{
// Move the cursor to reflect which
// arrow keys are pressed.
case VK_LEFT: // left arrow
pt.x -= repeat;
break;
case VK_RIGHT: // right arrow
pt.x += repeat;
break;
case VK_UP: // up arrow
pt.y -= repeat;
break;
case VK_DOWN: // down arrow
pt.y += repeat;
break;
default:
return 0;
}
repeat++; // Increment repeat count.
// Keep the cursor in the client area.
GetClientRect(hwnd, &rc);
if (pt.x >= rc.right)
{
pt.x = rc.right - 1;
}
else
{
if (pt.x < rc.left)
{
pt.x = rc.left;
}
}
if (pt.y >= rc.bottom)
pt.y = rc.bottom - 1;
else
if (pt.y < rc.top)
pt.y = rc.top;
// Convert client coordinates to screen coordinates.
ClientToScreen(hwnd, &pt);
SetCursorPos(pt.x, pt.y);
return 0;
case WM_KEYUP:
repeat = 1; // Clear repeat count.
return 0;
}