Date: | September 12, 2016 / year-entry #193 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20160912-00/?p=94295 |
Comments: | 14 |
Summary: | The obscure return values of the WM_MOUSEACTIVATE message. |
A customer had a dedicated system with two touch screens. One screen was covered by the main app window, and the other was covered by a secondary window. They needed focus to remain on the main app window because reasons.¹ One way of preventing the secondary window from
getting focus is to use the
Let's start with the new scratch program and make these changes. The first set of changes is basically the stuff we did in an earlier article to turn the main window into a logging window.
#include <strsafe.h> class RootWindow : public Window { public: ... void AppendText(LPCTSTR psz) { ListBox_SetCurSel(m_hwndChild, ListBox_AddString(m_hwndChild, psz)); } void LogMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szMsg[80]; StringCchPrintf(szMsg, 80, TEXT("%d\t0x%04x\t%p\t%p"), GetTickCount(), uMsg, wParam, lParam); AppendText(szMsg); } ... }; The logging comes from the side window: class SideWindow : public Window { public: SideWindow(RootWindow* prw) : m_prw(prw) {} virtual LPCTSTR ClassName() { return TEXT("SideWindow"); } static SideWindow *Create(RootWindow* prw); protected: LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); private: RootWindow* m_prw; }; LRESULT SideWindow::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_MOUSEACTIVATE: m_prw->LogMessage(uMsg, wParam, lParam); return MA_NOACTIVATE; case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: m_prw->LogMessage(uMsg, wParam, lParam); break; } return __super::HandleMessage(uMsg, wParam, lParam); } SideWindow *SideWindow::Create(RootWindow* prw) { SideWindow *self = new SideWindow(prw); if (self && self->WinCreateWindow(0, TEXT("SideWindow"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL)) { return self; } delete self; return NULL; }
The side window logs selected mouse messages
so we can see what's going on.
The interesting thing is that it responds to the
Let's finish up the program before discussing further. int PASCAL WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd) { ... RootWindow *prw = RootWindow::Create(); if (prw) { ShowWindow(prw->GetHWND(), nShowCmd); SideWindow *sw = SideWindow::Create(prw); ShowWindow(sw->GetHWND(), SW_SHOWNA); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } ... }
Okay, run this program, and it will open two windows.
(I didn't bother putting each one on a separate monitor.
You can use your imagination.)
While focus is on the main window,
use your finger or moues to click on the second window.
Observe that the second window does not activate,
but the logging window shows that it did receive the
So there you have it: A window that rejects activation but stil receives touch and mouse input. |
Comments (14)
Comments are closed. |
Is the footnote missing? Anyways, the requirement isn’t so obscure when you have mixed input scenarios, you want keyboard input go to the main application so it should keep focus even if you interact with the secondary window via mouse or touch.
The first paragraph has a footnote reference at the end, but there was no corresponding footnote.
Pac-Man would like to receive MA_NOACTIVATEANDEAT
And a minor error in the second to last paragraph: “use your finger or moues”. I’m amazed the spell checker doesn’t pick that up, but apparently a ‘moue’ is a ‘small grimace or expression to convey annoyance’. Learn something new every day.
Maybe Microsoft is working on a new “Moues” device and Raymond is testing it.
You should but pick up all your nits, not just those you like: “stil” in the last sentence.-P
It’s a French word. As for selective nit-picking, I assume Kevin didn’t spot “stil”. I didn’t, either, and I missed “moues” as well.
https://msdn.microsoft.com/en-us/library/ms997507.aspx
“If the layered window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and the mouse events will be passed to the other windows underneath the layered window.”
You can still make the WS_EX_TRANSPARENT window opaque with SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA);
A neat little application called net meter uses this to create a network usage chart that’s always on top and you can click through it.
I can think of many reasons I’d want to do this….
If the second monitor is purely for clicking on things, while the first has text fields for entry for instance.
It could also be they are hosting an external component that fails if the window loses focus. There is obviously something odd going on when they managed to get budget for two touch screens.
I wouldn’t be too surprised if this was an ultrasound – the ones I worked with have a large regular monitor mounted above, and a smaller touchscreen built-in to the control panel, and the touchscreen seems to behave this way.
This is what a scroll-bar control is using.
I wish more apps with floating palettes did this; the flicker as they “restore” activation back to their main window is really annoying.
The missing footnote is quite the subtle joke, took me a minute to get it.
I was just needing a way to do this. Thank you!