マウス操作

ウィンドウアプリはマウスで簡単に操作できるのが特徴のひとつです。
ここではマウス操作について説明します。

マウスボタン

マウスやキーボードのボタンは「押す」ものですが、プログラム的には「押して」「離す」という二つのメッセージが発生します。
マウスドラッグは「押してから離すまでの間」で判定します。

マウス左ボタンを押すとWM_LBUTTONDOWNメッセージが、離すとWM_LBUTTONUPメッセージが通知されます。
マウスボタンのメッセージは以下があります。

メッセージ 説明
WM_LBUTTONDOWN マウス左ボタンを押す
WM_LBUTTONUP マウス左ボタンを離す
WM_RBUTTONDOWN マウス右ボタンを押す
WM_RBUTTONUP マウス右ボタンを離す
WM_MBUTTONDOWN マウス中ボタンを押す
WM_MBUTTONUP マウス中ボタンを離す

簡単なサンプルコードです。


#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int l, r, c;
	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"クリック回数\n"
		L"L: %d\n"
		L"R: %d\n"
		L"C: %d\n";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, l, r, c);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK);

		EndPaint(hWnd, &ps);
		break;

	case WM_LBUTTONUP: //マウス左クリック
		l++;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_RBUTTONUP: //マウス右クリック
		r++;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_MBUTTONUP: //マウス中クリック
		c++;
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

マウスクリックのテスト

このサンプルコードではボタンを離した時をクリックとして処理しています。

多ボタンマウス

標準的なマウスは3ボタンが多いですが、それ以上のボタンを備えたマウスもあります。
Windows APIでは5ボタンまでの入力に対応しています。

第四、第五ボタンの操作はWM_XBUTTONDOWNWM_XBUTTONUPというメッセージで送られてきます。
どちらのボタンを押しても同じメッセージが通知されますが、ウィンドウプロシージャの第三引数WPARAMにボタン種類の情報が格納されています。
WPARAMにGET_XBUTTON_WPARAMマクロを使用することで、操作したボタンを示す定数を取り出すことができます。

定数 説明
XBUTTON1 第四ボタンの操作
XBUTTON2 第五ボタンの操作

#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int x1, x2;
	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"クリック回数\n"
		L"X1: %d\n"
		L"X2: %d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, x1, x2);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK);

		EndPaint(hWnd, &ps);
		break;

	case WM_XBUTTONUP: //マウス第四、第五ボタン
		if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
		{
			x1++;
		}
		else
		{
			x2++;
		}
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

マウス第四、第五ボタンクリックのテスト

ダブルクリック

マウスボタンのダブルクリックは「WM_○BUTTONDBLCLK」というメッセージが通知されます。

メッセージ 説明
WM_LBUTTONDBLCLK マウス左ボタンのダブルクリック
WM_RBUTTONDBLCLK マウス右ボタンのダブルクリック
WM_MBUTTONDBLCLK マウス中ボタンのダブルクリック
WM_XBUTTONDBLCLK マウス追加ボタンのダブルクリック

ただしこれらはそのままでは通知されません。
ダブルクリックメッセージを使用するにはウィンドウクラスの登録時に、styleメンバにCS_DBLCLKSフラグを追加する必要があります。


#include <windows.h>
#include <strsafe.h>

//省略

int APIENTRY wWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPWSTR lpCmdLine,
	int nCmdShow)
{
	//省略
}

//ウィンドウクラスの登録
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	//wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = NULL;

	return RegisterClassEx(&wcex);
}

//ウィンドウの作成
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	//省略
}

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int s, d;
	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"クリック回数\n"
		L"Single:\t%d\n"
		L"Double:\t%d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, s, d);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;
	case WM_LBUTTONUP: //マウス左クリック
		s++;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_LBUTTONDBLCLK: //マウス左ダブルクリック
		d++;
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

マウスダブルクリックのテスト

マウスホイール

マウスホイールの回転操作はWM_MOUSEWHEELメッセージが通知されます。
ホイールの水平操作(横スクロール)はWM_MOUSEHWHEELメッセージが通知されます。
(水平操作が可能なマウスのみ)

回転量はウィンドウプロシージャの第三引数WPARAMに格納されています。
実際の値を取り出すにはGET_WHEEL_DELTA_WPARAMマクロを使用します。


#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int wheelV, wheelH;

	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"マウスホイール\n"
		L"左クリックで値を初期化\n"
		L"WheelV:\t%d\n"
		L"WheelH:\t%d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, wheelV, wheelH);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;

	case WM_LBUTTONUP: //マウス左クリック
		//値を初期化
		wheelV = wheelH = 0;
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_MOUSEWHEEL: //ホイール垂直回転
		wheelV += GET_WHEEL_DELTA_WPARAM(wParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	case WM_MOUSEHWHEEL: //ホイール水平操作
		wheelH += GET_WHEEL_DELTA_WPARAM(wParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

このコードでは左クリックで値を初期化するようにしています。
マウスホイール操作のテスト

ホイール回転量はWindowsのコントロールパネルから変更可能ですが、ここで取得できる値はコントロールパネルの設定の影響を受けません。

マウス座標

現在のマウス座標(位置)は、マウス関連のメッセージが送られてきた時に、ウィンドウプロシージャの第四引数LPARAMに同時に送られてきます。
LPARAM型は整数値ですが、そのままでは座標としては扱えません。
X座標はGET_X_LPARAMマクロで、Y座標はGET_Y_LPARAMマクロでint型として取り出すことができます。
これらのマクロはwindowsx.hのインクルードが必要です。
(windows.hとは別物)


#include <windows.h>
#include <windowsx.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int x, y;
	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"マウス座標\n"
		L"X: %d\n"
		L"Y: %d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, x, y);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;

	case WM_LBUTTONUP: //マウス左クリック
		//lParamからマウス座標を取り出す
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

このコードはクライアント領域のクリックした時の位置を表示します。
マウス座標の取得

もしくはMAKEPOINTSマクロを使用することでもLPARAMを座標に変換できます。
これらはLPARAMをPOINTS構造体に変換します。

typedef struct tagPOINTS {
 SHORT x;
 SHORT y;
} POINTS, *PPOINTS;
座標情報を格納する構造体。
(SHORT版)

これはPOINT構造体のメンバがLONG型からSHORT型になっただけです。


POINTS points;

//省略
	switch (message)
	{
	case WM_LBUTTONUP: //マウス左クリック
		//lParamからマウス座標を取り出す
		points = MAKEPOINTS(lParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;
	}

マウス座標の取り出しにはLOWORDマクロ(X座標)とHIWORDマクロ(Y座標)を使用することも可能ですが、これは推奨されません。
これらのマクロは座標を符号なし整数(WORD型)として取り出しますが、座標がマイナスとなる場合(マルチディスプレイ環境など)で正しい値となりません。

値がマイナス値にならないことが確実な場合(クライアント領域のサイズの取得など)であればLOWORD/HIWORDマクロを使用しても問題ありません。

マウス座標を関数で取得/設定する

マウス座標はマウス関連のメッセージが送られてきたときに取得できますが、マウスメッセージに関係なくマウス座標を取得したい場合もあります。
そのような場合にはGetCursorPos関数で取得できます。
また、SetCursorPos関数でマウス座標を変更することもできます。

BOOL GetCursorPos(
 LPPOINT lpPoint
);
現在のマウスカーソル座標をlpPointに格納する。
成功した場合は0以外を返す。
失敗した場合は0を返す。
BOOL SetCursorPos(
 int X,
 int Y
);
現在のマウスカーソル座標を(X, Y)に設定する。
成功した場合は0以外を返す。
失敗した場合は0を返す。

LPPOINT型POINT構造体変数のポインタ型です。

この関数で取得/設定される座標はスクリーン座標です。
つまり、ウィンドウではなく画面の左上を(0, 0)とした座標です。


#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static POINT cursorPos;

	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"マウスのスクリーン座標\n"
		L"キーボード操作で情報を更新\n"
		L"左クリックでカーソルを右下にずらす\n"
		L"X:\t%d\n"
		L"Y:\t%d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, cursorPos.x, cursorPos.y);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;

	case WM_KEYDOWN: //キー押下
		GetCursorPos(&cursorPos);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_LBUTTONUP: //マウス左クリック
		GetCursorPos(&cursorPos);
		SetCursorPos(cursorPos.x += 10, cursorPos.y += 10);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

このコードはキーボードのキーを押下すると(どのキーでもOK)、現在のマウスカーソル位置の情報を更新します。
クライアント領域を左クリックするとマウスカーソル位置を少し右下にずらします。
マウス座標の取得

スクリーン座標とクライアント座標の変換

スクリーン座標をクライアント領域の座標に変換したい場合はScreenToClient関数を使用します。

BOOL ScreenToClient(
 HWND hWnd,
 LPPOINT lpPoint
);
スクリーン座標lpPointをウィンドウhWndのクライアント座標に変換する。
成功した場合は0以外を返す。
失敗した場合は0を返す。

反対に、クライアント座標をスクリーン座標に変換したい場合はClientToScreen関数を使用します。

BOOL ClientToScreen(
 HWND hWnd,
 LPPOINT lpPoint
);
ウィンドウhWndのクライアント座標lpPointをスクリーン座標に変換する。
成功した場合は0以外を返す。
失敗した場合は0を返す。

どちらの関数も第二引数のPOINT構造体に新しい座標が格納されます。
ポインタ渡しなので注意してください。

マウスの移動

マウスを動かすとWM_MOUSEMOVEメッセージが通知されます。
座標は他のマウスメッセージと同じく、LPARAMを調べることで取得できます。


#include <windows.h>
#include <windowsx.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int x, y;

	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"マウスのスクリーン座標\n"
		L"X:\t%d\n"
		L"Y:\t%d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, x, y);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;

	case WM_MOUSEMOVE: //マウス移動
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

このコードは、クライアント領域上でマウスカーソルを移動させるとその座標を表示します。
座標はスクリーン座標です。
マウス移動のテスト

ちなみにWM_MOUSEMOVEメッセージはマウスを動かしていないときでも送られてくることがあります。
例えばマウスカーソルがクライアント領域上にある状態でウィンドウのアクティブ状態が変化したときなどです。

マウスキャプチャ

カーソルがウィンドウ外(正確にはクライアント領域外)に移動するとマウスメッセージは通知されなくなります。
通常はウィンドウ外での操作は取得する必要はありませんが、マウスドラッグ中などはこれでは不都合な場合もあります。

ウィンドウ外でのマウス操作を取得する場合は、SetCapture関数を使用します。
SetCapture関数の使用後はReleaseCapture関数で元に戻します。

HWND SetCapture(
 HWND hWnd
);
ウィンドウhWndにマウスをキャプチャする。
戻り値は以前にマウスをキャプチャしていたウィンドウハンドル。
なければNULLを返す。
BOOL ReleaseCapture();
ウィンドウへのマウスキャプチャを解除する。
成功した場合は0以外を、失敗した場合は0を返す。

キャプチャとは「捕らえる」という意味で、ウィンドウ外でのマウスメッセージを「捕らえる」ことができます。
キャプチャ中はWM_LBUTTONDOWNメッセージなどのボタンダウン以外のマウスメッセージがウィンドウプロシージャに送られるようになります。
ただしキャプチャは「カーソルがウィンドウ上にあるとき」または「マウスボタンを押したままカーソルがウィンドウ外に出たとき」にのみ有効です。


#include <windows.h>
#include <windowsx.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rt;

	static int x, y;
	static POINT points[2];
	static char isDown;

	WCHAR buf[BUFFERSIZE];
	static const WCHAR* format = L"マウスのスクリーン座標\n"
		L"X:\t%d\n"
		L"Y:\t%d";

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		StringCchPrintf(buf, BUFFERSIZE, format, x, y);

		GetClientRect(hWnd, &rt);
		hdc = BeginPaint(hWnd, &ps);

		Rectangle(hdc, points[0].x, points[0].y, points[1].x, points[1].y);
		DrawText(hdc, buf, -1, &rt, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;

	case WM_LBUTTONDOWN:
		isDown = 1;
		points[0].x = points[1].x = GET_X_LPARAM(lParam);
		points[0].y = points[1].y = GET_Y_LPARAM(lParam);
		SetCapture(hWnd);
		break;

	case WM_LBUTTONUP:
		isDown = 0;
		ReleaseCapture();
		break;

	case WM_MOUSEMOVE: //マウス移動
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		if (isDown) {
			points[1].x = x;
			points[1].y = y;
		}
		InvalidateRect(hWnd, NULL, TRUE);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

このコードはクライアント領域でマウスをドラッグすると四角形を描画することができます。
ドラッグしたままカーソルがウィンドウ外へ出ても画面は更新され続けます。
クライアント領域外でのマウス移動検知のテスト

もしマウスキャプチャをしないと、ドラッグ中にカーソルがウィンドウ外へと出たときにWM_MOUSEMOVEメッセージが送られなくなり、画面が更新されなくなります。
またウィンドウ外でマウスボタンを離した場合にWM_LBUTTONUPなどのボタンアップメッセージも送られなくなるので、おかしな挙動となってしまいます。

なお、キャプチャ系の関数で操作できるのは現在のスレッドで作成されたウィンドウのみです。
マルチスレッドでの別スレッドや、別のプログラムで作成されたウィンドウはキャプチャ対象にできません。

GetCapture関数

GetCapture関数はマウスキャプチャしているウィンドウのハンドルを取得します。

HWND GetCapture();
マウスをキャプチャしているウィンドウのハンドルを返す。
なければNULL。

ボタンのダウン状況を調べる

マウスメッセージの通知時、マウスボタンの状態や修飾キー(Ctrlキー、Shiftキー)の状態を調べることができます。
これにより例えば複数ボタンの同時押しや修飾キーによって処理を分岐させることができます。

他のキーの状態はウィンドウプロシージャのWPARAMに送られてきます。
これを定数でビットAND演算することでキーの状態を調べることができます。
(ビット演算に関しては→ビット演算の活用法)

定数 説明
MK_SHIFT Shiftキーが押されている
MK_CONTROL Ctrlキーが押されている
MK_LBUTTON マウス左ボタンが押されている
MK_RBUTTON マウス右ボタンが押されている
MK_MBUTTON マウス中ボタンが押されている
MK_XBUTTON1 マウス第四ボタンが押されている
MK_XBUTTON2 マウス第五ボタンが押されている

例えば先ほどのマウスキャプチャのサンプルコードでは、マウスの状態を保存するためにstatic変数を用意していましたが、これを以下のように書き直すことができます。


static char isDown;

case WM_MOUSEMOVE: //マウス移動
	x = GET_X_LPARAM(lParam);
	y = GET_Y_LPARAM(lParam);
	if (isDown) {
		points[1].x = x;
		points[1].y = y;
	}
	InvalidateRect(hWnd, NULL, TRUE);

//↓

case WM_MOUSEMOVE: //マウス移動
	x = GET_X_LPARAM(lParam);
	y = GET_Y_LPARAM(lParam);
	if (wParam & MK_LBUTTON) { //マウス左ボタン
		points[1].x = x;
		points[1].y = y;
	}
	InvalidateRect(hWnd, NULL, TRUE);
	break;

ただし、非クライアント領域で発生するメッセージ(WM_NCLBUTTONDOWNメッセージなど)では、WPARAMにはこれとは異なる情報が格納されています。
非クライアント領域のメッセージは使用頻度が低いと思うので説明は省略します。