X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/feda30118705b9bb6b2fc966655048c39a703563..5f9fd7ea86d211e3681a71c9f70303aa72b5de3c:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index ec39a8be1d..3f8c4085f7 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -79,7 +79,7 @@ #include -#if !defined(__GNUWIN32__)|| defined(wxUSE_NORLANDER_HEADERS) +#ifndef __GNUWIN32_OLD__ #include #include #endif @@ -88,28 +88,16 @@ #include #endif -#if ( defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__ ) || defined(wxUSE_NORLANDER_HEADERS) - #include -#endif - -#ifndef __TWIN32__ - #ifdef __GNUWIN32__ - #ifndef wxUSE_NORLANDER_HEADERS - #include "wx/msw/gnuwin32/extra.h" - #endif +#if !defined(__GNUWIN32_OLD__) && !defined(__TWIN32__) + #ifdef __WIN95__ + #include + #endif +#else // broken compiler + #ifndef __TWIN32__ + #include "wx/msw/gnuwin32/extra.h" #endif #endif -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- - -// standard macros missing from some compilers headers -#ifndef GET_X_LPARAM - #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) - #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) -#endif // GET_X_LPARAM - // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- @@ -137,17 +125,22 @@ void wxRemoveHandleAssociation(wxWindow *win); void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win); wxWindow *wxFindWinFromHandle(WXHWND hWnd); +// this magical function is used to translate VK_APPS key presses to right +// mouse clicks +static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags); + // --------------------------------------------------------------------------- // event tables // --------------------------------------------------------------------------- - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) BEGIN_EVENT_TABLE(wxWindow, wxWindowBase) EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) EVT_INIT_DIALOG(wxWindow::OnInitDialog) EVT_IDLE(wxWindow::OnIdle) + EVT_SET_FOCUS(wxWindow::OnSetFocus) END_EVENT_TABLE() // =========================================================================== @@ -277,8 +270,12 @@ wxWindow::~wxWindow() if ( m_hWnd ) { - if ( !::DestroyWindow(GetHwnd()) ) - wxLogLastError("DestroyWindow"); + // VZ: test temp removed to understand what really happens here + //if (::IsWindow(GetHwnd())) + { + if ( !::DestroyWindow(GetHwnd()) ) + wxLogLastError("DestroyWindow"); + } // remove hWnd <-> wxWindow association wxRemoveHandleAssociation(this); @@ -480,7 +477,7 @@ bool wxWindow::SetCursor(const wxCursor& cursor) ::GetWindowRect(hWnd, &rect); if ( ::PtInRect(&rect, point) && !wxIsBusy() ) - ::SetCursor((HCURSOR)m_cursor.GetHCURSOR()); + ::SetCursor(GetHcursorOf(m_cursor)); return TRUE; } @@ -973,9 +970,9 @@ void wxWindow::OnIdle(wxIdleEvent& event) // by the time the OnIdle function is called, so 'state' may be // meaningless. int state = 0; - if ( ::GetKeyState(VK_SHIFT) != 0 ) + if ( wxIsShiftDown() ) state |= MK_SHIFT; - if ( ::GetKeyState(VK_CONTROL) != 0 ) + if ( wxIsCtrlDown() ) state |= MK_CONTROL; wxMouseEvent event(wxEVT_LEAVE_WINDOW); @@ -1472,7 +1469,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) // here we try to do all the job which ::IsDialogMessage() usually does // internally -#if 0 +#if 1 bool bProcess = TRUE; if ( msg->message != WM_KEYDOWN ) bProcess = FALSE; @@ -1482,8 +1479,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( bProcess ) { - bool bCtrlDown = (::GetKeyState(VK_CONTROL) & 0x100) != 0; - bool bShiftDown = (::GetKeyState(VK_SHIFT) & 0x100) != 0; + bool bCtrlDown = wxIsCtrlDown(); + bool bShiftDown = wxIsShiftDown(); // 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 @@ -1598,8 +1595,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) // don't process system keys here if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) ) { - if ( (msg->wParam == VK_TAB) && - (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) + if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() ) { // find the first notebook parent and change its page wxWindow *win = this; @@ -1612,7 +1608,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg) if ( nbook ) { - bool forward = !(::GetKeyState(VK_SHIFT) & 0x100); + bool forward = !wxIsShiftDown(); nbook->AdvanceSelection(forward); } @@ -1962,6 +1958,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) //else: get the dlg code from the DefWindowProc() break; + case WM_SYSKEYDOWN: case WM_KEYDOWN: // If this has been processed by an event handler, // return 0 now (we've handled it). @@ -2003,20 +2000,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) // click because both usually pop up a context menu case VK_APPS: { - // construct the key mask - WPARAM fwKeys = MK_RBUTTON; - if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 ) - fwKeys |= MK_CONTROL; - if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 ) - fwKeys |= MK_SHIFT; - - // simulate right mouse button click - DWORD dwPos = ::GetMessagePos(); - int x = GET_X_LPARAM(dwPos), - y = GET_Y_LPARAM(dwPos); - - ScreenToClient(&x, &y); - processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys); + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags); } break; #endif // VK_APPS @@ -2030,10 +2018,26 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) } break; + case WM_SYSKEYUP: case WM_KEYUP: - processed = HandleKeyUp((WORD) wParam, lParam); +#ifdef VK_APPS + // special case of VK_APPS: treat it the same as right mouse button + if ( wParam == VK_APPS ) + { + WPARAM flags; + int x, y; + + TranslateKbdEventToMouse(this, &x, &y, &flags); + processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags); + } + else +#endif // VK_APPS + { + processed = HandleKeyUp((WORD) wParam, lParam); + } break; + case WM_SYSCHAR: case WM_CHAR: // Always an ASCII character processed = HandleChar((WORD)wParam, lParam, TRUE); break; @@ -2292,6 +2296,17 @@ bool wxWindow::MSWCreate(int id, if ( width > -1 ) width1 = width; if ( height > -1 ) height1 = height; + // Unfortunately this won't work in WIN16. Unless perhaps + // we define WS_EX_CONTROLPARENT ourselves? +#ifndef __WIN16__ + // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or + // IsDialogMessage() won't work for us + if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL ) + { + extendedStyle |= WS_EX_CONTROLPARENT; + } +#endif + HWND hParent = (HWND)NULL; if ( parent ) hParent = (HWND) parent->GetHWND(); @@ -2519,6 +2534,33 @@ bool wxWindow::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- +void wxWindow::OnSetFocus(wxFocusEvent& event) +{ + // panel wants to track the window which was the last to have focus in it, + // so we want to set ourselves as the window which last had focus + // + // notice that it's also important to do it upwards the tree becaus + // otherwise when the top level panel gets focus, it won't set it back to + // us, but to some other sibling + wxWindow *win = this; + while ( win ) + { + wxWindow *parent = win->GetParent(); + wxPanel *panel = wxDynamicCast(parent, wxPanel); + if ( panel ) + { + panel->SetLastFocus(win); + } + + win = parent; + } + + wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"), + GetClassInfo()->GetClassName(), GetHandle()); + + event.Skip(); +} + bool wxWindow::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) @@ -2541,13 +2583,6 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) } #endif // wxUSE_CARET - // panel wants to track the window which was the last to have focus in it - wxPanel *panel = wxDynamicCast(GetParent(), wxPanel); - if ( panel ) - { - panel->SetLastFocus(this); - } - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); event.SetEventObject(this); @@ -2626,54 +2661,46 @@ bool wxWindow::HandleSetCursor(WXHWND hWnd, short nHitTest, int WXUNUSED(mouseMsg)) { - // don't set cursor for other windows, only for this one: this prevents - // children of this window from getting the same cursor as the parent has - // (don't forget that this message is propagated by default up the window - // parent-child hierarchy) - if ( GetHWND() == hWnd ) - { - // don't set cursor when the mouse is not in the client part - if ( nHitTest == HTCLIENT || nHitTest == HTERROR ) - { - HCURSOR hcursor = 0; - if ( wxIsBusy() ) - { - // from msw\utils.cpp - extern HCURSOR gs_wxBusyCursor; - - hcursor = gs_wxBusyCursor; - } - else - { - wxCursor *cursor = NULL; + // the logic is as follows: + // 1. if we have the cursor set it unless wxIsBusy() + // 2. if we're a top level window, set some cursor anyhow + // 3. if wxIsBusy(), set the busy cursor, otherwise the global one - if ( m_cursor.Ok() ) - { - cursor = &m_cursor; - } - else - { - // from msw\data.cpp - extern wxCursor *g_globalCursor; - - if ( g_globalCursor && g_globalCursor->Ok() ) - cursor = g_globalCursor; - } - - if ( cursor ) - hcursor = (HCURSOR)cursor->GetHCURSOR(); - } + HCURSOR hcursor = 0; + bool isBusy = wxIsBusy(); + if ( m_cursor.Ok() ) + { + hcursor = GetHcursorOf(m_cursor); + } - if ( hcursor ) + if ( !GetParent() ) + { + if ( isBusy ) + { + hcursor = wxGetCurrentBusyCursor(); + } + else if ( !hcursor ) + { + const wxCursor *cursor = wxGetGlobalCursor(); + if ( cursor && cursor->Ok() ) { - ::SetCursor(hcursor); - - return TRUE; + hcursor = GetHcursorOf(*cursor); } } } - return FALSE; + if ( hcursor ) + { + ::SetCursor(hcursor); + + // cursor set, stop here + return TRUE; + } + else + { + // pass up the window chain + return FALSE; + } } // --------------------------------------------------------------------------- @@ -2982,13 +3009,14 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) return popupMenu->MSWCommand(cmd, id); } - wxWindow *win; + wxWindow *win = (wxWindow*) NULL; if ( cmd == 0 || cmd == 1 ) // menu or accel - use id { // must cast to a signed type before comparing with other ids! win = FindItem((signed short)id); } - else + + if (!win && control) { // find it from HWND - this works even with the broken programs using // the same ids for different controls @@ -2996,17 +3024,25 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control) } if ( win ) + { return win->MSWCommand(cmd, id); - else + } + + // the messages sent from the in-place edit control used by the treectrl + // for label editing have id == 0, but they should _not_ be treated as menu + // messages (they are EN_XXX ones, in fact) so don't translate anything + // coming from a control to wxEVT_COMMAND_MENU_SELECTED + if ( !control ) { - // If no child window, it may be an accelerator, e.g. for - // a popup menu command. + // If no child window, it may be an accelerator, e.g. for a popup menu + // command wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); event.SetEventObject(this); event.SetId(id); event.SetInt(id); - return ProcessEvent(event); + + return GetEventHandler()->ProcessEvent(event); } return FALSE; @@ -3112,12 +3148,43 @@ bool wxWindow::HandleMouseMove(int x, int y, WXUINT flags) // keyboard handling // --------------------------------------------------------------------------- +// create the key event of the given type for the given key - used by +// HandleChar and HandleKeyDown/Up +wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType, + int id, + WXLPARAM lParam) const +{ + wxKeyEvent event(evType); + event.SetId(GetId()); + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); + event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN; + + event.m_eventObject = (wxWindow *)this; // const_cast + event.m_keyCode = id; + event.SetTimestamp(s_currentMsg.time); + + // translate the position to client coords + POINT pt; + GetCursorPos(&pt); + RECT rect; + GetWindowRect(GetHwnd(),&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + event.m_x = pt.x; + event.m_y = pt.y; + + return event; +} + // isASCII is TRUE only when we're called from WM_CHAR handler and not from // WM_KEYDOWN one bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) { + bool ctrlDown = FALSE; + int id; - bool tempControlDown = FALSE; if ( isASCII ) { // If 1 -> 26, translate to CTRL plus a letter. @@ -3126,142 +3193,86 @@ bool wxWindow::HandleChar(WXWORD wParam, WXLPARAM lParam, bool isASCII) { switch (id) { - case 13: - { + case 13: id = WXK_RETURN; break; - } - case 8: - { + + case 8: id = WXK_BACK; break; - } - case 9: - { + + case 9: id = WXK_TAB; break; - } - default: - { - tempControlDown = TRUE; + + default: + ctrlDown = TRUE; id = id + 96; - } } } } - else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + else if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) + { // it's ASCII and will be processed here only when called from - // WM_CHAR (i.e. when isASCII = TRUE) + // WM_CHAR (i.e. when isASCII = TRUE), don't process it now id = -1; } if ( id != -1 ) { - wxKeyEvent event(wxEVT_CHAR); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; + wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam)); + if ( ctrlDown ) + { + event.m_controlDown = TRUE; + } if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } bool wxWindow::HandleKeyDown(WXWORD wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_DOWN); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) { return TRUE; } - else return FALSE; - } - else - { - return FALSE; } + + return FALSE; } bool wxWindow::HandleKeyUp(WXWORD wParam, WXLPARAM lParam) { - int id; + int id = wxCharCodeMSWToWX(wParam); - if ( (id = wxCharCodeMSWToWX(wParam)) == 0 ) { + if ( !id ) + { + // normal ASCII char id = wParam; } - if ( id != -1 ) + if ( id != -1 ) // VZ: does this ever happen (FIXME)? { - wxKeyEvent event(wxEVT_KEY_UP); - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) - event.m_altDown = TRUE; - - event.m_eventObject = this; - event.m_keyCode = id; - event.SetTimestamp(s_currentMsg.time); - - POINT pt; - GetCursorPos(&pt); - RECT rect; - GetWindowRect(GetHwnd(),&rect); - pt.x -= rect.left; - pt.y -= rect.top; - - event.m_x = pt.x; event.m_y = pt.y; - + wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam)); if ( GetEventHandler()->ProcessEvent(event) ) return TRUE; - else - return FALSE; } - else - return FALSE; + + return FALSE; } // --------------------------------------------------------------------------- @@ -3394,8 +3405,8 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam, break; case SB_THUMBPOSITION: - event.m_isScrolling = FALSE; - /* fall-through */ + event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE; + break; case SB_THUMBTRACK: event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK; @@ -3610,6 +3621,48 @@ wxWindow *wxGetActiveWindow() return NULL; } +extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd) +{ + HWND hwnd = (HWND)hWnd; + + // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set + // by code in msw/radiobox.cpp), for all the others we just search up the + // window hierarchy + wxWindow *win = (wxWindow *)NULL; + if ( hwnd ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + if ( !win ) + { + // the radiobox pointer is stored in GWL_USERDATA only under Win32 +#ifdef __WIN32__ + // native radiobuttons return DLGC_RADIOBUTTON here and for any + // wxWindow class which overrides WM_GETDLGCODE processing to + // do it as well, win would be already non NULL + if ( ::SendMessage((HWND)hwnd, WM_GETDLGCODE, + 0, 0) & DLGC_RADIOBUTTON ) + { + win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA); + } + else +#endif // Win32 + { + // hwnd is not a wxWindow, try its parent next below + hwnd = ::GetParent(hwnd); + } + } + //else: it's a wxRadioButton, not a radiobutton from wxRadioBox + } + + while ( hwnd && !win ) + { + win = wxFindWinFromHandle((WXHWND)hwnd); + hwnd = ::GetParent(hwnd); + } + + return win; +} + // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE // in active frames and dialogs, regardless of where the focus is. static HHOOK wxTheKeyboardHook = 0; @@ -3625,18 +3678,19 @@ void wxSetKeyboardHook(bool doIt) wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(), #if defined(__WIN32__) && !defined(__TWIN32__) - GetCurrentThreadId()); + GetCurrentThreadId() // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right? #else - GetCurrentTask()); + GetCurrentTask() #endif + ); } else { UnhookWindowsHookEx(wxTheKeyboardHook); // avoids mingw warning about statement with no effect (FreeProcInstance // doesn't do anything under Win32) -#ifndef __GNUWIN32__ +#ifndef __GNUC__ FreeProcInstance(wxTheKeyboardHookProc); #endif } @@ -3648,8 +3702,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) DWORD hiWord = HIWORD(lParam); if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - int id; - if ( (id = wxCharCodeMSWToWX(wParam)) != 0 ) + int id = wxCharCodeMSWToWX(wParam); + if ( id != 0 ) { wxKeyEvent event(wxEVT_CHAR_HOOK); if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN ) @@ -3657,25 +3711,31 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) event.m_eventObject = NULL; event.m_keyCode = id; - /* begin Albert's fix for control and shift key 26.5 */ - event.m_shiftDown = (::GetKeyState(VK_SHIFT)&0x100?TRUE:FALSE); - event.m_controlDown = (::GetKeyState(VK_CONTROL)&0x100?TRUE:FALSE); - /* end Albert's fix for control and shift key 26.5 */ + event.m_shiftDown = wxIsShiftDown(); + event.m_controlDown = wxIsCtrlDown(); event.SetTimestamp(s_currentMsg.time); wxWindow *win = wxGetActiveWindow(); + wxEvtHandler *handler; if ( win ) { - if ( win->GetEventHandler()->ProcessEvent(event) ) - return 1; + handler = win->GetEventHandler(); + event.SetId(win->GetId()); } else { - if ( wxTheApp && wxTheApp->ProcessEvent(event) ) - return 1; + handler = wxTheApp; + event.SetId(-1); + } + + if ( handler && handler->ProcessEvent(event) ) + { + // processed + return 1; } } } + return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam); } @@ -4097,3 +4157,22 @@ const char *wxGetMessageName(int message) } } #endif //__WXDEBUG__ + +static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags) +{ + // construct the key mask + WPARAM& fwKeys = *flags; + + fwKeys = MK_RBUTTON; + if ( wxIsCtrlDown() ) + fwKeys |= MK_CONTROL; + if ( wxIsShiftDown() ) + fwKeys |= MK_SHIFT; + + // simulate right mouse button click + DWORD dwPos = ::GetMessagePos(); + *x = GET_X_LPARAM(dwPos); + *y = GET_Y_LPARAM(dwPos); + + win->ScreenToClient(x, y); +}