]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
adding new files for xti merge
[wxWidgets.git] / src / msw / window.cpp
index d389407b7007bf7e171d622d38bd26a093ca7c80..cd5f076e0036c3c810758387e27f64aa08852b7f 100644 (file)
     #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
 // ---------------------------------------------------------------------------
@@ -1429,7 +1437,8 @@ 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(wxT("SetWindowPos"));
         }
@@ -3229,7 +3238,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                                             wParam,
                                             lParam | (KF_EXTENDED << 16)
                                           );
-                        processed = HandleWindowEvent(event);
+
+                        // 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
@@ -4917,7 +4930,8 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 
 bool wxWindowMSW::MSWHasEraseBgHook() const
 {
-    return gs_eraseBgHooks.find(this) != gs_eraseBgHooks.end();
+    return gs_eraseBgHooks.find(const_cast<wxWindowMSW *>(this))
+                != gs_eraseBgHooks.end();
 }
 
 void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
@@ -5628,28 +5642,65 @@ void wxWindowMSW::GenerateMouseLeave()
 // keyboard handling
 // ---------------------------------------------------------------------------
 
+namespace
+{
+
+// 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
-wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
-                             WXWPARAM wParam,
-                             WXLPARAM lParam) const
+MSWInitAnyKeyEvent(wxKeyEvent& event,
+                   WXWPARAM wParam,
+                   WXLPARAM lParam,
+                   const wxWindowBase *win /* may be NULL */)
 {
-    event.SetId(GetId());
+    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(const_cast<wxWindow *>(this));
-
     event.m_rawCode = (wxUint32) wParam;
     event.m_rawFlags = (wxUint32) lParam;
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
 #endif
 
-    // translate the position to client coordinates
-    const wxPoint mousePos = ScreenToClient(wxGetMousePosition());
-    event.m_x = mousePos.x;
-    event.m_y = mousePos.y;
+    // 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;
+    }
+}
+
+} // anonymous namespace
+
+void
+wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
+                             WXWPARAM wParam,
+                             WXLPARAM lParam) const
+{
+    MSWInitAnyKeyEvent(event, wParam, lParam, this);
 }
 
 wxKeyEvent
@@ -5665,17 +5716,14 @@ wxWindowMSW::CreateKeyEvent(wxEventType evType,
     wxKeyEvent event(evType);
     InitAnyKeyEvent(event, wParam, lParam);
 
-    event.m_keyCode = wxMSWKeyboard::VKToWX(wParam, lParam);
+    event.m_keyCode = wxMSWKeyboard::VKToWX
+                                     (
+                                        wParam,
+                                        lParam
 #if wxUSE_UNICODE
-    if ( event.m_keyCode < WXK_START )
-    {
-        // It's an ASCII character, set Unicode key code to the same value
-        // for compatibility (both with the previous versions of wx and with
-        // the other ports), even if it's not very useful for these events as
-        // Unicode character is/should be mostly used by EVT_CHAR handlers.
-        event.m_uniChar = event.m_keyCode;
-    }
+                                        , &event.m_uniChar
 #endif // wxUSE_UNICODE
+                                     );
 
     return event;
 }
@@ -6158,32 +6206,73 @@ const struct wxKeyMapping
 
 } // anonymous namespace
 
-int VKToWX(WXWORD vk, WXLPARAM lParam)
+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:
@@ -6233,9 +6322,19 @@ int VKToWX(WXWORD vk, WXLPARAM lParam)
             break;
 
         default:
-            // must be a simple alphanumeric key and the values of them
-            // coincide in Windows and wx
-            wxk = vk;
+            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;
@@ -6446,13 +6545,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
@@ -6505,32 +6604,26 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        int id = wxMSWKeyboard::VKToWX(wParam, lParam);
-        if ( id >= WXK_START )
+        wchar_t uc;
+        int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
+        if ( id != WXK_NONE
+#if wxUSE_UNICODE
+                || static_cast<int>(uc) != WXK_NONE
+#endif // wxUSE_UNICODE
+                )
         {
+            const wxWindow * const win = wxGetActiveWindow();
+
             wxKeyEvent event(wxEVT_CHAR_HOOK);
-            if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-                event.m_altDown = true;
+            MSWInitAnyKeyEvent(event, wParam, lParam, win);
 
-            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
-            {
-                handler = wxTheApp;
-                event.SetId(wxID_ANY);
-            }
+#if wxUSE_UNICODE
+            event.m_uniChar = uc;
+#endif // wxUSE_UNICODE
+
+            wxEvtHandler * const handler = win ? win->GetEventHandler()
+                                               : wxTheApp;
 
             if ( handler && handler->ProcessEvent(event) )
             {