第33章 キー入力を知る その2


前回は、フツーのキーの 入力を知る方法を解説しました。今回は、アスキーコードに変換されない キーの入力と、本当の意味での特殊キー(F10とALT)の入力の取得について解説します。 すべてのキーから特殊キー(F10とALT)をのぞいた物を一般キーといいます。 一般のキーが押されるとWM_KEYDOWNが、離したときにはWM_KEYUPが 通知されます。普通は、WM_KEYDOWNを捕まえればよいですね。 このとき、wParamを調べると仮想キーコードがわかります。 仮想キーコードとは「VK_何とか」という物で「何とか」 のところにF1とかESCAPEとかがきます。

特殊キーは、WM_SYSKEYDOWNとWM_SYSKEYUPです。 では、サンプルのプログラムを見てみましょう。

// key02.cpp #include <windows.h> #include <windowsx.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void OnClose(HWND); void OnDestroy(HWND); void OnKeyDown(HWND); void Cls_OnKey(HWND, UINT, BOOL, int, UINT); void Cls_OnSysKey(HWND, UINT, BOOL, int, UINT); void Cls_OnPaint(HWND); char szClassName[] = "key02"; //ウィンドウクラス char str[256];

いつもと、少し趣を変えてみました。 マクロを使うのでwindowsx.hもインクルードしてあります。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; if (!hPrevInst) { if (!InitApp(hCurInst)) return FALSE; } if (!InitInstance(hCurInst, nCmdShow)) { return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }

これは、毎度おなじみのWinMainです。

//ウィンドウ・クラスの登録 BOOL InitApp(HINSTANCE hInst) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; return (RegisterClass(&wc)); }

ウィンドウクラスの登録もいつもと同じです。

//ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるキー入力", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 300, //幅 100, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

初期状態のウィンドウは少し小さめにしてみました。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { HANDLE_MSG(hwnd, WM_CLOSE, OnClose); HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy); HANDLE_MSG(hwnd, WM_KEYDOWN, Cls_OnKey); HANDLE_MSG(hwnd, WM_SYSKEYDOWN, Cls_OnSysKey); HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint); default: return (DefWindowProc(hwnd, msg, wParam, lParam)); } return 0L; }

おー!これはいつもと全然違うぞ!

はい。気分転換のためにマクロを使ってみました。 case WM_何とかがマクロになっています。 windowsx.hでHANDLE_MSGを検索するとわかります。

HANDLE_MSG(ウィンドウハンドル, メッセージ, このメッセージを処理する関数);

という感じで使います。 そして、メッセージの種類によってこれを処理するための関数の 引数と戻り値が決められています。 たとえばWM_KEYDOWNでは

/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */ #define HANDLE_WM_KEYDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)

のように定義されています。 HANDLE_MSG(hwnd, WM_KEYDOWN, fn);としたら、これを処理する関数の 戻り値とか、引数は上のコメントで囲まれたCls_OnKeyと同じにしてやればよいのです。

void OnClose(HWND hwnd) { int id; id = MessageBox(hwnd, (LPCTSTR)"終了してもよいですか", (LPCTSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) DestroyWindow(hwnd); return; }

いつもウィンドウプロシージャに書いていた処理も 関数にするとこんな風になります。

void OnDestroy(HWND hwnd) { PostQuitMessage(0); return; }

マクロにするかどうかは、全く趣味の問題です。(本当は16ビットから 32ビットに移行するとき重大な意味がありました。)

void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) { char *str_org = "押されたキーは「%c」です。"; char *str_org2 = "押されたキーは、「%s」です。"; if ((vk >= 0x41 && vk <=0x5A) || (vk >= 0x30 && vk <= 0x39)) { wsprintf((LPTSTR)str, (LPCTSTR)str_org, vk); }else { switch(vk) { case VK_TAB: wsprintf((LPSTR)str, (LPCTSTR)str_org2, "TAB"); break; case VK_SHIFT: wsprintf((LPSTR)str, (LPCTSTR)str_org2, "SHIFT"); break; case VK_ESCAPE: wsprintf((LPSTR)str, (LPCTSTR)str_org2, "ESC"); break; default: strcpy(str, "知らないキーです"); break; } } InvalidateRect(hwnd, NULL, TRUE); return; }

この関数には、vkに仮想キーコードが入っています。16ビットの時は、VK_AとかVK_Bとかいう のがありましたが、32ビットではアスキーコードと同じということでなくなったみたいです。
if ((vk >= 0x41 && vk <=0x5A) || (vk >= 0x30 && vk <= 0x39))
それで、if文を使って分けて処理をしてみました。

void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) { if (vk == VK_F10) strcpy(str, "F10が押されました。"); if (vk == VK_MENU) strcpy(str, "ALT(GRPH)キーが押されました"); InvalidateRect(hwnd, NULL, TRUE); return; }

ここで特殊キーの処理を自前でしてしまったので、本来の特殊キーの 働きはなくなってしまうことに注意してください。

void Cls_OnPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, (LPCTSTR)str, strlen(str)); EndPaint(hWnd, &ps); return; }

今回使ったようなマクロをメッセージ・クラッカーといいます。



[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

Update May/15/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。