m_selectedMenu(NULL),
m_selectedItem(0),
m_selectedItemFlags(0),
+ m_isLButtonDown(FALSE),
+ m_movedSinceDown(FALSE),
+ m_windowAtDown(NULL),
m_bandCount(0)
{
m_ptPrev.x = 0;
return S_FALSE;
}
+HRESULT CMenuFocusManager::IsTrackedWindowOrParent(HWND hWnd)
+{
+ for (int i = m_bandCount; --i >= 0;)
+ {
+ StackEntry& entry = m_bandStack[i];
+
+ if (entry.type != TrackedMenuEntry)
+ {
+ HRESULT hr = entry.mb->IsWindowOwner(hWnd);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ if (hr == S_OK)
+ return S_OK;
+ if (entry.mb->_IsPopup() == S_OK)
+ {
+ CComPtr<IUnknown> site;
+ CComPtr<IOleWindow> pw;
+ hr = entry.mb->GetSite(IID_PPV_ARG(IUnknown, &site));
+ if (FAILED_UNEXPECTEDLY(hr))
+ continue;
+ hr = IUnknown_QueryService(site, SID_SMenuBandParent, IID_PPV_ARG(IOleWindow, &pw));
+ if (FAILED_UNEXPECTEDLY(hr))
+ continue;
+
+ HWND hParent;
+ if (pw->GetWindow(&hParent) == S_OK && hParent == hWnd)
+ return S_OK;
+ }
+ }
+ }
+
+ return S_FALSE;
+}
+
LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg)
{
HWND child;
if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
return TRUE;
+
+ m_movedSinceDown = TRUE;
+
m_ptPrev = pt;
child = WindowFromPoint(pt);
StackEntry * entry = NULL;
- IsTrackedWindow(child, &entry);
+ if (IsTrackedWindow(child, &entry) == S_OK)
+ {
+ TRACE("MouseMove %d\n", m_isLButtonDown);
+ }
BOOL isTracking = FALSE;
- if (entry)
+ if (entry && (entry->type == MenuBarEntry || m_current->type != TrackedMenuEntry))
{
ScreenToClient(child, &pt);
iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
if (SendMessage(child, WM_USER_ISTRACKEDITEM, iHitTestResult, 0) == S_FALSE)
{
- TRACE("Hot item tracking detected a change (capture=%p)...\n", m_captureHwnd);
+ TRACE("Hot item tracking detected a change (capture=%p / cCapture=%p)...\n", m_captureHwnd, cCapture);
DisableMouseTrack(NULL, FALSE);
- if (isTracking && iHitTestResult>=0 && m_current->type == TrackedMenuEntry)
+ if (isTracking && iHitTestResult >= 0 && m_current->type == TrackedMenuEntry)
SendMessage(entry->hwnd, WM_CANCELMODE, 0, 0);
- PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, isTracking);
+ PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, MAKELPARAM(isTracking, TRUE));
if (m_current->type == TrackedMenuEntry)
return FALSE;
}
return TRUE;
}
-LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam)
+LRESULT CMenuFocusManager::ProcessMouseDown(MSG* msg)
+{
+ HWND child;
+ int iHitTestResult = -1;
+
+ TRACE("ProcessMouseDown %d %d %d\n", msg->message, msg->wParam, msg->lParam);
+
+ // Don't do anything if another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
+ return TRUE;
+
+
+ POINT pt = msg->pt;
+
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
+ return TRUE;
+
+ TRACE("MouseDown %d\n", m_isLButtonDown);
+
+ if (entry)
+ {
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+
+ if (iHitTestResult >= 0)
+ {
+ TRACE("MouseDown send %d\n", iHitTestResult);
+ entry->mb->_MenuBarMouseDown(child, iHitTestResult);
+ }
+ }
+
+ msg->message = WM_NULL;
+
+ m_isLButtonDown = TRUE;
+ m_movedSinceDown = FALSE;
+ m_windowAtDown = child;
+
+ TRACE("MouseDown end %d\n", m_isLButtonDown);
+
+ return TRUE;
+}
+
+LRESULT CMenuFocusManager::ProcessMouseUp(MSG* msg)
+{
+ HWND child;
+ int iHitTestResult = -1;
+
+ TRACE("ProcessMouseUp %d %d %d\n", msg->message, msg->wParam, msg->lParam);
+
+ // Don't do anything if another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
+ return TRUE;
+
+ if (!m_isLButtonDown)
+ return TRUE;
+
+ m_isLButtonDown = FALSE;
+
+ POINT pt = msg->pt;
+
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
+ return TRUE;
+
+ TRACE("MouseUp %d\n", m_isLButtonDown);
+
+ if (entry)
+ {
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+
+ if (iHitTestResult >= 0)
+ {
+ TRACE("MouseUp send %d\n", iHitTestResult);
+ entry->mb->_MenuBarMouseUp(child, iHitTestResult);
+ }
+ }
+
+ return TRUE;
+}
+
+LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
{
if (nCode < 0)
- return CallNextHookEx(m_hMsgFilterHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
if (nCode == MSGF_MENU)
{
BOOL callNext = TRUE;
- MSG* msg = reinterpret_cast<MSG*>(lParam);
+ MSG* msg = reinterpret_cast<MSG*>(hookLParam);
switch (msg->message)
{
case WM_NCLBUTTONDOWN:
case WM_LBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ case WM_RBUTTONDOWN:
if (m_menuBar)
{
POINT pt = msg->pt;
if (hoveringMenuBar)
{
m_menuBar->mb->_DisableMouseTrack(TRUE);
+ if (m_current->type == TrackedMenuEntry)
+ {
+ SendMessage(m_parent->hwnd, WM_CANCELMODE, 0, 0);
+ msg->message = WM_NULL;
+ }
}
}
break;
+ case WM_NCLBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_NCRBUTTONUP:
+ case WM_RBUTTONUP:
+ if (m_current && m_current->type != TrackedMenuEntry)
+ {
+ msg->message = WM_NULL;
+ }
+ break;
case WM_MOUSEMOVE:
callNext = ProcessMouseMove(msg);
break;
case WM_INITMENUPOPUP:
- DbgPrint("WM_INITMENUPOPUP %p %p\n", wParam, lParam);
- m_selectedMenu = reinterpret_cast<HMENU>(lParam);
+ TRACE("WM_INITMENUPOPUP %p %p\n", msg->wParam, msg->lParam);
+ m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
m_selectedItem = -1;
m_selectedItemFlags = 0;
break;
case WM_MENUSELECT:
- DbgPrint("WM_MENUSELECT %p %p\n", wParam, lParam);
- m_selectedMenu = reinterpret_cast<HMENU>(lParam);
- m_selectedItem = LOWORD(wParam);
- m_selectedItemFlags = HIWORD(wParam);
+ TRACE("WM_MENUSELECT %p %p\n", msg->wParam, msg->lParam);
+ m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
+ m_selectedItem = GET_X_LPARAM(msg->wParam);
+ m_selectedItemFlags = HIWORD(msg->wParam);
break;
case WM_KEYDOWN:
switch (msg->wParam)
}
break;
case VK_RIGHT:
- if (!(m_selectedItemFlags & MF_POPUP))
+ if (m_selectedItem < 0 || !(m_selectedItemFlags & MF_POPUP))
{
m_parent->mb->_MenuItemHotTrack(VK_RIGHT);
}
return 1;
}
- return CallNextHookEx(m_hMsgFilterHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
}
-LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
+LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
{
+ BOOL isLButton = FALSE;
if (nCode < 0)
- return CallNextHookEx(m_hGetMsgHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
if (nCode == HC_ACTION)
{
BOOL callNext = TRUE;
- MSG* msg = reinterpret_cast<MSG*>(lParam);
+ MSG* msg = reinterpret_cast<MSG*>(hookLParam);
POINT pt = msg->pt;
switch (msg->message)
{
case WM_NCLBUTTONDOWN:
case WM_LBUTTONDOWN:
+ isLButton = TRUE;
+
+ // fallthrough;
+ case WM_NCRBUTTONDOWN:
+ case WM_RBUTTONDOWN:
if (m_current->type == MenuPopupEntry)
{
HWND child = WindowFromPoint(pt);
- if (IsTrackedWindow(child) != S_OK)
+ if (IsTrackedWindowOrParent(child) != S_OK)
{
SetCapture(NULL);
m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
+ break;
}
}
+
+ if (isLButton)
+ {
+ ProcessMouseDown(msg);
+ }
+ break;
+ case WM_NCLBUTTONUP:
+ case WM_LBUTTONUP:
+ ProcessMouseUp(msg);
break;
case WM_MOUSEMOVE:
callNext = ProcessMouseMove(msg);
case VK_RMENU:
m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
break;
+ case VK_RETURN:
+ m_current->mb->_MenuItemHotTrack(MPOS_EXECUTE);
+ break;
case VK_LEFT:
m_current->mb->_MenuItemHotTrack(VK_LEFT);
break;
m_current->mb->_MenuItemHotTrack(VK_DOWN);
break;
}
+ msg->message = WM_NULL;
+ msg->lParam = 0;
+ msg->wParam = 0;
}
break;
}
return 1;
}
- return CallNextHookEx(m_hGetMsgHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
}
HRESULT CMenuFocusManager::PlaceHooks()
{
+ if (m_hMsgFilterHook)
+ {
+ WARN("GETMESSAGE hook already placed!\n");
+ return S_OK;
+ }
+ if (m_hMsgFilterHook)
+ {
+ WARN("MSGFILTER hook already placed!\n");
+ return S_OK;
+ }
if (m_current->type == TrackedMenuEntry)
{
TRACE("Entering MSGFILTER hook...\n");
HRESULT hr;
StackEntry * old = m_current;
+ TRACE("UpdateFocus\n");
+
if (old)
SetCapture(NULL);
HRESULT CMenuFocusManager::PushMenuBar(CMenuBand * mb)
{
+ DbgPrint("PushMenuBar %p\n", mb);
+
+ mb->AddRef();
+
_ASSERT(m_bandCount == 0);
HRESULT hr = PushToArray(MenuBarEntry, mb, NULL);
HRESULT CMenuFocusManager::PushMenuPopup(CMenuBand * mb)
{
+ DbgPrint("PushTrackedPopup %p\n", mb);
+
+ mb->AddRef();
+
_ASSERT(!m_current || m_current->type != TrackedMenuEntry);
HRESULT hr = PushToArray(MenuPopupEntry, mb, NULL);
HRESULT CMenuFocusManager::PushTrackedPopup(HMENU popup)
{
+ DbgPrint("PushTrackedPopup %p\n", popup);
+
_ASSERT(m_bandCount > 0);
_ASSERT(!m_current || m_current->type != TrackedMenuEntry);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
+ DbgPrint("PushTrackedPopup %p\n", popup);
+ m_selectedMenu = popup;
+ m_selectedItem = -1;
+ m_selectedItemFlags = 0;
+
return UpdateFocus();
}
CMenuBand * mbc;
HRESULT hr;
+ DbgPrint("PopMenuBar %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
+ {
+ m_entryUnderMouse = NULL;
+ }
+
hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
{
mbc->_SetParentBand(NULL);
+ mbc->Release();
+
hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CMenuBand * mbc;
HRESULT hr;
+ DbgPrint("PopMenuPopup %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
+ {
+ m_entryUnderMouse = NULL;
+ }
+
hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
{
mbc->_SetParentBand(NULL);
+ mbc->Release();
+
hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
HMENU hmenu;
HRESULT hr;
+ DbgPrint("PopTrackedPopup %p\n", popup);
+
hr = PopFromArray(&type, NULL, &hmenu);
if (FAILED_UNEXPECTEDLY(hr))
{