diff options
author | Alex Marsev <alex.marsev@gmail.com> | 2014-01-08 14:01:42 +0400 |
---|---|---|
committer | Kacper Michajłow <kasper93@gmail.com> | 2015-09-24 22:31:32 +0300 |
commit | e5f6b2c79ce1a211b71fa713f686e7acf6422f37 (patch) | |
tree | 80519bdc81818d1c149bd382f9904ee1ba26d6fa | |
parent | 799e2712e652429374e7e8c14d0d3eb2e45bc178 (diff) |
Mouse: send wheel messages to hovered windows
-rw-r--r-- | src/mpc-hc/MainFrm.h | 2 | ||||
-rw-r--r-- | src/mpc-hc/MouseTouch.cpp | 14 | ||||
-rw-r--r-- | src/mpc-hc/MouseTouch.h | 68 |
3 files changed, 84 insertions, 0 deletions
diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 4f7750936..fa3977749 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -188,6 +188,8 @@ private: EventClient m_eventc;
void EventCallback(MpcEvent ev);
+ CMainFrameMouseHook m_mouseHook;
+
enum {
TIMER_STREAMPOSPOLLER = 1,
TIMER_STREAMPOSPOLLER2,
diff --git a/src/mpc-hc/MouseTouch.cpp b/src/mpc-hc/MouseTouch.cpp index 1bb216088..39f1d8b8f 100644 --- a/src/mpc-hc/MouseTouch.cpp +++ b/src/mpc-hc/MouseTouch.cpp @@ -634,3 +634,17 @@ void CMouseWnd::OnDestroy() CMouse::InternalOnDestroy(); CWnd::OnDestroy(); } + +std::vector<CWnd*> CMainFrameMouseHook::GetRoots() +{ + std::vector<CWnd*> ret; + ret.reserve(2); + CMainFrame* pMainFrame = AfxGetMainFrame(); + if (pMainFrame) { + ret.emplace_back(pMainFrame); + if (pMainFrame->IsD3DFullScreenMode()) { + ret.emplace_back(pMainFrame->m_pFullscreenWnd); + } + } + return ret; +} diff --git a/src/mpc-hc/MouseTouch.h b/src/mpc-hc/MouseTouch.h index 0651330ec..8e094fc2a 100644 --- a/src/mpc-hc/MouseTouch.h +++ b/src/mpc-hc/MouseTouch.h @@ -21,6 +21,7 @@ #pragma once #include <map> +#include <vector> #include "EventDispatcher.h" @@ -164,3 +165,70 @@ private: return m_bD3DFS ? TABLET_DISABLE_PRESSANDHOLD : 0; } }; + +template <class T> +class CMouseWheelHook +{ + HHOOK m_hHook; + + static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode == HC_ACTION && wParam == WM_MOUSEWHEEL) { + const auto& msex = *reinterpret_cast<MOUSEHOOKSTRUCTEX*>(lParam); + if (CWnd* pFocus = CWnd::FromHandlePermanent(msex.hwnd)) { + if (CWnd* pFocusRoot = pFocus->GetAncestor(GA_ROOT)) { + for (CWnd* pRoot : T::GetRoots()) { + ASSERT(pRoot); + // only intercept messages to focused windows that have white-listed root windows + if (pRoot && *pRoot == *pFocusRoot) { + if (CWnd* pUnder = CWnd::WindowFromPoint(msex.pt)) { + if (CWnd* pUnderRoot = pUnder->GetAncestor(GA_ROOT)) { + if (*pUnderRoot == *pFocusRoot && + GetCurrentThreadId() == GetWindowThreadProcessId(pUnder->m_hWnd, nullptr)) { + // prepare MSG struct + MSG msg = { + pUnder->m_hWnd, + wParam, + CMouse::GetMouseFlags() | msex.mouseData, + MAKELPARAM(msex.pt.x, msex.pt.y), + GetMessageTime(), + msex.pt + }; + + // walk through pre-translate + if (CWnd::WalkPreTranslateTree(pUnderRoot->m_hWnd, &msg)) { + // the message shouldn't be dispatched + return TRUE; + } + + // dispatch the message + if (msg.hwnd) { + DispatchMessage(&msg); + } + } + } + } + return TRUE; + } + } + } + } + } + return CallNextHookEx(nullptr, nCode, wParam, lParam); + } + +public: + CMouseWheelHook() { + m_hHook = SetWindowsHookEx(WH_MOUSE, MouseProc, nullptr, GetCurrentThreadId()); + ASSERT(m_hHook); + } + + virtual ~CMouseWheelHook() { + if (m_hHook) { + VERIFY(UnhookWindowsHookEx(m_hHook)); + } + } +}; + +struct CMainFrameMouseHook : CMouseWheelHook<CMainFrameMouseHook> { + static std::vector<CWnd*> GetRoots(); +}; |