レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API マウス入力の概要

マウスはMicrosoft(R) Windows(TM) 用アプリケーションにとって重要なユーザー入力デバイスですが、 必須ではありません。Windows用アプリケーションはマウス インターフェイスをサポートしなければなりませんが、 ユーザー入力をマウスだけに頼らないようにしてください。アプリケーションは、 キーボードも完全にサポートしてください。

Windows用アプリケーションは、 ウィンドウに送信またはポストされるメッセージとしてマウス入力を受け取ります。ここでは、 Windowsがマウス入力を生成する方法と、 アプリケーションがマウス入力を受け取って処理する方法について説明します。[>>]ボタンを使って以下に示すトピックを順番に読んでください。または、 各トピックをクリックすると、 そのトピックの内容を表示できます。

マウス カーソル

マウスのキャプチャ

マウスの構成

マウス メッセージ

WM_NCHITTESTメッセージ

ウィンドウのアクティブ化

マウス カーソルの追跡

マウスによる直線の描画の例

ダブルクリック メッセージの処理

テキスト行の選択の例

マウス入力の関数とメッセージ

マウス カーソル

ユーザーがマウスを動かすと、 システムは、 「マウス カーソル」(ポインタともいう) と呼ばれるビットマップを画面上で移動します。マウス カーソルには、 「ホットスポット」と呼ばれる1ピクセルの点があります。ホットスポットは、 システムがカーソルの位置として追跡し、 認識する点です。通常、 マウス イベントが発生すると、 ホットスポットが位置するウィンドウは、 そのイベントによるマウス メッセージを受け取ります。マウス メッセージを受け取るウィンドウは、 アクティブなウィンドウやキーボード フォーカスを持つウィンドウだけとは限りません。

システムは、 マウスの速度を制御する変数を管理しています。マウスの速度とは、 ユーザーがマウスを動かしたときにカーソルが移動する距離です。マウスの速度を取得または設定するには、 SPI_GETMOUSEフラグかSPI_SETMOUSEフラグを指定してSystemParametersInfo関数を呼び出します。マウス カーソルについて詳しくは、 カーソルの概要を参照してください。

マウスのキャプチャ (捕捉)

通常、 システムは、 マウス イベントが発生したときにカーソルのホットスポットが存在するウィンドウにマウス メッセージをポストします。この動作を変更するには、 SetCapture関数を使って、 マウス メッセージが特定のウィンドウにディスパッチされるようにしてください。アプリケーションがReleaseCapture関数を呼び出すか、 ほかのキャプチャ ウィンドウを指定するか、 ほかのスレッドが作成したウィンドウをユーザーがクリックするまで、 この関数で指定したウィンドウはマウス メッセージをすべて受け取ります。

マウス入力をキャプチャできるのは、 前景ウィンドウだけです。マウス入力をキャプチャしようとした背景ウィンドウは、 カーソルのホットスポットが自分の可視領域にあるときに発生したマウス イベントのメッセージしか受け取りません。

マウス入力のキャプチャは、 カーソルがウィンドウの外に出てもマウス入力をすべて受け取りたいときに役立ちます。たとえば、 通常、 アプリケーションは、 マウス「ボタン ダウン」イベントが発生するとカーソル位置を追跡し、 「ボタン アップ」イベントが発生するまでカーソルを追い続けます。アプリケーションがマウス入力をキャプチャしていなければ、 ユーザーがウィンドウの外でマウス ボタンを離すとウィンドウはボタン アップ メッセージを受け取りません。

スレッドは、 GetCapture関数を使って、 自分のウィンドウのいずれかがマウスをキャプチャしているか調べることができます。スレッドのウィンドウのいずれかがマウスをキャプチャしていれば、 GetCaptureはそのウィンドウのハンドルを返します。

マウスの構成

Windows用アプリケーションではマウスは重要な入力デバイスですが、 マウスを持っていないユーザーもいます。システムにマウスがあるか調べるには、 SM_MOUSEPRESENTGetSystemMetrics関数に渡してください。

Windowsは、 3つ以下のボタンを持つマウスをサポートしています。3ボタン マウスの場合、 3つのボタンは、 それぞれ左ボタン、 中央ボタン、 右ボタンと呼ばれます。マウス ボタンに関するWindowsのメッセージや名前付き定数では、 L、 M、 Rを使ってボタンを識別しています。単一ボタン マウスのボタンは、 左ボタンとして扱われます。Windowsは複数ボタンのマウスをサポートしていますが、 ほとんどのアプリケーションは主に左ボタンを使用し、 そのほかのボタンがあってもほとんど使いません。

マウスのボタンの個数を調べるには、 SM_CMOUSEBUTTONSGetSystemMetrics関数に渡します。マウスを左利きユーザー用に設定するには、 SwapMouseButton関数を使って、 マウスの左ボタンとマウスの右ボタンの機能を交換します。また、 SystemParametersInfo関数にSPI_SETMOUSEBUTTONSWAPを渡してボタンの機能を交換することもできます。しかし、 マウスは共有リソースであるため、 ボタンの機能の交換はすべてのアプリケーションに影響します。

マウス メッセージ

ユーザーがマウスを動かしたり、 マウス ボタンを押したり離したりすると、 マウス入力イベントが生成されます。Windowsは、 マウス入力イベントをメッセージに変換し、 適切なスレッドのメッセージ キューにポストします。スレッドがメッセージを処理するよりも速く複数のマウス メッセージがポストされたときは、 Windowsは、 いちばん新しいマウス メッセージ以外をすべて廃棄します。

カーソルがウィンドウの境界内にあるときやウィンドウがマウスをキャプチャしているときにマウス イベントが発生すると、 ウィンドウはマウス メッセージを受け取ります。マウス メッセージには、 クライアント領域メッセージと非クライアント領域メッセージの2種類があります。通、 アプリケーションはクライアント領域メッセージを処理して、 非クライアント領域メッセージは無視します。

クライアント領域マウス メッセージ

ウィンドウのクライアント領域でマウス イベントが発生すると、 ウィンドウはクライアント領域マウス メッセージを受け取ります。ユーザーがクライアント領域内でカーソルを動かすと、 システムはウィンドウにWM_MOUSEMOVEメッセージをポストします。カーソルがクライアント領域にあるときにユーザーがマウス ボタンを押したり離したりすると、 システムは、 次に示すメッセージのいずれかをポストします。

メッセージ意味

WM_LBUTTONDBLCLKマウスの左ボタンがダブルクリックされました。

WM_LBUTTONDOWNマウスの左ボタンが押されました。

WM_LBUTTONUPマウスの左ボタンが離されました。

WM_MBUTTONDBLCLKマウスの中央ボタンがダブルクリックされました。

WM_MBUTTONDOWNマウスの中央ボタンが押されました。

WM_MBUTTONUPマウスの中央ボタンが離されました。

WM_RBUTTONDBLCLKマウスの右ボタンがダブルクリックされました。

WM_RBUTTONDOWNマウスの右ボタンが押されました。

WM_RBUTTONUPマウスの右ボタンが離されました。

メッセージのパラメータ

クライアント領域マウス メッセージのlParamパラメータは、 カーソルのホットスポットの位置を示します。下位ワードはホットスポットのx座標を示し、 上位ワードはy座標を示しています。座標は、 「クライアント座標系」で表現されます。クライアント座標系では、 画面上のすべての点は、 クライアント領域の左上隅 (0, 0) からの相対座標として表現されます。

wParamパラメータは、 マウス ボタンが発生した時点のほかのマウス ボタンやCtrlキー、 Shiftキーの状態を示すフラグです。ほかのマウス ボタンやCtrlキー、 Shiftキーの状態によってマウス メッセージの処理を変化させるには、 このフラグを調べてください。lParamパラメータは、 次に示す値の組み合わせです。

意味

MK_CONTROLCtrlキーが押されています。

MK_LBUTTONマウスの左ボタンが押されています。

MK_MBUTTONマウスの中央ボタンが押されています。

MK_RBUTTONマウスの右ボタンが押されています。

MK_SHIFTShiftキーが押されています。

ダブルクリック メッセージ

ユーザーがマウス ボタンをすばやく2回クリックすると、 システムはダブルクリック メッセージを生成します。ユーザーがボタンをクリックすると、 システムは、 カーソルのホットスポットを中心とする長方形を算出します。また、 クリックが発生した時刻を記録します。ユーザーが同じボタンをもう一度クリックすると、 システムは、 ホットスポットがまだこの長方形内にあるか調べて、 最初のクリックから経過した時間を計算します。ホットスポットが長方形内にあり、 経過時間がダブルクリック タイム アウト値を超えていなければ、 システムはダブルクリック メッセージを生成します。

ダブルクリック タイム アウト値を取得または設定するには、 GetDoubleClickTime関数とSetDoubleClickTime関数を使います。また、 SystemParametersInfo関数にSPI_SETDOUBLECLICKTIMEフラグを指定してダブルクリック タイム アウト値を設定したり、 SystemParametersInfoSPI_SETDOUBLECLKWIDTHフラグやSPI_SETDOUBLECLKHEIGHTフラグを指定して、 Windowsがダブルクリックを検出するのに使う長方形のサイズを設定できます。しかし、 ダブルクリック タイムアウト値や長方形の設定はすべてのアプリケーションに影響することに注意してください。

アプリケーション定義のウィンドウは、 デフォルトではダブルクリック メッセージを受け取りません。ダブルクリック メッセージにはシステムのオーバーヘッドが伴うため、 ダブルクリック メッセージは、 CS_DBLCLKSクラス スタイルを持つクラスに属するウィンドウにしか生成されません。このスタイルは、 ウィンドウ クラスを登録するときに指定してください。ウィンドウ クラスについて詳しくは、 ウィンドウ クラスの概要を参照してください。

ダブルクリック メッセージは、 4つ送られるメッセージの3番目に送られます。最初の2つのメッセージは、 最初のクリックで生成されたボタン ダウン メッセージとボタン アップ メッセージです。2回目のクリックでは、 ダブルクリック メッセージと、 ボタン アップ メッセージが生成されます。たとえば、 マウスの左ボタンをダブルクリックすると、 次に示すメッセージが生成されます。

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP

ウィンドウは常にダブルクリック メッセージよりもボタン ダウン メッセージを先に受け取るため、 ボタン ダウン メッセージで開始した作業をダブルクリック メッセージで拡張できます。たとえば、 Windowsペイントブラシ(TM) のカラー パレットの色をユーザーがクリックすると、 ペイントブラシは、 選択された色をパレットの横に表示します。ユーザーが色をダブルクリックすると、 ペイントブラシは、 その色をパレットの横に表示して、 [色の作成]ダイアログ ボックスを表示します。

非クライアント領域マウス メッセージ

ウィンドウのクライアント領域以外の部分でマウス イベントが発生すると、 ウィンドウは非クライアント領域マウス メッセージを受け取ります。ウィンドウの「非クライアント領域」は、 境界線、 メニュー バー、 タイトル バー、 スクロール バー、 コントロール メニュー(システム メニュー)、 アイコン化ボタン、 最大表示ボタンで構成されます。

Windowsは、 主に自分自身で使うために非クライアント領域メッセージを生成します。たとえば、 カーソルのホットスポットがウィンドウの境界線上に移動すると、 Windowsは、 非クライアント領域メッセージを使ってカーソルを双方向矢印に変更します。ウィンドウは、 非クライアント領域マウス メッセージをDefWindowProc関数に渡して、 Windowsの組み込みマウス インターフェイスを有効にしなければなりません。

各クライアント領域マウス メッセージには、 対応する非クライアント領域マウス メッセージがあります。これらのメッセージの名前はよく似ていますが、 非クライアント領域メッセージにはNCが付いています。たとえば、 非クライアント領域でカーソルを動かすとWM_NCMOUSEMOVEメッセージが生成され、 カーソルが非クライアント領域にあるときにマウスの左ボタンを押すとWM_NCLBUTTONDOWNメッセージが生成されます。

非クライアント領域マウス メッセージのlParamパラメータは、 カーソルのホットスポットのx座標とy座標を示すPOINTS構造体です。クライアント領域マウス メッセージの座標とは異なり、 この座標はクライアント座標系ではなく「画面座標系」で表現されます。画面座標系では、 画面上のすべての点は画面の左上隅 (0, 0) からの相対座標として表現されます。

wParamパラメータは、 「ヒット テスト コード」を示します。ヒット テスト コードとは、 マウス イベントが発生した非クライアント領域の部分を示す値です。WM_NCHITTESTメッセージで、 ヒット テスト値の目的を説明しています。

WM_NCHITTESTメッセージ

マウス イベントが発生すると、 システムは、 カーソルのホットスポットがあるウィンドウか、 マウスをキャプチャしているウィンドウにWM_NCHITTESTメッセージを送りす。Windowsは、 このメッセージを使って、 クライアント領域マウス メッセージと非クライアント領域マウス メッセージのどちらを送るかを判断します。マウス移動メッセージとマウス ボタン メッセージを受け取らなければならないアプリケーションは、 WM_NCHITTESTメッセージをDefWindowProc関数に渡さなければなりません。

WM_NCHITTESTメッセージのlParamパラメータは、 カーソルのホットスポットの画面座標を示します。DefWindowProc関数は、 この座標を調べて、 ホットスポットの位置を識別するヒット テスト コードを返します。ヒット テスト コードは、 次に示す値のいずれかです。

ホットスポットの位置

HTBORDERサイズ変更境界線を持たないウィンドウの境界線

HTBOTTOMウィンドウの下部の水平境界線

HTBOTTOMLEFTウィンドウ境界線の左下隅

HTBOTTOMRIGHTウィンドウ境界線の右下隅

HTCAPTIONタイトル バー

HTCLIENTクライアント領域

HTERROR画面の背景またはウィンドウ間の分割線 (HTNOWHEREと同じですが、 DefWindowProc関数は、 エラーを示すシステム ビープを生成します)。

HTGROWBOXサイズ ボックス (HTSIZEと同じです)

HTHSCROLL水平スクロール バー

HTLEFTウィンドウの左側の境界線

HTMENUメニュー

HTNOWHERE画面の背景またはウィンドウ間の分割線

HTREDUCEアイコン化ボタン

HTRIGHTウィンドウの右側の境界線

HTSIZEサイズ ボックス (HTGROWBOXと同じです)

HTSYSMENUコントロール メニューまたは子ウィンドウの[閉じる]ボタン

HTTOPウィンドウの上部の水平境界線

HTTOPLEFTウィンドウ境界線の左上隅

HTTOPRIGHTウィンドウ境界線の右上隅

HTTRANSPARENT現在ほかのウィンドウに覆われているウィンドウ

HTVSCROLL垂直スクロール バー

HTZOOM最大表示ボタン

カーソルがウィンドウのクライアント領域にあれば、 DefWindowProcは、 HTCLIENTヒット テスト コードをウィンドウ プロシージャに返します。ウィンドウが プロシージャがこのコードをシステムに返すと、 Windowsは、 カーソルのホットスポットの画面座標をクライアント座標に変換し、 適切なクライアント領域マウス メッセージをポストします。

カーソルのホットスポットがウィンドウの非クライアント領域にあれば、 DefWindowProc関数はHTCLIENT以外のヒット テスト コードのいずれかを返します。このようなヒット テスト コードをウィンドウ プロシージャが返すと、 Windowsは、 wParamパラメータにヒット テスト コード、 lParamパラメータにカーソルの座標を設定した非クライアント領域マウス メッセージをポストします。

ウィンドウのアクティブ化

アクティブでないトップ レベル ウィンドウやその子ウィンドウをユーザーがクリックすると、 Windowsは、 (ほかのメッセージとともに) WM_MOUSEACTIVATEメッセージをトップ レベル ウィンドウかその子ウィンドウに送ります。Windowsは、 ウィンドウにWM_NCHITTESTメッセージをポストしてからボタン ダウン メッセージをポストするまでの間にこのメッセージを送ります。WM_MOUSEACTIVATEをDefWindowProc関数に渡すと、 Windowsは、 トップ レベル ウィンドウをアクティブ化し、 ボタン ダウン メッセージをトップ レベル ウィンドウかその子ウィンドウにポストします。

ウィンドウは、 WM_MOUSEACTIVATEを処理することによって、 トップ レベル ウィンドウがマウス クリックによってアクティブになるかどうかどうかや、 クリックされたウィンドウがそれ以降のボタン ダウン メッセージを受け取るかどうかを制御できます。これを行うには、 WM_MOUSEACTIVATEを処理した後、 次に示す値のいずれかを返します。

意味

MA_ACTIVATEウィンドウをアクティブ化し、 マウス メッセージを廃棄しません。

MA_NOACTIVATEウィンドウをアクティブ化せず、 マウス メッセージを廃棄しません。

MA_ACTIVATEANDEATウィンドウをアクティブ化し、 マウス メッセージを廃棄します。

MA_NOACTIVATEANDEATウィンドウをアクティブ化しませんが、 マウス メッセージを廃棄します。

マウス入力の使用

次に示すトピックでは、 そのトピックの実行方法を説明しています。

マウス カーソルの追跡

ダブルクリック メッセージの処理

マウス カーソルの追跡

Windows用アプリケーションでは、 マウス カーソルの位置の追跡が必要になる場合があります。たとえば、 ほとんどの描画アプリケーションは、 描画操作中にマウス カーソルを追跡して、 ユーザーがマウスをドラッグしてウィンドウのクライアント領域に描画できるようにします。また、 ワード プロセッサ アプリケーションでは、 カーソルを追跡して、 ユーザーがマウスをクリック、 ドラッグして単語やテキスト ブロックを選択できるようにします。

通常、 カーソルを追跡するには、 WM_LBUTTONDOWNメッセージ、 WM_MOUSEMOVEメッセージ、 WM_LBUTTONUPメッセージを処理します。ウィンドウは、 WM_LBUTTONDOWNメッセージのlParamパラメータが示すカーソル位置を調べて、 カーソルの追跡を開始するか決定します。たとえば、 ワード プロセッサ アプリケーションは、 カーソルがテキスト行にあるときにWM_LBUTTONDOWNメッセージが発生したときだけカーソルの追跡を開始し、 カーソルがドキュメントの終端以降にあるときはカーソルを追跡しません。

カーソルの位置を追跡するには、 マウスの移動によってウィンドウにポストされる一連のWM_MOUSEMOVEメッセージを処理します。通常、 WM_MOUSEMOVEメッセージの処理には、 クライアント領域での描画操作の繰り返しが伴います。たとえば、 描画アプリケーションは、 マウスが移動するに従って直線を何度も再描画します。カーソルの追跡を中止するシグナルには、 WM_LBUTTONUPメッセージを使います。

マウスによる直線の描画の例

ここでは、 マウス カーソルを追跡する方法の例を示します。この例は、 ユーザーがマウスをドラッグしてウィンドウのクライアント領域に直線を描画できるようにするウィンドウ プロシージャの一部で構成されています。

ウィンドウ プロシージャは、 WM_LBUTTONDOWNメッセージを受け取ると、 マウスをキャプチャして、 カーソルの座標を保存します。このカーソル座標は、 直線の始点として使います。また、 ClipCursor関数を使って、 直線描画操作中はカーソルの移動をクライアント領域内に制限します。

最初のWM_MOUSEMOVEメッセージでは、 ウィンドウ プロシージャは、 始点から現在のカーソル位置まで直線を描画します。それ以降のWM_MOUSEMOVEメッセージでは、 ウィンドウ プロシージャは、 反転したペンの色で上書き描画することによって以前の直線を消去します。それから、 始点から新しいカーソル位置まで直線を描画します。

WM_LBUTTONUPメッセージは、 描画操作の終了を示します。ウィンドウ プロシージャは、 マウスのキャプチャを解放し、 クライアント領域からマウスを解放します。

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)
HWND hwndMain;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
HDC hdc;/* handle of device context*/
RECT rcClient;/* client area rectangle*/
POINT ptClientUL;/* client upper-left corner*/
POINT ptClientLR;/* client lower-right corner */
static POINTS ptsBegin;/* beginning point*/
static POINTS ptsEnd;/* new endpoint*/
static POINTS ptsPrevEnd;/* previous endpoint*/
static BOOL fPrevLine = FALSE; /* previous line flag*/

switch (uMsg) {
case WM_LBUTTONDOWN:

/* Capture mouse input. */

SetCapture(hwndMain);

/*
* Retrieve the screen coordinates of the client area,
* and convert them into client coordinates.
/*

GetClientRect(hwndMain, &rcClient);
ptClientUL.x = rcClient.left;
ptClientUL.y = rcClient.top;

/*
* Add one to the right and bottom sides, because the
* coordinates retrieved by GetClientRect do not
* include the far left and lowermost pixels.
*/

ptClientLR.x = rcClient.right + 1;
ptClientLR.y = rcClient.bottom + 1;
ClientToScreen(hwndMain, &ptClientUL);
ClientToScreen(hwndMain, &ptClientLR);

/*
* Copy the client coordinates of the client area
* to the rcClient structure. Confine the mouse cursor
* to the client area by passing the rcClient structure
* to the ClipCursor function.
*/

SetRect(&rcClient, ptClientUL.x, ptClientUL.y,
ptClientLR.x, ptClientLR.y);
ClipCursor(&rcClient);

/*
* Convert the cursor coordinates into a POINTS
* structure, which defines the beginning point of the
* line drawn during a WM_MOUSEMOVE message.
*/

ptsBegin = MAKEPOINTS(lParam);
return 0;

case WM_MOUSEMOVE:

/*
* When moving the mouse, the user must hold down
* the left mouse button to draw lines.
*/

if (wParam & MK_LBUTTON) {

/*
* Retrieve a device context (DC) for the client
* area.
*/

hdc = GetDC(hwndMain);

/*
* The following function ensures that pixels of
* the previously drawn line are set to white and
* those of the new line are set to black.
*/

SetROP2(hdc, R2_NOTXORPEN);

/*
* If a line was drawn during an earlier
* WM_MOUSEMOVE message, draw over it. This erases
* the line by setting the color of its pixels to
* white.
*/

if (fPrevLine) {
MoveToEx(hdc, ptsBegin.x, ptsBegin.y,
(LPPOINT) NULL);
LineTo(hdc, ptsPrevEnd.x, ptsPrevEnd.y);
}

/*
* Convert the current cursor coordinates to a
* POINTS structure, and then draw a new line.
*/

ptsEnd = MAKEPOINTS(lParam);
MoveToEx(hdc, ptsBegin.x, ptsBegin.y,
(LPPOINT) NULL);
LineTo(hdc, ptsEnd.x, ptsEnd.y);

/*
* Set the previous line flag, save the ending
* point of the new line, and then release the DC.
*/

fPrevLine = TRUE;
ptsPrevEnd = ptsEnd;
ReleaseDC(hwndMain, hdc);
}
break;

case WM_LBUTTONUP:

/*
* The user has finished drawing the line. Reset the
* previous line flag, release the mouse cursor, and
* release the mouse capture.
*/

fPrevLine = FALSE;
ClipCursor(NULL);
ReleaseCapture();
return 0;

case WM_DESTROY:
PostQuitMessage(0);
break;

.
. /* Process other messages. */
.
}

ダブルクリック メッセージの処理

ダブルクリック メッセージを取得するには、 CS_DBLCLKSクラス スタイルを持つウィンドウ クラスにウィンドウが属していなければなりません。このスタイルは、 次の例のように、 ウィンドウ クラスを登録するときに設定します。

BOOL InitApplication(hInstance)
HINSTANCE hInstance;
{
WNDCLASS wc;

wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWClass";

return RegisterClass(&wc);
}

ダブルクリック メッセージの前には、 必ずボタン ダウン メッセージが送られます。このため、 通常、 アプリケーションは、 ボタン ダウン メッセージで開始した作業をダブルクリック メッセージで拡張します。

テキスト行の選択の例

この例は、 簡単なワード プロセッサ アプリケーションの一部です。ユーザーは。テキスト行をクリックすることによってキャレットの位置を設定し、 ダブルクリックすることによってテキスト行を選択 (強調表示) できます。

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)
HWND hwndMain;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
{
HDC hdc;/* handle of device context*/
TEXTMETRIC tm;/* font size data*/
int i, j;/* loop counters*/
int cCR = 0;/* count of carriage returns*/
char ch;/* character from input buffer*/
static int nBegLine;/* beginning of selected line */
static int nCurrentLine = 0; /* currently selected line*/
static int nLastLine = 0;/* last text line*/
static int nCaretPosX = 0;/* x-coordinate of caret*/
static int cch = 0;/* number of characters entered */
static int nCharWidth = 0;/* exact width of a character*/
static char szHilite[128];/* text string to highlight*/
static DWORD dwCharX;/* average width of characters*/
static DWORD dwLineHeight;/* line height*/
static POINTS ptsCursor;/* coordinates of mouse cursor*/
static COLORREF crPrevText;/* previous text color*/
static COLORREF crPrevBk;/* previous background color*/
static PTCHAR pchInputBuf;/* address of input buffer*/
static BOOL fTextSelected = FALSE; /* text-selection flag*/


switch (uMsg) {
case WM_CREATE:

/* Get the metrics of the current font. */

hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);

/* Save the average character width and height. */

dwCharX = tm.tmAveCharWidth;
dwLineHeight = tm.tmHeight;

/* Allocate a buffer to store keyboard input. */

pchInputBuf = (LPSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));

return 0;

case WM_CHAR:
switch (wParam) {
case 0x08: /* backspace */
case 0x0A: /* linefeed */
case 0x1B: /* escape */
MessageBeep(0xFFFFFFFF);
return 0;

case 0x09: /* tab */

/* Convert tabs to four consecutive spaces. */

for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;

case 0x0D: /* carriage return */

/*
* Record the carriage return, and position the
* caret at the beginning of the new line.
*/

pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCurrentLine += 1;
break;

default: /* displayable character */

ch = (char) wParam;
HideCaret(hwndMain);

/*
* Retrieve the character's width, and display the
* character.
*/

hdc = GetDC(hwndMain);
GetCharWidth(hdc, (UINT) wParam, (UINT) wParam,
&nCharWidth);
TextOut(hdc, nCaretPosX,
nCurrentLine * dwLineHeight, &ch, 1);
ReleaseDC(hwndMain, hdc);

/* Store the character in the buffer. */

pchInputBuf[cch++] = ch;

/*
* Calculate the new horizontal position of
* the caret. If the new position exceeds the
* maximum, insert a carriage return and
* reposition the caret at the beginning of
* the next line.
*/

nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwMaxCharX) {
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCurrentLine;
}

ShowCaret(hwndMain);

break;
}
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
nLastLine = max(nLastLine, nCurrentLine);
break;

.
. /* Process other messages. */
.

case WM_LBUTTONDOWN:

/*
* If a line of text is currently highlighted, redraw
* the text to remove the highlighting.
*/

if (fTextSelected) {
hdc = GetDC(hwndMain);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
TextOut(hdc, 0, nCurrentLine * dwLineHeight,
szHilite, lstrlen(szHilite));
ReleaseDC(hwndMain, hdc);
ShowCaret(hwndMain);
fTextSelected = FALSE;
}

/* Save the current mouse-cursor coordinates. */

ptsCursor = MAKEPOINTS(lParam);

/*
* Determine which line the cursor is on, and save
* the line number. Do not allow line numbers greater
* than the number of the last line of text. The
* line number is later multiplied by the average height
* of the current font. The result is used to set the
* y-coordinate of the caret.
*/

nCurrentLine = min((int)(ptsCursor.y / dwLineHeight),
nLastLine);

/*
* Parse the text input buffer to find the first
* character in the selected line of text. Each
* line ends with a carriage return, so it is possible
* to count the carriage returns to find the selected
* line.
*/

cCR = 0;
nBegLine = 0;
if (nCurrentLine != 0) {
for (i = 0; (i < cch) &&
(cCR < nCurrentLine); i++) {
if (pchInputBuf[i] == 0x0D)
++cCR;
}
nBegLine = i;
}

/*
* Starting at the beginning of the selected line,
* measure the width of each character, summing the
* width with each character measured. Stop when the
* sum is greater than the x-coordinate of the cursor.
* The sum is used to set the x-coordinate of the caret.
*/

hdc = GetDC(hwndMain);
nCaretPosX = 0;
for (i = nBegLine;
(pchInputBuf[i] != 0x0D) && (i < cch); i++) {
ch = pchInputBuf[i];
GetCharWidth(hdc, (int) ch, (int) ch, &nCharWidth);
if ((nCaretPosX + nCharWidth) > ptsCursor.x)
break;
else
nCaretPosX += nCharWidth;
}
ReleaseDC(hwndMain, hdc);

/* Set the caret to the user-selected position. */

SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
break;

case WM_LBUTTONDBLCLK:

/* Copy the selected line of text to a buffer. */

for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&
(i < cch); i++)
szHilite[j++] = pchInputBuf[i];
szHilite[j] = '\0';

/*
* Hide the caret, invert the background and foreground
* colors, and then redraw the selected line.
*/

HideCaret(hwndMain);
hdc = GetDC(hwndMain);
crPrevText = SetTextColor(hdc, RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc, RGB(0, 0, 0));
TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite,
lstrlen(szHilite));
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
ReleaseDC(hwndMain, hdc);

fTextSelected = TRUE;
break;
.
. /* Process other messages. */
.
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}

マウス入力の関数とメッセージ

マウス入力の受信と処理に関する関数とメッセージを次に示します。

関数

GetCapture

GetDoubleClickTime

mouse_event

ReleaseCapture

SetCapture

SetDoubleClickTime

SwapMouseButton

メッセージ

WM_LBUTTONDBLCLK

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_MBUTTONDBLCLK

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MOUSEACTIVATE

WM_MOUSEMOVE

WM_NCHITTEST

WM_NCLBUTTONDBLCLK

WM_NCLBUTTONDOWN

WM_NCLBUTTONUP

WM_NCMBUTTONDBLCLK

WM_NCMBUTTONDOWN

WM_NCMBUTTONUP

WM_NCMOUSEMOVE

WM_NCRBUTTONDBLCLK

WM_NCRBUTTONDOWN

WM_NCRBUTTONUP

WM_RBUTTONDBLCLK

WM_RBUTTONDOWN

WM_RBUTTONUP

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします
inserted by FC2 system