views:

39

answers:

2

The main form opens a child form that has a handful of button CONTROLs on it. I need to trap keyboard events so I subclassed one of the controls. All is good until the control loses focus of course.

Ideally, as long as this child form is open I would like to assign the focus to this control and thus trap all the keystrokes, no matter where the user clicks.

I suspect superclassing might be a better way to go but I am not as familiar with it.

Perhaps what I should do is use accelerators on the main form?

ADDED: I should mention that the main form has a large listview control that is subclassed to recover up/down arrows and mousewheel etc.

+1  A: 

The traditional way is to install a keyboard hook (SetWindowsHookEx), but you need to inject it into every application, and it doesn't work across 32/64 bit boundaries.

What you can do however, and quite easily at that, is to poll the keyboard with GetKeyboardState on a timer and check whether your f1-f12 keys are activated. The timer can be as slow ticking as 100ms and it will catch almost everything while using virtually no resources.

Blindy
+1 as the way it's done for Windows, but as sellibitze says...
Steve314
Heh didn't even think that it might not be for windows, too used to only programming for it..
Blindy
Done. Windows 32bit
Mike Trader
A: 

Assuming that this is within Windows and the Win32 API, one option is to look for messages in your main GetMessage, TranslateMessage, DispatchMessage loop. You can special-case any message within this loop, irrespective of which window it's aimed at.

You should probably use IsChild to check that the message is intended for a control on your main window (as opposed to some dialog box or message box that might be displayed separately). Getting the logic right can be fiddly, too. It would be best to only intercept messages when you know your control has lost the focus, and only intercept the exact messages you need to.

Years ago, I wrote a library message loop with a lot of this built in. I had a simple manager class that held pointers to instances of my own little window class. The loop knew the difference between dialogs and normal windows, gave each window class a chance to spy on its childrens messages, and so on. You won't be able to run this directly and the conventions are a bit strange, but you might find this useful...

int c_Window_List::Message_Loop (void)
{
  MSG msg;
  bool l_Handled;

  while (GetMessage (&msg, NULL, 0, 0))
  {
    l_Handled = false;

    c_Windows::c_Cursor l_Cursor;
    bool                ok;

    for (ok = l_Cursor.Find_First (g_Windows); ok; ok = l_Cursor.Step_Next ())
    {
      if (IsChild (l_Cursor.Key (), msg.hwnd))
      {
        if (l_Cursor.Data ().f_Accelerators != NULL)
        {
          l_Handled = TranslateAccelerator (l_Cursor.Key (), l_Cursor.Data ().f_Accelerators, &msg);

          if (l_Handled)  break;
        }

        if (l_Cursor.Data ().f_Manager != 0)
        {
          l_Handled = l_Cursor.Data ().f_Manager->Spy_Msg (l_Cursor.Key (), msg);
        }

        if (l_Handled)  break;

        if (l_Cursor.Data ().f_Is_Dialog)
        {
          l_Handled = IsDialogMessage (l_Cursor.Key (), &msg);
          if (l_Handled)  break;
        }
      }
    }

    if (!l_Handled)
    {
      TranslateMessage (&msg);
      DispatchMessage  (&msg);
    }

    if (g_Windows.Size () == 0)
    {
      //  When all windows have closed, exit
      PostQuitMessage (0);
    }
  }

  return msg.wParam;
}

The f_ prefixes mean field - I picked up the m_ convention later, but this code hasn't been revisited in a very long time. f_Manager in particular points to an instance of my c_Window_Base class. The c_Cursor class is a kind of iterator, used to step through all the windows stored in the g_Windows variable (actually a static class member rather than a global).

Steve314
Since the Parent and child dialogs are both modeless I elected to just trap all key strokes from msg, looking for WM_KEYDOWN in msg.message then VK_F1 - VK_F12 in msg.wParam in the message pump.
Mike Trader