Tengo el código C++ cortado con tijeras debajo de un comentario en https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx
Y lo usaron (y variaciones sobre la misma) con éxito.
El usuario que lo escribió alega que se inspiró en una recomendación de ms sobre una guía de prácticas recomendadas de Windows Vista, para reenviar el evento de la rueda del mouse a la ventana que esté rodeada por el cursor del mouse. La virtud de su implementación es que no es muy intrusivo, simplemente lo suelta y establece los ganchos, haciendo referencia a su hilo principal. Evita reenviar el evento a ventanas que pertenecen a otros procesos, pero tal vez eso realmente podría ser algo bueno.
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;
}
Gracias por la idea, Alex! Parece un método viable. –
+1 para la advertencia, que de hecho es muy importante. – 0xC0000022L
@Alex, lamento no haber aceptado la respuesta antes, porque me di por vencido para implementar esta función en ese momento y luego olvidé esta pregunta ... Solo revisé todas las respuestas, y creo que la suya funcionaría. Lo siento por la recompensa ... –