#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
// ---------------------------------------------------------------------------
// 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)
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"));
}
}
#endif // !HAVE_TRACKMOUSEEVENT
- if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
- UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+ wxWindowBase::OnInternalIdle();
}
// Set this window to be the child of 'parent'.
}
}
break;
-#if 0
+
case WM_ENTERSIZEMOVE:
{
processed = HandleEnterSizeMove();
processed = HandleExitSizeMove();
}
break;
-#endif
+
case WM_SIZING:
{
LPRECT pRect = (LPRECT)lParam;
// generate CHAR events with WXK_HOME and not
// WXK_NUMPAD_HOME even if the "Home" key on numpad was
// pressed.
- event.m_keyCode = wxCharCodeMSWToWX
+ event.m_keyCode = wxMSWKeyboard::VKToWX
(
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
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)
// 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
wxKeyEvent event(evType);
InitAnyKeyEvent(event, wParam, lParam);
- event.m_keyCode = wxCharCodeMSWToWX(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;
}
// the_font.ReleaseResource();
}
+// ----------------------------------------------------------------------------
+// keyboard codes
+// ----------------------------------------------------------------------------
+
+namespace wxMSWKeyboard
+{
+
namespace
{
}
// 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
} // anonymous namespace
-int wxCharCodeMSWToWX(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:
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;
}
-WXWORD wxCharCodeWXToMSW(int wxk, bool *isExtended)
+WXWORD WXToVK(int wxk, bool *isExtended)
{
// check the table first
for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
return vk;
}
+} // namespace wxMSWKeyboard
+
// small helper for wxGetKeyState() and wxGetMouseState()
static inline bool wxIsKeyDown(WXWORD vk)
{
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 )
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
DWORD hiWord = HIWORD(lParam);
if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
{
- int id = wxCharCodeMSWToWX(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) )
{