41
41
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Mouse.git"
42
42
43
43
BUTTONS = ["left" , "right" , "middle" ]
44
+ DEFAULT_CURSOR = "/" .join (__file__ .split ("/" )[:- 1 ]) + "/mouse_cursor.bmp"
44
45
45
46
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
47
48
"""
48
49
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
50
51
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.
52
56
"""
53
57
mouse_interface_index , mouse_endpoint_address = None , None
54
58
mouse_device = None
@@ -101,17 +105,19 @@ def find_and_init_boot_mouse(cursor_image="/launcher_assets/mouse_cursor.bmp"):
101
105
mouse_device .set_configuration ()
102
106
103
107
# 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 )
107
113
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 )
110
116
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
113
119
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 )
115
121
116
122
# if no mouse found
117
123
return None
@@ -125,13 +131,13 @@ class BootMouse:
125
131
126
132
:param device: The usb device instance for the mouse
127
133
:param endpoint_address: The address of the mouse endpoint
128
- :param tilegrid: The TileGrid that holds the visible mouse cursor
129
134
:param was_attached: Whether the usb device was attached to the kernel
135
+ :param tilegrid: The TileGrid that holds the visible mouse cursor
130
136
:param scale: The scale of the group that the Mouse TileGrid will be put into.
131
137
Needed in order to properly clamp the mouse to the display bounds
132
138
"""
133
139
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
135
141
self .device = device
136
142
137
143
self .tilegrid = tilegrid
@@ -154,29 +160,44 @@ def __init__(self, device, endpoint_address, tilegrid, was_attached, scale=1):
154
160
If there's no new mouse data (nothing changes) this property can be checked to see
155
161
which buttons are currently pressed."""
156
162
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
158
173
159
174
@property
160
175
def x (self ) -> int :
161
176
"""
162
177
The x coordinate of the mouse cursor
163
178
"""
164
- return self .tilegrid .x
179
+ return self .tilegrid .x if self . tilegrid else self . _x
165
180
166
181
@x .setter
167
182
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
169
187
170
188
@property
171
189
def y (self ) -> int :
172
190
"""
173
191
The y coordinate of the mouse cursor
174
192
"""
175
- return self .tilegrid .y
193
+ return self .tilegrid .y if self . tilegrid else self . _y
176
194
177
195
@y .setter
178
196
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
180
201
181
202
def release (self ):
182
203
"""
@@ -206,22 +227,21 @@ def update(self):
206
227
except usb .core .USBError :
207
228
return None
208
229
209
- # update the mouse tilegrid x and y coordinates
230
+ # update the mouse x and y coordinates
210
231
# 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
225
245
226
246
self .pressed_btns = []
227
247
for i , button in enumerate (BUTTONS ):
0 commit comments