• ベストアンサー

ダイアログプログラムでEnterキーを検出するには?

おせわになります。 開発環境はWindowsXP、VisualC++.NET、SDK開発です。 ダイアログ上のテキストボックスでエンターキーが入力されたら、 値を取り込むというプログラムを考えています。 ただ、WM_KEYDOWNではENTERが検出できないで困っています。 WM_SYSKEYでもENTERを押してもOKボタンが押されてしまいます。 過去のログを見ますとTranslateMessageでフックするというような 記述がありますが、具体的なコードは無いでしょうか? メイン関数内のループでMSGを処理するのではと思っていますが 思うような動作が出来ません。

質問者が選んだベストアンサー

  • ベストアンサー
noname#50176
noname#50176
回答No.2

複数行のエディットフィールドであれば BOOL CALLBACK DlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) { static LONG preProc; switch (GetDlgCtrlID(hDlg)==IDC_EDIT1?WM_USER+1:msg) { case WM_USER+1: switch (msg) { case WM_CHAR: if (wParam==13) MessageBeep(0); } return CallWindowProcA((WNDPROC)preProc,hDlg,msg,wParam,lParam); case WM_INITDIALOG: preProc=SetWindowLong(GetDlgItem(hDlg,IDC_EDIT1),GWL_WNDPROC,(LONG)DlgProc); return 1; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: EndDialog(hDlg,0); return 1; } } return 0; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmdLine, int lCmdShow) { DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,DlgProc,0); return 0; } と言う感じ(重複サブクラスプロシージャ)でシンプルにできます。 ただし、1行専用フィールドと場合はスレッドフックが必要です。 <セット> hHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,0,GetCurrentThreadId()); <プロシージャ> LRESULT CALLBACK KeyboardProc(int code,WPARAM wParam,LPARAM lParam) { if (nCode===HC_ACTION) if (wParam==0xD) { ここでエンターキー入力の処理 } return CallNextHookEx(hHook,nCode,wParam,lParam); } と言った感じでできると思いますよ。 スレッドフックは参考URLを参照してください。

参考URL:
http://www.kumei.ne.jp/c_lang/sdk2/sdk_160.htm
oo5goo
質問者

補足

VTClientさんありがとうございます。 上記のコードを使ってエンターキーの検出ができました。 ありがとうございました。

その他の回答 (1)

回答No.1

ご希望の方法とは違うかもしれませんが、テキストボックス等のコントロールを含む ウィンドウのウィンドウプロシージャの変更を行うサブクラス化というものがあります。 HWND hwTx;    //テキストボックスのウィンドウハンドル WNDPROC wpDef;  //テキストボックスのデフォルトのウィンドウプロシージャのアドレス //ウィンドウプロシージャのアドレスを取得 wpDef = (WNDPROC)GetWindowLong( hwTx, GWL_WNDPROC ); //新たにウィンドウプロシージャを設定する SetWindowLong( hwTx, GWL_WNDPROC, (LONG)WinProcCnt ); //新しいウィンドウプロシージャ LRESULT CALLBACK WinProcCnt( HWND hw, UINT msg, WPARAM wp, LPARAM lp ) {   switch( msg ){     case WM_CHAR:       switch( LOWORD(wp) ){         case VK_RETURN:           //ENTER入力時の処理           break;       }   }   //デフォルトのウィンドウプロシージャへ   return CallWindowProc( wpDef, hw, msg, wp, lp ); }

参考URL:
http://wisdom.sakura.ne.jp/system/winapi/win32/win64.html
oo5goo
質問者

補足

回答ありがとうございます。 サブクラス化をしたのですが思ったような動作が出来ません。 状況としては、ダイアログのある場所をクリックすると CreateWindowでエディットボックス(改行無し)を作成し、数値を入れてEnterキーを押すと数値が反映されるようにしたいと思っています。 具体的には以下のコードを書いています。 //クリックした所にエディットボックスを貼り付ける g_hEdit=CreateWindow("EDIT",szText ,WS_CHILD | WS_VISIBLE | ES_RIGHT,//ウィンドウスタイル rcAll.left,rcAll.top,//X.Y rcAll.right-rcAll.left,rcAll.bottom-rcAll.top,//幅、高さ GetDlgItem(hWnd,IDC_LIST1), //親ウィンドウのハンドル (HMENU)IDC_LISTEDIT,//コントロールID g_Inst,//インスタンスハンドル NULL); //サブクラス化 g_orgListEditProc=(WNDPROC)SetWindowLong(g_hEdit,GWL_WNDPROC,(LONG)ListEditProc); SendMessage(g_hEdit, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(FALSE, 0)); SetFocus(g_hEdit); 新しいエディットボックスに数値を入れてエンターキーを押すと、 IDOKに飛んでしまうのです。 エディットボックス内に普通の数字を入れるとKEYDOWNで検知できているのですが、Enterキーは検知できません。WM_SYSKEYでも検知できません。 動作としては、エディットボックスではなくIDOKボタンにフォーカスが行っている状態のようにみえます。 状況を説明してみたのですがいかがでしょうか?

関連するQ&A

  • APIのメッセージループの流れとTranslateMessage

    while(GetMessage(&msg, NULL, 0, 0) > 0){ TranslateMessage(&msg); DispatchMessage(&msg); } もしも「a」が押されたときは、 GetMessageで受け取って TranslateMessageでWM_CHARに変換され DispatchMessageでWM_CHARとしてのメッセージが送られる という流れになるはずです。 けど、実際には一度プロシージャにWM_KEYDOWNが送られます。 TranslateMessageが先にメッセージを変換してるので、WM_KEYDOWNが送られることはありえないと思うのですが、なぜでしょうか。 何か重大な思い違いをしているのでしょうか・・?

  • WM_KEYDOWNでPrtScを捕まえる方法??

    ごく普通のウィンドウプロシージャでキーの判別を行っています 下記のように条件(1)が WM_KEYUP の際には(2)、(3)ともに検出します LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_KEYUP: ............ (1) switch(wp) { case VK_RETURN: { break; } ..... (2) case VK_SNAPSHOT: { break; } ..... (3) default: { break; } } break; } return; ところが条件(1)を WM_KEYDOWN に変更すると(2)の Enter は検出しますが、(3)の PrtSc を検出してくれません 質問1 なぜ PrtSc を WM_KEYDOWN では検出しないのですか? 質問2 WM_KEYUP WM_KEYDOWN のいずれか一方にしか反応しないキーはまだありますか? 質問3 どのようにしたら PrtSc の WM_KEYDOWN を捕まえることが出来ますか? 自分でも調べてみましたが、どうも判然と致しません 宜しくご指導のほどお願い申し上げます

  • ダイアログボックスのボタンコントロールのフォーカスについて

    ダイアログボックスのボタンコントロールのフォーカスについて 教えて下さい。  モーダルダイアログにボタン「OK」を一つ貼り付けて それを「標準のボタン」(BS_DEFPUSHBUTTON)として作成したのですが ダイアログ表示直後は下画像(1)のようになってエンターキーを押しても 反応しません。何度かカーソルキーを押すとようやく(2)のように ボタンに枠線がついてエンターで押せるようになるのですが ダイアログ表示直後に(2)のようにするにはどうするべきでしょうか? ダイアログのコールバック・プロシージャ(WM_INITDIALOG部分でボタン作成) LRESULT CALLBACK SettingWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){ switch (msg){ case WM_INITDIALOG: CreateWindowEx(0x00000000,"BUTTON","OK", WS_CHILD |WS_VISIBLE| WS_TABSTOP | BS_DEFPUSHBUTTON, 16,16,80,21,hWnd,(HMENU)IDOK,GetModuleHandle(0),0); return TRUE; } return FALSE; }

  • Ctrl + P のメッセージ送信

    印刷ダイアログを起動させるために Ctrl + P をメッセージ送信しようとしているのですが 書きのように記述しても実現できませんでした. ご存知の方がおりましたら、ご回答いただけませんでしょうか。 PostMessage hwindow, WM_KEYDOWN, 17, 0 PostMessage hwindow, WM_KEYDOWN, 80, 0 PostMessage hwindow, WM_KEYUP, 80, 0 PostMessage hwindow, WM_KEYUP, 17, 0

  • ダイアログボックスについて。

    ダイアログボックスについての質問です。 開発環境はVisual C++ 2005.netでありSDKを利用しています。 ダイアログボックスにPicture Controlを貼り付け、Combo Boxの内容が変わるたびにそのPicture Controlに画像を表示するようなプログラムを作りたいと考えています。 自分が考える手順としてはまずPicture Controlについてサブクラス化を行い、親のダイアログボックスが表示されると同時にPicture ControlのプロシージャでWM_CREATEメッセージを受け取り描画を行う。 そして親のダイアログボックスに貼り付けたCombo Boxの内容が変更された場合に、Picture ControlのウィンドウハンドルにむけてWM_PAINTメッセージを送信する。 こんな手順で行いたいのですが、少し不安な部分が出てきました。 Combo Boxの内容が変更され、Picture Controlのウィンドウハンドルに向けてWM_PAINTメッセージを送信し、Picture ControlプロシージャではWM_PAINTメッセージがきたとき画像の描画を行う場合、このプロシージャではどの画像を描画してよいか不明です。 そのため何番の画像の表示命令が来たのかを示すために、親のダイアログボックスに貼り付けたCombo Boxが変更された場合、Picture Controlに向けてWM_PAINTメッセージと表示画像番号をパラメータとして送信したいのです。 もちろんグローバル変数を用意すれば簡単なのですが、できるだけ使用しないように記述をしたいのです。そこで考えたのが、 SendMessage(GetDlgItem(hDlgWnd, IDC_PICTURE), WM_PAINT, 0, MAKELPARAM(0, number)); このようにnumberをLPARAMの下位ワードとして送信しようと考えました。 このメッセージ送信を行い、Picture ControlプロシージャでWM_PAINTメッセージが到着したとき、LOWORD(lparam)からnumberを取り出す。 実現したい目的のため、このような方法を考えましたが、エラーなく実行できるでしょうか? もしあやしい部分が見つかった場合はアドバイスをお願いします。そしてこの方法よりも簡単に処理できる方法があれば教えていただきたいです。 自分としてはサブクラス化は面倒なので、Picture Controlをオーナードローとして扱う方法も考えましたが、うまく動きませんでしたTT

  • Sleep(1)が1msでもどってこない。

    Sleep(1)が1msでもどってこない。 ゲームのループ処理を作っていまして、 空いている時間をシステムに返すためにSleep(1)を呼んで いるのですが、 while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { //ゲーム的な処理 //時間があまればSleep() } } といった定番なことをしているのですが、 30FPSで固定されません。 調べてみるとSleep(1)が2msくらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

  • ウィンドウ内でマウスが乗ると更新が止まります・・

    ウィンドウプロシージャ周りを触っているのですが、  ・ウィンドウにマウスが乗っていつつ、マウスが動いている時  ・キーボードーを押した瞬間 にメインループに処理が回らず 全体の処理が止まってしまいます。 上の問題を解決するには、どうすれば良いでしょうか? ※以下コード ---------------------------------------------- while(TRUE) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // 処理メッセージが無いとき WINDOWPLACEMENT wndpl; GetWindowPlacement(hWnd, &wndpl); if((wndpl.showCmd != SW_HIDE) && (wndpl.showCmd != SW_MINIMIZE) && (wndpl.showCmd != SW_SHOWMINIMIZED) && (wndpl.showCmd != SW_SHOWMINNOACTIVE)) { ... ゲームのような、常時更新が必要なループ処理 ... } } Sleep(1); // 最小化等でフリーズしないため } ---------------------------------------------- //以下メッセージ処理側の一部 case WM_KEYDOWN: if (wParam == VK_ESCAPE) { PostQuitMessage(0); } break; case WM_MOUSEMOVE: return DefWindowProc(hWnd, msg, wParam, lParam); default: return DefWindowProc(hWnd, msg, wParam, lParam); ---------------------------------------------- また、ゲームなどのリアルタイム更新に向いた ウィンドウプロシージャの作り方などの説明サイト等ご存知でしたら そちらも教えて頂けると幸いです。

  • モードレスダイアログのタブ移動

    メインループでメッセージを拾ってモードレスで表示した画面のTabキー制御を行いたいのですが、以下のプログラムでTabキーはコントロール間を移動しますが、移動の順番がタブオーダーと全く違います。 ------------------------------------------------- // メイン ウィンドウを作成して、実行します Form1^ m_form = gcnew Form1(); m_form->Show(); msg.message = WM_CREATE; while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (!IsDialogMessage( (HWND)m_form->Handle.ToPointer(), &msg )) { // メッセージが未処理の場合は処理を行う TranslateMessage(&msg); DispatchMessage(&msg); } } } ------------------------------------------------- m_form->ShowDialog(); にしたり、上記ループを Application::Run(gcnew Form1()); に変更するとちゃんとタブオーダーの順番で移動します。 訳有りで、ループ処理を変えたくはありません。 ネットで調べる限りタブ移動について「IsDialogMessage」を 入れるという疑問はあったのですが、それ以降の動作については 何も書かれていないようです。 上記ループの書き方でタブ移動がうまく行えない場合が あるのでしょうか? どなたかご存知でしたら教えてください

  • VBA API WM_KEYDOWN

    エクセル内のオブジェクトの移動を判定するため、マウスアップを検出しようと考えています。 GetAsyncKeyStateでできるのですが、エクセルが受け取るWM_KEYDOWNを受け取る方法はないのでしょうか? そもそもWindowsがイベント待ちで動いているのに、GetAsyncKeyStateだとループ処理で監視することになるので、すっきりしません。私だけでしょうか? ちなみに、新規に図形を作ったり、図形を移動したりしたときに処理したいですが、このイベントは準備されていないですよね?

  • コンボボックスのエディットでキー操作するには

    コンボボックスのメンバコントロールCEditでエンターを押した時、 何か処理をさせたい場合はどうすればいいのでしょうか? class CEditEX :public CEdit{ virtual BOOL PreTranslateMessage(MSG* pMsg){ if( (pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_RETURN) ){ TRACE("TEST\n");} return 0;} } }; CComboBox m_ComboBox; CEditEX m_EditEX; m_ComboBox.m_pWndEdit = m_EditEX; こうしたいのですが、pWndEdit がprotectedな為できません。 コンボボックスのエディット入力キーメッセージが上位ウィンドウに送られて来ることはないんでしょうか? コンボボックスでキーが押されたときに実行されるオーバーライド可能な関数はないのでしょうか? どうすればいいのか教えてください。

専門家に質問してみよう