Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Win32 API: How to catch escape key in Edit control?

Tags:

c++

winapi

I found that for some unknown reason when focus is in Edit control, the Escape key never produces a messages. Below is a code to create a parent window, and Edit control above it. In MyCallBckProcedure() I laid printf() under a *WM_COMMAND*, to catch a messages, produced by Edit. More over -- I even tried to print all the messages catched in MyCallBckProcedure(); but if focus on Edit, the escape key never produces any of messages. What a weird problem could be here?

#include <iostream>
#include <windows.h>
#include <stdio.h>

#define IDC_MAIN_EDIT 101

LRESULT __stdcall MyCallBckProcedure( HWND window, unsigned msg, WPARAM wp, LPARAM lp ){
    printf("%x ",msg);
    switch(msg){
        case WM_COMMAND://here should be catched the escape key of Edit
            printf("%x ",msg);
            break;
        case WM_KEYDOWN:
            printf("%x ",msg);
            if(wp == VK_ESCAPE)PostQuitMessage(0);
            break;
        case WM_DESTROY:
            std::cout << "\ndestroying window\n" ;
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc( window, msg, wp, lp ) ;

        break;
        case WM_SIZE:{
            HWND hEdit;
            RECT rcClient;

            GetClientRect(window, &rcClient);

            hEdit = GetDlgItem(window, IDC_MAIN_EDIT);
            SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
        }
        break;
    }
}

int main(){
    const char* const myclass = "myclass";
    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyCallBckProcedure,
                            0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                            LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
                            0, myclass, LoadIcon(0,IDI_APPLICATION) };
    if(RegisterClassEx(&wndclass)<0){
        printf("ERR: in registering window class\n");
        return 1;
    }
    //Creating window
    HWND window = CreateWindowEx( 0, myclass, "title",
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                   CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0 );
    if(!window){
        printf("ERR: in creating window\n");
        return 1;
    }
    ShowWindow( window, SW_SHOWDEFAULT );
    MSG msg;
    //creating TextBox on the window
    HFONT hfDefault;
    HWND hEdit;
    hEdit = CreateWindowEx(0, "edit", "", 
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        window, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
    if(hEdit == NULL){
        MessageBox(window, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
        return 1;
    }
    hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
    //Now resize TextBox to fill whole parent window
    RECT RectSize;
    GetClientRect(window,&RectSize);
    hEdit = GetDlgItem(window,IDC_MAIN_EDIT);
    SetWindowPos(hEdit, 0,0,0,RectSize.right,RectSize.bottom,SWP_NOZORDER);
    //Process messages
    while(GetMessage(&msg,0,0,0) ){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
like image 799
Hi-Angel Avatar asked Jan 26 '14 02:01

Hi-Angel


1 Answers

Pressing ESC while the Edit is in focus does not generate a WM_COMMAND message to the Edit's parent window. It generates WM_KEYDOWN, WM_KEYUP, WM_CHAR and WM_UNICHAR messages to the Edit window itself.

Update: You are only handling messages that are destined for the parent window. You need to assign a message procedure to the edit window instead, eg:

WNDPROC lpEditWndProc;

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    return CallWindowProc(lpEditWndProc, hWnd, uMsg, wParam, lParam);
}

...

HWND hEdit = CreateWindowEx(...);
#ifdef _WIN64
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#else
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWL_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#endif

Alternatively:

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

...

HWND hEdit = CreateWindowEx(...);
SetWindowSubclass(hEdit, &MyEditCallBckProcedure, 0, 0);
like image 191
Remy Lebeau Avatar answered Sep 18 '22 23:09

Remy Lebeau