#ifndef WX_PRECOMP
#include "wx/msw/wrapwin.h"
+ #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
+ #include "wx/msw/missing.h"
#include "wx/accel.h"
#include "wx/menu.h"
#include "wx/dc.h"
#include "wx/sizer.h"
#include "wx/intl.h"
#include "wx/log.h"
+ #include "wx/textctrl.h"
+ #include "wx/menuitem.h"
+ #include "wx/module.h"
#endif
#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
#include "wx/ownerdrw.h"
#endif
+#include "wx/hashmap.h"
#include "wx/evtloop.h"
-#include "wx/module.h"
#include "wx/power.h"
#include "wx/sysopt.h"
#endif
#endif
-#include "wx/menuitem.h"
-
#include "wx/msw/private.h"
#if wxUSE_TOOLTIPS
#include "wx/spinctrl.h"
#endif // wxUSE_SPINCTRL
-#include "wx/textctrl.h"
#include "wx/notebook.h"
#include "wx/listctrl.h"
+#include "wx/dynlib.h"
#include <string.h>
#include <windowsx.h>
#endif
-#include <commctrl.h>
-#include <pbt.h>
-
-#include "wx/msw/missing.h"
+#if !defined __WXWINCE__ && !defined NEED_PBT_H
+ #include <pbt.h>
+#endif
#if defined(__WXWINCE__)
#include "wx/msw/wince/missing.h"
#endif
#endif
-#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE)
+#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
} gs_lastMouseEvent;
#endif // wxUSE_MOUSEEVENT_HACK
+// hash containing the registered handlers for the custom messages
+WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
+ wxIntegerHash, wxIntegerEqual,
+ MSWMessageHandlers);
+
+static MSWMessageHandlers gs_messageHandlers;
+
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
m_mouseInWindow = false;
m_lastKeydownProcessed = false;
- m_childrenDisabled = NULL;
m_frozenness = 0;
m_hWnd = 0;
wxRemoveHandleAssociation(this);
}
- delete m_childrenDisabled;
-
}
// real construction (Init() must have been called before!)
return NULL;
}
-bool wxWindowMSW::Enable(bool enable)
+void wxWindowMSW::DoEnable( bool enable )
{
- if ( !wxWindowBase::Enable(enable) )
- return false;
-
HWND hWnd = GetHwnd();
if ( hWnd )
::EnableWindow(hWnd, (BOOL)enable);
-
- // the logic below doesn't apply to the top level windows -- otherwise
- // showing a modal dialog would result in total greying out (and ungreying
- // out later) of everything which would be really ugly
- if ( IsTopLevel() )
- return true;
-
- // when the parent is disabled, all of its children should be disabled as
- // well but when it is enabled back, only those of the children which
- // hadn't been already disabled in the beginning should be enabled again,
- // so we have to keep the list of those children
- for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
- node;
- node = node->GetNext() )
- {
- wxWindow *child = node->GetData();
- if ( child->IsTopLevel() )
- {
- // the logic below doesn't apply to top level children
- continue;
- }
-
- if ( enable )
- {
- // re-enable the child unless it had been disabled before us
- if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
- child->Enable();
- }
- else // we're being disabled
- {
- if ( child->IsEnabled() )
- {
- // disable it as children shouldn't stay enabled while the
- // parent is not
- child->Disable();
- }
- else // child already disabled, remember it
- {
- // have we created the list of disabled children already?
- if ( !m_childrenDisabled )
- m_childrenDisabled = new wxWindowList;
-
- m_childrenDisabled->Append(child);
- }
- }
- }
-
- if ( enable && m_childrenDisabled )
- {
- // we don't need this list any more, don't keep unused memory
- delete m_childrenDisabled;
- m_childrenDisabled = NULL;
- }
-
- return true;
}
bool wxWindowMSW::Show(bool show)
// don't "overwrite" busy cursor
if ( m_cursor.Ok() && !wxIsBusy() )
{
- ::SetCursor(GetHcursorOf(m_cursor));
+ // normally we should change the cursor only if it's over this window
+ // but we should do it always if we capture the mouse currently
+ bool set = HasCapture();
+ if ( !set )
+ {
+ HWND hWnd = GetHwnd();
+
+ POINT point;
+#ifdef __WXWINCE__
+ ::GetCursorPosWinCE(&point);
+#else
+ ::GetCursorPos(&point);
+#endif
+
+ RECT rect = wxGetWindowRect(hWnd);
+
+ set = ::PtInRect(&rect, point) != 0;
+ }
+
+ if ( set )
+ {
+ ::SetCursor(GetHcursorOf(m_cursor));
+ }
+ //else: will be set later when the mouse enters this window
}
return true;
if ( s_needToUpdate == -1 )
{
int verMaj, verMin;
- s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT &&
+ s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT &&
verMaj >= 5;
}
RECT *pr;
if ( prect )
{
- rect.left = prect->x;
- rect.top = prect->y;
- rect.right = prect->x + prect->width;
- rect.bottom = prect->y + prect->height;
+ wxCopyRectToRECT(*prect, rect);
pr = ▭
}
else
down ? pages : -pages);
}
+// ----------------------------------------------------------------------------
+// RTL support
+// ----------------------------------------------------------------------------
+
+void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
+{
+#ifdef __WXWINCE__
+ wxUnusedVar(dir);
+#else
+ const HWND hwnd = GetHwnd();
+ wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") );
+
+ LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ LONG styleNew = styleOld;
+ switch ( dir )
+ {
+ case wxLayout_LeftToRight:
+ styleNew &= ~WS_EX_LAYOUTRTL;
+ break;
+
+ case wxLayout_RightToLeft:
+ styleNew |= WS_EX_LAYOUTRTL;
+ break;
+
+ default:
+ wxFAIL_MSG(_T("unsupported layout direction"));
+ break;
+ }
+
+ if ( styleNew != styleOld )
+ {
+ ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew);
+ }
+#endif
+}
+
+wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
+{
+#ifdef __WXWINCE__
+ return wxLayout_Default;
+#else
+ const HWND hwnd = GetHwnd();
+ wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") );
+
+ return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL
+ ? wxLayout_RightToLeft
+ : wxLayout_LeftToRight;
+#endif
+}
+
+wxCoord
+wxWindowMSW::AdjustForLayoutDirection(wxCoord x,
+ wxCoord WXUNUSED(width),
+ wxCoord WXUNUSED(widthTotal)) const
+{
+ // Win32 mirrors the coordinates of RTL windows automatically, so don't
+ // redo it ourselves
+ return x;
+}
+
// ---------------------------------------------------------------------------
// subclassing
// ---------------------------------------------------------------------------
// update the internal variable
wxWindowBase::SetWindowStyleFlag(flags);
+ // and the real window flags
+ MSWUpdateStyle(flagsOld, GetExtraStyle());
+}
+
+void wxWindowMSW::SetExtraStyle(long exflags)
+{
+ long exflagsOld = GetExtraStyle();
+ if ( exflags == exflagsOld )
+ return;
+
+ // update the internal variable
+ wxWindowBase::SetExtraStyle(exflags);
+
+ // and the real window flags
+ MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld);
+}
+
+void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
+{
// now update the Windows style as well if needed - and if the window had
// been already created
if ( !GetHwnd() )
// we may need to call SetWindowPos() when we change some styles
bool callSWP = false;
- WXDWORD exstyle, exstyleOld;
- long style = MSWGetStyle(flags, &exstyle),
- styleOld = MSWGetStyle(flagsOld, &exstyleOld);
+ WXDWORD exstyle;
+ long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle);
+
+ // this is quite a horrible hack but we need it because MSWGetStyle()
+ // doesn't take exflags as parameter but uses GetExtraStyle() internally
+ // and so we have to modify the window exflags temporarily to get the
+ // correct exstyleOld
+ long exflagsNew = GetExtraStyle();
+ wxWindowBase::SetExtraStyle(exflagsOld);
+
+ WXDWORD exstyleOld;
+ long styleOld = MSWGetStyle(flagsOld, &exstyleOld);
+
+ wxWindowBase::SetExtraStyle(exflagsNew);
+
if ( style != styleOld )
{
::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
- // If any of the style changes changed any of the frame styles:
- // MSDN: SetWindowLong:
- // Certain window data is cached, so changes you make using
- // SetWindowLong will not take effect until you call the
- // SetWindowPos function. Specifically, if you change any of
- // the frame styles, you must call SetWindowPos with the
- // SWP_FRAMECHANGED flag for the cache to be updated properly.
-
+ // we need to call SetWindowPos() if any of the styles affecting the
+ // frame appearance have changed
callSWP = ((styleOld ^ style ) & (WS_BORDER |
WS_THICKFRAME |
WS_CAPTION |
const RECT *pRect;
if ( rect )
{
- mswRect.left = rect->x;
- mswRect.top = rect->y;
- mswRect.right = rect->x + rect->width;
- mswRect.bottom = rect->y + rect->height;
-
+ wxCopyRectToRECT(*rect, mswRect);
pRect = &mswRect;
}
else
// drag and drop
// ---------------------------------------------------------------------------
+#if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
+
+#if wxUSE_STATBOX
+
// we need to lower the sibling static boxes so controls contained within can be
// a drop target
-static inline void AdjustStaticBoxZOrder(wxWindow *parent)
+static void AdjustStaticBoxZOrder(wxWindow *parent)
{
// no sibling static boxes if we have no parent (ie TLW)
if ( !parent )
}
}
+#else // !wxUSE_STATBOX
+
+static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
+{
+}
+
+#endif // wxUSE_STATBOX/!wxUSE_STATBOX
+
+#endif // drag and drop is used
+
#if wxUSE_DRAG_AND_DROP
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
{
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
+#if USE_DEFERRED_SIZING
// if SetSize() had been called at wx level but not realized at Windows
// level yet (i.e. EndDeferWindowPos() not called), we still should return
// the new and not the old position to the other wx code
*y = m_pendingSize.y;
}
else // use current size
+#endif // USE_DEFERRED_SIZING
{
RECT rect = wxGetWindowRect(GetHwnd());
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
#if USE_DEFERRED_SIZING
- if ( IsTopLevel() || m_pendingSize == wxDefaultSize )
-#endif
- { // top level windows resizing is never deferred, so we can safely use
- // the current size here
- RECT rect = wxGetClientRect(GetHwnd());
-
- if ( x )
- *x = rect.right;
- if ( y )
- *y = rect.bottom;
- }
-#if USE_DEFERRED_SIZING
- else // non top level and using deferred sizing
+ if ( m_pendingSize != wxDefaultSize )
{
- // we need to calculate the *pending* client size here
+ // we need to calculate the client size corresponding to pending size
RECT rect;
rect.left = m_pendingPosition.x;
rect.top = m_pendingPosition.y;
if ( y )
*y = rect.bottom - rect.top;
}
-#endif
+ else
+#endif // USE_DEFERRED_SIZING
+ {
+ RECT rect = wxGetClientRect(GetHwnd());
+
+ if ( x )
+ *x = rect.right;
+ if ( y )
+ *y = rect.bottom;
+ }
}
void wxWindowMSW::DoGetPosition(int *x, int *y) const
// children, not for the dialogs/frames
if ( !IsTopLevel() )
{
+ if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+ {
+ // In RTL mode, we want the logical left x-coordinate,
+ // which would be the physical right x-coordinate.
+ point.x = rect.right;
+ }
+
// Since we now have the absolute screen coords, if there's a
// parent we must subtract its top left corner
if ( parent )
SIZE sizeRect;
TEXTMETRIC tm;
- ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+ ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
GetTextMetrics(hdc, &tm);
if ( x )
::ClientToScreen(hWnd, &point);
wxCurrentPopupMenu = menu;
#if defined(__WXWINCE__)
- UINT flags = 0;
-#else
- UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
-#endif
+ static const UINT flags = 0;
+#else // !__WXWINCE__
+ UINT flags = TPM_RIGHTBUTTON;
+ // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
+ // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
+ // side and not to use it there neither -- modify the test if it does work
+ // on these systems
+ if ( wxGetWinVersion() >= wxWinVersion_5 )
+ {
+ // using TPM_RECURSE allows us to show a popup menu while another menu
+ // is opened which can be useful and is supported by the other
+ // platforms, so allow it under Windows too
+ flags |= TPM_RECURSE;
+ }
+#endif // __WXWINCE__/!__WXWINCE__
+
::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
// we need to do it right now as otherwise the events are never going to be
// WM_GETDLGCODE: ask the control if it wants the key for itself,
// don't process it if it's the case (except for Ctrl-Tab/Enter
// combinations which are always processed)
- LONG lDlgCode = 0;
- if ( !bCtrlDown )
- {
- lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+ LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
- // surprizingly, 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 )
- {
- lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
- }
+ // surprizingly, 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 )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
}
bool bForward = true,
switch ( msg->wParam )
{
case VK_TAB:
- if ( lDlgCode & DLGC_WANTTAB ) {
+ if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
+ {
+ // let the control have the TAB
bProcess = false;
}
- else {
+ else // use it for navigation
+ {
// Ctrl-Tab cycles thru notebook pages
bWindowChange = bCtrlDown;
bForward = !bShiftDown;
bProcess = false;
break;
+ case VK_PRIOR:
+ bForward = false;
+ // fall through
+
+ case VK_NEXT:
+ // we treat PageUp/Dn as arrows because chances are that
+ // a control which needs arrows also needs them for
+ // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
+ if ( (lDlgCode & DLGC_WANTARROWS) && !bCtrlDown )
+ bProcess = false;
+ else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
+ bWindowChange = true;
+ break;
+
case VK_RETURN:
{
if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
{
// control wants to process Enter itself, don't
- // call IsDialogMessage() which would interpret
- // it
+ // call IsDialogMessage() which would consume it
return false;
}
+#if wxUSE_BUTTON
// currently active button should get enter press even
- // if there is a default button elsewhere
+ // if there is a default button elsewhere so check if
+ // this window is a button first
+ wxWindow *btn = NULL;
if ( lDlgCode & DLGC_DEFPUSHBUTTON )
{
// let IsDialogMessage() handle this for all
if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
{
// emulate the button click
- wxWindow *
- btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
- if ( btn )
- btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
}
bProcess = false;
}
- else // not a button itself
+ else // not a button itself, do we have default button?
{
-#if wxUSE_BUTTON
- wxButton *btn = wxDynamicCast(GetDefaultItem(),
- wxButton);
- if ( btn && btn->IsEnabled() )
+ wxTopLevelWindow *
+ tlw = wxDynamicCast(wxGetTopLevelParent(this),
+ wxTopLevelWindow);
+ if ( tlw )
{
- // if we do have a default button, do press it
- btn->MSWCommand(BN_CLICKED, 0 /* unused */);
-
- return true;
+ btn = wxDynamicCast(tlw->GetDefaultItem(),
+ wxButton);
}
- else // no default button
+ }
+
+ if ( btn && btn->IsEnabled() )
+ {
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ return true;
+ }
+
#endif // wxUSE_BUTTON
- {
+
#ifdef __WXWINCE__
- wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
- event.SetEventObject(this);
- if(GetEventHandler()->ProcessEvent(event))
- return true;
-#endif
- // this is a quick and dirty test for a text
- // control
- if ( !(lDlgCode & DLGC_HASSETSEL) )
- {
- // don't process Enter, the control might
- // need it for itself and don't let
- // ::IsDialogMessage() have it as it can
- // eat the Enter events sometimes
- return false;
- }
- else if (!IsTopLevel())
- {
- // if not a top level window, let parent
- // handle it
- return false;
- }
- //else: treat Enter as TAB: pass to the next
- // control as this is the best thing to do
- // if the text doesn't handle Enter itself
- }
- }
+ // map Enter presses into button presses on PDAs
+ wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
+ event.SetEventObject(this);
+ if ( GetEventHandler()->ProcessEvent(event) )
+ return true;
+#endif // __WXWINCE__
}
break;
}
}
- // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
- // message even when there is no cancel button and when the message is
- // needed by the control itself: in particular, it prevents the tree in
- // place edit control from being closed with Escape in a dialog
- if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
+ if ( ::IsDialogMessage(GetHwnd(), msg) )
{
- // ::IsDialogMessage() is broken and may sometimes hang the
- // application by going into an infinite loop, so we try to detect
- // [some of] the situations when this may happen and not call it
- // then
-
- // assume we can call it by default
- bool canSafelyCallIsDlgMsg = true;
-
- HWND hwndFocus = ::GetFocus();
-
- // if the currently focused window itself has WS_EX_CONTROLPARENT style, ::IsDialogMessage() will also enter
- // an infinite loop, because it will recursively check the child
- // windows but not the window itself and so if none of the children
- // accepts focus it loops forever (as it only stops when it gets
- // back to the window it started from)
- //
- // while it is very unusual that a window with WS_EX_CONTROLPARENT
- // style has the focus, it can happen. One such possibility is if
- // all windows are either toplevel, wxDialog, wxPanel or static
- // controls and no window can actually accept keyboard input.
-#if !defined(__WXWINCE__)
- if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
- {
- // pessimistic by default
- canSafelyCallIsDlgMsg = false;
- for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
- node;
- node = node->GetNext() )
- {
- wxWindow * const win = node->GetData();
- if ( win->AcceptsFocus() &&
- !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
- WS_EX_CONTROLPARENT) )
- {
- // it shouldn't hang...
- canSafelyCallIsDlgMsg = true;
-
- break;
- }
- }
- }
-#endif // !__WXWINCE__
-
- if ( canSafelyCallIsDlgMsg )
- {
- // ::IsDialogMessage() can enter in an infinite loop when the
- // currently focused window is disabled or hidden and its
- // parent has WS_EX_CONTROLPARENT style, so don't call it in
- // this case
- while ( hwndFocus )
- {
- if ( !::IsWindowEnabled(hwndFocus) ||
- !::IsWindowVisible(hwndFocus) )
- {
- // it would enter an infinite loop if we do this!
- canSafelyCallIsDlgMsg = false;
-
- break;
- }
-
- if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
- {
- // it's a top level window, don't go further -- e.g. even
- // if the parent of a dialog is disabled, this doesn't
- // break navigation inside the dialog
- break;
- }
-
- hwndFocus = ::GetParent(hwndFocus);
- }
- }
-
- // let IsDialogMessage() have the message if it's safe to call it
- if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
- {
- // IsDialogMessage() did something...
- return true;
- }
+ // IsDialogMessage() did something...
+ return true;
}
}
#endif // __WXUNIVERSAL__
#endif // wxUSE_ACCEL
}
-bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
{
- // preprocess all messages by default
- return true;
+ // all tests below have to deal with various bugs/misfeatures of
+ // IsDialogMessage(): we have to prevent it from being called from our
+ // MSWProcessMessage() in some situations
+
+ // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
+ {
+ return false;
+ }
+
+ // ::IsDialogMessage() is broken and may sometimes hang the application by
+ // going into an infinite loop when it tries to find the control to give
+ // focus to when Alt-<key> is pressed, so we try to detect [some of] the
+ // situations when this may happen and not call it then
+ if ( msg->message != WM_SYSCHAR )
+ return true;
+
+ // assume we can call it by default
+ bool canSafelyCallIsDlgMsg = true;
+
+ HWND hwndFocus = ::GetFocus();
+
+ // if the currently focused window itself has WS_EX_CONTROLPARENT style,
+ // ::IsDialogMessage() will also enter an infinite loop, because it will
+ // recursively check the child windows but not the window itself and so if
+ // none of the children accepts focus it loops forever (as it only stops
+ // when it gets back to the window it started from)
+ //
+ // while it is very unusual that a window with WS_EX_CONTROLPARENT
+ // style has the focus, it can happen. One such possibility is if
+ // all windows are either toplevel, wxDialog, wxPanel or static
+ // controls and no window can actually accept keyboard input.
+#if !defined(__WXWINCE__)
+ if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ // pessimistic by default
+ canSafelyCallIsDlgMsg = false;
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow * const win = node->GetData();
+ if ( win->CanAcceptFocus() &&
+ !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
+ WS_EX_CONTROLPARENT) )
+ {
+ // it shouldn't hang...
+ canSafelyCallIsDlgMsg = true;
+
+ break;
+ }
+ }
+ }
+#endif // !__WXWINCE__
+
+ if ( canSafelyCallIsDlgMsg )
+ {
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its
+ // parent has WS_EX_CONTROLPARENT style, so don't call it in
+ // this case
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = false;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+ }
+
+ return canSafelyCallIsDlgMsg;
}
// ---------------------------------------------------------------------------
LRESULT rc;
- if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+ if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
rc = wnd->MSWWindowProc(message, wParam, lParam);
else
rc = ::DefWindowProc(hWnd, message, wParam, lParam);
#ifdef HAVE_TRACKMOUSEEVENT
case WM_MOUSELEAVE:
- // filter out excess WM_MOUSELEAVE events sent after PopupMenu() (on XP at least)
+ // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
+ // (on XP at least)
if ( m_mouseInWindow )
{
GenerateMouseLeave();
// problems, so don't do it for them (unnecessary anyhow)
if ( !win->IsOfStandardClass() )
{
- if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ if ( message == WM_LBUTTONDOWN && win->CanAcceptFocus() )
win->SetFocus();
}
}
#endif // defined(WM_DRAWITEM)
case WM_GETDLGCODE:
- if ( !IsOfStandardClass() )
+ if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
{
// we always want to get the char events
rc.result = DLGC_WANTCHARS;
- if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ if ( HasFlag(wxWANTS_CHARS) )
{
// in fact, we want everything
rc.result |= DLGC_WANTARROWS |
#if defined(WM_HELP)
case WM_HELP:
{
- // HELPINFO doesn't seem to be supported on WinCE.
+ // by default, WM_HELP is propagated by DefWindowProc() upwards
+ // to the window parent but as we do it ourselves already
+ // (wxHelpEvent is derived from wxCommandEvent), we don't want
+ // to get the other events if we process this message at all
+ processed = true;
+
+ // WM_HELP doesn't use lParam under CE
#ifndef __WXWINCE__
HELPINFO* info = (HELPINFO*) lParam;
- // Don't yet process menu help events, just windows
- if (info->iContextType == HELPINFO_WINDOW)
+ if ( info->iContextType == HELPINFO_WINDOW )
{
-#endif
- wxWindowMSW* subjectOfHelp = this;
- bool eventProcessed = false;
- while (subjectOfHelp && !eventProcessed)
- {
- wxHelpEvent helpEvent(wxEVT_HELP,
- subjectOfHelp->GetId(),
+#endif // !__WXWINCE__
+ wxHelpEvent helpEvent
+ (
+ wxEVT_HELP,
+ GetId(),
#ifdef __WXWINCE__
- wxPoint(0,0)
+ wxGetMousePosition() // what else?
#else
- wxPoint(info->MousePos.x, info->MousePos.y)
+ wxPoint(info->MousePos.x, info->MousePos.y)
#endif
- );
-
- helpEvent.SetEventObject(this);
- eventProcessed =
- GetEventHandler()->ProcessEvent(helpEvent);
-
- // Go up the window hierarchy until the event is
- // handled (or not)
- subjectOfHelp = subjectOfHelp->GetParent();
- }
+ );
- processed = eventProcessed;
+ helpEvent.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(helpEvent);
#ifndef __WXWINCE__
}
- else if (info->iContextType == HELPINFO_MENUITEM)
+ else if ( info->iContextType == HELPINFO_MENUITEM )
{
wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
helpEvent.SetEventObject(this);
- processed = GetEventHandler()->ProcessEvent(helpEvent);
+ GetEventHandler()->ProcessEvent(helpEvent);
}
- //else: processed is already false
-#endif
+ else // unknown help event?
+ {
+ processed = false;
+ }
+#endif // !__WXWINCE__
}
break;
-#endif
+#endif // WM_HELP
#if !defined(__WXWINCE__)
case WM_CONTEXTMENU:
}
break;
+#ifndef __WXWINCE__
case WM_POWERBROADCAST:
{
bool vetoed;
rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
}
break;
+#endif // __WXWINCE__
+
+ default:
+ // try a custom message handler
+ const MSWMessageHandlers::const_iterator
+ i = gs_messageHandlers.find(message);
+ if ( i != gs_messageHandlers.end() )
+ {
+ processed = (*i->second)(this, message, wParam, lParam);
+ }
}
if ( !processed )
m_hWnd = (WXHWND)::CreateWindowEx
(
extendedStyle,
- className,
- title ? title : m_windowName.c_str(),
+ className.wx_str(),
+ title ? title : m_windowName.wx_str(),
style,
x, y, w, h,
(HWND)MSWGetParent(),
// Truncate tooltip length if needed as otherwise we might not have
// enough space for it in the buffer and MultiByteToWideChar() would
// return an error
- size_t tipLength = wxMin(ttip.Len(), WXSIZEOF(buf) - 1);
+ size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
// Convert to WideChar without adding the NULL character. The NULL
// character is added afterwards (this is more efficient).
(
CP_ACP,
0, // no flags
- ttip,
+ ttip.wx_str(),
tipLength,
buf,
WXSIZEOF(buf) - 1
return false;
}
-bool wxWindowMSW::HandlePower(WXWPARAM wParam,
+bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
WXLPARAM WXUNUSED(lParam),
- bool *vetoed)
+ bool *WXUNUSED_IN_WINCE(vetoed))
{
+#ifdef __WXWINCE__
+ // FIXME
+ return false;
+#else
wxEventType evtType;
switch ( wParam )
{
break;
case PBT_APMRESUMESUSPEND:
+#ifdef PBT_APMRESUMEAUTOMATIC
+ case PBT_APMRESUMEAUTOMATIC:
+#endif
evtType = wxEVT_POWER_RESUME;
break;
case PBT_APMBATTERYLOW:
case PBT_APMPOWERSTATUSCHANGE:
case PBT_APMOEMEVENT:
-#ifdef PBT_APMRESUMEAUTOMATIC
- case PBT_APMRESUMEAUTOMATIC:
-#endif
case PBT_APMRESUMECRITICAL:
evtType = wxEVT_NULL;
break;
*vetoed = event.IsVetoed();
return true;
+#endif
+}
+
+bool wxWindowMSW::IsDoubleBuffered() const
+{
+ for ( const wxWindowMSW *wnd = this;
+ wnd && !wnd->IsTopLevel(); wnd =
+ wnd->GetParent() )
+ {
+ if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED )
+ return true;
+ }
+
+ return false;
}
// ---------------------------------------------------------------------------
bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
{
- wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
- event.SetEventObject(this);
+ // notify windows on the capture stack about lost capture
+ // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
+ wxWindowBase::NotifyCaptureLost();
+ wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
+ wxMouseCaptureChangedEvent event(GetId(), win);
+ event.SetEventObject(this);
return GetEventHandler()->ProcessEvent(event);
}
bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
{
- wxDCTemp dc(hdc);
+ wxDCTemp dc(hdc, GetClientSize());
dc.SetHDC(hdc);
dc.SetWindow((wxWindow *)this);
m_mouseInWindow = true;
#ifdef HAVE_TRACKMOUSEEVENT
- WinStruct<TRACKMOUSEEVENT> trackinfo;
+ typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
+#ifdef __WXWINCE__
+ static const _TrackMouseEvent_t
+ s_pfn_TrackMouseEvent = _TrackMouseEvent;
+#else // !__WXWINCE__
+ static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
+ static bool s_initDone = false;
+ if ( !s_initDone )
+ {
+ wxLogNull noLog;
- trackinfo.dwFlags = TME_LEAVE;
- trackinfo.hwndTrack = GetHwnd();
+ wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
+ if ( dllComCtl32.IsLoaded() )
+ {
+ s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
+ dllComCtl32.GetSymbol(_T("_TrackMouseEvent"));
+ }
+
+ s_initDone = true;
+
+ // notice that it's ok to unload comctl32.dll here as it won't
+ // be really unloaded, being still in use because we link to it
+ // statically too
+ }
+
+ if ( s_pfn_TrackMouseEvent )
+#endif // __WXWINCE__/!__WXWINCE__
+ {
+ WinStruct<TRACKMOUSEEVENT> trackinfo;
+
+ trackinfo.dwFlags = TME_LEAVE;
+ trackinfo.hwndTrack = GetHwnd();
- // Use the commctrl.h _TrackMouseEvent(), which will call the real
- // TrackMouseEvent() if available or emulate it
- _TrackMouseEvent(&trackinfo);
+ (*s_pfn_TrackMouseEvent)(&trackinfo);
+ }
#endif // HAVE_TRACKMOUSEEVENT
wxMouseEvent event(wxEVT_ENTER_WINDOW);
}
}
#ifdef HAVE_TRACKMOUSEEVENT
- else
+ else // mouse not in window
{
// Check if we need to send a LEAVE event
// Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
// menu creation code
wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
- const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+ const wxChar *p = wxStrchr(item->GetText().wx_str(), _T('&'));
while ( p++ )
{
if ( *p == _T('&') )
return GetEventHandler()->ProcessEvent(event);
}
+// ----------------------------------------------------------------------------
+// custom message handlers
+// ----------------------------------------------------------------------------
+
+/* static */ bool
+wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+ wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
+ false, _T("registering handler for the same message twice") );
+
+ gs_messageHandlers[msg] = handler;
+ return true;
+}
+
+/* static */ void
+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?") );
+
+ gs_messageHandlers.erase(i);
+}
+
// ===========================================================================
// global functions
// ===========================================================================
return !lParam || (lParam & (1 << 24)) ? 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
+//
+// 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
+{
+ int vk;
+ wxKeyCode wxk;
+} gs_specialKeys[] =
+{
+ { VK_CANCEL, WXK_CANCEL },
+ { VK_BACK, WXK_BACK },
+ { VK_TAB, WXK_TAB },
+ { VK_CLEAR, WXK_CLEAR },
+ { VK_SHIFT, WXK_SHIFT },
+ { VK_CONTROL, WXK_CONTROL },
+ { VK_MENU , WXK_ALT },
+ { VK_PAUSE, WXK_PAUSE },
+ { VK_CAPITAL, WXK_CAPITAL },
+ { VK_SPACE, WXK_SPACE },
+ { VK_ESCAPE, WXK_ESCAPE },
+ { VK_SELECT, WXK_SELECT },
+ { VK_PRINT, WXK_PRINT },
+ { VK_EXECUTE, WXK_EXECUTE },
+ { VK_SNAPSHOT, WXK_SNAPSHOT },
+ { VK_HELP, WXK_HELP },
+
+ { VK_NUMPAD0, WXK_NUMPAD0 },
+ { VK_NUMPAD1, WXK_NUMPAD1 },
+ { VK_NUMPAD2, WXK_NUMPAD2 },
+ { VK_NUMPAD3, WXK_NUMPAD3 },
+ { VK_NUMPAD4, WXK_NUMPAD4 },
+ { VK_NUMPAD5, WXK_NUMPAD5 },
+ { VK_NUMPAD6, WXK_NUMPAD6 },
+ { VK_NUMPAD7, WXK_NUMPAD7 },
+ { VK_NUMPAD8, WXK_NUMPAD8 },
+ { VK_NUMPAD9, WXK_NUMPAD9 },
+ { VK_MULTIPLY, WXK_NUMPAD_MULTIPLY },
+ { VK_ADD, WXK_NUMPAD_ADD },
+ { VK_SUBTRACT, WXK_NUMPAD_SUBTRACT },
+ { VK_DECIMAL, WXK_NUMPAD_DECIMAL },
+ { VK_DIVIDE, WXK_NUMPAD_DIVIDE },
+
+ { VK_F1, WXK_F1 },
+ { VK_F2, WXK_F2 },
+ { VK_F3, WXK_F3 },
+ { VK_F4, WXK_F4 },
+ { VK_F5, WXK_F5 },
+ { VK_F6, WXK_F6 },
+ { VK_F7, WXK_F7 },
+ { VK_F8, WXK_F8 },
+ { VK_F9, WXK_F9 },
+ { VK_F10, WXK_F10 },
+ { VK_F11, WXK_F11 },
+ { VK_F12, WXK_F12 },
+ { VK_F13, WXK_F13 },
+ { VK_F14, WXK_F14 },
+ { VK_F15, WXK_F15 },
+ { VK_F16, WXK_F16 },
+ { VK_F17, WXK_F17 },
+ { VK_F18, WXK_F18 },
+ { VK_F19, WXK_F19 },
+ { VK_F20, WXK_F20 },
+ { VK_F21, WXK_F21 },
+ { VK_F22, WXK_F22 },
+ { VK_F23, WXK_F23 },
+ { VK_F24, WXK_F24 },
+
+ { VK_NUMLOCK, WXK_NUMLOCK },
+ { VK_SCROLL, WXK_SCROLL },
+
+#ifdef VK_APPS
+ { VK_LWIN, WXK_WINDOWS_LEFT },
+ { VK_RWIN, WXK_WINDOWS_RIGHT },
+ { VK_APPS, WXK_WINDOWS_MENU },
+#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 keySym, WXLPARAM lParam)
+int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
{
- int id;
- switch (keySym)
- {
- case VK_CANCEL: id = WXK_CANCEL; break;
- case VK_BACK: id = WXK_BACK; break;
- case VK_TAB: id = WXK_TAB; break;
- case VK_CLEAR: id = WXK_CLEAR; break;
- case VK_SHIFT: id = WXK_SHIFT; break;
- case VK_CONTROL: id = WXK_CONTROL; break;
- case VK_MENU : id = WXK_ALT; break;
- case VK_PAUSE: id = WXK_PAUSE; break;
- case VK_CAPITAL: id = WXK_CAPITAL; break;
- case VK_SPACE: id = WXK_SPACE; break;
- case VK_ESCAPE: id = WXK_ESCAPE; break;
- case VK_SELECT: id = WXK_SELECT; break;
- case VK_PRINT: id = WXK_PRINT; break;
- case VK_EXECUTE: id = WXK_EXECUTE; break;
- case VK_HELP : id = WXK_HELP; break;
- case VK_NUMPAD0: id = WXK_NUMPAD0; break;
- case VK_NUMPAD1: id = WXK_NUMPAD1; break;
- case VK_NUMPAD2: id = WXK_NUMPAD2; break;
- case VK_NUMPAD3: id = WXK_NUMPAD3; break;
- case VK_NUMPAD4: id = WXK_NUMPAD4; break;
- case VK_NUMPAD5: id = WXK_NUMPAD5; break;
- case VK_NUMPAD6: id = WXK_NUMPAD6; break;
- case VK_NUMPAD7: id = WXK_NUMPAD7; break;
- case VK_NUMPAD8: id = WXK_NUMPAD8; break;
- case VK_NUMPAD9: id = WXK_NUMPAD9; break;
- case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break;
- case VK_ADD: id = WXK_NUMPAD_ADD; break;
- case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break;
- case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break;
- case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break;
- case VK_F1: id = WXK_F1; break;
- case VK_F2: id = WXK_F2; break;
- case VK_F3: id = WXK_F3; break;
- case VK_F4: id = WXK_F4; break;
- case VK_F5: id = WXK_F5; break;
- case VK_F6: id = WXK_F6; break;
- case VK_F7: id = WXK_F7; break;
- case VK_F8: id = WXK_F8; break;
- case VK_F9: id = WXK_F9; break;
- case VK_F10: id = WXK_F10; break;
- case VK_F11: id = WXK_F11; break;
- case VK_F12: id = WXK_F12; break;
- case VK_F13: id = WXK_F13; break;
- case VK_F14: id = WXK_F14; break;
- case VK_F15: id = WXK_F15; break;
- case VK_F16: id = WXK_F16; break;
- case VK_F17: id = WXK_F17; break;
- case VK_F18: id = WXK_F18; break;
- case VK_F19: id = WXK_F19; break;
- case VK_F20: id = WXK_F20; break;
- case VK_F21: id = WXK_F21; break;
- case VK_F22: id = WXK_F22; break;
- case VK_F23: id = WXK_F23; break;
- case VK_F24: id = WXK_F24; break;
- case VK_NUMLOCK: id = WXK_NUMLOCK; break;
- case VK_SCROLL: id = WXK_SCROLL; break;
+ // 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;
+ }
+ // 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: id = ';'; break;
- case VK_OEM_PLUS: id = '+'; break;
- case VK_OEM_COMMA: id = ','; break;
- case VK_OEM_MINUS: id = '-'; break;
- case VK_OEM_PERIOD: id = '.'; break;
- case VK_OEM_2: id = '/'; break;
- case VK_OEM_3: id = '~'; break;
- case VK_OEM_4: id = '['; break;
- case VK_OEM_5: id = '\\'; break;
- case VK_OEM_6: id = ']'; break;
- case VK_OEM_7: id = '\''; break;
-
-#ifdef VK_APPS
- case VK_LWIN: id = WXK_WINDOWS_LEFT; break;
- case VK_RWIN: id = WXK_WINDOWS_RIGHT; break;
- case VK_APPS: id = WXK_WINDOWS_MENU; break;
-#endif // VK_APPS defined
+ 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;
// handle extended keys
case VK_PRIOR:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
break;
+
case VK_NEXT:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
break;
+
case VK_END:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
break;
+
case VK_HOME:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
break;
+
case VK_LEFT:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
break;
+
case VK_UP:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
break;
+
case VK_RIGHT:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
break;
+
case VK_DOWN:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
break;
+
case VK_INSERT:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
break;
+
case VK_DELETE:
- id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
+ wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
break;
+
case VK_RETURN:
// don't use ChooseNormalOrExtended() here as the keys are reversed
// here: numpad enter is the extended one
- id = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
+ wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
break;
default:
- id = 0;
- }
-
- return id;
-}
-
-WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual)
-{
- *isVirtual = true;
- WXWORD keySym;
- switch (id)
- {
- case WXK_CANCEL: keySym = VK_CANCEL; break;
- case WXK_CLEAR: keySym = VK_CLEAR; break;
- case WXK_SHIFT: keySym = VK_SHIFT; break;
- case WXK_CONTROL: keySym = VK_CONTROL; break;
- case WXK_ALT: keySym = VK_MENU; break;
- case WXK_PAUSE: keySym = VK_PAUSE; break;
- case WXK_CAPITAL: keySym = VK_CAPITAL; break;
- case WXK_PAGEUP: keySym = VK_PRIOR; break;
- case WXK_PAGEDOWN: keySym = VK_NEXT; break;
- case WXK_END: keySym = VK_END; break;
- case WXK_HOME : keySym = VK_HOME; break;
- case WXK_LEFT : keySym = VK_LEFT; break;
- case WXK_UP: keySym = VK_UP; break;
- case WXK_RIGHT: keySym = VK_RIGHT; break;
- case WXK_DOWN : keySym = VK_DOWN; break;
- case WXK_SELECT: keySym = VK_SELECT; break;
- case WXK_PRINT: keySym = VK_PRINT; break;
- case WXK_EXECUTE: keySym = VK_EXECUTE; break;
- case WXK_INSERT: keySym = VK_INSERT; break;
- case WXK_DELETE: keySym = VK_DELETE; break;
- case WXK_HELP : keySym = VK_HELP; break;
- case WXK_NUMPAD0: keySym = VK_NUMPAD0; break;
- case WXK_NUMPAD1: keySym = VK_NUMPAD1; break;
- case WXK_NUMPAD2: keySym = VK_NUMPAD2; break;
- case WXK_NUMPAD3: keySym = VK_NUMPAD3; break;
- case WXK_NUMPAD4: keySym = VK_NUMPAD4; break;
- case WXK_NUMPAD5: keySym = VK_NUMPAD5; break;
- case WXK_NUMPAD6: keySym = VK_NUMPAD6; break;
- case WXK_NUMPAD7: keySym = VK_NUMPAD7; break;
- case WXK_NUMPAD8: keySym = VK_NUMPAD8; break;
- case WXK_NUMPAD9: keySym = VK_NUMPAD9; break;
- case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break;
- case WXK_NUMPAD_ADD: keySym = VK_ADD; break;
- case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break;
- case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break;
- case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break;
- case WXK_F1: keySym = VK_F1; break;
- case WXK_F2: keySym = VK_F2; break;
- case WXK_F3: keySym = VK_F3; break;
- case WXK_F4: keySym = VK_F4; break;
- case WXK_F5: keySym = VK_F5; break;
- case WXK_F6: keySym = VK_F6; break;
- case WXK_F7: keySym = VK_F7; break;
- case WXK_F8: keySym = VK_F8; break;
- case WXK_F9: keySym = VK_F9; break;
- case WXK_F10: keySym = VK_F10; break;
- case WXK_F11: keySym = VK_F11; break;
- case WXK_F12: keySym = VK_F12; break;
- case WXK_F13: keySym = VK_F13; break;
- case WXK_F14: keySym = VK_F14; break;
- case WXK_F15: keySym = VK_F15; break;
- case WXK_F16: keySym = VK_F16; break;
- case WXK_F17: keySym = VK_F17; break;
- case WXK_F18: keySym = VK_F18; break;
- case WXK_F19: keySym = VK_F19; break;
- case WXK_F20: keySym = VK_F20; break;
- case WXK_F21: keySym = VK_F21; break;
- case WXK_F22: keySym = VK_F22; break;
- case WXK_F23: keySym = VK_F23; break;
- case WXK_F24: keySym = VK_F24; break;
- case WXK_NUMLOCK: keySym = VK_NUMLOCK; break;
- case WXK_SCROLL: keySym = VK_SCROLL; break;
- default:
- {
- *isVirtual = false;
- keySym = (WORD)id;
+ wxk = 0;
+ }
+
+ return wxk;
+}
+
+WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
+{
+ if ( isVirtual )
+ *isVirtual = true;
+
+ // check the table first
+ for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
+ {
+ if ( gs_specialKeys[n].wxk == wxk )
+ return gs_specialKeys[n].vk;
+ }
+
+ // and then check for special keys not included in the table
+ WXWORD vk;
+ switch ( wxk )
+ {
+ case WXK_PAGEUP:
+ case WXK_NUMPAD_PAGEUP:
+ vk = VK_PRIOR;
+ break;
+
+ case WXK_PAGEDOWN:
+ case WXK_NUMPAD_PAGEDOWN:
+ vk = VK_NEXT;
+ break;
+
+ case WXK_END:
+ case WXK_NUMPAD_END:
+ vk = VK_END;
+ break;
+
+ case WXK_HOME:
+ case WXK_NUMPAD_HOME:
+ vk = VK_HOME;
+ break;
+
+ case WXK_LEFT:
+ case WXK_NUMPAD_LEFT:
+ vk = VK_LEFT;
+ break;
+
+ case WXK_UP:
+ case WXK_NUMPAD_UP:
+ vk = VK_UP;
+ break;
+
+ case WXK_RIGHT:
+ case WXK_NUMPAD_RIGHT:
+ vk = VK_RIGHT;
+ break;
+
+ case WXK_DOWN:
+ case WXK_NUMPAD_DOWN:
+ vk = VK_DOWN;
+ break;
+
+ case WXK_INSERT:
+ case WXK_NUMPAD_INSERT:
+ vk = VK_INSERT;
+ break;
+
+ case WXK_DELETE:
+ case WXK_NUMPAD_DELETE:
+ vk = VK_DELETE;
+ break;
+
+ default:
+ if ( isVirtual )
+ *isVirtual = false;
+ vk = (WXWORD)wxk;
+ break;
+ }
+
+ return vk;
+}
+
+#ifndef SM_SWAPBUTTON
+ #define SM_SWAPBUTTON 23
+#endif
+
+// small helper for wxGetKeyState() and wxGetMouseState()
+static inline bool wxIsKeyDown(WXWORD vk)
+{
+ switch (vk)
+ {
+ case VK_LBUTTON:
+ if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON;
+ break;
+ case VK_RBUTTON:
+ if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON;
break;
- }
}
- return keySym;
+ // the low order bit indicates whether the key was pressed since the last
+ // call and the high order one indicates whether it is down right now and
+ // we only want that one
+ return (GetAsyncKeyState(vk) & (1<<15)) != 0;
}
bool wxGetKeyState(wxKeyCode key)
{
- bool bVirtual;
+ // although this does work under Windows, it is not supported under other
+ // platforms so don't allow it, you must use wxGetMouseState() instead
+ wxASSERT_MSG( key != VK_LBUTTON &&
+ key != VK_RBUTTON &&
+ key != VK_MBUTTON,
+ wxT("can't use wxGetKeyState() for mouse buttons") );
- wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
- WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
+ const WXWORD vk = wxCharCodeWXToMSW(key);
-//High order with GetAsyncKeyState only available on WIN32
-#ifdef __WIN32__
- //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)
+ // 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 )
{
-#endif
- //low order bit means LED is highlighted,
- //high order means key is down
- //Here, for compat with other ports we want both
- return GetKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) != 0;
+ // low order bit means LED is highlighted and high order one means the
+ // key is down; for compatibility with the other ports return true if
+ // either one is set
+ return GetKeyState(vk) != 0;
-#ifdef __WIN32__
}
- else
+ else // normal key
{
- //normal key
- //low order bit means key pressed since last call
- //high order means key is down
- //We want only the high order bit - the key may not be down if only low order
- return ( GetAsyncKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) & (1<<15) ) != 0;
+ return wxIsKeyDown(vk);
}
-#endif
}
ms.SetX(pt.x);
ms.SetY(pt.y);
- ms.SetLeftDown( (GetAsyncKeyState(VK_LBUTTON) & (1<<15)) != 0 );
- ms.SetMiddleDown( (GetAsyncKeyState(VK_MBUTTON) & (1<<15)) != 0 );
- ms.SetRightDown( (GetAsyncKeyState(VK_RBUTTON) & (1<<15)) != 0 );
+ ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
+ ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
+ ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
- ms.SetControlDown( (GetAsyncKeyState(VK_CONTROL) & (1<<15)) != 0 );
- ms.SetShiftDown( (GetAsyncKeyState(VK_SHIFT) & (1<<15)) != 0 );
- ms.SetAltDown( (GetAsyncKeyState(VK_MENU) & (1<<15)) != 0 );
+ ms.SetControlDown(wxIsKeyDown(VK_CONTROL));
+ ms.SetShiftDown(wxIsKeyDown(VK_SHIFT));
+ ms.SetAltDown(wxIsKeyDown(VK_MENU));
// ms.SetMetaDown();
return ms;
case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
case 0x00A8: return wxT("WM_NCMBUTTONUP");
case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
+
+ case 0x00B0: return wxT("EM_GETSEL");
+ case 0x00B1: return wxT("EM_SETSEL");
+ case 0x00B2: return wxT("EM_GETRECT");
+ case 0x00B3: return wxT("EM_SETRECT");
+ case 0x00B4: return wxT("EM_SETRECTNP");
+ case 0x00B5: return wxT("EM_SCROLL");
+ case 0x00B6: return wxT("EM_LINESCROLL");
+ case 0x00B7: return wxT("EM_SCROLLCARET");
+ case 0x00B8: return wxT("EM_GETMODIFY");
+ case 0x00B9: return wxT("EM_SETMODIFY");
+ case 0x00BA: return wxT("EM_GETLINECOUNT");
+ case 0x00BB: return wxT("EM_LINEINDEX");
+ case 0x00BC: return wxT("EM_SETHANDLE");
+ case 0x00BD: return wxT("EM_GETHANDLE");
+ case 0x00BE: return wxT("EM_GETTHUMB");
+ case 0x00C1: return wxT("EM_LINELENGTH");
+ case 0x00C2: return wxT("EM_REPLACESEL");
+ case 0x00C4: return wxT("EM_GETLINE");
+ case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
+ case 0x00C6: return wxT("EM_CANUNDO");
+ case 0x00C7: return wxT("EM_UNDO");
+ case 0x00C8: return wxT("EM_FMTLINES");
+ case 0x00C9: return wxT("EM_LINEFROMCHAR");
+ case 0x00CB: return wxT("EM_SETTABSTOPS");
+ case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
+ case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
+ case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
+ case 0x00CF: return wxT("EM_SETREADONLY");
+ case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
+ case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
+ case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
+ case 0x00D3: return wxT("EM_SETMARGINS");
+ case 0x00D4: return wxT("EM_GETMARGINS");
+ case 0x00D5: return wxT("EM_GETLIMITTEXT");
+ case 0x00D6: return wxT("EM_POSFROMCHAR");
+ case 0x00D7: return wxT("EM_CHARFROMPOS");
+ case 0x00D8: return wxT("EM_SETIMESTATUS");
+ case 0x00D9: return wxT("EM_GETIMESTATUS");
+
case 0x0100: return wxT("WM_KEYDOWN");
case 0x0101: return wxT("WM_KEYUP");
case 0x0102: return wxT("WM_CHAR");
case 0x011F: return wxT("WM_MENUSELECT");
case 0x0120: return wxT("WM_MENUCHAR");
case 0x0121: return wxT("WM_ENTERIDLE");
+
+ case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
+ case 0x0133: return wxT("WM_CTLCOLOREDIT");
+ case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
+ case 0x0135: return wxT("WM_CTLCOLORBTN");
+ case 0x0136: return wxT("WM_CTLCOLORDLG");
+ case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
+ case 0x0138: return wxT("WM_CTLCOLORSTATIC");
+ case 0x01E1: return wxT("MN_GETHMENU");
+
case 0x0200: return wxT("WM_MOUSEMOVE");
case 0x0201: return wxT("WM_LBUTTONDOWN");
case 0x0202: return wxT("WM_LBUTTONUP");
case 0x0290: return wxT("WM_IME_KEYDOWN");
case 0x0291: return wxT("WM_IME_KEYUP");
+ case 0x02A0: return wxT("WM_NCMOUSEHOVER");
+ case 0x02A1: return wxT("WM_MOUSEHOVER");
+ case 0x02A2: return wxT("WM_NCMOUSELEAVE");
+ case 0x02A3: return wxT("WM_MOUSELEAVE");
+
case 0x0300: return wxT("WM_CUT");
case 0x0301: return wxT("WM_COPY");
case 0x0302: return wxT("WM_PASTE");
case 0x030F: return wxT("WM_QUERYNEWPALETTE");
case 0x0310: return wxT("WM_PALETTEISCHANGING");
case 0x0311: return wxT("WM_PALETTECHANGED");
-#if wxUSE_HOTKEY
case 0x0312: return wxT("WM_HOTKEY");
-#endif
+
+ case 0x0317: return wxT("WM_PRINT");
+ case 0x0318: return wxT("WM_PRINTCLIENT");
// common controls messages - although they're not strictly speaking
// standard, it's nice to decode them nevertheless
POINT pt2;
pt2.x = pt.x;
pt2.y = pt.y;
- HWND hWndHit = ::WindowFromPoint(pt2);
- wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ;
- HWND hWnd = hWndHit;
+ HWND hWnd = ::WindowFromPoint(pt2);
- // Try to find a window with a wxWindow associated with it
- while (!win && (hWnd != 0))
- {
- hWnd = ::GetParent(hWnd);
- win = wxFindWinFromHandle((WXHWND) hWnd) ;
- }
- return win;
+ return wxGetWindowFromHWND((WXHWND)hWnd);
}
// Get the current mouse position.
}
return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
- };
+ }
private:
static HHOOK ms_hMsgHookProc;