Problem using CaptureMouse

I have written a wx application to draw a rectangle around a section of the screen and subsequently OCR that section an put the resulting text on the clipboard. The section is defined by clicking the mouse down at the start of the desired rectangle and releasing it once the mouse has been moved to the opposite corner. This works. But, for example, if I do this over the developer studio’s window, I find I am selecting text in the developer studio as well as drawing the rectangle. So what is CaptureMouse doing? Note that I can draw the rectangle and grab the section without using CaptureMouse. I only use it because I thought it would stop mouse events going to other windows. But it doesn’t seem to do so. Here’s the code:

import wx
from enum import Enum, auto

class State(Enum):
    WAITING = auto()
    INITIAL = auto()
    MOUSE_DOWN = auto()
    CLOSE = auto()


class ScreenGrabber(wx.Frame):
    def __init__(self):
        super().__init__(None)
        self.state = State.WAITING
        self.origin = wx.Point()
        self.current = wx.Point()
        self.Bind(wx.EVT_MOUSE_CAPTURE_CHANGED,self.OnMouseCaptureChangedEvent)
        self.Bind(wx.EVT_MOUSE_CAPTURE_LOST,self.OnMouseCaptureLostEvent)
        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
        self.wantCapture = False
        self.log = []

    def Start(self):
        self.state = State.INITIAL

    def Stop(self):
        self.state = State.CLOSE

    def Log(self, text):
        self.log.append(text)

    def OnTimer(self):
        if self.wantCapture and not self.HasCapture():
            self.Log('CaptureMouse re-called')
            self.CaptureMouse()
        mouseState : wx.MouseState = wx.GetMouseState()
        if self.state == State.WAITING:
            wx.CallLater(500, self.OnTimer)
        elif self.state == State.INITIAL:
            if mouseState.LeftIsDown():
                self.Log('CaptureMouse called')
                self.CaptureMouse()
                self.wantCapture = True
                self.origin = self.current = mouseState.GetPosition()
                self.state = State.MOUSE_DOWN
            wx.CallLater(20, self.OnTimer)
        elif self.state == State.MOUSE_DOWN:
            self.current = mouseState.GetPosition()
            self.DrawSection()
            if mouseState.LeftIsDown():
                wx.CallLater(20, self.OnTimer)
            else:
                self.GrabScreenSection()
                self.state = State.WAITING
                self.origin = wx.Point()
                self.current = wx.Point()
                self.ReleaseMouse()
                self.Log('ReleaseMouse called')
                self.wantCapture = False
                wx.CallLater(20, self.OnTimer)
        elif self.state == State.CLOSE:
            self.Close()
        else:
            wx.CallLater(20, self.OnTimer)

    def OnMouseCaptureChangedEvent(self, event):
        self.Log('OnMouseCaptureChangedEvent occurred')
        pass

    def OnMouseCaptureLostEvent(self, event):
        self.ReleaseMouse()
        self.Log('OnMouseCaptureLostEvent called: mouse released')
        pass

    def OnMouseEvent(self, event):
        if self.wantCapture:
            self.Log('OnMouseEvent called')
        pass

    def DrawSection(self):
        dc = wx.ScreenDC()
        dc.SetBrush(wx.Brush('white', wx.BRUSHSTYLE_TRANSPARENT))
        dc.StartDrawingOnTop()
        dc.DrawRectangle(x=self.origin[0], y=self.origin[1], width=abs(self.origin[0] - self.current[0]),
                         height=abs(self.origin[1] - self.current[1]))
        dc.EndDrawingOnTop()
        pass

    def  GrabScreenSection(self):
        print('Screen section grabbed')
        pass


if __name__ == "__main__":
    app = wx.App(None)
    grabber = ScreenGrabber()
    grabber.Show()
    grabber.Start()
    grabber.OnTimer()
    app.MainLoop()
    pass

type or paste code here

CaptureMouse is there to receive mouse events even when the pointer has left the original window.
E.g. when the user does a drag-select for scroll-selecting, you don’t want the mouse events to get lost or delivered to another widget of your application when the users leaves the window. You want to accelerate scrolling instead.

From your experience it seems, though, that the events are still delivered to other applications. Not sure how you could filter the mouse events before they get delivered.
I had a similar requirement for key events and found no way to do so without admin rights.

You may try to generate a ‘transparent’ window all over the screen and then handle the events.

Thanks Dietmar. In fact no mouse events are delivered to my application after it calls CaptureMouse! I had thought of doing what you suggest (use a transparent window), but it seemed like CaptureMouse was ideal.