]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Bring osx class naming into line with the other ports.
[wxWidgets.git] / src / msw / window.cpp
index fbf9c4ced005e1c48ba0cf3b4be88c58a178d0ae..0b1f0d3a3aacc0f50eff5227375e6108423f31d0 100644 (file)
@@ -79,6 +79,7 @@
 #endif
 
 #include "wx/msw/private.h"
+#include "wx/msw/private/keyboard.h"
 #include "wx/msw/dcclient.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/caret.h"
 #endif // wxUSE_CARET
 
+#if wxUSE_RADIOBOX
+    #include "wx/radiobox.h"
+#endif // wxUSE_RADIOBOX
+
 #if wxUSE_SPINCTRL
     #include "wx/spinctrl.h"
 #endif // wxUSE_SPINCTRL
     #define wxHAS_XBUTTON
 #endif
 
+#ifndef MAPVK_VK_TO_CHAR
+    #define MAPVK_VK_TO_CHAR 2
+#endif
+
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 extern wxMenu *wxCurrentPopupMenu;
 #endif
 
+#if wxUSE_UXTHEME
+// This is a hack used by the owner-drawn wxButton implementation to ensure
+// that the brush used for erasing its background is correctly aligned with the
+// control.
+extern wxWindowMSW *wxWindowBeingErased = NULL;
+#endif // wxUSE_UXTHEME
+
+namespace
+{
+
 // true if we had already created the std colour map, used by
 // wxGetStdColourMap() and wxWindow::OnSysColourChanged()           (FIXME-MT)
-static bool gs_hasStdCmap = false;
+bool gs_hasStdCmap = false;
 
 // last mouse event information we need to filter out the duplicates
 #if wxUSE_MOUSEEVENT_HACK
-static struct MouseEventInfoDummy
+struct MouseEventInfoDummy
 {
     // mouse position (in screen coordinates)
     wxPoint pos;
@@ -194,14 +213,38 @@ WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
                     wxIntegerHash, wxIntegerEqual,
                     MSWMessageHandlers);
 
-static MSWMessageHandlers gs_messageHandlers;
+MSWMessageHandlers gs_messageHandlers;
 
 // hash containing all our windows, it uses HWND keys and wxWindow* values
 WX_DECLARE_HASH_MAP(HWND, wxWindow *,
                     wxPointerHash, wxPointerEqual,
                     WindowHandles);
 
-static WindowHandles gs_windowHandles;
+WindowHandles gs_windowHandles;
+
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+// temporary override for WM_ERASEBKGND processing: we don't store this in
+// wxWindow itself as we don't need it during most of the time so don't
+// increase the size of all window objects unnecessarily
+WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *,
+                    wxPointerHash, wxPointerEqual,
+                    EraseBgHooks);
+
+EraseBgHooks gs_eraseBgHooks;
+
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+// If this variable is strictly positive, EVT_CHAR_HOOK is not generated for
+// Escape key presses as it can't be intercepted because it's needed by some
+// currently shown window, e.g. IME entry.
+//
+// This is currently global as we allow using UI from the main thread only
+// anyhow but could be replaced with a thread-specific value in the future if
+// needed.
+int gs_modalEntryWindowCount = 0;
+
+} // anonymous namespace
 
 // ---------------------------------------------------------------------------
 // private functions
@@ -241,7 +284,7 @@ static inline void wxBringWindowToTop(HWND hwnd)
     // raise top level parent to top of z order
     if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
     {
-        wxLogLastError(_T("SetWindowPos"));
+        wxLogLastError(wxT("SetWindowPos"));
     }
 }
 
@@ -301,119 +344,10 @@ bool GetCursorPosWinCE(POINT* pt)
 // method
 #ifdef __WXUNIVERSAL__
     IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
-#else // __WXMSW__
-#if wxUSE_EXTENDED_RTTI
-
-// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
-// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
-// windows with negative ids never can be recreated anyway
-
-bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
-{
-    const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
-    if ( win && win->GetId() < 0 )
-        return false ;
-    return true ;
-}
-
-IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
-
-// make wxWindowList known before the property is used
-
-wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
-
-template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
-{
-    wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
-}
-
-WX_DEFINE_FLAGS( wxWindowStyle )
-
-wxBEGIN_FLAGS( wxWindowStyle )
-    // new style border flags, we put them first to
-    // use them for streaming out
-
-    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
-    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
-    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
-    wxFLAGS_MEMBER(wxBORDER_RAISED)
-    wxFLAGS_MEMBER(wxBORDER_STATIC)
-    wxFLAGS_MEMBER(wxBORDER_NONE)
-
-    // old style border flags
-    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
-    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
-    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
-    wxFLAGS_MEMBER(wxRAISED_BORDER)
-    wxFLAGS_MEMBER(wxSTATIC_BORDER)
-    wxFLAGS_MEMBER(wxBORDER)
-
-    // standard window styles
-    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
-    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
-    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
-    wxFLAGS_MEMBER(wxWANTS_CHARS)
-    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
-    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
-    wxFLAGS_MEMBER(wxVSCROLL)
-    wxFLAGS_MEMBER(wxHSCROLL)
-
-wxEND_FLAGS( wxWindowStyle )
-
-wxBEGIN_PROPERTIES_TABLE(wxWindow)
-    wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
-    wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
-    wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
-    // Always constructor Properties first
-
-    wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
-    wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
-    wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
-    wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
-
-    // Then all relations of the object graph
-
-    wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
-
-   // and finally all other properties
-
-    wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
-    wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
-    wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
-    wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-#if 0
-    // possible property candidates (not in xrc) or not valid in all subclasses
-    wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString )
-    wxPROPERTY( Font , wxFont , SetFont , GetWindowFont  , )
-    wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString )
-    // MaxHeight, Width , MinHeight , Width
-    // TODO switch label to control and title to toplevels
-
-    wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
-    //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
-    // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
-    wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
-
-
-
-#endif
-wxEND_PROPERTIES_TABLE()
-
-wxBEGIN_HANDLERS_TABLE(wxWindow)
-wxEND_HANDLERS_TABLE()
-
-wxCONSTRUCTOR_DUMMY(wxWindow)
-
-#else
-    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
-#endif
-#endif // __WXUNIVERSAL__/__WXMSW__
+#endif // __WXUNIVERSAL__
 
 BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
     EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
-    EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
 #ifdef __WXWINCE__
     EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
 #endif
@@ -565,7 +499,9 @@ wxWindowMSW::~wxWindowMSW()
         //if (::IsWindow(GetHwnd()))
         {
             if ( !::DestroyWindow(GetHwnd()) )
+            {
                 wxLogLastError(wxT("DestroyWindow"));
+            }
         }
 
         // remove hWnd <-> wxWindow association
@@ -577,7 +513,7 @@ wxWindowMSW::~wxWindowMSW()
 /* static */
 const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
 {
-    return wxApp::GetRegisteredClassName(_T("wxWindow"), COLOR_BTNFACE);
+    return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE);
 }
 
 // real construction (Init() must have been called before!)
@@ -628,7 +564,7 @@ bool wxWindowMSW::Create(wxWindow *parent,
 void wxWindowMSW::SetFocus()
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
+    wxCHECK_RET( hWnd, wxT("can't set focus to invalid window") );
 
 #if !defined(__WXWINCE__)
     ::SetLastError(0);
@@ -643,7 +579,7 @@ void wxWindowMSW::SetFocus()
             HWND hwndFocus = ::GetFocus();
             if ( hwndFocus != hWnd )
             {
-                wxLogApiError(_T("SetFocus"), dwRes);
+                wxLogApiError(wxT("SetFocus"), dwRes);
             }
         }
     }
@@ -680,9 +616,21 @@ wxWindow *wxWindowBase::DoFindFocus()
 
 void wxWindowMSW::DoEnable( bool enable )
 {
-    HWND hWnd = GetHwnd();
-    if ( hWnd )
-        ::EnableWindow(hWnd, (BOOL)enable);
+    MSWEnableHWND(GetHwnd(), enable);
+}
+
+bool wxWindowMSW::MSWEnableHWND(WXHWND hWnd, bool enable)
+{
+    if ( !hWnd )
+        return false;
+
+    // If disabling focused control, we move focus to the next one, as if the
+    // user pressed Tab. That's because we can't keep focus on a disabled
+    // control, Tab-navigation would stop working then.
+    if ( !enable && ::GetFocus() == hWnd )
+        Navigate();
+
+    return ::EnableWindow(hWnd, (BOOL)enable) != 0;
 }
 
 bool wxWindowMSW::Show(bool show)
@@ -723,6 +671,9 @@ wxWindowMSW::MSWShowWithEffect(bool show,
                                wxShowEffect effect,
                                unsigned timeout)
 {
+    if ( effect == wxSHOW_EFFECT_NONE )
+        return Show(show);
+
     if ( !wxWindowBase::Show(show) )
         return false;
 
@@ -732,7 +683,7 @@ wxWindowMSW::MSWShowWithEffect(bool show,
     static bool s_initDone = false;
     if ( !s_initDone )
     {
-        wxDynamicLibrary dllUser32(_T("user32.dll"), wxDL_VERBATIM | wxDL_QUIET);
+        wxDynamicLibrary dllUser32(wxT("user32.dll"), wxDL_VERBATIM | wxDL_QUIET);
         wxDL_INIT_FUNC(s_pfn, AnimateWindow, dllUser32);
 
         s_initDone = true;
@@ -800,17 +751,17 @@ wxWindowMSW::MSWShowWithEffect(bool show,
 
 
         case wxSHOW_EFFECT_MAX:
-            wxFAIL_MSG( _T("invalid window show effect") );
+            wxFAIL_MSG( wxT("invalid window show effect") );
             return false;
 
         default:
-            wxFAIL_MSG( _T("unknown window show effect") );
+            wxFAIL_MSG( wxT("unknown window show effect") );
             return false;
     }
 
     if ( !(*s_pfnAnimateWindow)(GetHwnd(), timeout, dwFlags) )
     {
-        wxLogLastError(_T("AnimateWindow"));
+        wxLogLastError(wxT("AnimateWindow"));
 
         return false;
     }
@@ -844,7 +795,7 @@ void wxWindowMSW::DoReleaseMouse()
 {
     if ( !::ReleaseCapture() )
     {
-        wxLogLastError(_T("ReleaseCapture"));
+        wxLogLastError(wxT("ReleaseCapture"));
     }
 }
 
@@ -924,7 +875,7 @@ void wxWindowMSW::WarpPointer(int x, int y)
 
     if ( !::SetCursorPos(x, y) )
     {
-        wxLogLastError(_T("SetCursorPos"));
+        wxLogLastError(wxT("SetCursorPos"));
     }
 }
 
@@ -980,7 +931,7 @@ inline UINT WXOrientToSB(int orient)
 int wxWindowMSW::GetScrollPos(int orient) const
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
+    wxCHECK_MSG( hWnd, 0, wxT("no HWND in GetScrollPos") );
 
     return GetScrollPosition(hWnd, WXOrientToSB(orient));
 }
@@ -999,7 +950,7 @@ int wxWindowMSW::GetScrollRange(int orient) const
     {
         // Most of the time this is not really an error, since the return
         // value can also be zero when there is no scrollbar yet.
-        // wxLogLastError(_T("GetScrollInfo"));
+        // wxLogLastError(wxT("GetScrollInfo"));
     }
     maxPos = scrollInfo.nMax;
 
@@ -1015,7 +966,7 @@ int wxWindowMSW::GetScrollThumb(int orient) const
 void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
+    wxCHECK_RET( hWnd, wxT("SetScrollPos: no HWND") );
 
     WinStruct<SCROLLINFO> info;
     info.nPage = 0;
@@ -1054,10 +1005,14 @@ void wxWindowMSW::SetScrollbar(int orient,
         info.nMax = range - 1;      //  as both nMax and nMax are inclusive
         info.nPos = pos;
 
-        // enable the scrollbar if it had been disabled before by specifying
-        // SIF_DISABLENOSCROLL below: as we can't know whether this had been
-        // done or not just do it always
-        ::EnableScrollBar(hwnd, WXOrientToSB(orient), ESB_ENABLE_BOTH);
+        // We normally also reenable scrollbar in case it had been previously
+        // disabled by specifying SIF_DISABLENOSCROLL below but we should only
+        // do this if it has valid range, otherwise it would be enabled but not
+        // do anything.
+        if ( range >= pageSize )
+        {
+            ::EnableScrollBar(hwnd, WXOrientToSB(orient), ESB_ENABLE_BOTH);
+        }
     }
     //else: leave all the fields to be 0
 
@@ -1144,7 +1099,7 @@ void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
     wxUnusedVar(dir);
 #else
     wxCHECK_RET( GetHwnd(),
-                 _T("layout direction must be set after window creation") );
+                 wxT("layout direction must be set after window creation") );
 
     LONG styleOld = wxGetWindowExStyle(this);
 
@@ -1160,7 +1115,7 @@ void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
             break;
 
         default:
-            wxFAIL_MSG(_T("unsupported layout direction"));
+            wxFAIL_MSG(wxT("unsupported layout direction"));
             break;
     }
 
@@ -1176,7 +1131,7 @@ wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
 #ifdef __WXWINCE__
     return wxLayout_Default;
 #else
-    wxCHECK_MSG( GetHwnd(), wxLayout_Default, _T("invalid window") );
+    wxCHECK_MSG( GetHwnd(), wxLayout_Default, wxT("invalid window") );
 
     return wxHasWindowExStyle(this, WS_EX_LAYOUTRTL) ? wxLayout_RightToLeft
                                                      : wxLayout_LeftToRight;
@@ -1259,7 +1214,9 @@ void wxWindowMSW::AssociateHandle(WXWidget handle)
     if ( m_hWnd )
     {
       if ( !::DestroyWindow(GetHwnd()) )
+      {
         wxLogLastError(wxT("DestroyWindow"));
+      }
     }
 
     WXHWND wxhwnd = (WXHWND)handle;
@@ -1283,7 +1240,7 @@ bool wxCheckWindowWndProc(WXHWND hWnd,
     // TODO: get rid of wxTLWHiddenParent special case (currently it's not
     //       registered by wxApp but using ad hoc code in msw/toplevel.cpp);
     //       there is also a hidden window class used by sockets &c
-    return wxApp::IsRegisteredClassName(str) || str == _T("wxTLWHiddenParent");
+    return wxApp::IsRegisteredClassName(str) || str == wxT("wxTLWHiddenParent");
 }
 
 // ----------------------------------------------------------------------------
@@ -1388,9 +1345,10 @@ void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
                              exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
                                                          : HWND_NOTOPMOST,
                              0, 0, 0, 0,
-                             SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) )
+                             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
+                             SWP_FRAMECHANGED) )
         {
-            wxLogLastError(_T("SetWindowPos"));
+            wxLogLastError(wxT("SetWindowPos"));
         }
     }
 }
@@ -1484,7 +1442,7 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
         {
             default:
             case wxBORDER_DEFAULT:
-                wxFAIL_MSG( _T("unknown border style") );
+                wxFAIL_MSG( wxT("unknown border style") );
                 // fall through
 
             case wxBORDER_NONE:
@@ -1565,8 +1523,7 @@ void wxWindowMSW::OnInternalIdle()
     }
 #endif // !HAVE_TRACKMOUSEEVENT
 
-    if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
-        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+    wxWindowBase::OnInternalIdle();
 }
 
 // Set this window to be the child of 'parent'.
@@ -1651,7 +1608,7 @@ void wxWindowMSW::Update()
 {
     if ( !::UpdateWindow(GetHwnd()) )
     {
-        wxLogLastError(_T("UpdateWindow"));
+        wxLogLastError(wxT("UpdateWindow"));
     }
 
 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
@@ -1795,6 +1752,18 @@ void wxWindowMSW::DoGetClientSize(int *x, int *y) const
     if ( m_pendingSize != wxDefaultSize )
     {
         // we need to calculate the client size corresponding to pending size
+        //
+        // FIXME: Unfortunately this doesn't work correctly for the maximized
+        //        top level windows, the returned values are too small (e.g.
+        //        under Windows 7 on a 1600*1200 screen with task bar on the
+        //        right the pending size for a maximized window is 1538*1200
+        //        and WM_NCCALCSIZE returns 1528*1172 even though the correct
+        //        client size of such window is 1538*1182). No idea how to fix
+        //        it though, setting WS_MAXIMIZE in GWL_STYLE before calling
+        //        WM_NCCALCSIZE doesn't help and AdjustWindowRectEx() doesn't
+        //        work in this direction neither. So we just have to live with
+        //        the slightly wrong results and relayout the window when it
+        //        gets finally shown in its maximized state (see #11762).
         RECT rect;
         rect.left = m_pendingPosition.x;
         rect.top = m_pendingPosition.y;
@@ -1825,11 +1794,13 @@ void wxWindowMSW::DoGetPosition(int *x, int *y) const
     wxWindow * const parent = GetParent();
 
     wxPoint pos;
+#if wxUSE_DEFERRED_SIZING
     if ( m_pendingPosition != wxDefaultPosition )
     {
         pos = m_pendingPosition;
     }
     else // use current position
+#endif // wxUSE_DEFERRED_SIZING
     {
         RECT rect = wxGetWindowRect(GetHwnd());
 
@@ -1922,7 +1893,7 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
                                 SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
         if ( !hdwp )
         {
-            wxLogLastError(_T("DeferWindowPos"));
+            wxLogLastError(wxT("DeferWindowPos"));
         }
     }
 
@@ -2018,7 +1989,7 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
     {
         if ( sizeFlags & wxSIZE_AUTO_WIDTH )
         {
-            size = DoGetBestSize();
+            size = GetBestSize();
             width = size.x;
         }
         else
@@ -2034,9 +2005,9 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
         {
             if ( size.x == wxDefaultCoord )
             {
-                size = DoGetBestSize();
+                size = GetBestSize();
             }
-            //else: already called DoGetBestSize() above
+            //else: already called GetBestSize() above
 
             height = size.y;
         }
@@ -2108,11 +2079,41 @@ void wxWindowMSW::DoSetClientSize(int width, int height)
                            height + heightWin - rectClient.bottom,
                            TRUE) )
         {
-            wxLogLastError(_T("MoveWindow"));
+            wxLogLastError(wxT("MoveWindow"));
         }
     }
 }
 
+wxSize wxWindowMSW::DoGetBorderSize() const
+{
+    wxCoord border;
+    switch ( GetBorder() )
+    {
+        case wxBORDER_STATIC:
+        case wxBORDER_SIMPLE:
+            border = 1;
+            break;
+
+        case wxBORDER_SUNKEN:
+            border = 2;
+            break;
+
+        case wxBORDER_RAISED:
+        case wxBORDER_DOUBLE:
+            border = 3;
+            break;
+
+        default:
+            wxFAIL_MSG( wxT("unknown border style") );
+            // fall through
+
+        case wxBORDER_NONE:
+            border = 0;
+    }
+
+    return 2*wxSize(border, border);
+}
+
 // ---------------------------------------------------------------------------
 // text metrics
 // ---------------------------------------------------------------------------
@@ -2140,7 +2141,7 @@ void wxWindowMSW::DoGetTextExtent(const wxString& string,
                                   const wxFont *fontToUse) const
 {
     wxASSERT_MSG( !fontToUse || fontToUse->Ok(),
-                    _T("invalid font in GetTextExtent()") );
+                    wxT("invalid font in GetTextExtent()") );
 
     HFONT hfontToUse;
     if ( fontToUse )
@@ -2201,7 +2202,6 @@ static void wxYieldForCommandsOnly()
 
 bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
 {
-    menu->SetInvokingWindow(this);
     menu->UpdateUI();
 
     if ( x == wxDefaultCoord && y == wxDefaultCoord )
@@ -2244,8 +2244,6 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
     // for example) and so we do need to process the event immediately
     wxYieldForCommandsOnly();
 
-    menu->SetInvokingWindow(NULL);
-
     return true;
 }
 
@@ -2257,10 +2255,23 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
 
 WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
+    WXLRESULT rc;
     if ( m_oldWndProc )
-        return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+        rc = ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
     else
-        return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+        rc = ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+
+    // Special hack used by wxTextEntry auto-completion only: this event is
+    // sent after the normal keyboard processing so that its handler could use
+    // the updated contents of the text control, after taking the key that was
+    // pressed into account.
+    if ( nMsg == WM_CHAR )
+    {
+        wxKeyEvent event(CreateCharEvent(wxEVT_AFTER_CHAR, wParam, lParam));
+        HandleWindowEvent(event);
+    }
+
+    return rc;
 }
 
 bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
@@ -2284,7 +2295,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             // combinations which are always processed)
             LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
 
-            // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+            // surprisingly, DLGC_WANTALLKEYS bit mask doesn't contain the
             // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
             // it, of course, implies them
             if ( lDlgCode & DLGC_WANTALLKEYS )
@@ -2649,9 +2660,14 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
     // trace all messages: useful for the debugging but noticeably slows down
     // the code so don't do it by default
 #if wxDEBUG_LEVEL >= 2
-    wxLogTrace(wxTraceMessages,
+    // notice that we cast wParam and lParam to long to avoid mismatch with
+    // format specifiers in 64 bit builds where they are both int64 quantities
+    //
+    // casting like this loses information, of course, but it shouldn't matter
+    // much for this diagnostic code and it keeps the code simple
+    wxLogTrace("winmsg",
                wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"),
-               wxGetMessageName(message), hWnd, (long)wParam, lParam);
+               wxGetMessageName(message), hWnd, (long)wParam, (long)lParam);
 #endif // wxDEBUG_LEVEL >= 2
 
     wxWindowMSW *wnd = wxFindWinFromHandle(hWnd);
@@ -2740,7 +2756,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 }
             }
             break;
-#if 0
+
         case WM_ENTERSIZEMOVE:
             {
                 processed = HandleEnterSizeMove();
@@ -2752,7 +2768,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 processed = HandleExitSizeMove();
             }
             break;
-#endif
+
         case WM_SIZING:
             {
                 LPRECT pRect = (LPRECT)lParam;
@@ -2916,7 +2932,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
                     // this should never happen
                     wxCHECK_MSG( win, 0,
-                                 _T("FindWindowForMouseEvent() returned NULL") );
+                                 wxT("FindWindowForMouseEvent() returned NULL") );
                 }
 #ifdef __POCKETPC__
                 if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
@@ -3049,32 +3065,36 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
         case WM_SYSKEYDOWN:
         case WM_KEYDOWN:
-            // If this has been processed by an event handler, return 0 now
-            // (we've handled it).
+            // Generate the key down event in any case.
             m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
             if ( m_lastKeydownProcessed )
             {
+                // If it was processed by an event handler, we stop here,
+                // notably we intentionally don't generate char event then.
                 processed = true;
             }
-
-            if ( !processed )
+            else // key down event not handled
             {
+                // Examine the event to decide whether we need to generate a
+                // char event for it ourselves or let Windows do it. Window
+                // mostly only does it for the keys which produce printable
+                // characters (although there are exceptions, e.g. VK_ESCAPE or
+                // VK_BACK (but not VK_DELETE)) while we do it for all keys
+                // except the modifier ones (the wisdom of this is debatable
+                // but by now this decision is enshrined forever due to
+                // backwards compatibility).
                 switch ( wParam )
                 {
-                    // we consider these messages "not interesting" to OnChar, so
-                    // just don't do anything more with them
+                    // No wxEVT_CHAR events are generated for these keys at all.
                     case VK_SHIFT:
                     case VK_CONTROL:
                     case VK_MENU:
                     case VK_CAPITAL:
                     case VK_NUMLOCK:
                     case VK_SCROLL:
-                        processed = true;
-                        break;
 
-                    // avoid duplicate messages to OnChar for these ASCII keys:
-                    // they will be translated by TranslateMessage() and received
-                    // in WM_CHAR
+                    // Windows will send us WM_CHAR for these ones so we'll
+                    // generate wxEVT_CHAR for them later when we get it.
                     case VK_ESCAPE:
                     case VK_SPACE:
                     case VK_RETURN:
@@ -3084,6 +3104,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     case VK_SUBTRACT:
                     case VK_MULTIPLY:
                     case VK_DIVIDE:
+                    case VK_DECIMAL:
                     case VK_NUMPAD0:
                     case VK_NUMPAD1:
                     case VK_NUMPAD2:
@@ -3105,10 +3126,6 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     case VK_OEM_COMMA:
                     case VK_OEM_MINUS:
                     case VK_OEM_PERIOD:
-                        // 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
-                        processed = false;
                         break;
 
 #ifdef VK_APPS
@@ -3120,8 +3137,32 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif // VK_APPS
 
                     default:
-                        // do generate a CHAR event
-                        processed = HandleChar((WORD)wParam, lParam);
+                        if ( (wParam >= '0' && wParam <= '9') ||
+                                (wParam >= 'A' && wParam <= 'Z') )
+                        {
+                            // We'll get WM_CHAR for those later too.
+                            break;
+                        }
+
+                        // But for the rest we won't get WM_CHAR later so we do
+                        // need to generate the event right now.
+                        wxKeyEvent event(wxEVT_CHAR);
+                        InitAnyKeyEvent(event, wParam, lParam);
+
+                        // Set the "extended" bit in lParam because we want to
+                        // generate CHAR events with WXK_HOME and not
+                        // WXK_NUMPAD_HOME even if the "Home" key on numpad was
+                        // pressed.
+                        event.m_keyCode = wxMSWKeyboard::VKToWX
+                                          (
+                                            wParam,
+                                            lParam | (KF_EXTENDED << 16)
+                                          );
+
+                        // Don't produce events without any valid character
+                        // code (even if this shouldn't normally happen...).
+                        if ( event.m_keyCode != WXK_NONE )
+                            processed = HandleWindowEvent(event);
                 }
             }
             if (message == WM_SYSKEYDOWN)  // Let Windows still handle the SYSKEYs
@@ -3155,10 +3196,21 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             }
             else
             {
-                processed = HandleChar((WORD)wParam, lParam, true);
+                processed = HandleChar((WORD)wParam, lParam);
             }
             break;
 
+        case WM_IME_STARTCOMPOSITION:
+            // IME popup needs Escape as it should undo the changes in its
+            // entry window instead of e.g. closing the dialog for which the
+            // IME is used (and losing all the changes in the IME window).
+            gs_modalEntryWindowCount++;
+            break;
+
+        case WM_IME_ENDCOMPOSITION:
+            gs_modalEntryWindowCount--;
+            break;
+
 #if wxUSE_HOTKEY
         case WM_HOTKEY:
             processed = HandleHotKey((WORD)wParam, lParam);
@@ -3232,7 +3284,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 
         case WM_ERASEBKGND:
-            processed = HandleEraseBkgnd((WXHDC)wParam);
+            {
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                // check if an override was configured for this window
+                EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this);
+                if ( it != gs_eraseBgHooks.end() )
+                    processed = it->second->MSWEraseBgHook((WXHDC)wParam);
+                else
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                    processed = HandleEraseBkgnd((WXHDC)wParam);
+            }
+
             if ( processed )
             {
                 // we processed the message, i.e. erased the background
@@ -3412,9 +3474,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     // now alter the client size making room for drawing a
                     // themed border
                     RECT *rect;
+                    NCCALCSIZE_PARAMS *csparam = NULL;
                     if ( wParam )
                     {
-                        NCCALCSIZE_PARAMS *csparam = (NCCALCSIZE_PARAMS *)lParam;
+                        csparam = (NCCALCSIZE_PARAMS *)lParam;
                         rect = &csparam->rgrc[0];
                     }
                     else
@@ -3437,8 +3500,14 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                                  &rcClient) == S_OK )
                     {
                         InflateRect(&rcClient, -1, -1);
-                        *rect = rcClient;
-                        rc.result = WVR_REDRAW;
+                        if (wParam)
+                            csparam->rgrc[0] = rcClient;
+                        else
+                            *((RECT*)lParam) = rcClient;
+
+                        // WVR_REDRAW triggers a bug whereby child windows are moved up and left,
+                        // so don't use.
+                        // rc.result = WVR_REDRAW;
                     }
                 }
             }
@@ -3505,7 +3574,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
     if ( !processed )
     {
 #if wxDEBUG_LEVEL >= 2
-        wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
+        wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
                    wxGetMessageName(message));
 #endif // wxDEBUG_LEVEL >= 2
         rc.result = MSWDefWindowProc(message, wParam, lParam);
@@ -3568,33 +3637,22 @@ void wxWindowMSW::MSWDestroyWindow()
 {
 }
 
-bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+void wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
                                            const wxSize& size,
                                            int& x, int& y,
                                            int& w, int& h) const
 {
-    // yes, those are just some arbitrary hardcoded numbers
-    static const int DEFAULT_Y = 200;
-
-    bool nonDefault = false;
+    // CW_USEDEFAULT can't be used for child windows so just position them at
+    // the origin by default
+    x = pos.x == wxDefaultCoord ? 0 : pos.x;
+    y = pos.y == wxDefaultCoord ? 0 : pos.y;
 
-    if ( pos.x == wxDefaultCoord )
-    {
-        // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
-        // can just as well set it to CW_USEDEFAULT as well
-        x =
-        y = CW_USEDEFAULT;
-    }
-    else
-    {
-        // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
-        // neither because it is not handled as a special value by Windows then
-        // and so we have to choose some default value for it
-        x = pos.x;
-        y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
+    AdjustForParentClientOrigin(x, y);
 
-        nonDefault = true;
-    }
+    // We don't have any clearly good choice for the size by default neither
+    // but we must use something non-zero.
+    w = WidthDefault(size.x);
+    h = HeightDefault(size.y);
 
     /*
       NB: there used to be some code here which set the initial size of the
@@ -3612,49 +3670,6 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
           this and ignore any attempts to change the window size to the size it
           already has - so no WM_SIZE would be sent.
      */
-
-
-    // we don't use CW_USEDEFAULT here for several reasons:
-    //
-    //  1. it results in huge frames on modern screens (1000*800 is not
-    //     uncommon on my 1280*1024 screen) which is way too big for a half
-    //     empty frame of most of wxWidgets samples for example)
-    //
-    //  2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
-    //     the default is for whatever reason 8*8 which breaks client <->
-    //     window size calculations (it would be nice if it didn't, but it
-    //     does and the simplest way to fix it seemed to change the broken
-    //     default size anyhow)
-    //
-    //  3. there is just no advantage in doing it: with x and y it is
-    //     possible that [future versions of] Windows position the new top
-    //     level window in some smart way which we can't do, but we can
-    //     guess a reasonably good size for a new window just as well
-    //     ourselves
-
-    // However, on PocketPC devices, we must use the default
-    // size if possible.
-#ifdef _WIN32_WCE
-    if (size.x == wxDefaultCoord)
-        w = CW_USEDEFAULT;
-    else
-        w = size.x;
-    if (size.y == wxDefaultCoord)
-        h = CW_USEDEFAULT;
-    else
-        h = size.y;
-#else
-    if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
-    {
-        nonDefault = true;
-    }
-    w = WidthDefault(size.x);
-    h = HeightDefault(size.y);
-#endif
-
-    AdjustForParentClientOrigin(x, y);
-
-    return nonDefault;
 }
 
 WXHWND wxWindowMSW::MSWGetParent() const
@@ -3832,7 +3847,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
 
         if ( !len )
         {
-            wxLogLastError(_T("MultiByteToWideChar()"));
+            wxLogLastError(wxT("MultiByteToWideChar()"));
         }
 
         buf[len] = L'\0';
@@ -3956,8 +3971,7 @@ bool wxWindowMSW::HandleDestroy()
     {
         m_dropTarget->Revoke(m_hWnd);
 
-        delete m_dropTarget;
-        m_dropTarget = NULL;
+        wxDELETE(m_dropTarget);
     }
 #endif // wxUSE_DRAG_AND_DROP
 
@@ -4152,6 +4166,8 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
             y = pt.y;
         ScreenToClient(&x, &y);
         wxSetCursorEvent event(x, y);
+        event.SetId(GetId());
+        event.SetEventObject(this);
 
         bool processedEvtSetCursor = HandleWindowEvent(event);
         if ( processedEvtSetCursor && event.HasCursor() )
@@ -4223,7 +4239,7 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
             break;
 
         default:
-            wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam);
+            wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%d) event"), wParam);
             // fall through
 
         // these messages are currently not mapped to wx events
@@ -4316,7 +4332,7 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
             return false;
 
         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
-                         false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
+                         false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") );
 
         // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
         // the DC from being released
@@ -4382,7 +4398,7 @@ wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
             return false;
 
         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
-                        false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
+                        false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") );
 
         size_t w, h;
         bool rc = pMenuItem->OnMeasureItem(&w, &h);
@@ -4609,12 +4625,12 @@ extern wxCOLORMAP *wxGetStdColourMap()
             // reference bitmap which can tell us what the RGB values change
             // to.
             wxLogNull logNo; // suppress error if we couldn't load the bitmap
-            wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
+            wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS"));
             if ( stdColourBitmap.Ok() )
             {
                 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
                 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
-                              _T("forgot to update wxBITMAP_STD_COLOURS!") );
+                              wxT("forgot to update wxBITMAP_STD_COLOURS!") );
 
                 wxMemoryDC memDC;
                 memDC.SelectObject(stdColourBitmap);
@@ -4657,25 +4673,110 @@ extern wxCOLORMAP *wxGetStdColourMap()
     return s_cmap;
 }
 
+#if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR)
+    #define TMT_FILLCOLOR       3802
+    #define TMT_TEXTCOLOR       3803
+    #define TMT_BORDERCOLOR     3801
+#endif
+
+wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
+                                        int themePart,
+                                        int themeState,
+                                        MSWThemeColour themeColour,
+                                        wxSystemColour fallback) const
+{
+#if wxUSE_UXTHEME
+    const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+    if ( theme )
+    {
+        int themeProperty = 0;
+
+        // TODO: Convert this into a table? Sure would be faster.
+        switch ( themeColour )
+        {
+            case ThemeColourBackground:
+                themeProperty = TMT_FILLCOLOR;
+                break;
+            case ThemeColourText:
+                themeProperty = TMT_TEXTCOLOR;
+                break;
+            case ThemeColourBorder:
+                themeProperty = TMT_BORDERCOLOR;
+                break;
+            default:
+                wxFAIL_MSG(wxT("unsupported theme colour"));
+        };
+
+        wxUxThemeHandle hTheme((const wxWindow *)this, themeName);
+        COLORREF col;
+        HRESULT hr = theme->GetThemeColor
+                            (
+                                hTheme,
+                                themePart,
+                                themeState,
+                                themeProperty,
+                                &col
+                            );
+
+        if ( SUCCEEDED(hr) )
+            return wxRGBToColour(col);
+
+        wxLogApiError(
+            wxString::Format(
+                "GetThemeColor(%s, %i, %i, %i)",
+                themeName, themePart, themeState, themeProperty),
+            hr);
+    }
+#else
+    wxUnusedVar(themeName);
+    wxUnusedVar(themePart);
+    wxUnusedVar(themeState);
+    wxUnusedVar(themeColour);
+#endif
+    return wxSystemSettings::GetColour(fallback);
+}
+
 // ---------------------------------------------------------------------------
 // painting
 // ---------------------------------------------------------------------------
 
+// this variable is used to check that a paint event handler which processed
+// the event did create a wxPaintDC inside its code and called BeginPaint() to
+// validate the invalidated window area as otherwise we'd keep getting an
+// endless stream of WM_PAINT messages for this window resulting in a lot of
+// difficult to debug problems (e.g. impossibility to repaint other windows,
+// lack of timer and idle events and so on)
+extern bool wxDidCreatePaintDC;
+bool wxDidCreatePaintDC = false;
+
 bool wxWindowMSW::HandlePaint()
 {
     HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
     if ( !hRegion )
+    {
         wxLogLastError(wxT("CreateRectRgn"));
+    }
     if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
+    {
         wxLogLastError(wxT("GetUpdateRgn"));
+    }
 
     m_updateRegion = wxRegion((WXHRGN) hRegion);
 
+    wxDidCreatePaintDC = false;
+
     wxPaintEvent event(m_windowId);
     event.SetEventObject(this);
 
     bool processed = HandleWindowEvent(event);
 
+    if ( processed && !wxDidCreatePaintDC )
+    {
+        // do call MSWDefWindowProc() to validate the update region to avoid
+        // the problems mentioned above
+        processed = false;
+    }
+
     // note that we must generate NC event after the normal one as otherwise
     // BeginPaint() will happily overwrite our decorations with the background
     // colour
@@ -4706,105 +4807,158 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event)
 
 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 {
-    wxDCTemp dc(hdc, GetClientSize());
-    wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();
+    switch ( GetBackgroundStyle() )
+    {
+        case wxBG_STYLE_ERASE:
+        case wxBG_STYLE_COLOUR:
+            // we need to generate an erase background event
+            {
+                wxDCTemp dc(hdc, GetClientSize());
+                wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();
 
-    impl->SetHDC(hdc);
-    impl->SetWindow((wxWindow *)this);
+                impl->SetHDC(hdc);
+                impl->SetWindow((wxWindow *)this);
 
-    wxEraseEvent event(m_windowId, &dc);
-    event.SetEventObject(this);
-    bool rc = HandleWindowEvent(event);
+                wxEraseEvent event(m_windowId, &dc);
+                event.SetEventObject(this);
+                bool rc = HandleWindowEvent(event);
 
-    // must be called manually as ~wxDC doesn't do anything for wxDCTemp
-    impl->SelectOldObjects(hdc);
+                // must be called manually as ~wxDC doesn't do anything for
+                // wxDCTemp
+                impl->SelectOldObjects(hdc);
 
-    return rc;
+                if ( rc )
+                {
+                    // background erased by the user-defined handler
+                    return true;
+                }
+            }
+            // fall through
+
+        case wxBG_STYLE_SYSTEM:
+            if ( !DoEraseBackground(hdc) )
+            {
+                // let the default processing to take place if we didn't erase
+                // the background ourselves
+                return false;
+            }
+            break;
+
+        case wxBG_STYLE_PAINT:
+        case wxBG_STYLE_TRANSPARENT:
+            // no need to do anything here at all, background will be entirely
+            // redrawn in WM_PAINT handler
+            break;
+
+        default:
+            wxFAIL_MSG( "unknown background style" );
+    }
+
+    return true;
 }
 
-void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+bool wxWindowMSW::MSWHasEraseBgHook() const
 {
-    // standard non top level controls (i.e. except the dialogs) always erase
-    // their background themselves in HandleCtlColor() or have some control-
-    // specific ways to set the colours (common controls)
-    if ( IsOfStandardClass() && !IsTopLevel() )
-    {
-        event.Skip();
-        return;
-    }
+    return gs_eraseBgHooks.find(const_cast<wxWindowMSW *>(this))
+                != gs_eraseBgHooks.end();
+}
 
-    if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
+void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
+{
+    if ( child )
     {
-        // don't skip the event here, custom background means that the app
-        // is drawing it itself in its OnPaint(), so don't draw it at all
-        // now to avoid flicker
-        return;
+        if ( !gs_eraseBgHooks.insert(
+                EraseBgHooks::value_type(this, child)).second )
+        {
+            wxFAIL_MSG( wxT("Setting erase background hook twice?") );
+        }
     }
-
-    wxDC *dc = event.GetDC();
-    if (!dc) return;
-    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl();
-
-    // do default background painting
-    if ( !DoEraseBackground(GetHdcOf(*impl)) )
+    else // reset the hook
     {
-        // let the system paint the background
-        event.Skip();
+        if ( gs_eraseBgHooks.erase(this) != 1 )
+        {
+            wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
+        }
     }
 }
 
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
 {
     HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
     if ( !hbr )
         return false;
 
-    wxFillRect(GetHwnd(), (HDC)hDC, hbr);
+    // erase just the client area of the window, this is important for the
+    // frames to avoid drawing over the toolbar part of the window (you might
+    // think using WS_CLIPCHILDREN would prevent this from happening, but it
+    // clearly doesn't)
+    RECT rc;
+    wxCopyRectToRECT(GetClientRect(), rc);
+    ::FillRect((HDC)hDC, &rc, hbr);
 
     return true;
 }
 
 WXHBRUSH
-wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd)
+wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
 {
-    if ( m_hasBgCol )
+    // Test for the custom background brush first.
+    WXHBRUSH hbrush = MSWGetCustomBgBrush();
+    if ( hbrush )
     {
-        // our background colour applies to:
-        //  1. this window itself, always
-        //  2. all children unless the colour is "not inheritable"
-        //  3. even if it is not inheritable, our immediate transparent
-        //     children should still inherit it -- but not any transparent
-        //     children because it would look wrong if a child of non
-        //     transparent child would show our bg colour when the child itself
-        //     does not
-        wxWindow *win = wxFindWinFromHandle(hWnd);
-        if ( win == this ||
-                m_inheritBgCol ||
-                    (win && win->HasTransparentBackground() &&
-                        win->GetParent() == this) )
-        {
-            // draw children with the same colour as the parent
-            wxBrush *
-                brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
+        // We assume that this is either a stipple or hatched brush and not a
+        // solid one as otherwise it would have been enough to set the
+        // background colour and such brushes need to be positioned correctly
+        // in order to align when different windows are painted, so do it here.
+        RECT rc;
+        ::GetWindowRect(GetHwndOf(child), &rc);
+
+        ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
 
-            return (WXHBRUSH)GetHbrushOf(*brush);
+        if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
+        {
+            wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
         }
+
+        return hbrush;
+    }
+
+    // Otherwise see if we have a custom background colour.
+    if ( m_hasBgCol )
+    {
+        wxBrush *
+            brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
+
+        return (WXHBRUSH)GetHbrushOf(*brush);
     }
 
     return 0;
 }
 
-WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint)
+WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
 {
-    if ( !hWndToPaint )
-        hWndToPaint = GetHWND();
+    // Use the special wxWindowBeingErased variable if it is set as the child
+    // being erased.
+    wxWindowMSW * const child =
+#if wxUSE_UXTHEME
+                                wxWindowBeingErased ? wxWindowBeingErased :
+#endif
+                                this;
 
     for ( wxWindowMSW *win = this; win; win = win->GetParent() )
     {
-        WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint);
+        WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child);
         if ( hBrush )
             return hBrush;
 
+        // don't use the parent background if we're not transparent
+        if ( !win->HasTransparentBackground() )
+            break;
+
         // background is not inherited beyond top level windows
         if ( win->IsTopLevel() )
             break;
@@ -4928,7 +5082,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
             m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
             if ( !m_hDWP )
             {
-                wxLogLastError(_T("BeginDeferWindowPos"));
+                wxLogLastError(wxT("BeginDeferWindowPos"));
             }
             if (m_hDWP)
                 useDefer = true;
@@ -4941,7 +5095,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
     switch ( wParam )
     {
         default:
-            wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
+            wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") );
             // fall through nevertheless
 
         case SIZE_MAXHIDE:
@@ -4981,7 +5135,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
         // do put all child controls in place at once
         if ( !::EndDeferWindowPos(hDWP) )
         {
-            wxLogLastError(_T("EndDeferWindowPos"));
+            wxLogLastError(wxT("EndDeferWindowPos"));
         }
 
         // Reset our children's pending pos/size values.
@@ -5176,7 +5330,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 // still don't get move, enter nor leave events.
 static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
 {
-    wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
+    wxCHECK_MSG( x && y, win, wxT("NULL pointer in FindWindowForMouseEvent") );
 
     // first try to find a non transparent child: this allows us to send events
     // to a static text which is inside a static box, for example
@@ -5300,11 +5454,11 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
             {
                 // see comment in wxApp::GetComCtl32Version() explaining the
                 // use of wxLoadedDLL
-                wxLoadedDLL dllComCtl32(_T("comctl32.dll"));
+                wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
                 if ( dllComCtl32.IsLoaded() )
                 {
                     s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
-                        dllComCtl32.RawGetSymbol(_T("_TrackMouseEvent"));
+                        dllComCtl32.RawGetSymbol(wxT("_TrackMouseEvent"));
                 }
 
                 s_initDone = true;
@@ -5386,7 +5540,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
                                      &s_linesPerRotation, 0))
         {
             // this is not supposed to happen
-            wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
+            wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)"));
 
             // the default is 3, so use it if SystemParametersInfo() failed
             s_linesPerRotation = 3;
@@ -5429,7 +5583,7 @@ void wxWindowMSW::GenerateMouseLeave()
     if ( !::GetCursorPos(&pt) )
 #endif
     {
-        wxLogLastError(_T("GetCursorPos"));
+        wxLogLastError(wxT("GetCursorPos"));
     }
 
     // we need to have client coordinates here for symmetry with
@@ -5448,73 +5602,128 @@ void wxWindowMSW::GenerateMouseLeave()
 // keyboard handling
 // ---------------------------------------------------------------------------
 
-// create the key event of the given type for the given key - used by
-// HandleChar and HandleKeyDown/Up
-wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
-                                       int id,
-                                       WXLPARAM lParam,
-                                       WXWPARAM wParam) const
+namespace
 {
-    wxKeyEvent event(evType);
-    event.SetId(GetId());
+
+// Implementation of InitAnyKeyEvent() which can also be used when there is no
+// associated window: this can happen for the wxEVT_CHAR_HOOK events created by
+// the global keyboard hook (e.g. the event might have happened in a non-wx
+// window).
+void
+MSWInitAnyKeyEvent(wxKeyEvent& event,
+                   WXWPARAM wParam,
+                   WXLPARAM lParam,
+                   const wxWindowBase *win /* may be NULL */)
+{
+    if ( win )
+    {
+        event.SetId(win->GetId());
+        event.SetEventObject(const_cast<wxWindowBase *>(win));
+    }
+    else // No associated window.
+    {
+        // Use wxID_ANY for compatibility with the old code even if wxID_NONE
+        // would arguably make more sense.
+        event.SetId(wxID_ANY);
+    }
+
     event.m_shiftDown = wxIsShiftDown();
     event.m_controlDown = wxIsCtrlDown();
     event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
 
-    event.SetEventObject((wxWindow *)this); // const_cast
-    event.m_keyCode = id;
-#if wxUSE_UNICODE
-    event.m_uniChar = (wxChar) wParam;
-#endif
     event.m_rawCode = (wxUint32) wParam;
     event.m_rawFlags = (wxUint32) lParam;
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
 #endif
 
-    // translate the position to client coords
-    POINT pt;
-#ifdef __WXWINCE__
-    GetCursorPosWinCE(&pt);
-#else
-    GetCursorPos(&pt);
-#endif
-    RECT rect;
-    GetWindowRect(GetHwnd(),&rect);
-    pt.x -= rect.left;
-    pt.y -= rect.top;
+    // Event coordinates must be in window client coordinates system which
+    // doesn't make sense if there is no window.
+    //
+    // We could use screen coordinates for such events but this would make the
+    // logic of the event handlers more complicated: you'd need to test for the
+    // event object and interpret the coordinates differently according to
+    // whether it's NULL or not so unless somebody really asks for this let's
+    // just avoid the issue.
+    if ( win )
+    {
+        const wxPoint mousePos = win->ScreenToClient(wxGetMousePosition());
+        event.m_x = mousePos.x;
+        event.m_y = mousePos.y;
+    }
+}
 
-    event.m_x = pt.x;
-    event.m_y = pt.y;
+} // anonymous namespace
+
+void
+wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
+                             WXWPARAM wParam,
+                             WXLPARAM lParam) const
+{
+    MSWInitAnyKeyEvent(event, wParam, lParam, this);
+}
+
+wxKeyEvent
+wxWindowMSW::CreateKeyEvent(wxEventType evType,
+                            WXWPARAM wParam,
+                            WXLPARAM lParam) const
+{
+    // Catch any attempts to use this with WM_CHAR, it wouldn't work because
+    // wParam is supposed to be a virtual key and not a character here.
+    wxASSERT_MSG( evType != wxEVT_CHAR && evType != wxEVT_CHAR_HOOK,
+                    "CreateKeyEvent() can't be used for char events" );
+
+    wxKeyEvent event(evType);
+    InitAnyKeyEvent(event, wParam, lParam);
+
+    event.m_keyCode = wxMSWKeyboard::VKToWX
+                                     (
+                                        wParam,
+                                        lParam
+#if wxUSE_UNICODE
+                                        , &event.m_uniChar
+#endif // wxUSE_UNICODE
+                                     );
 
     return event;
 }
 
-// isASCII is true only when we're called from WM_CHAR handler and not from
-// WM_KEYDOWN one
-bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
+wxKeyEvent
+wxWindowMSW::CreateCharEvent(wxEventType evType,
+                             WXWPARAM wParam,
+                             WXLPARAM lParam) const
 {
-    int id;
-    if ( isASCII )
+    wxKeyEvent event(evType);
+    InitAnyKeyEvent(event, wParam, lParam);
+
+#if wxUSE_UNICODE
+    // TODO: wParam uses UTF-16 so this is incorrect for characters outside of
+    //       the BMP, we should use WM_UNICHAR to handle them.
+    event.m_uniChar = wParam;
+#endif // wxUSE_UNICODE
+
+    // Set non-Unicode key code too for compatibility if possible.
+    if ( wParam < 0x80 )
     {
-        id = wParam;
+        // It's an ASCII character, no need to translate it.
+        event.m_keyCode = wParam;
     }
-    else // we're called from WM_KEYDOWN
+    else
     {
-        // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
-        // to get numpad key codes: CHAR events should use the logical keys
-        // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
-        id = wxCharCodeMSWToWX(wParam);
-        if ( id == 0 )
+        // Check if this key can be represented (as a single character) in the
+        // current locale.
+        const wchar_t wc = wParam;
+        char ch;
+        if ( wxConvLibc.FromWChar(&ch, 1, &wc, 1) != wxCONV_FAILED )
         {
-            // it's ASCII and will be processed here only when called from
-            // WM_CHAR (i.e. when isASCII = true), don't process it now
-            return false;
+            // For compatibility continue to provide the key code in this field
+            // even though using GetUnicodeKey() is recommended now.
+            event.m_keyCode = static_cast<unsigned char>(ch);
         }
+        //else: Key can't be represented in the current locale, leave m_keyCode
+        //      as WXK_NONE and use GetUnicodeKey() to access the character.
     }
 
-    wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
-
     // the alphanumeric keys produced by pressing AltGr+something on European
     // keyboards have both Ctrl and Alt modifiers which may confuse the user
     // code as, normally, keys with Ctrl and/or Alt don't result in anything
@@ -5522,40 +5731,32 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
     // KEY_DOWN event would still have the correct modifiers if they're really
     // needed)
     if ( event.m_controlDown && event.m_altDown &&
-            (id >= 32 && id < 256) )
+            (event.m_keyCode >= 32 && event.m_keyCode < 256) )
     {
         event.m_controlDown =
         event.m_altDown = false;
     }
 
+    return event;
+}
+
+// isASCII is true only when we're called from WM_CHAR handler and not from
+// WM_KEYDOWN one
+bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
+{
+    wxKeyEvent event(CreateCharEvent(wxEVT_CHAR, wParam, lParam));
     return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int id = wxCharCodeMSWToWX(wParam, lParam);
-
-    if ( !id )
-    {
-        // normal ASCII char
-        id = wParam;
-    }
-
-    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
+    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
     return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int id = wxCharCodeMSWToWX(wParam, lParam);
-
-    if ( !id )
-    {
-        // normal ASCII char
-        id = wParam;
-    }
-
-    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
+    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, wParam, lParam));
     return HandleWindowEvent(event);
 }
 
@@ -5594,13 +5795,14 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                 //  menu creation code
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
-                const wxChar *p = wxStrchr(item->GetItemLabel().wx_str(), _T('&'));
+                const wxString label(item->GetItemLabel());
+                const wxChar *p = wxStrchr(label.wx_str(), wxT('&'));
                 while ( p++ )
                 {
-                    if ( *p == _T('&') )
+                    if ( *p == wxT('&') )
                     {
                         // this is not the accel char, find the real one
-                        p = wxStrchr(p + 1, _T('&'));
+                        p = wxStrchr(p + 1, wxT('&'));
                     }
                     else // got the accel char
                     {
@@ -5623,7 +5825,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
         else // failed to get the menu text?
         {
             // it's not fatal, so don't show error, but still log it
-            wxLogLastError(_T("GetMenuItemInfo"));
+            wxLogLastError(wxT("GetMenuItemInfo"));
         }
     }
 #endif
@@ -5797,7 +5999,7 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
                                   &scrollInfo) )
             {
                 // Not necessarily an error, if there are no scrollbars yet.
-                // wxLogLastError(_T("GetScrollInfo"));
+                // wxLogLastError(wxT("GetScrollInfo"));
             }
 
             event.SetPosition(scrollInfo.nTrackPos);
@@ -5823,7 +6025,7 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
 wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
 {
     wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
-                 false, _T("registering handler for the same message twice") );
+                 false, wxT("registering handler for the same message twice") );
 
     gs_messageHandlers[msg] = handler;
     return true;
@@ -5834,7 +6036,7 @@ wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
 {
     const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
     wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
-                 _T("unregistering non-registered handler?") );
+                 wxT("unregistering non-registered handler?") );
 
     gs_messageHandlers.erase(i);
 }
@@ -5870,24 +6072,34 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
     //   the_font.ReleaseResource();
 }
 
-// use the "extended" bit (24) of lParam to distinguish extended keys
-// from normal keys as the same key is sent
-static inline
+// ----------------------------------------------------------------------------
+// keyboard codes
+// ----------------------------------------------------------------------------
+
+namespace wxMSWKeyboard
+{
+
+namespace
+{
+
+// use the "extended" bit of lParam to distinguish extended keys from normal
+// keys as the same virtual key code is sent for both by Windows
+inline
 int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
 {
     // except that if lParam is 0, it means we don't have real lParam from
     // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
     // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
     // non-numpad (hence extended) key as this is a more common case
-    return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
+    return !lParam || (HIWORD(lParam) & KF_EXTENDED) ? keyExtended : keyNormal;
 }
 
 // this array contains the Windows virtual key codes which map one to one to
-// WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
+// WXK_xxx constants and is used in wxMSWKeyboard::VKToWX/WXToVK() below
 //
 // note that keys having a normal and numpad version (e.g. WXK_HOME and
 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
-static const struct wxKeyMapping
+const struct wxKeyMapping
 {
     int vk;
     wxKeyCode wxk;
@@ -5961,34 +6173,75 @@ static const struct wxKeyMapping
 #endif // VK_APPS defined
 };
 
-// Returns 0 if was a normal ASCII value, not a special key. This indicates that
-// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
-int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
+} // anonymous namespace
+
+int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
 {
+    int wxk;
+
     // check the table first
     for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
     {
         if ( gs_specialKeys[n].vk == vk )
-            return gs_specialKeys[n].wxk;
+        {
+            wxk = gs_specialKeys[n].wxk;
+            if ( wxk < WXK_START )
+            {
+                // Unicode code for this key is the same as its ASCII code.
+                if ( uc )
+                    *uc = wxk;
+            }
+
+            return wxk;
+        }
     }
 
     // keys requiring special handling
-    int wxk;
     switch ( vk )
     {
-        // the mapping for these keys may be incorrect on non-US keyboards so
-        // maybe we shouldn't map them to ASCII values at all
-        case VK_OEM_1:      wxk = ';'; break;
-        case VK_OEM_PLUS:   wxk = '+'; break;
-        case VK_OEM_COMMA:  wxk = ','; break;
-        case VK_OEM_MINUS:  wxk = '-'; break;
-        case VK_OEM_PERIOD: wxk = '.'; break;
-        case VK_OEM_2:      wxk = '/'; break;
-        case VK_OEM_3:      wxk = '~'; break;
-        case VK_OEM_4:      wxk = '['; break;
-        case VK_OEM_5:      wxk = '\\'; break;
-        case VK_OEM_6:      wxk = ']'; break;
-        case VK_OEM_7:      wxk = '\''; break;
+        case VK_OEM_1:
+        case VK_OEM_PLUS:
+        case VK_OEM_COMMA:
+        case VK_OEM_MINUS:
+        case VK_OEM_PERIOD:
+        case VK_OEM_2:
+        case VK_OEM_3:
+        case VK_OEM_4:
+        case VK_OEM_5:
+        case VK_OEM_6:
+        case VK_OEM_7:
+            // MapVirtualKey() returns 0 if it fails to convert the virtual
+            // key which nicely corresponds to our WXK_NONE.
+            wxk = ::MapVirtualKey(vk, MAPVK_VK_TO_CHAR);
+
+            if ( HIWORD(wxk) & 0x8000 )
+            {
+                // It's a dead key and we don't return anything at all for them
+                // as we simply don't have any way to indicate the difference
+                // between e.g. a normal "'" and "'" as a dead key -- and
+                // generating the same events for them just doesn't seem like a
+                // good idea.
+                wxk = WXK_NONE;
+            }
+
+            // In any case return this as a Unicode character value.
+            if ( uc )
+                *uc = wxk;
+
+            // For compatibility with the old non-Unicode code we continue
+            // returning key codes for Latin-1 characters directly
+            // (normally it would really only make sense to do it for the
+            // ASCII characters, not Latin-1 ones).
+            if ( wxk > 255 )
+            {
+                // But for anything beyond this we can only return the key
+                // value as a real Unicode character, not a wxKeyCode
+                // because this enum values clash with Unicode characters
+                // (e.g. WXK_LBUTTON also happens to be U+012C a.k.a.
+                // "LATIN CAPITAL LETTER I WITH BREVE").
+                wxk = WXK_NONE;
+            }
+            break;
 
         // handle extended keys
         case VK_PRIOR:
@@ -6034,78 +6287,106 @@ int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
         case VK_RETURN:
             // don't use ChooseNormalOrExtended() here as the keys are reversed
             // here: numpad enter is the extended one
-            wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
+            wxk = HIWORD(lParam) & KF_EXTENDED ? WXK_NUMPAD_ENTER : WXK_RETURN;
             break;
 
         default:
-            wxk = 0;
+            if ( (vk >= '0' && vk <= '9') || (vk >= 'A' && vk <= 'Z') )
+            {
+                // A simple alphanumeric key and the values of them coincide in
+                // Windows and wx for both ASCII and Unicode codes.
+                wxk = vk;
+            }
+            else // Something we simply don't know about at all.
+            {
+                wxk = WXK_NONE;
+            }
+
+            if ( uc )
+                *uc = vk;
     }
 
     return wxk;
 }
 
-WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
+WXWORD WXToVK(int wxk, bool *isExtended)
 {
-    if ( isVirtual )
-        *isVirtual = true;
-
     // check the table first
     for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
     {
         if ( gs_specialKeys[n].wxk == wxk )
+        {
+            // All extended keys (i.e. non-numpad versions of the keys that
+            // exist both in the numpad and outside of it) are dealt with
+            // below.
+            if ( isExtended )
+                *isExtended = false;
+
             return gs_specialKeys[n].vk;
+        }
     }
 
     // and then check for special keys not included in the table
+    bool extended = false;
     WXWORD vk;
     switch ( wxk )
     {
         case WXK_PAGEUP:
+            extended = true;
         case WXK_NUMPAD_PAGEUP:
             vk = VK_PRIOR;
             break;
 
         case WXK_PAGEDOWN:
+            extended = true;
         case WXK_NUMPAD_PAGEDOWN:
             vk = VK_NEXT;
             break;
 
         case WXK_END:
+            extended = true;
         case WXK_NUMPAD_END:
             vk = VK_END;
             break;
 
         case WXK_HOME:
+            extended = true;
         case WXK_NUMPAD_HOME:
             vk = VK_HOME;
             break;
 
         case WXK_LEFT:
+            extended = true;
         case WXK_NUMPAD_LEFT:
             vk = VK_LEFT;
             break;
 
         case WXK_UP:
+            extended = true;
         case WXK_NUMPAD_UP:
             vk = VK_UP;
             break;
 
         case WXK_RIGHT:
+            extended = true;
         case WXK_NUMPAD_RIGHT:
             vk = VK_RIGHT;
             break;
 
         case WXK_DOWN:
+            extended = true;
         case WXK_NUMPAD_DOWN:
             vk = VK_DOWN;
             break;
 
         case WXK_INSERT:
+            extended = true;
         case WXK_NUMPAD_INSERT:
             vk = VK_INSERT;
             break;
 
         case WXK_DELETE:
+            extended = true;
         case WXK_NUMPAD_DELETE:
             vk = VK_DELETE;
             break;
@@ -6123,15 +6404,18 @@ WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
             else
 #endif // !__WXWINCE__
             {
-                if ( isVirtual )
-                    *isVirtual = false;
                 vk = (WXWORD)wxk;
             }
     }
 
+    if ( isExtended )
+        *isExtended = extended;
+
     return vk;
 }
 
+} // namespace wxMSWKeyboard
+
 // small helper for wxGetKeyState() and wxGetMouseState()
 static inline bool wxIsKeyDown(WXWORD vk)
 {
@@ -6164,7 +6448,7 @@ bool wxGetKeyState(wxKeyCode key)
                         key != VK_MBUTTON,
                     wxT("can't use wxGetKeyState() for mouse buttons") );
 
-    const WXWORD vk = wxCharCodeWXToMSW(key);
+    const WXWORD vk = wxMSWKeyboard::WXToVK(key);
 
     // if the requested key is a LED key, return true if the led is pressed
     if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
@@ -6230,13 +6514,13 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
         win = wxFindWinFromHandle(hwnd);
         if ( !win )
         {
-#if wxUSE_RADIOBOX
+#if wxUSE_RADIOBOX && !defined(__WXUNIVERSAL__)
             // 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, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
             {
-                win = (wxWindow *)wxGetWindowUserData(hwnd);
+                win = wxRadioBox::GetFromRadioButtonHWND(hwnd);
             }
             //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
 #endif // wxUSE_RADIOBOX
@@ -6289,37 +6573,44 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        int id = wxCharCodeMSWToWX(wParam, lParam);
-        if ( id != 0 )
+        wchar_t uc;
+        int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
+
+        // Don't intercept keyboard entry (notably Escape) if a modal window
+        // (not managed by wx, e.g. IME one) is currently opened as more often
+        // than not it needs all the keys for itself.
+        //
+        // Also don't catch it if a window currently captures the mouse as
+        // Escape is normally used to release the mouse capture and if you
+        // really need to catch all the keys in the window that has mouse
+        // capture it can be easily done in its own EVT_CHAR handler as it is
+        // certain to have focus while it has the capture.
+        if ( !gs_modalEntryWindowCount && !::GetCapture() )
         {
-            wxKeyEvent event(wxEVT_CHAR_HOOK);
-            if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-                event.m_altDown = true;
-
-            event.SetEventObject(NULL);
-            event.m_keyCode = id;
-            event.m_shiftDown = wxIsShiftDown();
-            event.m_controlDown = wxIsCtrlDown();
-#ifndef __WXWINCE__
-            event.SetTimestamp(::GetMessageTime());
-#endif
-            wxWindow *win = wxGetActiveWindow();
-            wxEvtHandler *handler;
-            if ( win )
-            {
-                handler = win->GetEventHandler();
-                event.SetId(win->GetId());
-            }
-            else
+            if ( id != WXK_NONE
+#if wxUSE_UNICODE
+                    || static_cast<int>(uc) != WXK_NONE
+#endif // wxUSE_UNICODE
+                    )
             {
-                handler = wxTheApp;
-                event.SetId(wxID_ANY);
-            }
+                const wxWindow * const win = wxGetActiveWindow();
 
-            if ( handler && handler->ProcessEvent(event) )
-            {
-                // processed
-                return 1;
+                wxKeyEvent event(wxEVT_CHAR_HOOK);
+                MSWInitAnyKeyEvent(event, wParam, lParam, win);
+
+                event.m_keyCode = id;
+#if wxUSE_UNICODE
+                event.m_uniChar = uc;
+#endif // wxUSE_UNICODE
+
+                wxEvtHandler * const handler = win ? win->GetEventHandler()
+                                                   : wxTheApp;
+
+                if ( handler && handler->ProcessEvent(event) )
+                {
+                    // processed
+                    return 1;
+                }
             }
         }
     }
@@ -6340,7 +6631,7 @@ void wxSetKeyboardHook(bool doIt)
                               );
         if ( !wxTheKeyboardHook )
         {
-            wxLogLastError(_T("SetWindowsHookEx(wxKeyboardHook)"));
+            wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)"));
         }
     }
     else // uninstall
@@ -6901,10 +7192,10 @@ static void WinCEUnregisterHotKey(int modifiers, int id)
     typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
 
     UnregisterFunc1Proc procUnregisterFunc;
-    hCoreDll = LoadLibrary(_T("coredll.dll"));
+    hCoreDll = LoadLibrary(wxT("coredll.dll"));
     if (hCoreDll)
     {
-        procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1"));
+        procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, wxT("UnregisterFunc1"));
         if (procUnregisterFunc)
             procUnregisterFunc(modifiers, id);
         FreeLibrary(hCoreDll);
@@ -6932,7 +7223,7 @@ bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
 
     if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
     {
-        wxLogLastError(_T("RegisterHotKey"));
+        wxLogLastError(wxT("RegisterHotKey"));
 
         return false;
     }
@@ -6948,7 +7239,7 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
 
     if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
     {
-        wxLogLastError(_T("UnregisterHotKey"));
+        wxLogLastError(wxT("UnregisterHotKey"));
 
         return false;
     }
@@ -6960,12 +7251,10 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
 
 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int hotkeyId = wParam;
-    int virtualKey = HIWORD(lParam);
     int win_modifiers = LOWORD(lParam);
 
-    wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
-    event.SetId(hotkeyId);
+    wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, HIWORD(lParam)));
+    event.SetId(wParam);
     event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
     event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
     event.m_altDown = (win_modifiers & MOD_ALT) != 0;
@@ -7001,7 +7290,7 @@ public:
 
         if ( !ms_hMsgHookProc )
         {
-            wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
+            wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)"));
 
             return false;
         }