Search code examples
cwinapitabs

How to make a multi-line textbox's tab-stop working in win32api application


I have a win32api application written in c here. All controls in main window are created manually like this:

hEditSource = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
                WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_MULTILINE | ES_READONLY,
                someLeft, someTop, someWidth, someHeight,
                hWndMain, NULL, hInst, NULL);

At first I didn't apply IsDialogMessage test in main message loop so all controls' tab stop won't work. Now I have it done, every control are OK except the multi-line textbox above. Indeed nothing happens when press tab in it. No focus moving, no tab charactor inserting(it will discard read-only style afterwards).

Other textboxes are all single-line ones, looks like this:

editSearch = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
               WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP,
               someLeft, someTop, someWidth, someHeight,
               hWndMain, NULL, hInst, NULL);

It seems sth related to multiple line style is the cause. But in C# winform, it is very easy to create a multi-line edit with working tab-stop (it is the default behavior of a textbox, whether it is multi-line). I have tried to use spy++, to find if there is any clue in window style. However, 2 textboxes' window style are indentical if the only difference is the "Accept Tab" property.

Rightnow I cannot find another way to locate the root cause. Does anyone have a clue? Any help will be appreciated.


Solution

  • The behaviour of the IsDialogMessage is influenced by how the controls respond to WM_GETDLGCODE. As documented, for a multi-line edit control the following is returned by the default window procedure:

     DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | DLGC_WANTALLKEYS
    

    The inclusion of DLGC_WANTALLKEYS stops IsDialogMessage from responding to TAB and moving the focus to the next control. So, you will need to subclass your multi-line edit control and remove that flag. The sub-classed window procedure might look like this:

    LRESULT CALLBACK MultiLineEditWndProc(HWND hWnd, UINT message, WPARAM wParam, 
        LPARAM lParam)
    {
        LRESULT res = CallWindowProc(wpOld, hWnd, message, wParam, lParam);
        switch (message)
        {
        case WM_GETDLGCODE:
            res &= ~DLGC_WANTALLKEYS;
        }
        return res;
    }