Author: dquintana Date: Sat Mar 15 21:38:15 2014 New Revision: 62509
URL: http://svn.reactos.org/svn/reactos?rev=62509&view=rev Log: [RSHELL] * Fix keyboard navigation and hottracking behaviour. One glitch remains where quickly moving the mouse to a parent's toolbar item, and returning to the submenu before it closes, won't restore the parent's hot item to the one with the submenu.
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp branches/shell-experiments/base/shell/rshell/CMenuBand.h branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp branches/shell-experiments/base/shell/rshell/CMenuFocusManager.h branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp branches/shell-experiments/base/shell/rshell/CMenuToolbars.h
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -345,6 +345,35 @@ hr = _CallCB(SMC_INITMENU, 0, 0); if (FAILED_UNEXPECTEDLY(hr)) return hr; + } + + CComPtr<IObjectWithSite> ows; + if (SUCCEEDED(m_subMenuParent->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows)))) + { + CComPtr<IServiceProvider> sp; + if (SUCCEEDED(ows->GetSite(IID_PPV_ARG(IServiceProvider, &sp)))) + { + CComPtr<IDeskBar> db0; + if (SUCCEEDED(sp->QueryInterface(IID_PPV_ARG(IDeskBar, &db0)))) + { + CComPtr<IUnknown> unk0; + if (SUCCEEDED(db0->GetClient(&unk0))) + { + CComPtr<IDeskBar> db; + if (SUCCEEDED(IUnknown_QueryService(unk0, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db)))) + { + CComPtr<IDeskBar> db1; + if (SUCCEEDED(IUnknown_QueryService(m_site, SID_SMenuBandParent, IID_PPV_ARG(IDeskBar, &db1)))) + { + if (fShow) + db->SetClient(db1); + else + db->SetClient(NULL); + } + } + } + } + } }
if (m_dwFlags & SMINIT_VERTICAL) @@ -494,8 +523,11 @@
HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient) { - UNIMPLEMENTED; - return S_OK; + if (m_subMenuChild) + m_subMenuChild = NULL; + if (!punkClient) + return S_OK; + return punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild)); }
HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient) @@ -673,6 +705,10 @@
HRESULT CMenuBand::_OnHotItemChanged(CMenuToolbarBase * tb, INT id) { + if (m_subMenuChild && id == -1) + { + return S_FALSE; + } m_hotBar = tb; m_hotItem = id; if (m_staticToolbar) m_staticToolbar->OnHotItemChanged(tb, id); @@ -779,7 +815,6 @@ } if (m_staticToolbar) m_staticToolbar->OnPopupItemChanged(toolbar, item); if (m_SFToolbar) m_SFToolbar->OnPopupItemChanged(toolbar, item); - m_subMenuChild = popup; if (popup) { if (m_subMenuParent) @@ -792,6 +827,15 @@ return S_OK; }
+HRESULT CMenuBand::_DisableMouseTrack(BOOL bDisable) +{ + if (m_staticToolbar) + m_staticToolbar->DisableMouseTrack(bDisable); + if (m_SFToolbar) + m_SFToolbar->DisableMouseTrack(bDisable); + return S_OK; +} + HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS) { UNIMPLEMENTED;
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuBand.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuBand.h [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -176,6 +176,7 @@ HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id); HRESULT _MenuItemHotTrack(DWORD changeType); HRESULT _OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude, CMenuToolbarBase * toolbar, INT item); + HRESULT _DisableMouseTrack(BOOL bDisable);
BOOL UseBigIcons() {
Modified: branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -607,8 +607,6 @@
LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { - DbgPrint("BaseBar %08p (de)activated (%08x, %08x).\n", m_hWnd, wParam, lParam); - // BUG in ReactOS: WM_ACTIVATE/WA_INACTIVE makes no sense with lParam==hWnd if (LOWORD(wParam) != 0 || reinterpret_cast<HWND>(lParam) == m_hWnd) {
Modified: branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -115,13 +115,76 @@ CMenuFocusManager::CMenuFocusManager() : m_currentBand(NULL), m_currentFocus(NULL), - m_bandCount(0) + m_bandCount(0), + m_mouseTrackDisabled(FALSE), + m_lastMoveFlags(0), + m_lastMovePos(0) { m_threadId = GetCurrentThreadId(); }
CMenuFocusManager::~CMenuFocusManager() { +} + +void CMenuFocusManager::DisableMouseTrack(HWND enableTo, BOOL disableThis) +{ + BOOL bDisable = FALSE; + + int i = m_bandCount; + while (--i >= 0) + { + CMenuBand * band = m_bandStack[i]; + + HWND hwnd; + HRESULT hr = band->_GetTopLevelWindow(&hwnd); + if (FAILED_UNEXPECTEDLY(hr)) + break; + + if (hwnd == enableTo) + { + band->_DisableMouseTrack(disableThis); + bDisable = TRUE; + } + else + { + band->_DisableMouseTrack(bDisable); + } + } + + if (m_mouseTrackDisabled == bDisable) + { + if (bDisable) + { + SetCapture(m_currentFocus); + } + else + ReleaseCapture(); + + m_mouseTrackDisabled = bDisable; + } +} + +HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd) +{ + if (hWnd == m_currentFocus) + return S_OK; + + int i = m_bandCount - 1; + while (--i >= 0) + { + CMenuBand * band = m_bandStack[i]; + + HWND hwnd; + HRESULT hr = band->_GetTopLevelWindow(&hwnd); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (hwnd == hWnd) + return S_OK; + } + + return S_FALSE; }
LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) @@ -129,6 +192,8 @@ if (nCode < 0) return CallNextHookEx(m_hHook, nCode, wParam, lParam);
+ DWORD pos = GetMessagePos(); + if (nCode == HC_ACTION) { BOOL callNext = TRUE; @@ -138,10 +203,33 @@
switch (msg->message) { + case WM_ACTIVATE: // does not trigger + ActivationChange(msg->hwnd); case WM_CLOSE: + break; + case WM_MOUSEMOVE: + if (m_lastMoveFlags != wParam || m_lastMovePos != pos) + { + m_lastMoveFlags = wParam; + m_lastMovePos = pos; + + POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) }; + + HWND window = WindowFromPoint(pt); + + if (IsTrackedWindow(window) == S_OK) + { + DisableMouseTrack(window, FALSE); + } + else + { + DisableMouseTrack(NULL, FALSE); + } + } break; case WM_SYSKEYDOWN: case WM_KEYDOWN: + DisableMouseTrack(m_currentFocus, TRUE); switch (msg->wParam) { case VK_MENU: @@ -193,6 +281,36 @@ return S_OK; }
+HRESULT CMenuFocusManager::ActivationChange(HWND newHwnd) +{ + HRESULT hr; + CMenuBand * newBand = NULL; + + CMenuBand * band; + PeekArray(&band); + + while (m_bandCount >= 0) + { + HWND hwnd; + hr = band->_GetTopLevelWindow(&hwnd); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (hwnd == newHwnd) + { + newBand = band; + break; + } + else + { + PopFromArray(NULL); + PeekArray(&band); + } + } + + return UpdateFocus(newBand); +} + HRESULT CMenuFocusManager::UpdateFocus(CMenuBand * newBand) { HRESULT hr; @@ -217,6 +335,11 @@ return hr; }
+ CHAR title[1024]; + GetWindowTextA(newFocus, title, 1024); + + DbgPrint("Focus is now at %08p, hwnd=%08x, title='%s'. m_bandCount=%d\n", newBand, newFocus, title, m_bandCount); + m_currentFocus = newFocus; m_currentBand = newBand;
@@ -239,14 +362,33 @@ CMenuBand * mbc; HRESULT hr;
- hr = PopFromArray(&mbc); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - if (mb != mbc) + HWND newFocus; + hr = mb->_GetTopLevelWindow(&newFocus); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + DbgPrint("Trying to pop %08p, hwnd=%08x\n", mb, newFocus); + + do { + hr = PopFromArray(&mbc); + if (FAILED_UNEXPECTEDLY(hr)) + { + mbc = NULL; + return hr; + } + } + while (mbc && mb != mbc); + + hr = PeekArray(&mb); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = UpdateFocus(mb); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (!mbc) return E_FAIL;
- hr = PeekArray(&mbc); - - return UpdateFocus(mbc); -} + return S_OK; +}
Modified: branches/shell-experiments/base/shell/rshell/CMenuFocusManager.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuFocusManager.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuFocusManager.h [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -43,6 +43,9 @@ HWND m_currentFocus; HHOOK m_hHook; DWORD m_threadId; + BOOL m_mouseTrackDisabled; + WPARAM m_lastMoveFlags; + LPARAM m_lastMovePos;
// TODO: make dynamic #define MAX_RECURSE 20 @@ -64,10 +67,14 @@ BEGIN_COM_MAP(CMenuFocusManager) END_COM_MAP()
+private: LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam); HRESULT PlaceHooks(HWND window); HRESULT RemoveHooks(HWND window); HRESULT UpdateFocus(CMenuBand * newBand); + HRESULT ActivationChange(HWND newHwnd); + void DisableMouseTrack(HWND enableTo, BOOL disableThis); + HRESULT IsTrackedWindow(HWND hWnd);
public: HRESULT PushMenu(CMenuBand * mb);
Modified: branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -40,6 +40,12 @@ #define TIMERID_HOTTRACK 1 #define SUBCLASS_ID_MENUBAND 1
+HRESULT CMenuToolbarBase::DisableMouseTrack(BOOL bDisable) +{ + m_disableMouseTrack = bDisable; + return S_OK; +} + HRESULT CMenuToolbarBase::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult) { NMHDR * hdr; @@ -82,7 +88,7 @@ return OnCommand(wParam, 0, theResult);
case TBN_HOTITEMCHANGE: - return OnHotItemChange(reinterpret_cast<LPNMTBHOTITEM>(hdr)); + return OnHotItemChange(reinterpret_cast<LPNMTBHOTITEM>(hdr), theResult);
case NM_RCLICK: return OnContextMenu(reinterpret_cast<LPNMMOUSE>(hdr)); @@ -183,7 +189,8 @@ CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) : m_hwnd(NULL), m_useFlatMenus(FALSE), - m_SubclassOld(NULL), + m_SubclassOld(NULL), + m_disableMouseTrack(FALSE), m_menuBand(menuBand), m_hwndToolbar(NULL), m_dwMenuFlags(0), @@ -417,18 +424,34 @@ return m_SubclassOld(hWnd, uMsg, wParam, lParam); }
-HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot) -{ +HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult) +{ + if (m_disableMouseTrack && hot->dwFlags & HICF_MOUSE) + { + *theResult = 1; + return S_OK; + } + if (hot->dwFlags & HICF_LEAVING) { KillTimer(m_hwndToolbar, TIMERID_HOTTRACK); - m_hotItem = -1; - m_menuBand->_OnHotItemChanged(NULL, -1); - m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); + + if (m_menuBand->_OnHotItemChanged(NULL, -1) == S_FALSE) + { + *theResult = 1; + return S_OK; + } + else + { + m_hotItem = -1; + m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); + return S_OK; + } } else if (m_hotItem != hot->idNew) { - if (m_toolbarFlags & SMINIT_VERTICAL) + if (hot->dwFlags & HICF_MOUSE && + m_toolbarFlags & SMINIT_VERTICAL) { DWORD elapsed = 0; SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0); @@ -438,6 +461,7 @@ m_hotItem = hot->idNew; m_menuBand->_OnHotItemChanged(this, m_hotItem); m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); + return S_OK; } return S_OK; } @@ -693,11 +717,9 @@
if (btn.dwData) { - m_hotItem = btn.idCommand; - if (prev != m_hotItem) + if (prev != btn.idCommand) { SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0); - return m_menuBand->_OnHotItemChanged(this, m_hotItem); } return S_OK; } @@ -713,11 +735,9 @@ } }
- m_hotItem = -1; - if (prev != m_hotItem) + if (prev != -1) { SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0); - m_menuBand->_OnHotItemChanged(NULL, -1); } return S_FALSE; }
Modified: branches/shell-experiments/base/shell/rshell/CMenuToolbars.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuToolbars.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuToolbars.h [iso-8859-1] Sat Mar 15 21:38:15 2014 @@ -29,6 +29,7 @@ HFONT m_marlett; BOOL m_useFlatMenus; WNDPROC m_SubclassOld; + BOOL m_disableMouseTrack;
protected: CMenuBand * m_menuBand; @@ -67,12 +68,14 @@ HRESULT DoContextMenu(IContextMenu* contextMenu);
HRESULT ChangeHotItem(DWORD changeType); - HRESULT OnHotItemChange(const NMTBHOTITEM * hot); + HRESULT OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult);
HRESULT GetIdealSize(SIZE& size); HRESULT SetPosSize(int x, int y, int cx, int cy);
void InvalidateDraw(); + + HRESULT DisableMouseTrack(BOOL bDisable);
virtual HRESULT FillToolbar(BOOL clearFirst=FALSE) = 0; virtual HRESULT OnContextMenu(NMMOUSE * rclick) = 0;