1344 lines
33 KiB
C++
1344 lines
33 KiB
C++
// ==========================================================================
|
|
// Class Implementation :
|
|
// COXIntelliMouse
|
|
// ==========================================================================
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "OXIntelliMouse.h"
|
|
#include "UTB64Bit.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
IMPLEMENT_DYNAMIC(COXIntelliMouse, COXHookWnd);
|
|
|
|
// Constructor
|
|
COXIntelliMouse::COXIntelliMouse()
|
|
{
|
|
// initialize variables
|
|
Reset();
|
|
|
|
m_nStartEventID=0;
|
|
m_dwKeyState=0;
|
|
|
|
// load splash window bitmap
|
|
//
|
|
m_splashWnd.LoadBitmap(IDB_OX_INTELLITARGET);
|
|
|
|
// create cursors
|
|
//
|
|
HCURSOR hCursor;
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_LEFT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_LEFT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_TOPLEFT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_TOPLEFT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_TOP));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_TOP,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_TOPRIGHT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_TOPRIGHT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_RIGHT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_RIGHT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_BOTTOMRIGHT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_BOTTOMRIGHT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_BOTTOM));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_BOTTOM,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_BOTTOMLEFT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_BOTTOMLEFT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_LEFTRIGHT));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_LEFTRIGHT,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_TOPBOTTOM));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_TOPBOTTOM,hCursor);
|
|
|
|
hCursor = AfxGetApp()->LoadCursor(MAKEINTRESOURCE(IDC_OX_SCRL_ALL));
|
|
ASSERT(hCursor!=NULL);
|
|
m_arrScrollCursor.SetAt(SCRL_ALL,hCursor);
|
|
|
|
ASSERT(m_arrScrollCursor.GetCount()==ID_ICONCOUNT);
|
|
|
|
// create helper window
|
|
//
|
|
// make it transparent
|
|
if(!m_helperWnd.CreateEx(WS_EX_TRANSPARENT|WS_EX_TOOLWINDOW,
|
|
AfxRegisterWndClass(CS_DBLCLKS),_T(""),WS_POPUP,0,0,0,0,NULL,NULL))
|
|
{
|
|
TRACE(_T("COXIntelliMouse::COXIntelliMouse: unable to create helper window!\n"));
|
|
AfxThrowResourceException();
|
|
}
|
|
ASSERT(::IsWindow(m_helperWnd.m_hWnd));
|
|
|
|
m_pOldForegroundWnd=NULL;
|
|
|
|
}
|
|
|
|
// Destructor
|
|
COXIntelliMouse::~COXIntelliMouse()
|
|
{
|
|
m_arrScrollCursor.RemoveAll();
|
|
m_arrScrollRect.RemoveAll();
|
|
|
|
if(::IsWindow(m_helperWnd.m_hWnd))
|
|
{
|
|
m_helperWnd.DestroyWindow();
|
|
}
|
|
}
|
|
|
|
void COXIntelliMouse::Reset()
|
|
{
|
|
m_bIsHandling=FALSE;
|
|
m_dwScrollFlag=SCRL_NONE;
|
|
m_nScrollTimerID=0;
|
|
m_scrollDirection=SCRL_NONE;
|
|
m_szScrollSize=CSize(0,0);
|
|
m_ptStart=CPoint(-1,-1);
|
|
}
|
|
|
|
BOOL COXIntelliMouse::Attach(CWnd* pWnd,
|
|
const UINT nStartEventID/*=WM_MBUTTONDOWN*/,
|
|
const DWORD dwKeyState/*=0*/)
|
|
{
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
|
|
HookWindow(pWnd);
|
|
|
|
m_nStartEventID=nStartEventID;
|
|
m_dwKeyState=dwKeyState;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXIntelliMouse::Detach()
|
|
{
|
|
UnhookWindow();
|
|
|
|
CancelIntelliMouseSupport();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
LRESULT COXIntelliMouse::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
#ifdef _WINDLL
|
|
#ifndef _AFXEXT
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
ASSERT(::IsWindow(m_hWndHooked));
|
|
|
|
if(msg==m_nStartEventID && !m_bIsHandling)
|
|
{
|
|
BOOL bKeyState=TRUE;
|
|
if(bKeyState && (m_dwKeyState&KEYPRESSED_CONTROL)!=0)
|
|
bKeyState=(GetKeyState(VK_CONTROL)<0);
|
|
if(bKeyState && (m_dwKeyState&KEYPRESSED_SHIFT)!=0)
|
|
bKeyState=(GetKeyState(VK_SHIFT)<0);
|
|
if(bKeyState && (m_dwKeyState&KEYPRESSED_ALT)!=0)
|
|
bKeyState=(GetKeyState(VK_MENU)<0);
|
|
|
|
if(bKeyState)
|
|
if(LaunchIntelliMouseSupport())
|
|
return (LRESULT)0;
|
|
}
|
|
|
|
|
|
if(m_bIsHandling && ::GetCapture()!=m_hWndHooked)
|
|
CancelIntelliMouseSupport();
|
|
|
|
|
|
if(m_bIsHandling)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_NCMOUSEMOVE:
|
|
case WM_MOUSEMOVE:
|
|
{
|
|
// define scroll direction
|
|
//
|
|
CPoint ptTest;
|
|
::GetCursorPos(&ptTest);
|
|
m_scrollDirection=FindScrollDirectionFromPoint(ptTest);
|
|
ASSERT(m_scrollDirection!=SCRL_NONE);
|
|
ShowScrollCursor(m_scrollDirection);
|
|
|
|
// update scroll speed
|
|
//
|
|
CRect rect;
|
|
VERIFY(m_arrScrollRect.Lookup(m_scrollDirection,rect));
|
|
switch(m_scrollDirection)
|
|
{
|
|
case SCRL_LEFT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.right)/ID_SCROLLCOEF,0);
|
|
break;
|
|
}
|
|
case SCRL_TOPLEFT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.right)/ID_SCROLLCOEF,
|
|
(ptTest.y-rect.bottom)/10);
|
|
break;
|
|
}
|
|
case SCRL_TOP:
|
|
{
|
|
m_szScrollSize=CSize(0,(ptTest.y-rect.bottom)/10);
|
|
break;
|
|
}
|
|
case SCRL_TOPRIGHT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.left)/ID_SCROLLCOEF,
|
|
(ptTest.y-rect.bottom)/10);
|
|
break;
|
|
}
|
|
case SCRL_RIGHT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.left)/ID_SCROLLCOEF,0);
|
|
break;
|
|
}
|
|
case SCRL_BOTTOMRIGHT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.left)/ID_SCROLLCOEF,
|
|
(ptTest.y-rect.top)/10);
|
|
break;
|
|
}
|
|
case SCRL_BOTTOM:
|
|
{
|
|
m_szScrollSize=CSize(0,(ptTest.y-rect.top)/10);
|
|
break;
|
|
}
|
|
case SCRL_BOTTOMLEFT:
|
|
{
|
|
m_szScrollSize=CSize((ptTest.x-rect.right)/ID_SCROLLCOEF,
|
|
(ptTest.y-rect.top)/10);
|
|
break;
|
|
}
|
|
case SCRL_TOPBOTTOM:
|
|
case SCRL_LEFTRIGHT:
|
|
case SCRL_ALL:
|
|
{
|
|
m_szScrollSize=CSize(0,0);
|
|
break;
|
|
}
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case WM_SETCURSOR:
|
|
{
|
|
return TRUE;
|
|
}
|
|
case WM_TIMER:
|
|
{
|
|
if(wp==m_nScrollTimerID)
|
|
{
|
|
int nScrollCode;
|
|
BOOL bScrollViewDerived=
|
|
GetHookedWnd()->IsKindOf(RUNTIME_CLASS(CScrollView));
|
|
if(m_szScrollSize.cx!=0)
|
|
{
|
|
nScrollCode=m_szScrollSize.cx>0 ? SB_LINERIGHT : SB_LINELEFT;
|
|
for(int nIndex=0; nIndex<abs(m_szScrollSize.cx); nIndex++)
|
|
{
|
|
if(bScrollViewDerived)
|
|
{
|
|
((CScrollView*)GetHookedWnd())->
|
|
OnScroll(MAKEWORD((BYTE)nScrollCode,-1),0);
|
|
}
|
|
else
|
|
{
|
|
GetHookedWnd()->SendMessage(WM_HSCROLL,
|
|
MAKEWPARAM(nScrollCode,0),(LPARAM)NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_szScrollSize.cy!=0)
|
|
{
|
|
nScrollCode=m_szScrollSize.cy>0 ? SB_LINEDOWN : SB_LINEUP;
|
|
for(int nIndex=0; nIndex<abs(m_szScrollSize.cy); nIndex++)
|
|
{
|
|
if(bScrollViewDerived)
|
|
{
|
|
((CScrollView*)GetHookedWnd())->
|
|
OnScroll(MAKEWORD(-1,(BYTE)nScrollCode),0);
|
|
}
|
|
else
|
|
{
|
|
GetHookedWnd()->SendMessage(WM_VSCROLL,
|
|
MAKEWPARAM(nScrollCode,0),(LPARAM)NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update scroll info
|
|
GetHookedScrollInfo();
|
|
|
|
return (LRESULT)0;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDBLCLK:
|
|
case WM_NCLBUTTONDOWN:
|
|
case WM_NCRBUTTONDOWN:
|
|
case WM_NCMBUTTONDOWN:
|
|
case WM_NCLBUTTONDBLCLK:
|
|
case WM_NCRBUTTONDBLCLK:
|
|
case WM_NCMBUTTONDBLCLK:
|
|
{
|
|
CancelIntelliMouseSupport();
|
|
|
|
CPoint point;
|
|
::GetCursorPos(&point);
|
|
CWnd* pWnd=CWnd::WindowFromPoint(point);
|
|
ASSERT(pWnd);
|
|
|
|
UINT nHitTest=(int)pWnd->SendMessage(WM_NCHITTEST,0,
|
|
MAKELONG(point.x,point.y));
|
|
if(nHitTest==HTCLIENT)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_NCLBUTTONDOWN:
|
|
{
|
|
msg=WM_LBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_NCRBUTTONDOWN:
|
|
{
|
|
msg=WM_RBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_NCMBUTTONDOWN:
|
|
{
|
|
msg=WM_MBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_NCLBUTTONDBLCLK:
|
|
{
|
|
msg=WM_LBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_NCRBUTTONDBLCLK:
|
|
{
|
|
msg=WM_RBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_NCMBUTTONDBLCLK:
|
|
{
|
|
msg=WM_MBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
}
|
|
pWnd->ScreenToClient(&point);
|
|
}
|
|
else
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
{
|
|
msg=WM_NCLBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_RBUTTONDOWN:
|
|
{
|
|
msg=WM_NCRBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_MBUTTONDOWN:
|
|
{
|
|
msg=WM_NCMBUTTONDOWN;
|
|
break;
|
|
}
|
|
case WM_LBUTTONDBLCLK:
|
|
{
|
|
msg=WM_NCLBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_RBUTTONDBLCLK:
|
|
{
|
|
msg=WM_NCRBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
case WM_MBUTTONDBLCLK:
|
|
{
|
|
msg=WM_NCMBUTTONDBLCLK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
wp=nHitTest;
|
|
lp=MAKELONG(point.x,point.y);
|
|
|
|
if(pWnd->m_hWnd!=m_hWndHooked)
|
|
{
|
|
// pWnd->PostMessage(msg,wp,lp);
|
|
return (LRESULT)0;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
CancelIntelliMouseSupport();
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// I don't handle it: pass along
|
|
return COXHookWnd::WindowProc(msg,wp,lp);
|
|
}
|
|
|
|
BOOL COXIntelliMouse::GetHookedScrollInfo()
|
|
{
|
|
ASSERT(m_hWndHooked!=NULL);
|
|
ASSERT(::IsWindow(m_hWndHooked));
|
|
|
|
CRect rect;
|
|
::GetClientRect(m_hWndHooked,rect);
|
|
|
|
::ZeroMemory((void*)&m_scrollHorzInfo,sizeof(m_scrollHorzInfo));
|
|
m_scrollHorzInfo.cbSize=sizeof(m_scrollHorzInfo);
|
|
m_scrollHorzInfo.fMask=SIF_ALL;
|
|
if(!GetHookedWnd()->GetScrollInfo(SB_HORZ,&m_scrollHorzInfo) ||
|
|
(m_scrollHorzInfo.nMax==0 || m_scrollHorzInfo.nPage==0 ||
|
|
m_scrollHorzInfo.nMax<(int)m_scrollHorzInfo.nPage))
|
|
{
|
|
m_dwScrollFlag&=~(SCRL_LEFT|SCRL_RIGHT);
|
|
}
|
|
else
|
|
{
|
|
if(m_scrollHorzInfo.nPos>0)
|
|
m_dwScrollFlag|=SCRL_LEFT;
|
|
else
|
|
m_dwScrollFlag&=~SCRL_LEFT;
|
|
|
|
if(m_scrollHorzInfo.nPos+(int)m_scrollHorzInfo.nPage<=m_scrollHorzInfo.nMax)
|
|
m_dwScrollFlag|=SCRL_RIGHT;
|
|
else
|
|
m_dwScrollFlag&=~SCRL_RIGHT;
|
|
}
|
|
|
|
|
|
::ZeroMemory((void*)&m_scrollVertInfo,sizeof(m_scrollVertInfo));
|
|
m_scrollVertInfo.cbSize=sizeof(m_scrollVertInfo);
|
|
m_scrollVertInfo.fMask=SIF_ALL;
|
|
if(!GetHookedWnd()->GetScrollInfo(SB_VERT,&m_scrollVertInfo) ||
|
|
m_scrollVertInfo.nMax==0 || m_scrollVertInfo.nPage==0 ||
|
|
m_scrollVertInfo.nMax<(int)m_scrollVertInfo.nPage)
|
|
{
|
|
m_dwScrollFlag&=~(SCRL_TOP|SCRL_BOTTOM);
|
|
}
|
|
else
|
|
{
|
|
if(m_scrollVertInfo.nPos>0)
|
|
m_dwScrollFlag|=SCRL_TOP;
|
|
else
|
|
m_dwScrollFlag&=~SCRL_TOP;
|
|
|
|
if(m_scrollVertInfo.nPos+(int)m_scrollVertInfo.nPage<=m_scrollVertInfo.nMax)
|
|
m_dwScrollFlag|=SCRL_BOTTOM;
|
|
else
|
|
m_dwScrollFlag&=~SCRL_BOTTOM;
|
|
}
|
|
|
|
if((m_dwScrollFlag&SCRL_LEFT)==0 && m_szScrollSize.cx<0)
|
|
m_szScrollSize.cx=0;
|
|
if((m_dwScrollFlag&SCRL_RIGHT)==0 && m_szScrollSize.cx>0)
|
|
m_szScrollSize.cx=0;
|
|
if((m_dwScrollFlag&SCRL_TOP)==0 && m_szScrollSize.cy<0)
|
|
m_szScrollSize.cy=0;
|
|
if((m_dwScrollFlag&SCRL_BOTTOM)==0 && m_szScrollSize.cy>0)
|
|
m_szScrollSize.cy=0;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXIntelliMouse::CalculateScrollRects(const CSize& szSplashWindowBitmap,
|
|
const CPoint& ptStart,
|
|
SCROLLDIRECTION scrollDirection)
|
|
{
|
|
CRect rect(-1,-1,-1,-1);
|
|
m_arrScrollRect.SetAt(SCRL_NONE,rect);
|
|
m_arrScrollRect.SetAt(SCRL_LEFT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_TOPLEFT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_TOP,rect);
|
|
m_arrScrollRect.SetAt(SCRL_TOPRIGHT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_RIGHT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOMRIGHT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOM,rect);
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOMLEFT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_ALL,rect);
|
|
m_arrScrollRect.SetAt(SCRL_LEFTRIGHT,rect);
|
|
m_arrScrollRect.SetAt(SCRL_TOPBOTTOM,rect);
|
|
|
|
// screen's dimension (big enough :-))
|
|
int nWidthScreen=::GetSystemMetrics(SM_CXSCREEN);
|
|
int nHeightScreen=::GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
if((m_dwScrollFlag&SCRL_LEFT)!=0 || (m_dwScrollFlag&SCRL_RIGHT)!=0)
|
|
{
|
|
// rectangle for left scrolling area
|
|
rect.left=0;
|
|
rect.right=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
if((m_dwScrollFlag&SCRL_TOP)!=0 || (m_dwScrollFlag&SCRL_BOTTOM)!=0)
|
|
{
|
|
rect.top=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
rect.bottom=rect.top+szSplashWindowBitmap.cy;
|
|
}
|
|
else
|
|
{
|
|
rect.top=0;
|
|
rect.bottom=nHeightScreen;
|
|
}
|
|
m_arrScrollRect.SetAt(SCRL_LEFT,rect);
|
|
|
|
// rectangle for right scrolling area
|
|
rect.right=nWidthScreen;
|
|
rect.left=ptStart.x+szSplashWindowBitmap.cx/2+szSplashWindowBitmap.cx%2;
|
|
if((m_dwScrollFlag&SCRL_TOP)!=0 || (m_dwScrollFlag&SCRL_BOTTOM)!=0)
|
|
{
|
|
rect.top=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
rect.bottom=rect.top+szSplashWindowBitmap.cy;
|
|
}
|
|
else
|
|
{
|
|
rect.top=0;
|
|
rect.bottom=nHeightScreen;
|
|
}
|
|
m_arrScrollRect.SetAt(SCRL_RIGHT,rect);
|
|
}
|
|
|
|
if((m_dwScrollFlag&SCRL_TOP)!=0 || (m_dwScrollFlag&SCRL_BOTTOM)!=0)
|
|
{
|
|
// rectangle for top scrolling area
|
|
rect.top=0;
|
|
rect.bottom=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
if((m_dwScrollFlag&SCRL_LEFT)!=0 || (m_dwScrollFlag&SCRL_RIGHT)!=0)
|
|
{
|
|
rect.left=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
rect.right=rect.left+szSplashWindowBitmap.cx;
|
|
}
|
|
else
|
|
{
|
|
rect.left=0;
|
|
rect.right=nWidthScreen;
|
|
}
|
|
m_arrScrollRect.SetAt(SCRL_TOP,rect);
|
|
|
|
// rectangle for bottom scrolling area
|
|
rect.bottom=nHeightScreen;
|
|
rect.top=ptStart.y+szSplashWindowBitmap.cy/2+szSplashWindowBitmap.cy%2;
|
|
if((m_dwScrollFlag&SCRL_LEFT)!=0 || (m_dwScrollFlag&SCRL_RIGHT)!=0)
|
|
{
|
|
rect.left=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
rect.right=rect.left+szSplashWindowBitmap.cx;
|
|
}
|
|
else
|
|
{
|
|
rect.left=0;
|
|
rect.right=nWidthScreen;
|
|
}
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOM,rect);
|
|
}
|
|
|
|
if(((m_dwScrollFlag&SCRL_TOP)!=0 || (m_dwScrollFlag&SCRL_BOTTOM)!=0) &&
|
|
((m_dwScrollFlag&SCRL_LEFT)!=0 || (m_dwScrollFlag&SCRL_RIGHT)!=0))
|
|
{
|
|
// rectangle for topleft scrolling area
|
|
rect.top=0;
|
|
rect.bottom=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
rect.left=0;
|
|
rect.right=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
m_arrScrollRect.SetAt(SCRL_TOPLEFT,rect);
|
|
|
|
// rectangle for topright scrolling area
|
|
rect.left=ptStart.x+szSplashWindowBitmap.cx/2+szSplashWindowBitmap.cx%2;
|
|
rect.right=nWidthScreen;
|
|
m_arrScrollRect.SetAt(SCRL_TOPRIGHT,rect);
|
|
|
|
// rectangle for bottomleft scrolling area
|
|
rect.top=ptStart.y+szSplashWindowBitmap.cy/2+szSplashWindowBitmap.cy%2;
|
|
rect.bottom=nHeightScreen;
|
|
rect.left=0;
|
|
rect.right=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOMLEFT,rect);
|
|
|
|
// rectangle for bottomright scrolling area
|
|
rect.left=ptStart.x+szSplashWindowBitmap.cx/2+szSplashWindowBitmap.cx%2;
|
|
rect.right=nWidthScreen;
|
|
m_arrScrollRect.SetAt(SCRL_BOTTOMRIGHT,rect);
|
|
|
|
// rectangle for non-scrolling area which equals to the size
|
|
// of splash window
|
|
rect.left=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
rect.top=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
rect.right=rect.left+szSplashWindowBitmap.cx;
|
|
rect.bottom=rect.top+szSplashWindowBitmap.cy;
|
|
m_arrScrollRect.SetAt(scrollDirection,rect);
|
|
}
|
|
else
|
|
{
|
|
// rectangle for non-scrolling
|
|
if((m_dwScrollFlag&SCRL_LEFT)!=0 || (m_dwScrollFlag&SCRL_RIGHT)!=0)
|
|
{
|
|
rect.left=ptStart.x-szSplashWindowBitmap.cx/2;
|
|
rect.top=0;
|
|
rect.right=rect.left+szSplashWindowBitmap.cx;
|
|
rect.bottom=nHeightScreen;
|
|
m_arrScrollRect.SetAt(scrollDirection,rect);
|
|
}
|
|
else if((m_dwScrollFlag&SCRL_TOP)!=0 || (m_dwScrollFlag&SCRL_BOTTOM)!=0)
|
|
{
|
|
rect.left=0;
|
|
rect.top=ptStart.y-szSplashWindowBitmap.cy/2;
|
|
rect.right=nWidthScreen;
|
|
rect.bottom=rect.top+szSplashWindowBitmap.cy;
|
|
m_arrScrollRect.SetAt(scrollDirection,rect);
|
|
}
|
|
else
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void COXIntelliMouse::ShowScrollCursor(SCROLLDIRECTION scrollDirection) const
|
|
{
|
|
ASSERT(scrollDirection!=SCRL_NONE);
|
|
|
|
HANDLE hCursor=NULL;
|
|
VERIFY(m_arrScrollCursor.Lookup(scrollDirection,hCursor));
|
|
ASSERT(hCursor!=NULL);
|
|
|
|
::SetCursor((HCURSOR)hCursor);
|
|
}
|
|
|
|
|
|
SCROLLDIRECTION COXIntelliMouse::
|
|
FindScrollDirectionFromPoint(const CPoint& ptTest) const
|
|
{
|
|
CRect rect;
|
|
SCROLLDIRECTION scrollDirection=SCRL_NONE;
|
|
BOOL bSuccess=FALSE;
|
|
POSITION pos=m_arrScrollRect.GetStartPosition();
|
|
while(pos!=NULL)
|
|
{
|
|
m_arrScrollRect.GetNextAssoc(pos,scrollDirection,rect);
|
|
if(rect.PtInRect(ptTest))
|
|
{
|
|
bSuccess=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!bSuccess)
|
|
scrollDirection=SCRL_NONE;
|
|
|
|
return scrollDirection;
|
|
}
|
|
|
|
void COXIntelliMouse::CancelIntelliMouseSupport()
|
|
{
|
|
if(m_bIsHandling)
|
|
{
|
|
m_bIsHandling=FALSE;
|
|
|
|
// hide splash window
|
|
m_splashWnd.Hide();
|
|
|
|
// hide helper window
|
|
m_helperWnd.SetWindowPos(&CWnd::wndBottom,0,0,0,0,
|
|
SWP_HIDEWINDOW|SWP_NOREDRAW);
|
|
ASSERT(::IsWindow(m_pOldForegroundWnd->m_hWnd));
|
|
m_pOldForegroundWnd->SetForegroundWindow();
|
|
|
|
// release capture
|
|
::ReleaseCapture();
|
|
|
|
// kill scrolling timer
|
|
if(m_nScrollTimerID!=0)
|
|
{
|
|
::KillTimer(m_hWndHooked,m_nScrollTimerID);
|
|
}
|
|
}
|
|
|
|
// reset all internal variables
|
|
Reset();
|
|
}
|
|
|
|
BOOL COXIntelliMouse::LaunchIntelliMouseSupport()
|
|
{
|
|
if(GetHookedScrollInfo() && m_dwScrollFlag!=SCRL_NONE)
|
|
{
|
|
ASSERT(m_nScrollTimerID==0);
|
|
// setup timer
|
|
m_nScrollTimerID=::SetTimer(m_hWndHooked,
|
|
ID_INTELLIMOUSESCROLLTIMER,ID_INTELLIMOUSESCROLLDELAY,NULL);
|
|
if(m_nScrollTimerID!=0)
|
|
{
|
|
// start point
|
|
::GetCursorPos(&m_ptStart);
|
|
|
|
// get size of splash window bitmap
|
|
//
|
|
m_splashWnd.SetUserCancel(FALSE);
|
|
COXSplashWndDIB* pDIB=m_splashWnd.GetDIB();
|
|
ASSERT(pDIB!=NULL);
|
|
ASSERT(pDIB->GetBitmap()!=NULL);
|
|
BITMAP bm;
|
|
pDIB->GetBitmapInfo(bm);
|
|
|
|
// use helper window
|
|
//
|
|
m_pOldForegroundWnd=CWnd::GetForegroundWindow();
|
|
if(m_pOldForegroundWnd==NULL)
|
|
m_pOldForegroundWnd=CWnd::GetDesktopWindow();
|
|
m_helperWnd.SetWindowPos(&CWnd::wndTopMost,0,0,
|
|
::GetSystemMetrics(SM_CXSCREEN),
|
|
::GetSystemMetrics(SM_CYSCREEN),
|
|
SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOREDRAW);
|
|
|
|
// show splash window
|
|
//
|
|
CPoint ptDisplayAt(m_ptStart.x-bm.bmWidth/2,
|
|
m_ptStart.y-bm.bmHeight/2);
|
|
if(!m_splashWnd.Show(SPLASH_NOTIMER,NULL,&ptDisplayAt))
|
|
{
|
|
// kill scrolling timer
|
|
::KillTimer(m_hWndHooked,m_nScrollTimerID);
|
|
m_nScrollTimerID=0;
|
|
// hide helper window
|
|
m_helperWnd.SetWindowPos(&CWnd::wndBottom,0,0,0,0,
|
|
SWP_HIDEWINDOW|SWP_NOREDRAW);
|
|
ASSERT(::IsWindow(m_pOldForegroundWnd->m_hWnd));
|
|
m_pOldForegroundWnd->SetForegroundWindow();
|
|
}
|
|
else
|
|
{
|
|
// current scroll direction
|
|
if(((m_dwScrollFlag&SCRL_TOP)!=0 ||
|
|
(m_dwScrollFlag&SCRL_BOTTOM)!=0) &&
|
|
((m_dwScrollFlag&SCRL_LEFT)!=0 ||
|
|
(m_dwScrollFlag&SCRL_RIGHT)!=0))
|
|
m_scrollDirection=SCRL_ALL;
|
|
else if((m_dwScrollFlag&SCRL_TOP)!=0 ||
|
|
(m_dwScrollFlag&SCRL_BOTTOM)!=0)
|
|
m_scrollDirection=SCRL_TOPBOTTOM;
|
|
else if((m_dwScrollFlag&SCRL_LEFT)!=0 ||
|
|
(m_dwScrollFlag&SCRL_RIGHT)!=0)
|
|
m_scrollDirection=SCRL_LEFTRIGHT;
|
|
else
|
|
ASSERT(FALSE);
|
|
|
|
// calculate rectangles
|
|
//
|
|
CalculateScrollRects(CSize(bm.bmWidth,bm.bmHeight),m_ptStart,
|
|
m_scrollDirection);
|
|
|
|
// scroll sizes
|
|
m_szScrollSize=CSize(0,0);
|
|
|
|
// set mouse cursor
|
|
ShowScrollCursor(m_scrollDirection);
|
|
|
|
// capture all mouse messages
|
|
::SetCapture(m_hWndHooked);
|
|
|
|
// we are in the scrolling mode
|
|
m_bIsHandling=TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// static variables
|
|
CMap<DWORD,DWORD,COXIntelliMouseOrganizer*,COXIntelliMouseOrganizer*>
|
|
COXIntelliMouseOrganizer::m_arrThreadOrganizers;
|
|
|
|
HHOOK COXIntelliMouseOrganizer::m_pfnOriginalCBTHookProc=NULL;
|
|
HHOOK COXIntelliMouseOrganizer::m_pfnOriginalGetMessageHookProc=NULL;
|
|
/////////////////
|
|
|
|
|
|
// Constructor
|
|
COXIntelliMouseOrganizer::COXIntelliMouseOrganizer() :
|
|
m_pfnOldCBTHookProc(NULL),
|
|
m_dwThreadID(NULL),
|
|
m_pfnOldGetMessageHookProc(NULL),
|
|
m_nThreadOrigStartEventID(NULL),
|
|
m_dwThreadOrigKeyState(NULL)
|
|
{
|
|
}
|
|
|
|
// Destructor
|
|
COXIntelliMouseOrganizer::~COXIntelliMouseOrganizer()
|
|
{
|
|
if(IsAttachedAllInThread())
|
|
VERIFY(DetachAllInThread());
|
|
else
|
|
VERIFY(Detach(NULL));
|
|
|
|
int nCount=PtrToInt(m_arrUsedObjects.GetSize());
|
|
for(int nIndex=0; nIndex<nCount; nIndex++)
|
|
{
|
|
COXIntelliMouse* pIntelliMouseObject=m_arrUsedObjects[nIndex];
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
ASSERT(!pIntelliMouseObject->IsHooked());
|
|
delete pIntelliMouseObject;
|
|
}
|
|
m_arrUsedObjects.RemoveAll();
|
|
|
|
ASSERT(m_pfnOriginalCBTHookProc==NULL);
|
|
ASSERT(m_pfnOldCBTHookProc==NULL);
|
|
ASSERT(m_pfnOriginalGetMessageHookProc==NULL);
|
|
}
|
|
|
|
COXIntelliMouse* COXIntelliMouseOrganizer::Attach(CWnd* pWnd,
|
|
UINT nStartEventID/*=WM_MBUTTONDOWN*/,
|
|
DWORD dwKeyState/*=0*/)
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(::IsWindow(pWnd->m_hWnd));
|
|
|
|
HWND hWndAttached=pWnd->GetSafeHwnd();
|
|
ASSERT(::IsWindow(hWndAttached));
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
if(m_arrAttachedWnd.Lookup(hWndAttached,pIntelliMouseObject))
|
|
{
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
ASSERT(pIntelliMouseObject->IsHooked());
|
|
ASSERT(pIntelliMouseObject->GetHookedWnd()->GetSafeHwnd()==hWndAttached);
|
|
TRACE(_T("COXIntelliMouseOrganizer::Attach: specified window already attached to an intelli mouse object\n"));
|
|
return pIntelliMouseObject;
|
|
}
|
|
|
|
if(IsRejected(hWndAttached))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if(IsAttachedAllInThread())
|
|
{
|
|
CString sWndClass;
|
|
::GetClassName(pWnd->GetSafeHwnd(),sWndClass.GetBuffer(512),512);
|
|
|
|
if(!IsQualified(pWnd->GetSafeHwnd(),sWndClass))
|
|
{
|
|
m_mapRejectedControls.SetAt(pWnd->GetSafeHwnd(),1);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if(m_arrUsedObjects.GetSize()>0)
|
|
{
|
|
pIntelliMouseObject=m_arrUsedObjects[0];
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
ASSERT(!pIntelliMouseObject->IsHooked());
|
|
m_arrUsedObjects.RemoveAt(0);
|
|
}
|
|
else
|
|
{
|
|
pIntelliMouseObject=new COXIntelliMouse;
|
|
}
|
|
|
|
if(pIntelliMouseObject->Attach(pWnd,nStartEventID,dwKeyState))
|
|
{
|
|
m_arrAttachedWnd.SetAt(hWndAttached,pIntelliMouseObject);
|
|
return pIntelliMouseObject;
|
|
}
|
|
else
|
|
{
|
|
// save the object in the array of COXIntelliMouse objects
|
|
// that can be used later
|
|
m_arrUsedObjects.Add(pIntelliMouseObject);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL COXIntelliMouseOrganizer::Detach(CWnd* pWnd/*=NULL*/)
|
|
{
|
|
if(pWnd==NULL)
|
|
{
|
|
POSITION pos=m_arrAttachedWnd.GetStartPosition();
|
|
HWND hAttachedWnd=NULL;
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
while(pos!=NULL)
|
|
{
|
|
m_arrAttachedWnd.GetNextAssoc(pos,hAttachedWnd,pIntelliMouseObject);
|
|
if(pIntelliMouseObject!=NULL && pIntelliMouseObject->IsHooked() &&
|
|
pIntelliMouseObject->GetHookedWnd()->GetSafeHwnd()!=hAttachedWnd)
|
|
{
|
|
|
|
COXIntelliMouse* pTheSameIntelliMouseObject=NULL;
|
|
if(m_arrAttachedWnd.
|
|
Lookup(pIntelliMouseObject->GetHookedWnd()->GetSafeHwnd(),
|
|
pTheSameIntelliMouseObject))
|
|
{
|
|
ASSERT(pIntelliMouseObject==pTheSameIntelliMouseObject);
|
|
}
|
|
else
|
|
{
|
|
if(pIntelliMouseObject->IsHooked())
|
|
pIntelliMouseObject->Detach();
|
|
// save the object in the array of COXIntelliMouse objects
|
|
// that can be used later
|
|
m_arrUsedObjects.Add(pIntelliMouseObject);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
ASSERT(::IsWindow(hAttachedWnd) || pIntelliMouseObject==NULL ||
|
|
(pIntelliMouseObject!=NULL && !pIntelliMouseObject->IsHooked()));
|
|
if(pIntelliMouseObject!=NULL)
|
|
{
|
|
if(pIntelliMouseObject->IsHooked())
|
|
pIntelliMouseObject->Detach();
|
|
// save the object in the array of COXIntelliMouse objects
|
|
// that can be used later
|
|
m_arrUsedObjects.Add(pIntelliMouseObject);
|
|
}
|
|
}
|
|
}
|
|
m_arrAttachedWnd.RemoveAll();
|
|
}
|
|
else
|
|
{
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
CWnd* pAttachedWnd=(CWnd*)pWnd;
|
|
if(!m_arrAttachedWnd.Lookup(pAttachedWnd->GetSafeHwnd(),pIntelliMouseObject))
|
|
return FALSE;
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
m_arrAttachedWnd.RemoveKey(pAttachedWnd->GetSafeHwnd());
|
|
if(pIntelliMouseObject!=NULL)
|
|
{
|
|
if(pIntelliMouseObject->IsHooked())
|
|
pIntelliMouseObject->Detach();
|
|
// save the object in the array of COXIntelliMouse objects
|
|
// that can be used later
|
|
m_arrUsedObjects.Add(pIntelliMouseObject);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT COXIntelliMouseOrganizer::GetStartEventID(CWnd* pWnd) const
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(IsAttached(pWnd));
|
|
return GetIntelliMouseObject(pWnd)->GetStartEventID();
|
|
}
|
|
|
|
UINT COXIntelliMouseOrganizer::GetKeyPressedState(CWnd* pWnd) const
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
ASSERT(IsAttached(pWnd));
|
|
return GetIntelliMouseObject(pWnd)->GetKeyPressedState();
|
|
}
|
|
|
|
|
|
BOOL COXIntelliMouseOrganizer::SetStartEventID(CWnd* pWnd,
|
|
UINT nStartEventID,
|
|
DWORD dwKeyState/*=0*/)
|
|
{
|
|
if(pWnd==NULL)
|
|
{
|
|
if(IsAttachedAllInThread())
|
|
{
|
|
m_nThreadOrigStartEventID=nStartEventID;
|
|
m_dwThreadOrigKeyState=dwKeyState;
|
|
}
|
|
POSITION pos=m_arrAttachedWnd.GetStartPosition();
|
|
HWND hAttachedWnd=NULL;
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
while(pos!=NULL)
|
|
{
|
|
m_arrAttachedWnd.GetNextAssoc(pos,hAttachedWnd,pIntelliMouseObject);
|
|
ASSERT(::IsWindow(hAttachedWnd));
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
pIntelliMouseObject->SetStartEventID(nStartEventID,dwKeyState);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COXIntelliMouse* pIntelliMouseObject=GetIntelliMouseObject(pWnd);
|
|
if(pIntelliMouseObject==NULL)
|
|
return FALSE;
|
|
pIntelliMouseObject->SetStartEventID(nStartEventID,dwKeyState);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
COXIntelliMouse* COXIntelliMouseOrganizer::
|
|
GetIntelliMouseObject(const CWnd* pWnd) const
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
CWnd* pAttachedWnd=(CWnd*)pWnd;
|
|
if(!m_arrAttachedWnd.Lookup(pAttachedWnd->GetSafeHwnd(),pIntelliMouseObject))
|
|
{
|
|
pIntelliMouseObject=NULL;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pIntelliMouseObject->IsHooked());
|
|
ASSERT(pIntelliMouseObject->GetHookedWnd()==pAttachedWnd);
|
|
}
|
|
|
|
return pIntelliMouseObject;
|
|
}
|
|
|
|
BOOL COXIntelliMouseOrganizer::IsAttached(const CWnd* pWnd) const
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
if(pWnd==NULL)
|
|
return FALSE;
|
|
|
|
COXIntelliMouse* pIntelliMouseObject=NULL;
|
|
CWnd* pAttachedWnd=(CWnd*)pWnd;
|
|
if(m_arrAttachedWnd.Lookup(pAttachedWnd->GetSafeHwnd(),pIntelliMouseObject))
|
|
{
|
|
ASSERT(pIntelliMouseObject!=NULL);
|
|
ASSERT(pIntelliMouseObject->IsHooked());
|
|
ASSERT(pIntelliMouseObject->GetHookedWnd()==pAttachedWnd);
|
|
if(pIntelliMouseObject!=NULL)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXIntelliMouseOrganizer::IsRejected(HWND hWnd) const
|
|
{
|
|
DWORD dwReason=0;
|
|
BOOL bResult=m_mapRejectedControls.Lookup(hWnd,dwReason);
|
|
ASSERT(!bResult || dwReason!=0);
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL COXIntelliMouseOrganizer::
|
|
AttachAllInThread(DWORD dwThreadID/*=::GetCurrentThreadId()*/,
|
|
UINT nStartEventID/*=WM_MBUTTONDOWN*/,
|
|
DWORD dwKeyState/*=0*/)
|
|
{
|
|
if(IsAttachedAllInThread())
|
|
{
|
|
TRACE(_T("COXIntelliMouseOrganizer::AttachAllInThread: this object already attached to a thread\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
COXIntelliMouseOrganizer* pOrganizer=NULL;
|
|
if(m_arrThreadOrganizers.Lookup(dwThreadID,pOrganizer))
|
|
{
|
|
ASSERT(pOrganizer!=NULL);
|
|
TRACE(_T("COXIntelliMouseOrganizer::AttachAllInThread: specified thread already attached to a COXIntelliMouseOrganizer object\n"));
|
|
return FALSE;
|
|
}
|
|
m_arrThreadOrganizers.SetAt(dwThreadID,this);
|
|
|
|
m_dwThreadID=dwThreadID;
|
|
|
|
m_nThreadOrigStartEventID=nStartEventID;
|
|
m_dwThreadOrigKeyState=dwKeyState;
|
|
|
|
// go through all windows and attach them
|
|
::EnumWindows(&EnumThreadWindows,(LPARAM)this);
|
|
|
|
// setup hooks for Computer Based Training
|
|
if(m_pfnOriginalCBTHookProc==NULL)
|
|
{
|
|
m_pfnOriginalCBTHookProc=
|
|
::SetWindowsHookEx(WH_CBT,IntelliMouseCBTHookProc,NULL,dwThreadID);
|
|
m_pfnOldCBTHookProc=m_pfnOriginalCBTHookProc;
|
|
}
|
|
else
|
|
{
|
|
m_pfnOldCBTHookProc=
|
|
::SetWindowsHookEx(WH_CBT,IntelliMouseCBTHookProc,NULL,dwThreadID);
|
|
}
|
|
|
|
// setup hooks for GetMessage
|
|
if(m_pfnOriginalGetMessageHookProc==NULL)
|
|
{
|
|
m_pfnOriginalGetMessageHookProc=::SetWindowsHookEx(WH_GETMESSAGE,
|
|
IntelliMouseGetMessageHookProc,NULL,dwThreadID);
|
|
m_pfnOldGetMessageHookProc=m_pfnOriginalGetMessageHookProc;
|
|
}
|
|
else
|
|
{
|
|
m_pfnOldGetMessageHookProc=::SetWindowsHookEx(WH_GETMESSAGE,
|
|
IntelliMouseGetMessageHookProc,NULL,dwThreadID);
|
|
}
|
|
|
|
SetStartEventID(NULL,nStartEventID,dwKeyState);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXIntelliMouseOrganizer::AttachAllWindows(HWND hWndStartFrom)
|
|
{
|
|
ASSERT(hWndStartFrom!=NULL);
|
|
|
|
HWND hWnd=hWndStartFrom;
|
|
while(hWnd!=NULL)
|
|
{
|
|
DWORD dwThreadID=::GetWindowThreadProcessId(hWnd,NULL);
|
|
if(dwThreadID!=GetAttachedThread())
|
|
break;
|
|
|
|
CWnd* pWnd=CWnd::FromHandlePermanent(hWnd);
|
|
if(pWnd!=NULL && !IsAttached(pWnd) && !IsRejected(hWnd))
|
|
{
|
|
Attach(pWnd);
|
|
}
|
|
|
|
// loop through children
|
|
HWND hWndChild=::GetWindow(hWnd,GW_CHILD);
|
|
if(hWndChild!=NULL && !IsRejected(hWnd) && !IsAttached(pWnd))
|
|
AttachAllWindows(hWndChild);
|
|
|
|
// loop through windows
|
|
hWnd=::GetWindow(hWnd,GW_HWNDNEXT);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK COXIntelliMouseOrganizer::
|
|
IntelliMouseCBTHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
if(nCode>=0 && ::IsWindow((HWND)wParam))
|
|
{
|
|
DWORD dwThreadID=::GetWindowThreadProcessId((HWND)wParam,NULL);
|
|
COXIntelliMouseOrganizer* pOrganizer=NULL;
|
|
if(COXIntelliMouseOrganizer::m_arrThreadOrganizers.
|
|
Lookup(dwThreadID,pOrganizer))
|
|
{
|
|
ASSERT(pOrganizer!=NULL);
|
|
ASSERT(pOrganizer->IsAttachedAllInThread());
|
|
|
|
if(nCode==HCBT_DESTROYWND)
|
|
{
|
|
// check if the window that is about to be destroyed
|
|
// had been added to intelli mouse organizer list
|
|
CWnd* pWnd=CWnd::FromHandle((HWND)wParam);
|
|
if(pWnd!=NULL && pOrganizer->IsAttached(pWnd))
|
|
VERIFY(pOrganizer->Detach(pWnd));
|
|
}
|
|
else
|
|
{
|
|
// check if new window is created and attach it.
|
|
CWnd* pWnd=CWnd::FromHandlePermanent((HWND)wParam);
|
|
if(pWnd!=NULL && !pOrganizer->IsAttached(pWnd))
|
|
{
|
|
POSITION pos=NULL;
|
|
COXIntelliMouse* pIntelliMouseObject=
|
|
pOrganizer->GetFirstIntelliMouseObject(pos);
|
|
if(pIntelliMouseObject!=NULL)
|
|
{
|
|
pOrganizer->
|
|
Attach(pWnd,pIntelliMouseObject->GetStartEventID(),
|
|
pIntelliMouseObject->GetKeyPressedState());
|
|
}
|
|
else
|
|
{
|
|
pOrganizer->
|
|
Attach(pWnd,pOrganizer->m_nThreadOrigStartEventID,
|
|
pOrganizer->m_dwThreadOrigKeyState);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ::CallNextHookEx(pOrganizer->GetSavedCBTHookProc(),
|
|
nCode,wParam,lParam);
|
|
}
|
|
}
|
|
return ::CallNextHookEx(COXIntelliMouseOrganizer::GetOriginalCBTHookProc(),
|
|
nCode,wParam,lParam);
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK COXIntelliMouseOrganizer::
|
|
IntelliMouseGetMessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
if(nCode>=0 && ::IsWindow(((MSG*)lParam)->hwnd))
|
|
{
|
|
DWORD dwThreadID=::GetWindowThreadProcessId(((MSG*)lParam)->hwnd,NULL);
|
|
COXIntelliMouseOrganizer* pOrganizer=NULL;
|
|
if(COXIntelliMouseOrganizer::
|
|
m_arrThreadOrganizers.Lookup(dwThreadID,pOrganizer))
|
|
{
|
|
ASSERT(pOrganizer!=NULL);
|
|
ASSERT(pOrganizer->IsAttachedAllInThread());
|
|
|
|
// check if new window is created and attach it.
|
|
CWnd* pWnd=CWnd::FromHandlePermanent(((MSG*)lParam)->hwnd);
|
|
if(pWnd!=NULL && !pOrganizer->IsAttached(pWnd))
|
|
{
|
|
POSITION pos=NULL;
|
|
COXIntelliMouse* pIntelliMouseObject=
|
|
pOrganizer->GetFirstIntelliMouseObject(pos);
|
|
if(pIntelliMouseObject!=NULL)
|
|
{
|
|
pOrganizer->
|
|
Attach(pWnd,pIntelliMouseObject->GetStartEventID(),
|
|
pIntelliMouseObject->GetKeyPressedState());
|
|
}
|
|
else
|
|
{
|
|
pOrganizer->
|
|
Attach(pWnd,pOrganizer->m_nThreadOrigStartEventID,
|
|
pOrganizer->m_dwThreadOrigKeyState);
|
|
}
|
|
}
|
|
|
|
return ::CallNextHookEx(pOrganizer->GetSavedGetMessageHookProc(),
|
|
nCode,wParam,lParam);
|
|
}
|
|
}
|
|
|
|
return ::CallNextHookEx(COXIntelliMouseOrganizer::GetOriginalGetMessageHookProc(),
|
|
nCode,wParam,lParam);
|
|
}
|
|
|
|
|
|
BOOL CALLBACK COXIntelliMouseOrganizer::EnumThreadWindows(HWND hWnd, LPARAM lParam)
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
ASSERT(lParam!=NULL);
|
|
ASSERT(::IsWindow(hWnd));
|
|
COXIntelliMouseOrganizer* pOrganizer=(COXIntelliMouseOrganizer*)lParam;
|
|
ASSERT(pOrganizer->IsAttachedAllInThread());
|
|
|
|
DWORD dwThreadID=::GetWindowThreadProcessId(hWnd,NULL);
|
|
if(dwThreadID==pOrganizer->GetAttachedThread())
|
|
{
|
|
pOrganizer->AttachAllWindows(hWnd);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXIntelliMouseOrganizer::DetachAllInThread()
|
|
{
|
|
if(!IsAttachedAllInThread())
|
|
return FALSE;
|
|
|
|
ASSERT(m_dwThreadID!=NULL);
|
|
ASSERT(m_pfnOldCBTHookProc!=NULL);
|
|
ASSERT(m_pfnOriginalCBTHookProc!=NULL);
|
|
ASSERT(m_pfnOldGetMessageHookProc!=NULL);
|
|
ASSERT(m_pfnOriginalGetMessageHookProc!=NULL);
|
|
|
|
// unhook CBT
|
|
if(m_pfnOldCBTHookProc!=NULL)
|
|
{
|
|
VERIFY(::UnhookWindowsHookEx(m_pfnOldCBTHookProc));
|
|
m_pfnOldCBTHookProc=NULL;
|
|
m_pfnOriginalCBTHookProc=NULL;
|
|
}
|
|
|
|
// unhook GetMessage
|
|
if(m_pfnOldGetMessageHookProc!=NULL)
|
|
{
|
|
VERIFY(::UnhookWindowsHookEx(m_pfnOldGetMessageHookProc));
|
|
m_pfnOldGetMessageHookProc=NULL;
|
|
m_pfnOriginalGetMessageHookProc=NULL;
|
|
}
|
|
|
|
// clear map of rejected windows
|
|
m_mapRejectedControls.RemoveAll();
|
|
|
|
m_arrThreadOrganizers.RemoveKey(m_dwThreadID);
|
|
|
|
m_dwThreadID=NULL;
|
|
|
|
return Detach(NULL);
|
|
}
|
|
|