4141__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Mouse.git"
4242
4343BUTTONS = ["left" , "right" , "middle" ]
44+ DEFAULT_CURSOR = "/" .join (__file__ .split ("/" )[:- 1 ]) + "/mouse_cursor.bmp"
4445
4546
46- def find_and_init_boot_mouse (cursor_image = "/launcher_assets/mouse_cursor.bmp" ):
47+ def find_and_init_boot_mouse (cursor_image = DEFAULT_CURSOR ): # noqa: PLR0912
4748 """
4849 Scan for an attached boot mouse connected via USB host.
49- If one is found initialize an instance of BootMouse class
50+ If one is found initialize an instance of :class:` BootMouse` class
5051 and return it.
51- :return: The BootMouse instance or None if no mouse was found.
52+
53+ :param cursor_image: Provide the absolute path to the desired cursor bitmap image. If set as
54+ `None`, the :class:`BootMouse` instance will not control a :class:`displayio.TileGrid` object.
55+ :return: The :class:`BootMouse` instance or None if no mouse was found.
5256 """
5357 mouse_interface_index , mouse_endpoint_address = None , None
5458 mouse_device = None
@@ -101,17 +105,19 @@ def find_and_init_boot_mouse(cursor_image="/launcher_assets/mouse_cursor.bmp"):
101105 mouse_device .set_configuration ()
102106
103107 # load the mouse cursor bitmap
104- if not isinstance (cursor_image , str ):
105- raise TypeError ("cursor_image must be a string" )
106- mouse_bmp = OnDiskBitmap (cursor_image )
108+ if isinstance (cursor_image , str ):
109+ mouse_bmp = OnDiskBitmap (cursor_image )
110+
111+ # make the background pink pixels transparent
112+ mouse_bmp .pixel_shader .make_transparent (0 )
107113
108- # make the background pink pixels transparent
109- mouse_bmp . pixel_shader . make_transparent ( 0 )
114+ # create a TileGrid for the mouse, using its bitmap and pixel_shader
115+ mouse_tg = TileGrid ( mouse_bmp , pixel_shader = mouse_bmp . pixel_shader )
110116
111- # create a TileGrid for the mouse, using its bitmap and pixel_shader
112- mouse_tg = TileGrid ( mouse_bmp , pixel_shader = mouse_bmp . pixel_shader )
117+ else :
118+ mouse_tg = None
113119
114- return BootMouse (mouse_device , mouse_endpoint_address , mouse_tg , mouse_was_attached )
120+ return BootMouse (mouse_device , mouse_endpoint_address , mouse_was_attached , mouse_tg )
115121
116122 # if no mouse found
117123 return None
@@ -125,13 +131,13 @@ class BootMouse:
125131
126132 :param device: The usb device instance for the mouse
127133 :param endpoint_address: The address of the mouse endpoint
128- :param tilegrid: The TileGrid that holds the visible mouse cursor
129134 :param was_attached: Whether the usb device was attached to the kernel
135+ :param tilegrid: The TileGrid that holds the visible mouse cursor
130136 :param scale: The scale of the group that the Mouse TileGrid will be put into.
131137 Needed in order to properly clamp the mouse to the display bounds
132138 """
133139
134- def __init__ (self , device , endpoint_address , tilegrid , was_attached , scale = 1 ): # noqa: PLR0913, too many args
140+ def __init__ (self , device , endpoint_address , was_attached , tilegrid = None , scale = 1 ): # noqa: PLR0913, too many args
135141 self .device = device
136142
137143 self .tilegrid = tilegrid
@@ -154,29 +160,44 @@ def __init__(self, device, endpoint_address, tilegrid, was_attached, scale=1):
154160 If there's no new mouse data (nothing changes) this property can be checked to see
155161 which buttons are currently pressed."""
156162
157- self .display_size = (supervisor .runtime .display .width , supervisor .runtime .display .height )
163+ if tilegrid is not None :
164+ self .display_size = (
165+ supervisor .runtime .display .width ,
166+ supervisor .runtime .display .height ,
167+ )
168+ self .tilegrid .x , self .tilegrid .y = (
169+ x // 2 for x in self .display_size
170+ ) # center cursor in display
171+ else :
172+ self ._x , self ._y = 0 , 0
158173
159174 @property
160175 def x (self ) -> int :
161176 """
162177 The x coordinate of the mouse cursor
163178 """
164- return self .tilegrid .x
179+ return self .tilegrid .x if self . tilegrid else self . _x
165180
166181 @x .setter
167182 def x (self , new_x : int ) -> None :
168- self .tilegrid .x = new_x
183+ if self .tilegrid :
184+ self .tilegrid .x = new_x
185+ else :
186+ self ._x = new_x
169187
170188 @property
171189 def y (self ) -> int :
172190 """
173191 The y coordinate of the mouse cursor
174192 """
175- return self .tilegrid .y
193+ return self .tilegrid .y if self . tilegrid else self . _y
176194
177195 @y .setter
178196 def y (self , new_y : int ) -> None :
179- self .tilegrid .y = new_y
197+ if self .tilegrid :
198+ self .tilegrid .y = new_y
199+ else :
200+ self ._y = new_y
180201
181202 def release (self ):
182203 """
@@ -206,22 +227,21 @@ def update(self):
206227 except usb .core .USBError :
207228 return None
208229
209- # update the mouse tilegrid x and y coordinates
230+ # update the mouse x and y coordinates
210231 # based on the delta values read from the mouse
211- self .tilegrid .x = max (
212- 0 ,
213- min (
214- (self .display_size [0 ] // self .scale ) - 1 ,
215- self .tilegrid .x + int (round ((self .buffer [1 ] / self .sensitivity ), 0 )),
216- ),
217- )
218- self .tilegrid .y = max (
219- 0 ,
220- min (
221- (self .display_size [1 ] // self .scale ) - 1 ,
222- self .tilegrid .y + int (round ((self .buffer [2 ] / self .sensitivity ), 0 )),
223- ),
224- )
232+ dx , dy = self .buffer [1 :3 ]
233+ dx = int (round ((dx / self .sensitivity ), 0 ))
234+ dy = int (round ((dy / self .sensitivity ), 0 ))
235+ if self .tilegrid :
236+ self .tilegrid .x = max (
237+ 0 , min ((self .display_size [0 ] // self .scale ) - 1 , self .tilegrid .x + dx )
238+ )
239+ self .tilegrid .y = max (
240+ 0 , min ((self .display_size [1 ] // self .scale ) - 1 , self .tilegrid .y + dy )
241+ )
242+ else :
243+ self ._x += dx
244+ self ._y += dy
225245
226246 self .pressed_btns = []
227247 for i , button in enumerate (BUTTONS ):
0 commit comments