You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
9.3 KiB
C++

2 years ago
// XTPMouseManager.cpp : implementation of the CXTPMouseManager class.
//
// This file is a part of the XTREME COMMANDBARS MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPHookManager.h"
#include "XTPCommandBarsDefines.h"
#include "XTPMouseManager.h"
#include "XTPCommandBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CThreadLocal<CXTPMouseManager> CXTPMouseManager::_xtpMouseThreadState;
static CPoint ptMouse;
#define TID_MOUSELEAVE 113341
CXTPMouseManager::CXTPMouseManager()
{
m_hHookMouse = 0;
m_nLock = 0;
m_hwndLeave = 0;
m_bForceExpanded = FALSE;
m_pSelected = 0;
m_bIgnoreLButtonUp = FALSE;
#ifdef _AFXDLL
m_pModuleState = 0;
#endif
SetupHook(TRUE);
}
CXTPMouseManager::~CXTPMouseManager()
{
SetupHook(FALSE);
}
void CXTPMouseManager::DeliverMessage(CXTPCommandBar* pCapture, WPARAM wParam, POINT pt)
{
if (!pCapture->GetSafeHwnd())
return;
switch (wParam)
{
case WM_MOUSEMOVE:
case WM_NCMOUSEMOVE:
if (pCapture->m_nLockRecurse <= 0)
{
pCapture->ScreenToClient(&pt);
pCapture->OnMouseMove(0, pt);
}
break;
case WM_LBUTTONDOWN:
case WM_NCLBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_NCRBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_NCMBUTTONDOWN:
SendTrackLost();
break;
case WM_LBUTTONUP:
case WM_NCLBUTTONUP:
if (!IsMouseLocked())
SendTrackLost();
break;
}
}
CXTPCommandBar* CXTPMouseManager::HitTest(POINT point) const
{
HWND hWndMouse = ::WindowFromPoint(point);
const CTrackArray& arrTracked = m_arrTracked;
int i;
for (i = (int)arrTracked.GetSize() - 1; i >= 0; i--)
{
CXTPCommandBar* pCommandBar = arrTracked[i];
if (!pCommandBar->GetSafeHwnd())
continue;
int nHtCode = pCommandBar->OnMouseHitTest(point);
if ((nHtCode != HTERROR) && ((nHtCode == HTCLIENT) || ::IsChild(pCommandBar->GetSafeHwnd(), hWndMouse)))
{
return pCommandBar;
}
}
return NULL;
}
BOOL CXTPMouseManager::PreviewTackLost(CXTPCommandBar* pContextMenu, MSG* msg) const
{
if (!(msg->message == WM_LBUTTONDOWN || msg->message == WM_RBUTTONDOWN || msg->message == WM_MBUTTONDOWN ||
msg->message == WM_NCLBUTTONDOWN || msg->message == WM_NCRBUTTONDOWN))
{
return FALSE;
}
CPoint point;
GetCursorPos(&point);
CXTPCommandBar* pCommandBar = HitTest(point);
if (pCommandBar)
{
if (pCommandBar->m_nLockRecurse == 0 || pContextMenu->m_nLockRecurse != 0)
return FALSE;
}
HWND hWndMouse = ::WindowFromPoint(point);
if (m_arrTracked.GetSize() > 0)
{
const CTrustedArray& arrTrusted = m_arrTrusted;
for (int i = 0; i < arrTrusted.GetSize(); i++)
{
HWND hWnd = arrTrusted[i];
if (IsWindow(hWnd) && IsWindowVisible(hWnd) && CXTPWindowRect(hWnd).PtInRect(point))
{
return FALSE;
}
}
if (hWndMouse)
{
if (GetClassLong(hWndMouse, GCL_STYLE) & CS_IME)
return FALSE;
}
}
return TRUE;
}
BOOL CXTPMouseManager::IsRelated(HWND hWndParent, HWND hWnd) const
{
hWnd = ::GetParent(hWnd);
while (hWnd)
{
if (hWnd == hWndParent)
return TRUE;
hWnd = ::GetParent(hWnd);
}
return FALSE;
}
BOOL CXTPMouseManager::PreTranslateMouseEvents(WPARAM wParam, POINT point)
{
HWND hWndMouse = ::WindowFromPoint(point);
CTrackArray& arrTracked = m_arrTracked;
int i;
for (i = (int)arrTracked.GetSize() - 1; i >= 0; i--)
{
CXTPCommandBar* pCommandBar = arrTracked[i];
if (!pCommandBar->GetSafeHwnd())
continue;
int nHtCode = pCommandBar->OnMouseHitTest(point);
if ((nHtCode != HTERROR) && ((nHtCode == HTCLIENT) || ::IsChild(pCommandBar->GetSafeHwnd(), hWndMouse) || IsRelated(pCommandBar->GetSafeHwnd(), hWndMouse)))
{
if (pCommandBar->m_nLockRecurse > 0 && wParam != WM_MOUSEMOVE && wParam != WM_NCMOUSEMOVE && !m_bIgnoreLButtonUp)
{
SendTrackLostRecurse();
ptMouse = 0;
}
return FALSE;
}
}
if (arrTracked.GetSize() > 0)
{
CTrustedArray& arrTrusted = m_arrTrusted;
for (i = 0; i < arrTrusted.GetSize(); i++)
{
HWND hWnd = arrTrusted[i];
if (IsWindow(hWnd) && IsWindowVisible(hWnd) && CXTPWindowRect(hWnd).PtInRect(point))
{
return FALSE;
}
}
}
if (hWndMouse && arrTracked.GetSize() > 0)
{
if (GetClassLong(hWndMouse, GCL_STYLE) & CS_IME)
return FALSE;
}
for (i = 0; i < arrTracked.GetSize(); i++)
{
DeliverMessage(arrTracked.GetAt(i), wParam, point);
}
return FALSE;
}
LRESULT CALLBACK CXTPMouseManager::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CXTPMouseManager* pMouseManager = XTPMouseManager();
if (nCode != HC_ACTION)
return CallNextHookEx(pMouseManager->m_hHookMouse, nCode, wParam, lParam);
PMOUSEHOOKSTRUCT pHook = (PMOUSEHOOKSTRUCT)lParam;
CPoint point = pHook->pt;
CTrackArray& arrTracked = pMouseManager->m_arrTracked;
if (wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN)
pMouseManager->m_bIgnoreLButtonUp = FALSE;
if ((wParam == WM_LBUTTONUP || wParam == WM_NCLBUTTONUP) && pMouseManager->m_bIgnoreLButtonUp)
{
pMouseManager->m_bIgnoreLButtonUp = FALSE;
return TRUE;
}
if (arrTracked.GetSize() != 0 && (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE) && ptMouse == point)
return TRUE;
ptMouse = point;
if (pMouseManager->m_arrTracked.GetSize() == 0)
return CallNextHookEx(pMouseManager->m_hHookMouse, nCode, wParam, lParam);
SAFE_MANAGE_STATE(pMouseManager->m_pModuleState);
if (pMouseManager->PreTranslateMouseEvents(wParam, point))
{
return 1;
}
return CallNextHookEx(pMouseManager->m_hHookMouse, nCode, wParam, lParam);
}
void CXTPMouseManager::SetupHook(BOOL bHook)
{
if (bHook && m_hHookMouse == 0)
{
m_hHookMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, 0, GetCurrentThreadId ());
}
if (!bHook && m_hHookMouse)
{
UnhookWindowsHookEx(m_hHookMouse);
m_hHookMouse = 0;
}
}
void CXTPMouseManager::SetTrack(CXTPCommandBar* pTrack, BOOL /*bCaptureMouse*/)
{
#ifdef _AFXDLL
m_pModuleState = AfxGetModuleState();
#endif
if (m_arrTracked.GetSize() == 0 && m_pSelected && m_pSelected != pTrack)
m_pSelected->OnTrackEnter();
if (m_arrTracked.Find(pTrack) == -1)
m_arrTracked.Add(pTrack);
}
void CXTPMouseManager::RemoveTrack(CXTPCommandBar* pTrack)
{
int nIndex = m_arrTracked.Find(pTrack);
if (nIndex != -1)
{
m_arrTracked.RemoveAt(nIndex);
}
if (m_arrTracked.GetSize() == 0)
{
RefreshCursor();
}
m_bIgnoreLButtonUp = FALSE;
}
void AFX_CDECL CXTPMouseManager::RefreshCursor()
{
ptMouse = CPoint(-1, -1);
CPoint pt;
GetCursorPos(&pt);
SetCursorPos(pt.x, pt.y);
}
void CXTPMouseManager::SendTrackLost()
{
while (m_arrTracked.GetSize() > 0)
{
m_arrTracked[0]->OnTrackLost();
}
}
BOOL CXTPMouseManager::IsTopParentActive(HWND hWnd)
{
return CXTPDrawHelpers::IsTopParentActive(hWnd);
}
void CALLBACK CXTPMouseManager::TrackMouseTimerProc (HWND hWnd, UINT /*uMsg*/, UINT idEvent, DWORD /*dwTime*/)
{
RECT rect;
POINT pt;
if (!IsWindow(hWnd))
{
KillTimer (hWnd, idEvent);
XTPMouseManager()->m_hwndLeave = 0;
return;
}
GetWindowRect(hWnd, &rect);
::GetCursorPos (&pt);
BOOL bTopParentActive = GetParent(hWnd) == 0 || (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUP) || IsTopParentActive(hWnd);
if (!::PtInRect (&rect, pt) || !bTopParentActive)
{
KillTimer (hWnd, idEvent);
XTPMouseManager()->m_hwndLeave = 0;
::PostMessage (hWnd, WM_MOUSELEAVE, 0, 0);
}
}
void CXTPMouseManager::TrackMouseLeave(HWND hwnd)
{
if (m_hwndLeave == hwnd) return;
if (m_hwndLeave && hwnd != m_hwndLeave && IsWindow(m_hwndLeave))
SendMessage(m_hwndLeave, WM_MOUSELEAVE, 0, 0);
m_hwndLeave = hwnd;
::SetTimer (hwnd, TID_MOUSELEAVE, 50,
(TIMERPROC) TrackMouseTimerProc);
}
void CXTPMouseManager::AddTrustedWindow(HWND hWnd)
{
m_arrTrusted.Add(hWnd);
}
void CXTPMouseManager::RemoveTrustedWindow(HWND hWnd)
{
m_arrTrusted.Remove(hWnd);
}
void CXTPMouseManager::LockTrackRecurse(BOOL bLockTrack)
{
for (int i = 0; i < (int)m_arrTracked.GetSize(); i++)
{
m_arrTracked[i]->m_nLockRecurse += bLockTrack ? +1 : -1;
}
}
CXTPCommandBar* CXTPMouseManager::GetTopTracked() const
{
if (m_arrTracked.GetSize() == NULL)
return NULL;
return m_arrTracked.GetAt(m_arrTracked.GetSize() - 1);
}
BOOL CXTPMouseManager::IsTrackedLock(const CXTPCommandBar* pItem /*= NULL*/)
{
if (m_arrTracked.GetSize() == NULL)
return FALSE;
if (pItem == NULL)
return TRUE;
if (pItem->m_nLockRecurse > 0)
return TRUE;
return m_arrTracked.Find(pItem) == -1;
}
BOOL CXTPMouseManager::IsTrackedLockRecurse() const
{
if (m_arrTracked.GetSize() == 0)
return FALSE;
return m_arrTracked[0]->m_nLockRecurse > 0;
}
void CXTPMouseManager::SendTrackLostRecurse()
{
if (m_arrTracked.GetSize() == 0)
return;
BOOL bLocked = m_arrTracked[0]->m_nLockRecurse > 0;
if (bLocked)
for (int i = 0; i < (int)m_arrTracked.GetSize(); i++)
{
if (m_arrTracked[i]->m_nLockRecurse == 0)
m_arrTracked[i]->OnTrackLost();
}
}