// // lbmenu.cpp // #include "private.h" #include "candmenu.h" #include "cuimenu.h" #include "globals.h" #include "candutil.h" #include "wcand.h" // // // #define g_dwMenuStyle UIWINDOW_TOPMOST | UIWINDOW_TOOLWINDOW | UIWINDOW_OFC10MENU | UIWINDOW_HASSHADOW ////////////////////////////////////////////////////////////////////////////// // // CCandMenuItem // ////////////////////////////////////////////////////////////////////////////// /* C C A N D M E N U I T E M */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CCandMenuItem::CCandMenuItem( CCandMenu *pCandMenu ) { m_pCandMenu = pCandMenu; } /* ~ C C A N D M E N U I T E M */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CCandMenuItem::~CCandMenuItem( void ) { } /* I N S E R T T O U I */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ BOOL CCandMenuItem::InsertToUI( CUIFMenu *pCuiMenu ) { UINT uFlags = MF_BYPOSITION; if (_dwFlags & TF_LBMENUF_SEPARATOR) { uFlags |= MF_SEPARATOR; pCuiMenu->InsertSeparator(); return TRUE; } if (_dwFlags & TF_LBMENUF_SUBMENU) { Assert(m_pCandMenu); CUIFMenu *pCuiMenuSub = ((CCandMenu *)_pSubMenu)->CreateMenuUI( TRUE /* sub menu */ ); CUIFMenuItem *pCuiItem = new CUIFMenuItem(pCuiMenu); if (!pCuiItem) { return FALSE; } pCuiItem->Initialize(); pCuiItem->Init((UINT)-1, _bstr); pCuiItem->SetSub(pCuiMenuSub); if (_hbmp) { pCuiItem->SetBitmap(_hbmp); } if (_hbmpMask) { pCuiItem->SetBitmapMask(_hbmpMask); } pCuiMenu->InsertItem(pCuiItem); return TRUE; } CUIFMenuItem *pCuiItem = new CUIFMenuItem(pCuiMenu); if (!pCuiItem) { return FALSE; } pCuiItem->Initialize(); pCuiItem->Init(_uId, _bstr); if (_dwFlags & TF_LBMENUF_GRAYED) { pCuiItem->Gray(TRUE); } if (_dwFlags & TF_LBMENUF_CHECKED) { pCuiItem->Check(TRUE); } else if (_dwFlags & TF_LBMENUF_RADIOCHECKED) { pCuiItem->RadioCheck(TRUE); } if (_hbmp) { pCuiItem->SetBitmap(_hbmp); } if (_hbmpMask) { pCuiItem->SetBitmapMask(_hbmpMask); } pCuiMenu->InsertItem(pCuiItem); return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // CCandMenu // ////////////////////////////////////////////////////////////////////////////// /* C C A N D M E N U */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CCandMenu::CCandMenu( HINSTANCE hInst ) { NONCLIENTMETRICS ncm; m_hInst = hInst; m_pCUIMenu = NULL; memset( &m_lf, 0, sizeof(m_lf) ); m_pCandWnd = NULL; ncm.cbSize = sizeof(ncm); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, FALSE)) { ConvertLogFontAtoW( &ncm.lfMenuFont, &m_lf ); } } /* ~ C C A N D M E N U */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CCandMenu::~CCandMenu() { } /* A D D R E F */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ STDAPI_(ULONG) CCandMenu::AddRef(void) { return CCicLibMenu::AddRef(); } /* R E L E A S E */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ STDAPI_(ULONG) CCandMenu::Release(void) { return CCicLibMenu::Release(); } /* Q U E R Y I N T E R F A C E */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ STDAPI CCandMenu::QueryInterface(REFIID riid, void **ppvObj) { if (IsEqualIID( riid, IID_ITfCandUIMenuExtension )) { if (ppvObj == NULL) { return E_POINTER; } *ppvObj = SAFECAST( this, ITfCandUIMenuExtension* ); AddRef(); return S_OK; } return CCicLibMenu::QueryInterface( riid, ppvObj ); } /* S E T F O N T */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ STDAPI CCandMenu::SetFont( LOGFONTW *plf ) { if (plf == NULL) { return E_INVALIDARG; } m_lf = *plf; return S_OK; } /* G E T F O N T */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ STDAPI CCandMenu::GetFont( LOGFONTW *plf ) { if (plf == NULL) { return E_INVALIDARG; } *plf = m_lf; return S_OK; } /* S H O W P O P U P */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ UINT CCandMenu::ShowPopup( CCandWindowBase *pCandWnd, const POINT pt, const RECT *prcArea ) { if (m_pCUIMenu) { return 0; } m_pCandWnd = pCandWnd; UINT uRet = 0; if (m_pCUIMenu = CreateMenuUI( FALSE /* not sub menu */)) { uRet = m_pCUIMenu->ShowModalPopup( m_pCandWnd, prcArea, TRUE ); delete m_pCUIMenu; m_pCUIMenu = NULL; } m_pCandWnd = NULL; return uRet; } /* C L O S E P O P U P */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ void CCandMenu::ClosePopup( void ) { if (m_pCUIMenu != NULL) { PostThreadMessage( GetCurrentThreadId(), WM_NULL, 0, 0 ); } } /* C R E A T E M E N U U I */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFMenu *CCandMenu::CreateMenuUI( BOOL fSubMenu ) { CUIFCandMenu *pCuiMenu; int i; if (fSubMenu) { pCuiMenu = new CUIFCandMenu( m_hInst, g_dwMenuStyle, 0 ); } else { pCuiMenu = new CUIFCandMenuParent( m_hInst, g_dwMenuStyle, 0, m_pCandWnd ); } pCuiMenu->Initialize(); pCuiMenu->ResetMenuFont( &m_lf ); for (i = 0; i < _rgItem.Count(); i++) { CCandMenuItem *pItem = (CCandMenuItem *)_rgItem.Get(i); pItem->InsertToUI( pCuiMenu ); } return pCuiMenu; } /* G E T M E N U U I */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFMenu *CCandMenu::GetMenuUI( void ) { return m_pCUIMenu; } // // // /* C U I F C A N D M E N U */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFCandMenu::CUIFCandMenu( HINSTANCE hInst, DWORD dwWndStyle, DWORD dwMenuStyle ) : CUIFMenu( hInst, dwWndStyle, dwMenuStyle ) { } /* ~ C U I F C A N D M E N U */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFCandMenu::~CUIFCandMenu( void ) { } /* R E S E T M E N U F O N T */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ void CUIFCandMenu::ResetMenuFont( LOGFONTW *plf ) { ClearMenuFont(); SetFont( OurCreateFontIndirectW( plf ) ); } // // // /* C U I F C A N D M E N U P A R E N T */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFCandMenuParent::CUIFCandMenuParent( HINSTANCE hInst, DWORD dwWndStyle, DWORD dwMenuStyle, CCandWindowBase *pCandWnd ) : CUIFCandMenu( hInst, dwWndStyle, dwMenuStyle ) { m_pCandWnd = pCandWnd; } /* ~ C U I F C A N D M E N U P A R E N T */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ CUIFCandMenuParent::~CUIFCandMenuParent( void ) { UninstallHook(); } /* I N I T S H O W */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ BOOL CUIFCandMenuParent::InitShow( CUIFWindow *pcuiWndParent, const RECT *prc, BOOL fVertical, BOOL fAnimate ) { BOOL fSucceed = TRUE; if (!CUIFMenu::InitShow( pcuiWndParent, prc, fVertical, fAnimate )) { fSucceed = FALSE; } if (!InstallHook()) { fSucceed = FALSE; } if (m_pCandWnd != NULL) { m_pCandWnd->OnMenuOpened(); } return fSucceed; } /* U N I N I T S H O W */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ BOOL CUIFCandMenuParent::UninitShow() { BOOL fSucceed = TRUE; if (!CUIFMenu::UninitShow()) { fSucceed = FALSE; } if (!UninstallHook()) { fSucceed = FALSE; } if (m_pCandWnd != NULL) { m_pCandWnd->OnMenuClosed(); } return fSucceed; } /* M O D A L M E S S A G E L O O P */ /*------------------------------------------------------------------------------ NOTE: we need to use PeekMessage to cancel candidate menu in unknown mouse message (w/o eating...) ------------------------------------------------------------------------------*/ void CUIFCandMenuParent::ModalMessageLoop( void ) { MSG msg; while (TRUE) { while (!PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE )) { WaitMessage(); } if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) { if (msg.message == WM_NULL) { break; } else if (msg.message == WM_QUIT) { PostQuitMessage( (int)msg.wParam ); break; } // check hooked mouse message (messages sent to another window) else if (msg.message == g_msgHookedMouse) { if (((msg.wParam != WM_MOUSEMOVE) && (msg.wParam != WM_NCMOUSEMOVE))) { CancelMenu(); break; } msg.hwnd = GetWnd(); msg.message = (UINT)msg.wParam; msg.wParam = 0; } // check hooked keyboard messages (all keyboard messages) else if (msg.message == g_msgHookedKey) { UINT message; CUIFMenu *pMenuObj = GetTopSubMenu(); if (HIWORD(msg.lParam) & KF_ALTDOWN) { message = (HIWORD(msg.lParam) & KF_UP) ? WM_SYSKEYUP : WM_SYSKEYDOWN; } else { message = (HIWORD(msg.lParam) & KF_UP) ? WM_KEYUP : WM_KEYDOWN; } if (message == WM_SYSKEYDOWN) { CancelMenu(); } msg.hwnd = (pMenuObj != NULL) ? pMenuObj->GetWnd() : NULL; msg.message = message; } TranslateMessage(&msg); DispatchMessage(&msg); } } } /* I N S T A L L H O O K */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ BOOL CUIFCandMenuParent::InstallHook( void ) { HHOOK hHookKeyboard; HHOOK hHookMouse; if (!g_ShareMem.Create()) { return FALSE; } if (!g_ShareMem.LockData()) { return FALSE; } hHookKeyboard = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, m_hInstance, NULL ); hHookMouse = SetWindowsHookEx( WH_MOUSE, MouseProc, m_hInstance, NULL ); g_ShareMem.GetData()->dwThreadId = GetCurrentThreadId(); g_ShareMem.GetData()->hHookKeyboard = hHookKeyboard; g_ShareMem.GetData()->hHookMouse = hHookMouse; g_ShareMem.GetData()->hWndMenu = GetWnd(); g_ShareMem.UnlockData(); return (hHookKeyboard != NULL) && (hHookMouse != NULL); } /* U N I N S T A L L H O O K */ /*------------------------------------------------------------------------------ ------------------------------------------------------------------------------*/ BOOL CUIFCandMenuParent::UninstallHook( void ) { HHOOK hHook; if (!g_ShareMem.LockData()) { return FALSE; } if (g_ShareMem.GetData()->dwThreadId != GetCurrentThreadId()) { g_ShareMem.UnlockData(); return FALSE; } hHook = g_ShareMem.GetData()->hHookKeyboard; if (hHook != NULL) { UnhookWindowsHookEx( hHook ); } hHook = g_ShareMem.GetData()->hHookMouse; if (hHook != NULL) { UnhookWindowsHookEx( hHook ); } g_ShareMem.GetData()->dwThreadId = 0; g_ShareMem.GetData()->hHookKeyboard = NULL; g_ShareMem.GetData()->hHookMouse = NULL; g_ShareMem.GetData()->hWndMenu = NULL; g_ShareMem.UnlockData(); g_ShareMem.Close(); return TRUE; } /* K E Y B O A R D P R O C */ /*------------------------------------------------------------------------------ Hook function for keyboard message Forward all keyboard message as g_msgHookedKey to the manu window thread ------------------------------------------------------------------------------*/ LRESULT CALLBACK CUIFCandMenuParent::KeyboardProc( int code, WPARAM wParam, LPARAM lParam ) { LRESULT lResult = 0; BOOL fEatMessage = FALSE; if (!g_ShareMem.LockData()) { return 0; } if (code == HC_ACTION || code == HC_NOREMOVE) { PostThreadMessage( g_ShareMem.GetData()->dwThreadId, g_msgHookedKey, wParam, lParam ); fEatMessage = TRUE; } if ((code < 0) || !fEatMessage) { lResult = CallNextHookEx( g_ShareMem.GetData()->hHookKeyboard, code, wParam, lParam ); } else { lResult = (LRESULT)TRUE; } g_ShareMem.UnlockData(); return lResult; } /* M O U S E P R O C */ /*------------------------------------------------------------------------------ Hook function for mouse message Forward mouse message sent to non-menu window (excluding mouse movement) as g_msgHookedMouse to the manu window thread ------------------------------------------------------------------------------*/ LRESULT CALLBACK CUIFCandMenuParent::MouseProc( int code, WPARAM wParam, LPARAM lParam ) { LRESULT lResult = 0; BOOL fEatMessage = FALSE; if (!g_ShareMem.LockData()) { return 0; } if (code == HC_ACTION || code == HC_NOREMOVE) { MOUSEHOOKSTRUCT *pmhs = (MOUSEHOOKSTRUCT *)lParam; UINT message = (UINT)wParam; if (GetCurrentThreadId() == g_ShareMem.GetData()->dwThreadId) { HWND hWndTemp = pmhs->hwnd; HWND hWndMenu = g_ShareMem.GetData()->hWndMenu; while ((hWndTemp != NULL) && (hWndTemp != hWndMenu)) { hWndTemp = GetParent( hWndTemp ); } if (hWndTemp == NULL /* not menu window */) { if ((message != WM_NCMOUSEMOVE) && (message != WM_MOUSEMOVE)) { PostThreadMessage( g_ShareMem.GetData()->dwThreadId, g_msgHookedMouse, wParam, MAKELPARAM(pmhs->pt.x, pmhs->pt.y) ); } else { fEatMessage = (message == WM_NCMOUSEMOVE); } } } else { if ((message != WM_NCMOUSEMOVE) && (message != WM_MOUSEMOVE)) { PostThreadMessage( g_ShareMem.GetData()->dwThreadId, g_msgHookedMouse, wParam, MAKELPARAM(pmhs->pt.x, pmhs->pt.y) ); } } } if ((code < 0) || !fEatMessage) { lResult = CallNextHookEx( g_ShareMem.GetData()->hHookMouse, code, wParam, lParam ); } else { lResult = (LRESULT)TRUE; } g_ShareMem.UnlockData(); return lResult; }