]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
fix for (too big) combobox height
[wxWidgets.git] / src / msw / window.cpp
index 3a49e008d6ba02ccaed4fa6057c09f01af798bb6..edc10844eab053ab6d65b144762fd378d49de026 100644 (file)
 #include "wx/intl.h"
 #include "wx/log.h"
 
-
 #include "wx/textctrl.h"
+#include "wx/notebook.h"
 
 #include <string.h>
 
-#if !defined(__GNUWIN32__)|| defined(wxUSE_NORLANDER_HEADERS)
+#ifndef __GNUWIN32_OLD__
     #include <shellapi.h>
     #include <mmsystem.h>
 #endif
     #include <windowsx.h>
 #endif
 
-#if ( defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__ ) || defined(wxUSE_NORLANDER_HEADERS)
-    #include <commctrl.h>
-#endif
-
-#ifndef __TWIN32__
-    #ifdef __GNUWIN32__
-        #ifndef wxUSE_NORLANDER_HEADERS
-            #include "wx/msw/gnuwin32/extra.h"
-        #endif
+#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__)
+    #ifdef __WIN95__
+        #include <commctrl.h>
+    #endif
+#else // broken compiler
+    #ifndef __TWIN32__
+        #include "wx/msw/gnuwin32/extra.h"
     #endif
 #endif
 
-// ---------------------------------------------------------------------------
-// macros
-// ---------------------------------------------------------------------------
-
-// standard macros missing from some compilers headers
-#ifndef GET_X_LPARAM
-    #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
-    #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
-#endif // GET_X_LPARAM
-
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
@@ -119,7 +107,7 @@ extern MSG s_currentMsg;
 
 wxMenu *wxCurrentPopupMenu = NULL;
 extern wxList WXDLLEXPORT wxPendingDelete;
-extern wxChar wxCanvasClassName[];
+extern const wxChar *wxCanvasClassName;
 
 // ---------------------------------------------------------------------------
 // private functions
@@ -137,19 +125,26 @@ void wxRemoveHandleAssociation(wxWindow *win);
 void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win);
 wxWindow *wxFindWinFromHandle(WXHWND hWnd);
 
+// this magical function is used to translate VK_APPS key presses to right
+// mouse clicks
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags);
+
+// get the current state of SHIFT/CTRL keys
+static inline bool IsShiftDown() { return (GetKeyState(VK_SHIFT) & 0x100) != 0; }
+static inline bool IsCtrlDown() { return (GetKeyState(VK_CONTROL) & 0x100) != 0; }
+
 // ---------------------------------------------------------------------------
 // event tables
 // ---------------------------------------------------------------------------
 
-#if !USE_SHARED_LIBRARY
-    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
-#endif
+IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
 
 BEGIN_EVENT_TABLE(wxWindow, wxWindowBase)
     EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground)
     EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
     EVT_INIT_DIALOG(wxWindow::OnInitDialog)
     EVT_IDLE(wxWindow::OnIdle)
+    EVT_SET_FOCUS(wxWindow::OnSetFocus)
 END_EVENT_TABLE()
 
 // ===========================================================================
@@ -163,6 +158,17 @@ END_EVENT_TABLE()
 // Find an item given the MS Windows id
 wxWindow *wxWindow::FindItem(long id) const
 {
+    wxControl *item = wxDynamicCast(this, wxControl);
+    if ( item )
+    {
+        // i it we or one of our "internal" children?
+        if ( item->GetId() == id ||
+             (item->GetSubcontrols().Index(id) != wxNOT_FOUND) )
+        {
+            return item;
+        }
+    }
+
     wxWindowList::Node *current = GetChildren().GetFirst();
     while (current)
     {
@@ -172,19 +178,6 @@ wxWindow *wxWindow::FindItem(long id) const
         if ( wnd )
             return wnd;
 
-        if ( childWin->IsKindOf(CLASSINFO(wxControl)) )
-        {
-            wxControl *item = (wxControl *)childWin;
-            if ( item->GetId() == id )
-                return item;
-            else
-            {
-                // In case it's a 'virtual' control (e.g. radiobox)
-                if ( item->GetSubcontrols().Member((wxObject *)id) )
-                    return item;
-            }
-        }
-
         current = current->GetNext();
     }
 
@@ -281,8 +274,11 @@ wxWindow::~wxWindow()
 
     if ( m_hWnd )
     {
-        if ( !::DestroyWindow(GetHwnd()) )
-            wxLogLastError("DestroyWindow");
+        if (::IsWindow(GetHwnd()))
+        {
+            if ( !::DestroyWindow(GetHwnd()) )
+                wxLogLastError("DestroyWindow");
+        }
 
         // remove hWnd <-> wxWindow association
         wxRemoveHandleAssociation(this);
@@ -1213,9 +1209,9 @@ void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
         return;
     }
 
-    if ( x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+    if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
         x = currentX;
-    if ( y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+    if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
         y = currentY;
 
     AdjustForParentClientOrigin(x, y, sizeFlags);
@@ -1473,6 +1469,10 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
     {
         // intercept dialog navigation keys
         MSG *msg = (MSG *)pMsg;
+
+        // here we try to do all the job which ::IsDialogMessage() usually does
+        // internally
+#if 1
         bool bProcess = TRUE;
         if ( msg->message != WM_KEYDOWN )
             bProcess = FALSE;
@@ -1482,8 +1482,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 
         if ( bProcess )
         {
-            bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0;
-            bool bShiftDown = (::GetKeyState(VK_SHIFT) & 0x100) != 0;
+            bool bCtrlDown = IsCtrlDown();
+            bool bShiftDown = IsShiftDown();
 
             // WM_GETDLGCODE: ask the control if it wants the key for itself,
             // don't process it if it's the case (except for Ctrl-Tab/Enter
@@ -1590,6 +1590,35 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
                 }
             }
         }
+#else
+        // let ::IsDialogMessage() do almost everything and handle just the
+        // things it doesn't here: Ctrl-TAB for switching notebook pages
+        if ( msg->message == WM_KEYDOWN )
+        {
+            // don't process system keys here
+            if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
+            {
+                if ( (msg->wParam == VK_TAB) && IsCtrlDown() )
+                {
+                    // find the first notebook parent and change its page
+                    wxWindow *win = this;
+                    wxNotebook *nbook = NULL;
+                    while ( win && !nbook )
+                    {
+                        nbook = wxDynamicCast(win, wxNotebook);
+                        win = win->GetParent();
+                    }
+
+                    if ( nbook )
+                    {
+                        bool forward = !IsShiftDown();
+
+                        nbook->AdvanceSelection(forward);
+                    }
+                }
+            }
+        }
+#endif // 0
 
         if ( ::IsDialogMessage(GetHwnd(), msg) )
             return TRUE;
@@ -1836,7 +1865,20 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             break;
 
         case WM_MOUSEMOVE:
+           {
+                short x = LOWORD(lParam);
+                short y = HIWORD(lParam);
+
+                processed = HandleMouseMove(x, y, wParam);
+           }
+           break;
+
         case WM_LBUTTONDOWN:
+           // set focus to this window
+           SetFocus();
+
+           // fall through
+
         case WM_LBUTTONUP:
         case WM_LBUTTONDBLCLK:
         case WM_RBUTTONDOWN:
@@ -1919,6 +1961,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             //else: get the dlg code from the DefWindowProc()
             break;
 
+        case WM_SYSKEYDOWN:
         case WM_KEYDOWN:
             // If this has been processed by an event handler,
             // return 0 now (we've handled it).
@@ -1946,6 +1989,8 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
                 case VK_RETURN:
                 case VK_BACK:
                 case VK_TAB:
+                case VK_ADD:
+                case VK_SUBTRACT:
                     // but set processed to FALSE, not TRUE to still pass them to
                     // the control's default window proc - otherwise built-in
                     // keyboard handling won't work
@@ -1958,20 +2003,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
                 // click because both usually pop up a context menu
                 case VK_APPS:
                     {
-                        // construct the key mask
-                        WPARAM fwKeys = MK_RBUTTON;
-                        if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
-                            fwKeys |= MK_CONTROL;
-                        if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
-                            fwKeys |= MK_SHIFT;
-
-                        // simulate right mouse button click
-                        DWORD dwPos = ::GetMessagePos();
-                        int x = GET_X_LPARAM(dwPos),
-                            y = GET_Y_LPARAM(dwPos);
-
-                        ScreenToClient(&x, &y);
-                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys);
+                        WPARAM flags;
+                        int x, y;
+
+                        TranslateKbdEventToMouse(this, &x, &y, &flags);
+                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
                     }
                     break;
 #endif // VK_APPS
@@ -1985,10 +2021,26 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             }
             break;
 
+        case WM_SYSKEYUP:
         case WM_KEYUP:
-            processed = HandleKeyUp((WORD) wParam, lParam);
+#ifdef VK_APPS
+            // special case of VK_APPS: treat it the same as right mouse button
+            if ( wParam == VK_APPS )
+            {
+                WPARAM flags;
+                int x, y;
+
+                TranslateKbdEventToMouse(this, &x, &y, &flags);
+                processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags);
+            }
+            else
+#endif // VK_APPS
+            {
+                processed = HandleKeyUp((WORD) wParam, lParam);
+            }
             break;
 
+        case WM_SYSCHAR:
         case WM_CHAR: // Always an ASCII character
             processed = HandleChar((WORD)wParam, lParam, TRUE);
             break;
@@ -2153,7 +2205,7 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win)
     if ( oldWin && (oldWin != win) )
     {
         wxString str(win->GetClassInfo()->GetClassName());
-        wxLogError("Bug! Found existing HWND %X for new window of class %s", (int) hWnd, (const char*) str);
+        wxLogError(wxT("Bug! Found existing HWND %X for new window of class %s"), (int) hWnd, (const wxChar*) str);
     }
     else if (!oldWin)
     {
@@ -2247,6 +2299,17 @@ bool wxWindow::MSWCreate(int id,
     if ( width > -1 ) width1 = width;
     if ( height > -1 ) height1 = height;
 
+    // Unfortunately this won't work in WIN16. Unless perhaps
+    // we define WS_EX_CONTROLPARENT ourselves?
+#ifndef __WIN16__
+    // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
+    // IsDialogMessage() won't work for us
+    if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
+    {
+        extendedStyle |= WS_EX_CONTROLPARENT;
+    }
+#endif
+
     HWND hParent = (HWND)NULL;
     if ( parent )
         hParent = (HWND) parent->GetHWND();
@@ -2325,7 +2388,7 @@ bool wxWindow::MSWCreate(int id,
         HWND hWnd = (HWND) node->GetKeyInteger();
         if (hWnd != (HWND) m_hWnd)
         {
-            wxLogError("A second HWND association is being added for the same window!");
+            wxLogError(wxT("A second HWND association is being added for the same window!"));
         }
     }
 #endif
@@ -2474,6 +2537,33 @@ bool wxWindow::HandleDestroy()
 // activation/focus
 // ---------------------------------------------------------------------------
 
+void wxWindow::OnSetFocus(wxFocusEvent& event)
+{
+    // panel wants to track the window which was the last to have focus in it,
+    // so we want to set ourselves as the window which last had focus
+    //
+    // notice that it's also important to do it upwards the tree becaus
+    // otherwise when the top level panel gets focus, it won't set it back to
+    // us, but to some other sibling
+    wxWindow *win = this;
+    while ( win )
+    {
+        wxWindow *parent = win->GetParent();
+        wxPanel *panel = wxDynamicCast(parent, wxPanel);
+        if ( panel )
+        {
+            panel->SetLastFocus(win);
+        }
+
+        win = parent;
+    }
+
+    wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"),
+               GetClassInfo()->GetClassName(), GetHandle());
+
+    event.Skip();
+}
+
 bool wxWindow::HandleActivate(int state,
                               bool WXUNUSED(minimized),
                               WXHWND WXUNUSED(activate))
@@ -2496,13 +2586,6 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd))
     }
 #endif // wxUSE_CARET
 
-    // panel wants to track the window which was the last to have focus in it
-    wxPanel *panel = wxDynamicCast(GetParent(), wxPanel);
-    if ( panel )
-    {
-        panel->SetLastFocus(this);
-    }
-
     wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
     event.SetEventObject(this);
 
@@ -2666,10 +2749,9 @@ bool wxWindow::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct)
     {
         return ((wxControl *)item)->MSWOnDraw(itemStruct);
     }
-    else
-#endif
-        return FALSE;
+#endif // USE_OWNER_DRAWN
 
+    return FALSE;
 }
 
 bool wxWindow::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
@@ -2938,14 +3020,32 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
         return popupMenu->MSWCommand(cmd, id);
     }
 
-    wxWindow *win = FindItem(id);
-    if ( !win )
+    wxWindow *win;
+    if ( cmd == 0 || cmd == 1 ) // menu or accel - use id
+    {
+        // must cast to a signed type before comparing with other ids!
+        win = FindItem((signed short)id);
+    }
+    else
     {
+        // find it from HWND - this works even with the broken programs using
+        // the same ids for different controls
         win = wxFindWinFromHandle(control);
     }
 
     if ( win )
         return win->MSWCommand(cmd, id);
+    else
+    {
+        // If no child window, it may be an accelerator, e.g. for
+        // a popup menu command.
+
+        wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
+        event.SetEventObject(this);
+        event.SetId(id);
+        event.SetInt(id);
+        return ProcessEvent(event);
+    }
 
     return FALSE;
 }
@@ -3050,12 +3150,43 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags)
 // keyboard handling
 // ---------------------------------------------------------------------------
 
+// create the key event of the given type for the given key - used by
+// HandleChar and HandleKeyDown/Up
+wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType,
+                                    int id,
+                                    WXLPARAM lParam) const
+{
+    wxKeyEvent event(evType);
+    event.SetId(GetId());
+    event.m_shiftDown = IsShiftDown();
+    event.m_controlDown = IsCtrlDown();
+    event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
+
+    event.m_eventObject = (wxWindow *)this; // const_cast
+    event.m_keyCode = id;
+    event.SetTimestamp(s_currentMsg.time);
+
+    // translate the position to client coords
+    POINT pt;
+    GetCursorPos(&pt);
+    RECT rect;
+    GetWindowRect(GetHwnd(),&rect);
+    pt.x -= rect.left;
+    pt.y -= rect.top;
+
+    event.m_x = pt.x;
+    event.m_y = pt.y;
+
+    return event;
+}
+
 // isASCII is TRUE only when we're called from WM_CHAR handler and not from
 // WM_KEYDOWN one
 bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII)
 {
+    bool ctrlDown = FALSE;
+
     int id;
-    bool tempControlDown = FALSE;
     if ( isASCII )
     {
         // If 1 -> 26, translate to CTRL plus a letter.
@@ -3064,142 +3195,86 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII)
         {
             switch (id)
             {
-            case 13:
-                {
+                case 13:
                     id = WXK_RETURN;
                     break;
-                }
-            case 8:
-                {
+
+                case 8:
                     id = WXK_BACK;
                     break;
-                }
-            case 9:
-                {
+
+                case 9:
                     id = WXK_TAB;
                     break;
-                }
-            default:
-                {
-                    tempControlDown = TRUE;
+
+                default:
+                    ctrlDown = TRUE;
                     id = id + 96;
-                }
             }
         }
     }
-    else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 )
+    {
         // it's ASCII and will be processed here only when called from
-        // WM_CHAR (i.e. when isASCII = TRUE)
+        // WM_CHAR (i.e. when isASCII = TRUE), don't process it now
         id = -1;
     }
 
     if ( id != -1 )
     {
-        wxKeyEvent event(wxEVT_CHAR);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
+        wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam));
+        if ( ctrlDown )
+        {
+            event.m_controlDown = TRUE;
+        }
 
         if ( GetEventHandler()->ProcessEvent(event) )
             return TRUE;
-        else
-            return FALSE;
     }
-    else
-        return FALSE;
+
+    return FALSE;
 }
 
 bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam)
 {
-    int id;
+    int id = wxCharCodeMSWToWX(wParam);
 
-    if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    if ( !id )
+    {
+        // normal ASCII char
         id = wParam;
     }
 
-    if ( id != -1 )
+    if ( id != -1 ) // VZ: does this ever happen (FIXME)?
     {
-        wxKeyEvent event(wxEVT_KEY_DOWN);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
-
+        wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam));
         if ( GetEventHandler()->ProcessEvent(event) )
         {
             return TRUE;
         }
-        else return FALSE;
-    }
-    else
-    {
-        return FALSE;
     }
+
+    return FALSE;
 }
 
 bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam)
 {
-    int id;
+    int id = wxCharCodeMSWToWX(wParam);
 
-    if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) {
+    if ( !id )
+    {
+        // normal ASCII char
         id = wParam;
     }
 
-    if ( id != -1 )
+    if ( id != -1 ) // VZ: does this ever happen (FIXME)?
     {
-        wxKeyEvent event(wxEVT_KEY_UP);
-        event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-        event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-        if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            event.m_altDown = TRUE;
-
-        event.m_eventObject = this;
-        event.m_keyCode = id;
-        event.SetTimestamp(s_currentMsg.time);
-
-        POINT pt;
-        GetCursorPos(&pt);
-        RECT rect;
-        GetWindowRect(GetHwnd(),&rect);
-        pt.x -= rect.left;
-        pt.y -= rect.top;
-
-        event.m_x = pt.x; event.m_y = pt.y;
-
+        wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam));
         if ( GetEventHandler()->ProcessEvent(event) )
             return TRUE;
-        else
-            return FALSE;
     }
-    else
-        return FALSE;
+
+    return FALSE;
 }
 
 // ---------------------------------------------------------------------------
@@ -3331,8 +3406,11 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam,
         event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN;
         break;
 
-    case SB_THUMBTRACK:
     case SB_THUMBPOSITION:
+        event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
+        break;
+
+    case SB_THUMBTRACK:
         event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK;
         break;
 
@@ -3545,6 +3623,48 @@ wxWindow *wxGetActiveWindow()
     return NULL;
 }
 
+extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
+{
+    HWND hwnd = (HWND)hWnd;
+
+    // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
+    // by code in msw/radiobox.cpp), for all the others we just search up the
+    // window hierarchy
+    wxWindow *win = (wxWindow *)NULL;
+    if ( hwnd )
+    {
+        win = wxFindWinFromHandle((WXHWND)hwnd);
+        if ( !win )
+        {
+            // the radiobox pointer is stored in GWL_USERDATA only under Win32
+#ifdef __WIN32__
+            // native radiobuttons return DLGC_RADIOBUTTON here and for any
+            // wxWindow class which overrides WM_GETDLGCODE processing to
+            // do it as well, win would be already non NULL
+            if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE,
+                               0, 0) & DLGC_RADIOBUTTON )
+            {
+                win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA);
+            }
+            else
+#endif // Win32
+            {
+                // hwnd is not a wxWindow, try its parent next below
+                hwnd = ::GetParent(hwnd);
+            }
+        }
+        //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
+    }
+
+    while ( hwnd && !win )
+    {
+        win = wxFindWinFromHandle((WXHWND)hwnd);
+        hwnd = ::GetParent(hwnd);
+    }
+
+    return win;
+}
+
 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
 // in active frames and dialogs, regardless of where the focus is.
 static HHOOK wxTheKeyboardHook = 0;
@@ -3560,18 +3680,19 @@ void wxSetKeyboardHook(bool doIt)
         wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
 
 #if defined(__WIN32__) && !defined(__TWIN32__)
-            GetCurrentThreadId());
+            GetCurrentThreadId()
         //      (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
 #else
-            GetCurrentTask());
+            GetCurrentTask()
 #endif
+            );
     }
     else
     {
         UnhookWindowsHookEx(wxTheKeyboardHook);
         // avoids mingw warning about statement with no effect (FreeProcInstance
         // doesn't do anything under Win32)
-#ifndef __GNUWIN32__
+#ifndef __GNUC__
         FreeProcInstance(wxTheKeyboardHookProc);
 #endif
     }
@@ -3583,8 +3704,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        int id;
-        if ( (id = wxCharCodeMSWToWX(wParam)) != 0 )
+        int id = wxCharCodeMSWToWX(wParam);
+        if ( id != 0 )
         {
             wxKeyEvent event(wxEVT_CHAR_HOOK);
             if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
@@ -3592,25 +3713,31 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 
             event.m_eventObject = NULL;
             event.m_keyCode = id;
-            /* begin Albert's fix for control and shift key 26.5 */
-            event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE);
-            event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE);
-            /* end Albert's fix for control and shift key 26.5 */
+            event.m_shiftDown = IsShiftDown();
+            event.m_controlDown = IsCtrlDown();
             event.SetTimestamp(s_currentMsg.time);
 
             wxWindow *win = wxGetActiveWindow();
+            wxEvtHandler *handler;
             if ( win )
             {
-                if ( win->GetEventHandler()->ProcessEvent(event) )
-                    return 1;
+                handler = win->GetEventHandler();
+                event.SetId(win->GetId());
             }
             else
             {
-                if ( wxTheApp && wxTheApp->ProcessEvent(event) )
-                    return 1;
+                handler = wxTheApp;
+                event.SetId(-1);
+            }
+
+            if ( handler && handler->ProcessEvent(event) )
+            {
+                // processed
+                return 1;
             }
         }
     }
+
     return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
 }
 
@@ -4032,3 +4159,22 @@ const char *wxGetMessageName(int message)
     }
 }
 #endif //__WXDEBUG__
+
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags)
+{
+    // construct the key mask
+    WPARAM& fwKeys = *flags;
+
+    fwKeys = MK_RBUTTON;
+    if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
+        fwKeys |= MK_CONTROL;
+    if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
+        fwKeys |= MK_SHIFT;
+
+    // simulate right mouse button click
+    DWORD dwPos = ::GetMessagePos();
+    *x = GET_X_LPARAM(dwPos);
+    *y = GET_Y_LPARAM(dwPos);
+
+    win->ScreenToClient(x, y);
+}