Home > database >  Win32 API - how to access mouse events with layered transparent window WNDPROC or hook?
Win32 API - how to access mouse events with layered transparent window WNDPROC or hook?

Time:02-23

I have a window which serves as an overlay, and only has some part of it non-transparent. The window has extended styles

WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED

And the transparency is set with:

SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 0, LWA_COLORKEY);

I do want to read the mouse events to implement the interactive part of the overlay.

So far i tried catching messages like

WM_MOUSEMOVE,
WM_KEYDOWN,
WM_NCLBUTTONDOWN,

in my WNDPROC and there they didn't fire. I assumed that was due to some of the window extended styles, and by removing one at a time i found out that it was layered window attribute which caused it. Sadly my app does depend on this attribute for its transparency.

Then i tried registering a windows hook for that very process and thread to intercept the mouse events. I don't know the internals of hooks at all - but i thought they get access to the messages before they enter the application's queue hence i hoped i could read them before whatever interferes passes them on. That didn't work sadly. I registered the hook like so:

app_state.hhook = SetWindowsHookExW(WH_MOUSE,
                                    Some(Self::HOOKPROC),
                                    GetModuleHandleW(null_mut()),
                                    GetCurrentThreadId();

And the actual HOOKPROC was defined like this:

pub unsafe extern "system" fn HOOKPROC(ncode: c_int, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
    println!("fired!");
    CallNextHookEx(null_mut(), ncode, wparam, lparam)
}

Sadly this didn't output anything to STDOUT, but I do think that hook was registered as unhook function didn't return 0.

My next idea was to put the hook in the process which manages the previous window. However the below doesn't work.

app_state.hhook = SetWindowsHookExW(WH_MOUSE,
                                    Some(Self::HOOKPROC),
                                    GetModuleHandleW(null_mut()),
                                    GetWindowThreadProcessId(
                                    GetWindow(hwnd, GW_HWNDPREV), null_mut())
                                    );

I think that it's due to the fact that i need to place the hook in a separate dll but event if it does work - this solution seem to be very dirty and will probably work in very few cases without requiring elevated privileges. What can i do to achieve the desired via accepted and cohesive code?

CodePudding user response:

Just get rid of the WS_EX_TRANSPARENT style and use WS_EX_LAYERED by itself, and let the OS handle mouse input normally (no hook needed). Fully transparent pixels will fall-through as expected, and the window will receive input messages on non-transparent pixels.

  • Related