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

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

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

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

Windows API キーボード入力の概要

Microsoft(R) Windows(TM) 用のアプリケーションは、 マウスからの入力と同様にキーボードからのユーザー入力を受け取るようにしなければなりません。ウィンドウベースのアプリケーションは、 キーボード入力を、 ウィンドウにポストされるメッセージの形式で受け取ります。このトピックでは、 Windowsがキーボード入力を生成する方法と、 アプリケーションがその入力を受け取り、 処理する方法について説明します。

[>>] ボタンを使って以下に示すトピックを順番に読んでください。または、各トピックをクリックすると、 そのトピックの内容を表示できます。

キーボード入力のモデル

キーボード フォーカスとアクティブ化

キーストローク メッセージ

文字メッセージ

キーの状態

キーストロークと文字の変換

ホット キーのサポート

キーストローク メッセージの処理

文字メッセージの変換

文字メッセージの処理

キャレットの使用

: キーボード入力の表示

キーボード関数とキーボード メッセージ

キーボード入力のモデル

Windowsは、 現在のキーボードに対応するキーボード デバイスドライバをインストールすることにより、 アプリケーションに対してデバイスに依存しないキーボード サポートを提供しています。また、 Windowsは、 ユーザーまたはアプリケーションが現在選択している (各国の) 言語固有のキーボード配列を使って、 言語に依存しないキーボード サポートを提供しています。キーボード デバイス ドライバはキーボードから走査コードを受け取ります。その走査コードはキーボード配列に送られ、そこでメッセージに変換されてからアプリケーションの適切なウィンドウに送られます。

キーボードの各キーには、 「走査コード」と呼ばれる一意な値が付けられています。走査コードとは、 キーボードのキーに対して付けられている、デバイスに依存するID値のことです。ユーザーがキーを入力すると、 キーボードは2つの走査コードを生成します。1つはユーザーがキーを押したときに生成され、 もう1つはユーザーがキーを離したときに生成されます。

キーボード デバイス ドライバはこの走査コードを解釈し、 それを「仮想キー コード」と呼ばれるものに変換 (マップ) します。仮想キー コードとは、 キーの意味を識別するためにWindowsで定義されている、 デバイスに依存しない値のことです。走査コードを変換した後、 キーボード配列は、 走査コードや仮想キーコードなどキーストロークに関する情報を持つメッセージを作成して、それをシステム メッセージ キューに置きます。Windowsは、 このメッセージをシステム メッセージ キューから取り出し、適切なスレッドのメッセージ キューに送ります。さらに、 スレッドのメッセージ ループはメッセージを取り出して、 適切なウィンドウ プロシージャに渡して処理させます。次の図は、 Windowsのキーホード入力モデルを示したものです。

キーボード フォーカスとアクティブ化

Windowsは、 キーボード フォーカスを持つウィンドウを作成したスレッドのメッセージキューに、 キーボード メッセージを送ります。「キーボード フォーカス」とは、 ウィンドウの一時的なプロパティ (属性) のことです。Windowsは、 ユーザーの指示に従ってキーボード フォーカスを別のウィンドウに移すことにより、ディスプレイ上のすべてのウィンドウに対してキーボードを共有させています。キーボード フォーカスを持つウィンドウは、 フォーカスがほかのウィンドウに移されるまで、 (ウィンドウを作成したスレッドのメッセージ キューから) すべてのキーボード メッセージを受け取ります。

ウィンドウを持っているスレッドは、 GetFocus関数を呼び出して、 そのスレッドのウィンドウのうちのどれが現在キーボード フォーカスを持っているかを判断することができます (持っていないこともある)。また、 スレッドはSetFocus関数を呼び出して、 スレッドのウィンドウの1つにキーボード フォーカスを与えることができます。あるウィンドウから別のウィンドウにキーボード フォーカスが移されると、 システムは、フォーカスを失ったウィンドウにWM_KILLFOCUSメッセージを送ってから、フォーカスを取得したウィンドウにWM_SETFOCUSメッセージを送ります。

キーボード フォーカスの概念は、 アクティブ ウィンドウの概念と関係があります。「アクティブ ウィンドウ」とは、ユーザーが現在作業をしているトップ レベル ウィンドウのことです。キーボード フォーカスを持つウィンドウは、 アクティブ ウィンドウ、 またはアクティブ ウィンドウの子ウィンドウのいずれかになります。そのため、ユーザーが簡単にアクティブ ウィンドウを識別することができるように、 システムはそのウィンドウをZ順序上でいちばん上に置き、タイトル バー (もしあれば) と境界を強調表示します。

ユーザーは、 ウィンドウをクリックしたり、 Alt+TabキーかAlt+Escキーの組み合わせを使ってウィンドウを選択したり、あるいはタスク リストから選択したりすることによって、 トップ レベル ウィンドウをアクティブ化することができます。スレッドは、 SetActiveWindow関数を使ってトップレベル ウィンドウをアクティブ化できます。また、 GetActiveWindow関数を使って、作成したトップ レベル ウィンドウがアクティブかどうかを判断することができます。

あるウィンドウが非アクティブ化されて別のウィンドウがアクティブ化されるとき、 Windowsはまず、 非アクティブ化されるウィンドウにWM_ACTIVATEメッセージを送り、 次にアクティブ化されるウィンドウに同じメッセージを送ります。メッセージのwParamパラメータの下位ワードは、ウィンドウが非アクティブ化されるときは0であり、 アクティブ化されるときは0以外の値になります。デフォルトウィンドウ プロシージャがWM_ACTIVATEメッセージを受け取ると、 アクティブ ウィンドウにキーボード フォーカスを設定します。

キーストローク メッセージ

あるキーが押されると、 キーボード フォーカスを持つウィンドウに関連付けられているスレッド メッセージ キューに、 WM_KEYDOWNメッセージまたはWM_SYSKEYDOWNメッセージが置かれます。キーが離されると、 WM_KEYUPメッセージまたはWM_SYSKEYUPメッセージがキューに置かれます。

通常、 キーアップ メッセージとキーダウン メッセージはペアで発生しますが、 キーボードのオート リピート機能が働くまでユーザーがキーを押し続けると、システムは多数のWM_KEYDOWNメッセージまたはWM_SYSKEYDOWNメッセージを連続的に生成し、ユーザーがキーを離したときにWM_KEYUPメッセージまたはWM_SYSKEYUPメッセージを1つ生成します。

システム キーストロークとシステム以外のキーストローク

Windowsは、 システム キーストロークとシステム以外のキーストロークとを区別します。システムキーストロークは、 システム キーストローク メッセージであるWM_SYSKEYDOWNおよびWM_SYSKEYUPを生成します。システム以外のキーストロークは、 シテスム以外のキーストローク メッセージであるWM_KEYDOWNおよびWM_KEYUPを生成します。

ウィンドウ プロシージャがシステム キーストローク メッセージを処理しなければならないときは、 メッセージを処理した後に、それらのメッセージをプロシージャからDefWindowProc関数に必ず渡すようにしてください。そうしないと、そのウィンドウがキーボード フォーカスを持っているときに、 Altキーを含むすべてのシステム操作が常に使用できなくなります。つまり、 ユーザーはウィンドウのメニューやコントロール メニューにアクセスできなくなり、 Alt+EscキーやAlt+Tabキーの組み合わせでほかのウィンドウをアクティブ化することもできなくなります。

システム キーストローク メッセージは、 主にアプリケーションではなくWindowsが利用します。Windowsはこれらのメッセージを使って、 メニューへの組み込みキーボード インターフェイスを提供し、 ユーザーがアクティブ化するウィンドウを制御できるようにしています。システムキーストローク メッセージは、 Altキーとの組み合わせとしてキーを入力したとき、または、 どのウィンドウもキーボード フォーカスを持っていない場合 (アクティブなアプリケーションがアイコン化されている場合など) にユーザーが入力をしたときに、 生成されます。この場合、 メッセージはアクティブ ウィンドウに関連付けられているメッセージ キューに送られます。

システム以外のキーストローク メッセージは、 アプリケーション ウィンドウが使用します。DefWindowProc関数は、 それらのメッセージ対して何も行いません。ウィンドウプロシージャは、 必要のないシステム以外のキーストローク メッセージを破棄することができます。

仮想キー コード

キーストローク メッセージのwParamパラメータには、 押したり離したりしたキーの仮想キー コードが格納されています。ウィンドウ プロシージャは仮想キーコードの値に応じて、 キーストローク メッセージを処理したり無視したりできます。

ふつう、 ウィンドウ プロシージャはキーストローク メッセージのごく一部だけを処理し、 残りはすべて無視します。たとえば、ウィンドウ プロシージャはWM_KEYDOWNキーストロークメッセージだけを処理する場合があり、 しかもそのうちカーソル移動キー、 Shiftキー (制御キーとも呼ばれます)、およびファンクション キーを含むものだけを処理します。典型的なウィンドウ プロシージャは、 文字キーのキーストローク メッセージは処理しません。その代わりに、 TranslateMessage関数を使ってメッセージを文字メッセージに変換します。TranslateMessageと文字メッセージについて詳しくは、 文字メッセージを参照してください。

キーストローク メッセージ フラグ

キーストローク メッセージのlParamパラメータには、 メッセージを生成したキーストロークに関する追加情報が格納されています。この情報としては、 リピートカウント、 走査コード、 拡張キー フラグ、 コンテキスト コード、 以前のキー状態フラグ、 および遷移状態フラグがあります。次の図は、 lParamパラメータ内における各フラグの位置とその値を示したものです。

リピート カウント

キーストローク メッセージが1つ以上のキーストロークを表わしているかどうかを判断する場合に、リピート カウントを調べることができます。システムは、 アプリケーションの処理速度よりも速くキーボードがWM_KEYDOWNメッセージまたはWM_SYSKEYDOWNメッセージを生成したときに、 リピート カウントをインクリメントします。この動作は、キーボードのオート リピート機能が動くまでユーザーがキーを押し続けたときに発生します。システムは、 発生した個々のキーダウン メッセージをシステム メッセージキューに設定するのではなく、 それらのメッセージを1つのキーダウン メッセージにまとめて、 リピート カウントをインクリメントします。キーを離すとオートリピート機能が働かなくなるため、 WM_KEYUPメッセージとWM_SYSKEYUPメッセージのリピートカウントは常に1になります。

走査コード

走査コードは、 ユーザーがキーを押したときにキーボード ハードウェアが生成する値です。このコードはデバイスに依存する値であり、押されたキーを識別します。また、 キーが表わす文字とはまったく異なります。通常、 アプリケーションは走査コードを無視し、 その代わりにデバイスに依存しない仮想キーコードを使って、 キーストローク メッセージを解釈します。

拡張キー フラグ

拡張キー フラグは、 キーストローク メッセージが拡張キーボード上の追加キーのいずれかから生成されたものかどうかを示すフラグです。拡張キーは、キーボートの右側のAltキーとCtrlキー、 数値キーパッドの左側にあるInsertDelete HomeEndPageUp PageDownの各キーと方向キー、 NumLockキー、 Breakキー (またはCtrl+Pause) キー、 PrintScreenキー、 および数値キーパッド上の/キーとEnterキーから構成されます。拡張キーフラグは、 キーが拡張キーのときにセットされます。

コンテキスト コード

コンテキスト コードとは、 キーストローク メッセージが生成されたときにAltキーが押されていたかどうかを示すものです。このコードが1ならばAltキーが押されていたことを示し、 0ならば押されていなかったことを示します。

以前のキー状態フラグ

以前のキー状態フラグとは、 キーストローク メッセージを生成したキーが以前に押されていたかどうかを示すフラグです。以前にキーが押されていたときは1、 押されていなかったときは0になります。このフラグを使えば、 キーストローク メッセージがキーボードのオートリピート機能により発生したものかどうかを判断することができます。オート リピート機能によって生成されたWM_KEYDOWNWM_SYSKEYDOWNのキーストローク メッセージに対しては、 このフラグは1にセットされます。WM_KEYUPメッセージとWM_SYSKEYUPメッセージに対しては、常に0になります。

遷移状態フラグ

遷移状態フラグとは、 キーストローク メッセージがキーを押して生成されたのか、 またはキーを離して生成されたのかを示すフラグです。このフラグは、 WM_KEYDOWNメッセージとWM_SYSKEYDOWNメッセージに対しては、常に0になります。WM_KEYUPメッセージとWM_SYSKEYUPメッセージに対しては、 常に1にセットされます。

文字メッセージ

キーストローク メッセージはキーストロークに関する多くの情報を提供しますが、 文字キーのキーストロークに対する文字コードは提供しません。アプリケーションで文字コードを取得するためには、 TranslateMessage関数をスレッドのメッセージループに含める必要があります。TranslateMessageは、キーボード配列にWM_KEYDOWNメッセージまたはWM_SYSKEYDOWNメッセージを渡します。すると、キーボード配列は、 まずメッセージの仮想キー コードを調べ、 それが文字キーに対応している場合はその文字キーと等価な文字コードを提供します (このときShiftキーやCapsLockキーの状態も考慮されます)。次に、 キーボード配列は文字コードを含む文字メッセージを生成して、 メッセージ キューの先頭にそれを置きます。そして、 メッセージループの次のループの実行時に、 キューから文字メッセージを取り出し、 それを適切なウィンドウ プロシージャにディスパッチします。

システム以外の文字メッセージ

ウィンドウ プロシージャは、 WM_CHARWM_DEADCHARWM_SYSCHAR、 およびWM_SYSDEADCHARの、 4つの異なる文字メッセージを受け取ることができます。TranslateMessage関数は、 WM_KEYDOWNメッセージを処理したときには、 WM_CHARメッセージまたはWM_DEADCHARメッセージを生成します。同様に、 WM_SYSKEYDOWNメッセージを処理したときには、 WM_SYSCHARメッセージまたはWM_SYSDEADCHARメッセージを生成します。

キーボード入力を処理するアプリケーションは、 通常、 WM_CHAR以外のメッセージを無視し、 それらをDefWindowProc関数に渡します。WindowsWM_SYSCHARメッセージとWM_SYSDEADCHARメッセージを使って、メニューのニーモニック機能を実装しています。

すべての文字メッセージのwParamパラメータには、 押されたキーの文字コードが含まれています。文字コードの値は、 メッセージを受け取るウィンドウのウィンドウクラスに依存します。ウィンドウ クラスの登録の際にUnicode(TM) 版のRegisterWindowClass関数を使っている場合、システムはそのクラスのすべてのウィンドウにUnicode文字を提供します。ANSI ASCII版を使っている場合には、 Windows文字セットからASCII文字コードを提供します。Unicodeについて詳しくは、 文字列操作とUnicodeの概要を参照してください。

文字メッセージのlParamパラメータの内容は、 それを生成するために変換されたキーダウン メッセージのlParamパラメータの内容とまったく同じです。lParamパラメータの内容について詳しくは、 キーストロークメッセージの「キーストローク メッセージ フラグ」を参照してください。

デッド文字メッセージ

英語以外のキーボードには、 それだけを押しても文字を生成しないような文字キーが含まれていることがあります。このようなキーは、それを押した直後のキーストロークによって生成される文字に追加される、 発音記号の入力に使われるもので、 「デッド キー」と呼ばれます。デッド キーの例としては、ドイツ語キーボードのサーカムフレックス キーがあります。サーカムフレックス付きの o という文字を入力するには、 サーカムフレックスキーに続けて o キーを押します。すると、 キーボード フォーカスを持つウィンドウは次の一連のメッセージを受け取ります。

WM_KEYDOWN

WM_DEADCHAR

WM_KEYUP

WM_KEYDOWN

WM_CHAR

WM_KEYUP

TranslateMessageは、 デッド キーからのWM_KEYDOWNメッセージを処理するときに、 WM_DEADCHARメッセージを生成します。WM_DEADCHARメッセージのwParamパラメータにはデッド キーの発音記号の文字コードが含まれていますが、 アプリケーションは通常はこのメッセージを無視します。その代わりに、後続のキーストロークによって生成されるWM_CHARメッセージを処理します。WM_CHARメッセージのwParamパラメータには、 発音記号付きの文字の文字コードが含まれています。後続のキーストロークによって発音記号と結合できない文字が生成された場合は、 Windowsは複数のWM_CHARメッセージを生成します。1つ目のメッセージのwParamパラメータには発音記号の文字コードが含まれ、 2つ目のメッセージのwParamパラメータには後続の文字キーの文字コードが含まれています。

TranslateMessage関数は、 システム デッド キー (Altキーと組み合わせて押されたデッドキー) からのWM_SYSKEYDOWNメッセージを処理するときに、 WM_SYSDEADCHARメッセージを生成します。アプリケーションは、 通常はWM_SYSDEADCHARメッセージを無視します。

キーの状態

キーボード メッセージを処理する間、 アプリケーションは現在のメッセージを生成したキーのほかに、 別のキーの状態を知らなければならない場合があります。たとえば、 Shift+Endキーを押してテキストのブロックを強調表示できるワードプロセッシング アプリケーションでは、 Endキーからのキーストロークメッセージを受け取ったときに、 Shiftキーの状態をチェックしなければなりません。アプリケーションは、 GetKeyState関数を使って、現在のメッセージが生成された時点での仮想キーの状態を判断することができます。また、 GetAsyncKeyState関数を使って、 ある仮想キーの現在の状態を取得することができます。

キーボード配列はキー名の一覧を保持しています。1文字を生成するキーの名前は、キーが生成する名前と同じです。TabEnterなどの文字以外のキーの名前は、文字列として格納されています。アプリケーションはGetKeyNameTextを呼び出して、デバイス ドライバから各キーの名前を取得することができます。

キーストロークと文字の変換

Windowsには、 さまざまなキーストローク メッセージから提供される走査コードや文字コード、および仮想キー コードの変換を行う多くの特殊用途関数が実装されています。これらの関数には、 MapVirtualKeyToAscii ToUnicodeVkKeyScanなどの関数があります。

ホット キーのサポート

Windowsは、 アプリケーションがホット キーの定義に利用できる一連の関数を提供しています。「ホットキー」とは、 WM_HOTKEYメッセージを生成するキーの組み合わせのことです。このWM_HOTKEYメッセージは、 スレッドのメッセージキューにすでに存在するほかのどのメッセージよりも優先して、 システムがキューの先頭に置きます。ホット キーは、 アプリケーションがユーザーから優先度の高いキーボード入力を取得する際に使います。たとえば、 Ctrl+Cキーの組み合わせからなるホット キーを定義して、時間のかかる処理をユーザーが中止できるようにすることができます。

ホット キーを定義するには、 WM_HOTKEYメッセージを生成するキーの組み合わせ、 メッセージを受け取るウィンドウのハンドル、 およびホット キーのIDを指定して、 RegisterHotKey関数を呼び出します。ユーザーがホットキーを押すと、 指定されたウィンドウを作成したスレッドのメッセージ キューにWM_HOTKEYメッセージが置かれます。メッセージのwParamパラメータにはホット キーのIDが含まれています。アプリケーションは1つのスレッドに対して複数のホット キーを定義できますが、スレッドの各ホット キーにはそれぞれ一意なIDを持たせなければなりません。アプリケーションの終了前には、 UnregisterHotKeyを使ってホットキーを破棄してください。

ホット キー コントロールを使って、 ユーザーがホット キーを選択しやすいようにすることができます。ホットキー コントロールは、 一般に、 ウィンドウをアクティブにするホット キーを定義するために使われます。コントロールでは、 RegisterHotKey関数とUnregisterHotKey関数は使われません。その代わり、ホット キー コントロールを使うアプリケーションでは、 一般にWM_SETHOTKEYメッセージを使ってホット キーを設定します。ユーザーがホットキーを押すと、 システムはSC_HOTKEYを指定してWM_SYSCOMMANDメッセージを送ります。

キーボード入力の使用

ウィンドウは、 キーストローク メッセージと文字メッセージという形でキーボード入力を受け取ります。ウィンドウに関連付けられているメッセージループは、 キーストローク メッセージを対応する文字メッセージに変換するコードを含む必要があります。ウィンドウがキーボード入力をクライアント領域に表示する場合は、キャレットを作成して表示し、 次の文字が入力される位置を示す必要があります。次のトピックから、 キーボード入力の受け取り、 処理、 表示に関するコードを説明します。

キーストローク メッセージの処理

キーボード フォーカスを持つウィンドウのウィンドウ プロシージャは、 ユーザーがキーボードから入力したときにキーストロークメッセージを受け取ります。キーストローク メッセージは、 WM_KEYDOWNWM_KEYUP WM_SYSKEYDOWN、 およびWM_SYSKEYUPです。通常のウィンドウ プロシージャは、 WM_KEYDOWNメッセージを除くすべてのキーストロークを無視します。ユーザーがキーを押すと、 WindowsWM_KEYDOWNメッセージをポストします。

ウィンドウ プロシージャがWM_KEYDOWNメッセージを受け取ると、 メッセージに付随する仮想キー コードを調べ、 キーストロークをどのように処理するかを判断します。仮想キーコードは、 メッセージのwParamパラメータに格納されています。通常、アプリケーションは、 ファンクション キーやカーソル移動キー、 また、 InsertDelete HomeEndなどの特殊用途のキーを含む文字以外のキーから生成されるキーストロークだけを処理します。

次の例は、 アプリケーションがキーストローク メッセージを取得して処理するために使う典型的なウィンドウ プロシージャの枠組みを示したものです。

case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
.
. /* Process the LEFT ARROW key. */
.

break;

case VK_RIGHT:
.
. /* Process the RIGHT ARROW key. */
.

break;

case VK_UP:
.
. /* Process the UP ARROW key. */
.

break;

case VK_DOWN:
.
. /* Process the DOWN ARROW key. */
.

break;

case VK_HOME:
.
. /* Process the HOME key. */
.

break;

case VK_END:
.
. /* Process the END key. */
.

break;

case VK_INSERT:
.
. /* Process the INS key. */
.

break;

case VK_DELETE:
.
. /* Process the DEL key. */
.

break;

case VK_F2:
.
. /* Process the F2 key. */
.

break;

.
. /* Process other noncharacter keystrokes. */
.

default:
break;
}

文字メッセージの変換

ユーザーから文字入力を受け取るスレッドは、 TranslateMessage関数をメッセージ ループに含めなければなりません。この関数はキーストロークメッセージの仮想キー コードを調べ、 そのコードが文字に対応していれば、 メッセージ キューに文字メッセージを置きます。文字メッセージは次のメッセージ ループの実行時に取り出され、ディスパッチされます。メッセージのwParamパラメータには文字コードが含まれています。

通常、 スレッドのメッセージ ループは、 TranslateMessage関数を使って仮想キー メッセージだけでなくすべてのメッセージを変換するようにしてください。TranslateMessageはほかの種類のメッセージには何の作用もしませんが、キーボード入力が正しく変換されたことを保証します。次の例は、 典型的なスレッド メッセージ ループにTranslateMessage関数を含める方法を示しています。

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
if (TranslateAccelerator(hwndMain, haccl, &msg) == 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

文字メッセージの処理

TranslateMessage関数が仮想キー コードを対応する文字キーに変換するとき、 ウィンドウ プロシージャは文字メッセージを受け取ります。文字メッセージは、 WM_CHARWM_DEADCHARWM_SYSCHAR、 およびWM_SYSDEADCHARです。通常のウィンドウプロシージャは、 WM_CHARを除くすべての文字メッセージを無視します。ユーザーが次のいずれかのキーを押すと、 TranslateMessage関数はWM_CHARメッセージを生成します。

任意の文字キー

BackSpaceキー

Enterキー (キャリッジ リターン)

Escキー

Shift+Enterキー (ラインフィード)

Tabキー

ウィンドウ プロシージャは、 WM_CHARを受け取ると、 メッセージに付随している文字コードを調べ、 文字をどのように処理するかを判断します。文字コードはメッセージのwParamパラメータに格納されています。

次の例は、 文字メッセージを受け取ってそれを処理するために通常のアプリケーションが使うウィンドウ プロシージャの枠組みを示したものです。

case WM_CHAR:
switch (wParam) {
case 0x08:
.
. /* Process a backspace. */
.

break;

case 0x0A:
.
. /* Process a linefeed. */
.

break;

case 0x1B:
.
. /* Process an escape. */
.

break;

case 0x09:
.
. /* Process a tab. */
.

break;

case 0x0D:
.
. /* Process a carriage return. */
.

break;

default:
.
. /* Process displayable characters. */
.

break;
}

キャレットの使用

キーボード入力を受け取るウィンドウは、 通常、 ウィンドウのクライアント領域にユーザーが入力した文字を表示します。クライアント領域で次の文字を表示すべき位置を示すには、キャレットを使ってください。また、 キーボード フォーカスを取得したときにキャレットを作成して表示し、 フォーカスを失ったときにキャレットを非表示にして破棄してください。これらの作業は、 WM_SETFOCUSメッセージおよびWM_KILLFOCUSメッセージの処理の中で行うことができます。キャレットについて詳しくは、 キャレットの概要を参照してください。

キーボード入力の表示

ここでは、 アプリケーションがキーボードから文字を受け取り、 ウィンドウのクライアント領域にそれを表示して、各文字入力に対してキャレットの位置を更新する方法について説明します。また、 Home Endの各キーストロークに応答してキャレットを動かす方法と、 Shift+キーの組み合わせに応答して選択されたテキストを強調表示する方法を示します。

この例では、 WM_CREATEメッセージの処理中、 ウィンドウ プロシージャはキーボード入力を格納しておくために64Kのバッファを割り当てます。また、 このウィンドウ プロシージャは現在ロードされているフォントのメトリックスを取得し、 そのフォントの文字の高さと平均幅を保存します。これらの高さと幅の情報は、 WM_SIZEメッセージの処理の中でクライアント領域のサイズに基づいて1行の長さと最大行数を計算するために使われます。

WM_SETFOCUSメッセージを処理するときは、 キャレットを作成して表示し、 WM_KILLFOCUSメッセージを処理するときにキャレットを非表示にして削除します。

WM_CHARメッセージを処理するときは、 文字を表示し、 それらを入力バッファに格納して、 キャレット位置を更新します。また、 タブ文字を連続する4つの空白文字に変換します。バックスペース、 ラインフィード、 エスケープ文字に対してはビープ音を鳴らしますが、 ほかには何の処理も行いません。

WM_KEYDOWNメッセージを処理するときは、 キャレットの左、 右、 行末、 および行頭への移動を実行します。キーの動作を処理するときは、 Shiftキーの状態を調べ、 押されていればキャレットを動かすときにキャレットの右側にある文字を強調表示します。

次のコードは、 Unicode(TM) ANSIのどちらでもコンパイルできるように記述されています。ソース コードの中でUnicodeを定義すれば、文字列はUnicode文字として扱われます。定義しない場合は、 ANSI文字として扱われます。

#define BUFSIZE 65535
#define SHIFTED 0x8000

LONG APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)
HWND hwndMain;
UINT uMsg;
UINT wParam;
LONG lParam;
{
HDC hdc;/* handle of device context*/
TEXTMETRIC tm;/* structure for text metrics*/
static DWORD dwCharX;/* average width of characters*/
static DWORD dwCharY;/* height of characters*/
static DWORD dwClientX;/* width of client area*/
static DWORD dwClientY;/* height of client area*/
static DWORD dwLineLen;/* line length*/
static DWORD dwLines;/* text lines in client area*/
static int nCaretPosX = 0; /* horizontal position of caret*/
static int nCaretPosY = 0; /* vertical position of caret*/
static int nCharWidth = 0; /* width of a character*/
static int cch = 0;/* characters in buffer*/
static int nCurChar = 0;/* index of current character*/
static PTCHAR pchInputBuf; /* address of input buffer*/
int i, j;/* loop counters*/
int cCR = 0;/* count of carriage returns*/
int nCRIndex = 0;/* index of last carriage return */
int nVirtKey;/* virtual-key code*/
TCHAR szBuf[128];/* temporary buffer*/
TCHAR ch;/* current character*/
PAINTSTRUCT ps;/* required by BeginPaint*/
RECT rc;/* output rectangle for DrawText */
SIZE sz;/* string dimensions*/
COLORREF crPrevText;/* previous text color*/
COLORREF crPrevBk;/* previous background color*/

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;
dwCharY = tm.tmHeight;

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

pchInputBuf = (LPTSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));
return 0;

case WM_SIZE:

/* Save the new width and height of the client area. */

dwClientX = LOWORD(lParam);
dwClientY = HIWORD(lParam);

/*
* Calculate the maximum width of a line and the
* maximum number of lines in the client area.
*/

dwLineLen = dwClientX - dwCharX;
dwLines = dwClientY / dwCharY;
break;


case WM_SETFOCUS:

/*
* Create, position, and display the caret when the
* window receives the keyboard focus.
*/

CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
ShowCaret(hwndMain);
break;

case WM_KILLFOCUS:

/*
* Hide and destroy the caret when the window loses the
* keyboard focus.
*/

HideCaret(hwndMain);
DestroyCaret();
break;

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;
nCaretPosY += 1;
break;

default: /* displayable character */

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

/*
* Retrieve the character's width and output
* the character.
*/

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

/* Store the character in the buffer. */

pchInputBuf[cch++] = ch;

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

nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwLineLen) {
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCaretPosY;
}
nCurChar = cch;
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;

case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT: /* LEFT ARROW */

/*
* The caret can move only to the beginning of
* the current line.
*/

if (nCaretPosX > 0) {
HideCaret(hwndMain);

/*
* Retrieve the character to the left of
* the caret, calculate the character's
* width, then subtract the width from the
* current horizontal position of the caret
* to obtain the new position.
*/

ch = pchInputBuf[--nCurChar];
hdc = GetDC(hwndMain);
GetCharWidth(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = max(nCaretPosX - nCharWidth,
0);
ShowCaret(hwndMain);
}
break;

case VK_RIGHT: /* RIGHT ARROW */

/*
* Caret moves to the right or, when a carriage
* return is encountered, to the beginning of
* the next line.
*/

if (nCurChar < cch) {
HideCaret(hwndMain);

/*
* Retrieve the character to the right of
* the caret. If it's a carriage return,
* position the caret at the beginning of
* the next line.
*/

ch = pchInputBuf[nCurChar];
if (ch == 0x0D) {
nCaretPosX = 0;
nCaretPosY++;
}

/*
* If the character isn't a carriage
* return, check to see whether the SHIFT
* key is down. If it is, invert the text
* colors and output the character.
*/

else {
hdc = GetDC(hwndMain);
nVirtKey = GetKeyState(VK_SHIFT);
if (nVirtKey & SHIFTED) {
crPrevText = SetTextColor(hdc,
RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc,
RGB(0,0,0));
TextOut(hdc, nCaretPosX,
nCaretPosY * dwCharY,
&ch, 1);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
}

/*
* Get the width of the character and
* calculate the new horizontal
* position of the caret.
*/

GetCharWidth(hdc, ch, ch, &nCharWidth);
ReleaseDC(hwndMain, hdc);
nCaretPosX = nCaretPosX + nCharWidth;
}
nCurChar++;
ShowCaret(hwndMain);
break;
}
break;

case VK_UP: /* UP ARROW*/
case VK_DOWN: /* DOWN ARROW */
MessageBeep(0xFFFFFFFF);
return 0;

case VK_HOME: /* HOME */

/*
* Set the caret's position to the upper left
* corner of the client area.
*/

nCaretPosX = nCaretPosY = 0;
nCurChar = 0;
break;

case VK_END: /* END */

/* Move the caret to the end of the text. */

for (i=0; i < cch; i++) {

/*
* Count the carriage returns and save the
* index of the last one.
*/

if (pchInputBuf[i] == 0x0D) {
cCR++;
nCRIndex = i + 1;
}
}
nCaretPosY = cCR;

/*
* Copy all text between the last carriage
* return and the end of the keyboard input
* buffer to a temporary buffer.
*/

for (i = nCRIndex, j = 0; i < cch; i++, j++)
szBuf[j] = pchInputBuf[i];
szBuf[j] = TEXT('\0');

/*
* Retrieve the text extent and use it
* to set the horizontal position of the
* caret.
*/

hdc = GetDC(hwndMain);
GetTextExtentPoint32(hdc, szBuf, lstrlen(szBuf),
&sz);
nCaretPosX = sz.cx;
ReleaseDC(hwndMain, hdc);
nCurChar = cch;
break;

default:
break;
}
SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);
break;

case WM_PAINT:
if (cch == 0)/* nothing in input buffer */
break;

hdc = BeginPaint(hwndMain, &ps);
HideCaret(hwndMain);

/*
* Set the clipping rectangle, and then draw the text
* into it.
*/

SetRect(&rc, 0, 0, dwLineLen, dwClientY);
DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);

ShowCaret(hwndMain);
EndPaint(hwndMain, &ps);
break;
.
. /* Process other messages. */
.
case WM_DESTROY:
PostQuitMessage(0);

/* Free the input buffer. */

GlobalFree((HGLOBAL) pchInputBuf);
break;

default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}

キーボード関数とキーボード メッセージ

キーボード入力を受け取り処理するための関数とメッセージの一覧を、 次に示します。

関数

ActivateKeyboardLayout

EnableWindow

GetActiveWindow

GetAsyncKeyState

GetFocus

GetKeyboardLayoutName

GetKeyboardState

GetKeyNameText

GetKeyState

IsWindowEnabled

keybd_event

LoadKeyboardLayout

MapVirtualKey

OemKeyScan

RegisterHotKey

SetActiveWindow

SetFocus

SetKeyboardState

ToAscii

ToUnicode

UnloadKeyboardLayout

UnregisterHotKey

VkKeyScan

使われなくなったか、 または削除された関数

GetKBCodePage

メッセージ

WM_ACTIVATE

WM_CHAR

WM_DEADCHAR

WM_HOTKEY

WM_KEYDOWN

WM_KEYUP

WM_KILLFOCUS

WM_SETFOCUS

WM_SYSCHAR

WM_SYSDEADCHAR

WM_SYSKEYDOWN

WM_SYSKEYUP

▲ページトップに戻る

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