Search code examples
winapicheckboxmousecapture

Do I have the right idea with using SetCapture() for a windowless checkbox?


My Table control uses windowless checkboxes (because there can be an arbitrary number of checkboxes here). Right now, I use TrackMouseEvent(TME_LEAVE) and manually checking if the mouse is in the checkbox rect during a WM_LBUTTONUP. I have TODOs marked in my code for the edge cases that this causes, such as a missing WM_LBUTTONUP when the mouse has left the client area.

Now I notice today's The Old New Thing says buttons use mouse captures. This got me thinking, and after looking into it, mouse captures would fit what I need more appropriately; if my assumptions are correct it would handle the various edge cases I mentioned above and be more correct in general.

In particular, the assumptions I make are: I should abandon any capture-related operations on a WM_CAPTURECHANGED even if every other condition is met. I will get a WM_CAPTURECHANGED after a ReleaseCapture(). After a SetCapture(), I will always end with either a WM_LBUTTONUP or a WM_CAPTURECHANGED, whichever comes first.

I've read both MSDN and a few articles I've found by Googling "setcapture correct use"; I just want to make sure I've got the right idea and will be implementing this correctly. Do I?

on WM_LBUTTONDOWN
    if the button is in a checkbox
        SetCapture()
        mark that we're in checkbox clicking mode
on WM_MOUSEMOVE
    if we are in checkbox clicking mode
        draw the checkbox in the pressed state
on WM_LBUTTONUP
    if we are in checkbox clicking mode
        leave checkbox clicking mode
        THEN call ReleaseCapture(), so we can ignore its WM_CAPTURECHANGED
        if the mouse was released in the same checkbox
            toggle it
on WM_CAPTURECHANGED
    if we are in checkbox clicking mode
        abandon checkbox clicking mode and leave the checkbox untoggled, even if the mouse is hovering over the checkbox

Do I have the right idea here? And in particular, is my order of operations for WM_LBUTTONDOWN correct? Thanks.


Solution

  • What you have said is basically right, although a real checkbox tracks WM_MOUSEMOVE while in "clicking mode" and displays the checkbox in its original state if the mouse moves off of it. So to emulate that you should have:

    on WM_MOUSEMOVE
        if we are in checkbox clicking mode
            if mouse is over the checkbox
                draw the checkbox in the pressed (toggled) state
            else
                draw the checkbox in the original state