Search code examples
c#windows-messagescefsharpmessage-pump

C# Windows (touch -> click/focus) messages between Form and Controls (WM_xxx)


I have a 3rd party open-source control (not important which one really, but its CefSharp's Chromium Web browser [v 43]).

Initially, there was a problem where if a form menu was open when you clicked inside the control, the menu was not dismissing itself (as if the control was swallowing the click event).

To circumvent this, the sample application suggested intercepting the WM_MOUSEACTIVATE message between the form and the control, and reacting by posting a WM_NCLBUTTONDOWN back to an element on the containing form (in my case, a panel bar). This solved that issue.

However, it created another. Now, once you touch inside the control (touch screen) at least 3 times, you can no longer touch an element outside of that control. You have to click [the external element] with a mouse to restore the level of focus it needs to respond to touch events again.

I have discovered that if I also intercept the WM_SETCURSOR message (to the control) and block the pump for 5ms (Thread.Sleep()), then the problem magically goes away.

I would love to know whats happening. I'm in between the theories that it's a threading/context issue, or delaying the WM_SETCURSOR message is allowing an adjacent message in the form to process first (which can't be true as they share the same thread).

So, I ran a test (without the 5ms sleep) and recorded all the messages received by the control and form in real time. During the test, I clicked on my panel bar (above the browser control) with the mouse, and then touched (long and short) various areas inside the control, and then touched the bar again (which was ignored).

enter image description here

Here are the messages:

10/13/2015 02:37:00.295 PM  Form: WM_PARENTNOTIFY       1. [Click bar]
10/13/2015 02:37:00.295 PM  Form: WM_MOUSEACTIVATE

10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST      2. [Touch 1 -long]
10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.458 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:05.458 PM  Form: 587
10/13/2015 02:37:05.458 PM  Chromium: 587
10/13/2015 02:37:05.458 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:05.458 PM  Chromium: 585
10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.458 PM  Chromium: 716
10/13/2015 02:37:05.458 PM  Chromium: WM_TOUCH  (x23)
10/13/2015 02:37:05.458 PM  Chromium: 582
10/13/2015 02:37:05.458 PM  Chromium: 581       (x22)
10/13/2015 02:37:05.674 PM  Chromium: 583
10/13/2015 02:37:05.674 PM  Chromium: 586
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_MOUSEMOVE
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:05.674 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_LBUTTONDOWN
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_LBUTTONUP

10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST      3. [Touch 2 -long]
10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.509 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:10.509 PM  Form: 587
10/13/2015 02:37:10.509 PM  Chromium: 587
10/13/2015 02:37:10.509 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:10.509 PM  Chromium: 585
10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.509 PM  Chromium: 716
10/13/2015 02:37:10.509 PM  Chromium: WM_TOUCH  (x27)
10/13/2015 02:37:10.509 PM  Chromium: 582
10/13/2015 02:37:10.509 PM  Chromium: 581       (x25)
10/13/2015 02:37:10.755 PM  Chromium: 583
10/13/2015 02:37:10.755 PM  Chromium: 586
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_MOUSEMOVE
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:10.755 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_LBUTTONDOWN
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_LBUTTONUP

10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST      4. [Touch 3 -short]
10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:25.525 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:25.525 PM  Form: 587
10/13/2015 02:37:25.525 PM  Chromium: 587
10/13/2015 02:37:25.525 PM  Chromium: 585
10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:25.525 PM  Chromium: 716
10/13/2015 02:37:25.525 PM  Chromium: WM_TOUCH  (x7)
10/13/2015 02:37:25.525 PM  Chromium: 582
10/13/2015 02:37:25.525 PM  Chromium: 581       (x5)
10/13/2015 02:37:25.586 PM  Chromium: 583
10/13/2015 02:37:25.586 PM  Chromium: 586

10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST      5. [Touch 4 -short]
10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:30.440 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:30.440 PM  Form: 587
10/13/2015 02:37:30.440 PM  Chromium: 587
10/13/2015 02:37:30.440 PM  Chromium: 585
10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:30.440 PM  Chromium: 716
10/13/2015 02:37:30.440 PM  Chromium: WM_TOUCH  (x10)
10/13/2015 02:37:30.440 PM  Chromium: 582
10/13/2015 02:37:30.440 PM  Chromium: 581       (x8)
10/13/2015 02:37:30.518 PM  Chromium: 583
10/13/2015 02:37:30.518 PM  Chromium: 586

10/13/2015 02:37:35.324 PM  Form: WM_NCHITTEST          6. [Bar (i button) touch -ignored]
10/13/2015 02:37:35.324 PM  Form: WM_NCHITTEST
10/13/2015 02:37:35.324 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:35.324 PM  Form: 587
10/13/2015 02:37:35.324 PM  Form: 282

According to these, the 3rd and 4th touches broke the focus. We can see the chromium control stopped receiving the last bunch of messages after the 586. I'm guessing its the lack of WM_PARENTNOTIFY back up to the form that's caused the issue.

I can't find any information on the 282, 581, 582, 583, 586 and 587 messages. I could maybe react to the 586 message, and manually post a WM_PARENTNOTIFY to the form? I'm not sure what effect receiving two of those in quick succession would do?

Does anybody know why the 5ms sleep on on WM_SETCURSOR keeps these messages flowing?

Or any better ideas on the fix?


Solution

  • Once I included the panel control, button and all mouse events I could think of, I was able to spot a pattern:

    This is a touch that worked:

    ....
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:10.263 PM  Chromium: WM_MOUSEMOVE
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Form: WM_PARENTNOTIFY
    10/14/2015 01:00:10.263 PM  Chromium: WM_MOUSEACTIVATE              <--
    10/14/2015 01:00:10.263 PM  panelBrowserHeader: WM_NCLBUTTONDOWN    <--
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR                  <--
    10/14/2015 01:00:10.263 PM  Chromium: WM_LBUTTONDOWN
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:10.263 PM  Chromium: WM_LBUTTONUP
    

    This is one that didn't:

    ....
    10/14/2015 01:00:15.240 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:15.240 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSEMOVE
    10/14/2015 01:00:15.240 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:15.240 PM  Form: WM_PARENTNOTIFY
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSEACTIVATE              <--
    10/14/2015 01:00:15.240 PM  Chromium: WM_SETCURSOR                  <--
    10/14/2015 01:00:15.240 PM  panelBrowserHeader: WM_NCLBUTTONDOWN    <--
    10/14/2015 01:00:15.240 PM  Chromium: WM_LBUTTONDOWN
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSELEAVE     
    

    The problem was, the WM_NCLBUTTONDOWN event (being posted as a reaction to the WM_MOUSEACTIVATE message) was sometimes happening after the next scheduled WM_SETCURSOR message. This appears to give the illusion that the touch event finished outside the bounds of its originating control, so it triggered itself a WM_MOUSELEAVE message.

    By delaying the WM_SETCURSOR message it ensures they fire in correct order.

    I am still confused by this, as I was sure the message pump is one single threaded loop time slicing its way through every control's message queue. So by blocking execution when my Chromium control received a WM_CURSOR message I thought I was blocking all message queues existing on that GUI thread.

    Anywho, it answered the question of why such a random "fix" was bypassing the problem.