How to redirect mouse wheel message to other windows?
Asked Answered
E

5

7

I'm developing a Word addin for MS Word on Windows, and this addin has as 'advanced task pane' showing and docking on the left side of the Word document window (it's treeview(outline) showing a list of Word documents for fast editing multiple documents in a project).

My question is, the Word document window responds to mouse wheel message only when it's focused, but I want to be able to scroll the document with mouse wheel whenever the mouse cursor is hovering on it even the Word document window doesn't have a input focus.

Any hints in this particular case? Thank you!

Expectoration answered 5/5, 2011 at 11:18 Comment(0)
C
7

Not quite sure it will work, but I'd try the following:

Implement a global low-level mouse hook using the SetWindowsHookEx function. In the hook procedure, which should be called on mouse wheel scroll events, check if the window under mouse cursor is the Word document window. If so, set a shared flag indicating the needed scroll action. Don't send WM_VSCROLL directly from the hook procedure! This procedure has to be really fast and simple.

Now, in your add-in's message loop check the flag and if it is set, send WM_VSCROLL to the Word document window.

Carve answered 5/5, 2011 at 12:4 Comment(3)
Thanks for the idea, Alex! Looks like a viable method.Expectoration
@Alex, I'm sorry for not accepting the answer earlier, because I gave up to implement this function at that time and then forgot this question... Just reviewed all the answers, and I guess yours would work. Sorry for the bounty...Expectoration
This seems to be the exact system described in the MSDN docs to the WM_MOUSEWHEEL message. MSDN:WM_MOUSEWHEEL ... just use your mouse wheel to go all the way to the bottom!Lorient
R
2

Perhaps you could make use of the SetCapture(hWnd) Windows API function. This will cause all mouse events to go to your hWnd instead of whatever hWnd might normally expect to receive them. If you capture when the mouse enters the Word document window, and ReleaseCapture() when the mouse leaves or Word gains focus, it should work alright.

Disclaimer: I've used mouse capturing in C# before, but I've never done it in C++. I don't know if it behaves exactly the same way.

Runagate answered 18/5, 2011 at 14:34 Comment(0)
O
0

Try the following , this might help you.

1) Handle WM_MOUSEHOVER message.

2) In the handler , use SendMessage, with WM_VSCROLL as the message parameter .

Ocam answered 19/5, 2011 at 19:51 Comment(0)
C
0

Using Spy++ I saw that the window that gets the messages is of the class _Wwg (At least 2003 is) and it is responding to the WM_MOUSEWHEEL message. So you would send that window a WM_MOUSEWHELL message when you want it to scroll.

Cannibalism answered 19/5, 2011 at 23:34 Comment(0)
B
0

I've got the C++ code snipped below from a comment in https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx

And I used it (and variations on it) successfully.

The user who wrote it claims it was inspired by a ms recommendation on a Windows Vista best practices guide, to forward the mouse wheel event to whatever window is hovered by the mouse cursor. The virtue of his/her implementation is that it's completely unintrusive, you just drop it and it set the hooks, referencing your main thread. It avoids forwarding the event to windows belonging to other processes, but perhaps that could actually be a good thing.

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;
}
Bindle answered 16/10, 2015 at 18:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.