如何将鼠标滚轮消息重定向到其他窗口?

7
我正在开发一个Word插件,用于Windows上的MS Word。这个插件有一个“高级任务窗格”,显示在Word文档窗口的左侧并停靠在那里(它的树形视图(大纲)显示了项目中多个Word文档的列表,以便快速编辑)。
我的问题是,Word文档窗口只有在获得焦点时才响应鼠标滚轮消息,但我想能够在鼠标光标悬停在其上时使用鼠标滚轮滚动文档,即使Word文档窗口没有输入焦点。
在这种情况下,有什么提示吗?谢谢!
5个回答

7
我不太确定这个方法是否有效,但我建议尝试以下步骤:
使用SetWindowsHookEx函数实现全局低级别鼠标钩子。 在钩子过程中,应在鼠标滚轮滚动事件上调用,检查鼠标光标下的窗口是否为Word文档窗口。 如果是,则设置一个共享标志,指示所需的滚动操作。 请勿直接从钩子过程发送WM_VSCROLL!此过程必须非常快速和简单。
现在,在您的插件消息循环中检查该标志,如果已设置,则向Word文档窗口发送WM_VSCROLL。

谢谢你的想法,Alex!看起来是可行的方法。 - Edwin Yip
@Alex,非常抱歉我之前没有接受你的答案,因为当时我放弃了实现这个函数,然后忘记了这个问题...刚刚查看了所有答案,我想你的应该可以。对于悬赏感到抱歉... - Edwin Yip
这似乎是MSDN文档中描述的WM_MOUSEWHEEL消息的确切系统。MSDN:WM_MOUSEWHEEL ...只需使用您的鼠标滚轮滚动到底部即可! - Dave

2
也许您可以使用 Windows API 函数 SetCapture(hWnd),将所有鼠标事件发送到您的 hWnd,而不是通常接收它们的任何 hWnd。如果在鼠标进入 Word 文档窗口时捕获并在鼠标离开或 Word 获得焦点时使用 ReleaseCapture(),那么它应该能正常工作。
免责声明:我以前在 C# 中使用过鼠标捕获,但我从未在 C++ 中尝试过,不知道它是否完全相同。

0
尝试以下方法,这可能会对您有所帮助。
1)处理WM_MOUSEHOVER消息。
2)在处理程序中,使用SendMessage,并将WM_VSCROLL作为消息参数。

0

使用 Spy++ 我发现接收消息的窗口是类 _Wwg(至少在2003年是这样的),它响应 WM_MOUSEWHEEL 消息。因此,当您想要滚动时,可以向该窗口发送一个 WM_MOUSEWHELL 消息。


0

我从https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx的评论中获取了下面的 C++ 代码片段。

我已经成功地使用了它(以及其变体)。

编写此代码的用户声称,这是受 Windows Vista 最佳实践指南上微软建议的启发,可以将鼠标滚轮事件转发到鼠标光标悬停的任何窗口。他 / 她实现的优点在于它完全不会造成干扰,只需放置并设置钩子引用您的主线程即可。它避免将事件转发到其他进程所属的窗口,但也许这实际上是件好事。

namespace {
      LRESULT CALLBACK mouseInputHook(int nCode, WPARAM wParam, LPARAM lParam) {
    //"if nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function
    //without further processing and should return the value returned by CallNextHookEx"
    if (nCode >= 0) {
      MSG& msgInfo = *reinterpret_cast<MSG*>(lParam);

      if (msgInfo.message == WM_MOUSEWHEEL ||
          msgInfo.message == WM_MOUSEHWHEEL) {
        POINT pt = {};
        pt.x = ((int)(short)LOWORD(msgInfo.lParam)); //yes, there's also msgInfo.pt, but let's not take chances
        pt.y = ((int)(short)HIWORD(msgInfo.lParam)); //

        //visible child window directly under cursor; attention: not necessarily from our process!
        //http://blogs.msdn.com/b/oldnewthing/archive/2010/12/30/10110077.aspx
        if (HWND hWin = ::WindowFromPoint(pt))
          if (msgInfo.hwnd != hWin && ::GetCapture() == nullptr) {
            DWORD winProcessId = 0;
            ::GetWindowThreadProcessId(//no-fail!
                hWin, //_In_ HWND hWnd,
                &winProcessId); //_Out_opt_ LPDWORD lpdwProcessId
            if (winProcessId == ::GetCurrentProcessId()) //no-fail!
              msgInfo.hwnd = hWin; //it would be a bug to set handle from another process here
          }
      }
    }

    return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
  }

  struct Dummy {

    Dummy() {
      hHook = ::SetWindowsHookEx(WH_GETMESSAGE, //__in int idHook,
          mouseInputHook, //__in HOOKPROC lpfn,
          nullptr, //__in HINSTANCE hMod,
          ::GetCurrentThreadId()); //__in DWORD dwThreadId
      assert(hHook);
    }

    ~Dummy() {
      if (hHook)
        ::UnhookWindowsHookEx(hHook);
    }

   private:
    HHOOK hHook;
  } dummy;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接