Link to home
Start Free TrialLog in
Avatar of Pber
PberFlag for Canada

asked on

Keypress in Combo Win32

I'm trying to catch when a certain key is pressed in a combo box.  I'm not programming in MFC.  

I was trying to capture the last key pressed by the CBN_EDITCHANGE notification, but that is not cutting it.  I'm now trying to use WM_CHAR, but I'm having problems.  How would I detect if the '\' key is pressed in a combo box via WM_CHAR (or whatever method is the best in this case).

The combo box is in a dialog box and here's the dialog callback...

LRESULT CALLBACK dlgAddDriveProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
    case WM_INITDIALOG:
    {
      return TRUE;
    }
    case WM_COMMAND:
      switch LOWORD(wParam)
      {
        case IDOK:
          EndDialog(hDlg, LOWORD(wParam));
          return TRUE;
          break;
        case IDCANCEL:
          EndDialog(hDlg, LOWORD(wParam));            
          return TRUE;
          break;      
        case IDC_COMBO2:
          if (HIWORD(wParam) == CBN_EDITCHANGE)
          {
            //Tried using CBN_EDITCHANGE, but ran into logistical problems and would rather catch a keypress In the combo
          }
       }
  }
  return FALSE;


Avatar of rcarlan
rcarlan

You need to subclass the edit-box part of the combo-box for this, and handle the WM_KEYDOWN or WM_KEYUP in it (not in the dialog). There are no notification messages from the combo-box to the parent dialog on key presses.

Radu
Avatar of jkr
1st of all, I am not really sure whether a ComboBox sends all keystroke notifs to the parent dialog - you should find what msgs are being sent. Try to e.g.

LRESULT CALLBACK dlgAddDriveProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    WORD    wNotifyCode;
    WORD    wID;
    HWND    hwndCtl;
    char acBuf [ 255];

 switch (message)
 {
   case WM_INITDIALOG:
   {
     return TRUE;
   }
   case WM_COMMAND:
    wNotifyCode =   HIWORD  (wParam);   // notification code
    wID         =   LOWORD  (wParam);   // item, control, or accelerator identifier
    hwndCtl     =   (HWND) lParam;          // handle of control
    switch LOWORD(wID)
     {
       case IDOK:
         EndDialog(hDlg, LOWORD(wParam));
         return TRUE;
         break;
       case IDCANCEL:
         EndDialog(hDlg, LOWORD(wParam));          
         return TRUE;
         break;    
        case IDC_COMBO2:
        wsprintf(acBuf,"Received from ComboBox: %d\n",wNotifyCode);
        OutputDebugString(acBuf);
        break;
      }
 }
 return FALSE;
}

and check the output using e.g. http://www.sysinternals.com/ntw2k/freeware/debugview.shtml - then we can go about intercepting the correct notifs, if any.
Avatar of Pber

ASKER

I tried this another callback just for the combo in the dialog callback, but it would seem the combo doesn't receive a WM_CHAR notification.

JKR: I'm trying to setup debugview, I'll let you know how it goes.

RCARLIN:  how do I subclass just the edit portion of the combo box.

LRESULT CALLBACK dlgAddDriveProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
      wchar_t sz1[256]=L"";

      switch (message)
      {
            case WM_INITDIALOG:
                  {
                  pOldWndProc = (WNDPROC)SetWindowLong(GetDlgItem(hDlg, IDC_COMBO2),GWL_WNDPROC,(LONG)ComboBoxProc);
                  return TRUE;
                  }
...

LRESULT CALLBACK ComboBoxProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{      
/*
      switch(msg)
      {
            
         case WM_CHAR:
            MessageBox(0, L"WM_CHAR received", L"Keypress", MB_OK);
            break;

      }
*/
      if (msg == WM_CHAR)
      {
            MessageBox(0, L"WM_CHAR received", L"Keypress", MB_OK);
      }

//return pOldWndProc(hwnd, msg, wparam, lparam);
  return CallWindowProc(pOldWndProc, hwnd,
        msg, wparam, lparam);
}

...but I bel
>>I'm trying to setup debugview, I'll let you know how it goes

Unzip it to a directory and start it :o)
Avatar of Pber

ASKER

The output from the debugview would seem to confirm that the WM_CHAR notification isn't sent from the combo.  

I get the following from debugview:

Received from ComboBox: 5
That seems to be

#define CBN_EDITCHANGE      5

which will not help much. Then, you'll indeed have to subclass the window proc, e.g.

#define WM_BACKSLASHNOTIFY WM_USER + 0x100

HWND g_hDlg;
WNDPROC g_pOldWndProc;

LRESULT CALLBACK NewWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {

 if ( WM_KEYDOWN == msg && '\' == wParam) PostMessage ( g_hDlg, WM_BACKSLASHNOTIFY, 0, 0);

  return CallWindowProc (g_pOldWndProc, hWnd, msg, wParam, lParam);
}


LRESULT CALLBACK dlgAddDriveProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch (message)
 {
   case WM_BACKSLASHNOTIFY:
   {
        // '\' was entered in ComboBox
   }
   case WM_INITDIALOG:
   {
   ´ g_pOldWndProc = (WNDPROC)SetWindowLongPtr (hDlg,GWLP_WNDPROC, (LONG_PTR)NewWndProc);
     return TRUE;
   }
   case WM_COMMAND:
     switch LOWORD(wParam)
     {
       case IDOK:
         EndDialog(hDlg, LOWORD(wParam));
         return TRUE;
         break;
       case IDCANCEL:
         EndDialog(hDlg, LOWORD(wParam));          
         return TRUE;
         break;    
      }
 }
 return FALSE;

Avatar of Pber

ASKER

Still having some issues with the callback.  It's being called, but msg is never = to WM_KEYDOWN.

LRESULT CALLBACK DlgBoxProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{      

      wchar_t sz[256];
      swprintf(sz,L"DlgBoxProc: msg=%d : WM_KEYDOWN=%d  wParam=%c",msg,WM_KEYDOWN,wParam);
      OutputDebugString(sz);

 if ( WM_KEYDOWN == msg && '\\' == wParam) PostMessage ( g_hDlg, WM_BACKSLASHNOTIFY, 0, 0);

  return CallWindowProc(pOldWndProc, hwnd, msg, wParam, lParam);
}


debugview output (when '\' pressed):

DlgBoxProc: msg 273 : WM_KEYDOWN wParam=?
DlgBoxProc: msg 307 : WM_KEYDOWN wParam=?

Sorry, I was wrong about the keycode - try

     wchar_t sz[256];
    swprintf(sz,L"DlgBoxProc: msg=%d : WM_KEYDOWN=%d  wParam=%d",msg,WM_KEYDOWN,wParam);
    OutputDebugString(sz);

 if ( WM_KEYDOWN == msg && VK_OEM_5== wParam) PostMessage ( g_hDlg, WM_BACKSLASHNOTIFY, 0, 0);

(according to http://msdn.microsoft.com/library/en-us/winui/winui/WindowsUserInterface/UserInput/VirtualKeyCodes.asp "Virtual-Key Codes ")
Avatar of Pber

ASKER

Thanks,

I screwed up with the output of debugview, it should have read:

DlgBoxProc: msg=273 : WM_KEYDOWN=256 wParam=?
DlgBoxProc: msg=307 : WM_KEYDOWN=256 wParam=?

what about: WM_KEYDOWN == msg  are they bitmasks?

No, 'WM_KEYDOWN' is 245:

#define WM_KEYDOWN                      0x0100

But it seems that you're not receiving that...
Avatar of Pber

ASKER

If I look in SPY++ I can see the messages, but the handle for the EDIT portion the combo box.  How do I get the handle of the EDIT box in the combo...
Is the handle listed as a child of the combo box?
Avatar of Pber

ASKER

Yes it is classified as the first child
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Pber

ASKER

That's it.

HWND hEdit = GetWindow ( hComboBox, GW_CHILD);
g_pOldWndProc = (WNDPROC)SetWindowLongPtr (hEdit ,GWLP_WNDPROC, (LONG_PTR)NewWndProc);

Thanks