Friday, October 9, 2015

Mouse wheel redirecting to proper window

Not so long time ago, Microsoft decided to change behavior of mouse wheel in their software and guidelines alike. At the beginning, when wheels weren't as popular as today, using mouse wheel caused to scroll currently focused control in the active window. It means that mouse position wasn't taken into consideration there. However, more intuitive solution seems to be affecting currently hovered control, no matter which window is focused. That is what Microsoft changed in their documentations — to be more precise under Mouse wheel guidelines:

Make the mouse wheel take effect without clicking or having input focus. Hovering is sufficient.

Unfortunately, I noticed that wxWidgets preserves the old behavior or simply doesn't change anything (I'm not sure — I've just started learning and using this library), so only focused control receives the WM_MOUSEWHEEL message. This can be a little annoying for example in FileZilla, which uses wxWidgets. It creates differences between Windows and other systems — which use the hovering way. I believe the library makers will move with the times and change it soon, so I will have to change tense of the this paragraph to past [; .

Anyway, to make your software even more awesome, you can redirect mouse wheel events to other applications under mouse, but without focus. Normally, such events (messages) are received only by an active window (without using hooks of course). Wouldn't it be great for example to scroll web browser on other monitor without activating it? I just can't stop myself from making an advertisement of Notepad++ here.

It's one out of few programs for Windows OS, which implement such behavior. I don't understand why it's so uncommon. Actually, you can write it in a few lines of code. In application message loop or window procedure simply check whether WM_MOUSEWHEEL belongs to your window using WindowFromPoint(POINT) with point included in lParam. The code is presented below:


if (message == WM_MOUSEWHEEL) {
    POINT mousePos = {
        GET_X_LPARAM(lParam),
        GET_Y_LPARAM(lParam)
    };
    HWND hWndPointed = WindowFromPoint(mousePos);
    if (hWndPointed != NULL && hWndPointed != hwnd){
        PostMessage(hWndPointed, WM_MOUSEWHEEL, wParam, lParam);
        return 0;
    }
}

It can also be simply implemented in your wxWidgets application by overriding MSWWindowProc method in custom frame class derived from wxFrame:

WXLRESULT YourFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) {
    // Redirect mouse wheel to other windows
    if (message == WM_MOUSEWHEEL) {
        POINT mousePos = {
            GET_X_LPARAM(lParam),
            GET_Y_LPARAM(lParam)
        };
        HWND hWndPointed = WindowFromPoint(mousePos);
        if (hWndPointed != nullptr && hWndPointed != this->GetHWND()){
            PostMessage(hWndPointed, WM_MOUSEWHEEL, wParam, lParam);
            return 0;
        }
    }
    return wxFrame::MSWWindowProc(message, wParam, lParam);
}

Just imagine every application properly redirecting mouse wheel to others..

EDIT: I've found a great piece of software for Windows you can install to achieve that behavior on all windows: KatMouse.

No comments:

Post a Comment