Question

I am trying to get a GUI running for a C++ application but I am having an issue with key press events. Basically, everything works fine, as long as I do not click on any buttons (the main window registers key events), but as soon as I click on a button, the main window loses focus and it no longer captures key events. This might be a stupid question, but I am very new to C++. This is some of the code I am using:

Creation of the main window:

hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Application Name",  /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               540,                 /* The programs width */
               250,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

Creation of one of the buttons:

CreateWindow(TEXT("button"), TEXT("Start"),
                 WS_VISIBLE | WS_CHILD,
                 x, y, width, height,
                 hwnd, (HMENU) 6, NULL, NULL);

I have also noticed that whenever I click on a button, the WM_KILLFOCUS event is fired, which is why I think that this is a focus issue. I have also tried capturing the WM_KILLFOCUS event and then set the focus again with SetActiveWindow but that crashed my program.

Any help would be appreciated :)

Was it helpful?

Solution 2

It turned out that I was using the wrong function (SetWindowActive). Assaf Levy's answer seemed to complex for me and I thought that there might be another way around this. I managed to find the SetFocus function which gives the focus to any given window by providing it it's handle.

To make it work, what I needed to do was to, once that the the necessary code was executed within the WM_COMMAND block, I called the SetFocus function with the handle of the main window. This gave focus back to the main window and allowed it to receive events.

Note, putting the SetFocus in the WM_KILLFOCUS block will cause the buttons and any other component in it to become unresponsive to events.

OTHER TIPS

This is by design. The main window is a window, but so the button is a window, and only one can have focus at any given time. If you don't want the button to "steal" the focus, add an OnFocus handler (or intercept WM_SETFOCUS) and immediately return focus to the previous window (I believe it's in the WPARAM of WM_SETFOCUS).

An easy hack would be:

  1. hMyButton = CreateWindow("button", ...).
  2. Define a MyButtonProc(HWND, UINT, WPARAM, LPARAM) function.
  3. Call SetWindowLong(hMyButton, GWL_WNDPROC, (LONG)MyButtonProc). Save the value returned by this function in a g_OldButtonProc.
  4. Inside MyButtonProc() catch WM_SETFOCUS, and call SetFocus(hMyMainWindow). Always return CallWindowProc(h_OldButtonProc, hwnd, msg, ...) at the end of your MyButtonProc() function, unless the message was WM_SETFOCUS.

That will do the trick (tested).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top