|
9 | 9 | the player successfully reveals all squares without mines or clicks on a mine.
|
10 | 10 | """
|
11 | 11 | import array
|
12 |
| -import time |
13 | 12 | from displayio import Group, OnDiskBitmap, TileGrid, Bitmap, Palette
|
14 | 13 | from adafruit_display_text.bitmap_label import Label
|
15 | 14 | from adafruit_display_text.text_box import TextBox
|
16 |
| -import adafruit_usb_host_descriptors |
17 | 15 | from eventbutton import EventButton
|
18 | 16 | import supervisor
|
19 | 17 | import terminalio
|
20 |
| -import usb.core |
| 18 | +from adafruit_usb_host_mouse import find_and_init_boot_mouse |
21 | 19 | from gamelogic import GameLogic, BLANK, INFO_BAR_HEIGHT, DIFFICULTIES
|
22 | 20 | from menu import Menu, SubMenu
|
23 | 21 |
|
|
49 | 47 | color_depth=16,
|
50 | 48 | )
|
51 | 49 | display = framebufferio.FramebufferDisplay(fb)
|
| 50 | + supervisor.runtime.display = display |
52 | 51 |
|
53 | 52 | game_logic = GameLogic(display) # pylint: disable=no-value-for-parameter
|
54 | 53 |
|
|
76 | 75 | ui_group = Group()
|
77 | 76 | main_group.append(ui_group)
|
78 | 77 |
|
79 |
| -# Create the mouse graphics and add to the main group |
80 |
| -mouse_bmp = OnDiskBitmap("bitmaps/mouse_cursor.bmp") |
81 |
| -mouse_bmp.pixel_shader.make_transparent(0) |
82 |
| -mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) |
83 |
| -mouse_tg.x = display.width // 2 |
84 |
| -mouse_tg.y = display.height // 2 |
85 |
| -main_group.append(mouse_tg) |
86 |
| - |
87 | 78 | MENU_ITEM_HEIGHT = INFO_BAR_HEIGHT
|
88 | 79 |
|
89 | 80 | def create_game_board():
|
@@ -116,63 +107,24 @@ def update_ui():
|
116 | 107 | mines_left_label.text = f"Mines: {game_logic.mines_left}"
|
117 | 108 | elapsed_time_label.text = f"Time: {game_logic.elapsed_time}"
|
118 | 109 |
|
119 |
| -# variable for the mouse USB device instance |
120 |
| -mouse = None |
121 |
| - |
122 |
| -# wait a second for USB devices to be ready |
123 |
| -time.sleep(1) |
124 |
| - |
125 |
| -good_devices = False |
126 |
| -wait_time = time.monotonic() + 10 # wait up to 20 seconds for a good device to be found |
127 |
| -while not good_devices and time.monotonic() < wait_time: |
128 |
| - for device in usb.core.find(find_all=True): |
129 |
| - if device.manufacturer is not None: |
130 |
| - good_devices = True |
131 |
| - break |
132 |
| -# scan for connected USB devices |
133 |
| -for device in usb.core.find(find_all=True): |
134 |
| - # print information about the found devices |
135 |
| - print(f"{device.idVendor:04x}:{device.idProduct:04x}") |
136 |
| - print(device.manufacturer, device.product) |
137 |
| - print(device.serial_number) |
138 |
| - |
139 |
| - mouse_intfc,mouse_endpt = adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) |
140 |
| - if (mouse_intfc is None or mouse_endpt is None): |
141 |
| - continue # Not a mouse device |
142 |
| - |
143 |
| - # assume this device is the mouse |
144 |
| - mouse = device |
145 |
| - |
146 |
| - # detach from kernel driver if active |
147 |
| - if mouse.is_kernel_driver_active(mouse_intfc): |
148 |
| - mouse.detach_kernel_driver(mouse_intfc) |
149 |
| - |
150 |
| - # set the mouse configuration so it can be used |
151 |
| - mouse.set_configuration() |
152 |
| - |
153 |
| - # Verify mouse works by reading from it |
154 |
| - buf = array.array("b", [0] * 4) |
155 |
| - try: |
156 |
| - # Try to read some data with a short timeout |
157 |
| - data = mouse.read(mouse_endpt, buf, timeout=100) |
158 |
| - print(f"Mouse test read successful: {data} bytes - {buf}") |
159 |
| - break |
160 |
| - except usb.core.USBTimeoutError: |
161 |
| - # Timeout is normal if mouse isn't moving |
162 |
| - print("Mouse connected but not sending data (normal)") |
163 |
| - break |
164 |
| - except Exception as e: # pylint: disable=broad-except |
165 |
| - print(f"Mouse test read failed: {e}") |
166 |
| - # Continue to try next device or retry |
167 |
| - mouse = None |
168 | 110 |
|
| 111 | +# variable for the mouse USB device instance |
| 112 | +mouse = find_and_init_boot_mouse(cursor_image="bitmaps/mouse_cursor.bmp") |
169 | 113 | if mouse is None:
|
170 | 114 | raise RuntimeError("No mouse found. Please connect a USB mouse.")
|
171 | 115 |
|
| 116 | +mouse.sensitivity = 4 # Slow the mouse down a bit |
| 117 | +mouse_tg = mouse.tilegrid |
| 118 | +mouse_tg.x = display.width // 2 |
| 119 | +mouse_tg.y = display.height // 2 |
| 120 | + |
| 121 | +# add mouse graphic to main_group |
| 122 | +main_group.append(mouse_tg) |
| 123 | + |
172 | 124 | buf = array.array("b", [0] * 4)
|
173 | 125 | waiting_for_release = False
|
174 | 126 | left_button = right_button = False
|
175 |
| -mouse_coords = (0, 0) |
| 127 | +mouse_coords = (display.width // 2, display.height // 2) |
176 | 128 |
|
177 | 129 | # Create the UI Elements (Ideally fit into 320x16 area)
|
178 | 130 | # Label for the Mines Left (Left of Center)
|
@@ -279,45 +231,47 @@ def hide_group(group):
|
279 | 231 |
|
280 | 232 | menus = (reset_menu, difficulty_menu)
|
281 | 233 |
|
| 234 | +# Mouse state |
| 235 | +last_left_button_state = 0 |
| 236 | +last_right_button_state = 0 |
| 237 | +left_button_pressed = False |
| 238 | +right_button_pressed = False |
| 239 | + |
282 | 240 | # main loop
|
283 | 241 | while True:
|
284 | 242 | update_ui()
|
285 |
| - # attempt mouse read |
286 |
| - try: |
287 |
| - # try to read data from the mouse, small timeout so the code will move on |
288 |
| - # quickly if there is no data |
289 |
| - while True: |
290 |
| - try: |
291 |
| - # read data from the mouse endpoint |
292 |
| - data_len = mouse.read(mouse_endpt, buf, timeout=10) |
293 |
| - if data_len > 0: |
294 |
| - break |
295 |
| - except usb.core.USBTimeoutError: |
296 |
| - # if we get a timeout error, it means there is no data available |
297 |
| - pass |
298 |
| - except usb.core.USBError as exc: |
299 |
| - # if we get a USBError, We may be getting no endpoint msgs which can be waited out |
300 |
| - pass |
301 |
| - |
302 |
| - left_button = buf[0] & 0x01 |
303 |
| - right_button = buf[0] & 0x02 |
304 |
| - |
305 |
| - # if there was data, then update the mouse cursor on the display |
306 |
| - # using min and max to keep it within the bounds of the display |
307 |
| - mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1] // 2)) |
308 |
| - mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2] // 2)) |
309 |
| - mouse_coords = (mouse_tg.x, mouse_tg.y) |
310 |
| - |
311 |
| - if waiting_for_release and not left_button and not right_button: |
312 |
| - # If both buttons are released, we can process the next click |
313 |
| - waiting_for_release = False |
314 |
| - |
315 |
| - # timeout error is raised if no data was read within the allotted timeout |
316 |
| - except usb.core.USBTimeoutError: |
317 |
| - # no problem, just go on |
318 |
| - pass |
319 |
| - except AttributeError as exc: |
320 |
| - raise RuntimeError("Mouse not found") from exc |
| 243 | + # update cursor position, and check for clicks |
| 244 | + buttons = mouse.update() |
| 245 | + |
| 246 | + # Extract button states |
| 247 | + if buttons is None: |
| 248 | + left_button = 0 |
| 249 | + right_button = 0 |
| 250 | + else: |
| 251 | + left_button = 1 if 'left' in buttons else 0 |
| 252 | + right_button = 1 if 'right' in buttons else 0 |
| 253 | + |
| 254 | + # Detect button presses |
| 255 | + if left_button == 1 and last_left_button_state == 0: |
| 256 | + left_button_pressed = True |
| 257 | + elif left_button == 0 and last_left_button_state == 1: |
| 258 | + left_button_pressed = False |
| 259 | + |
| 260 | + if right_button == 1 and last_right_button_state == 0: |
| 261 | + right_button_pressed = True |
| 262 | + elif right_button == 0 and last_right_button_state == 1: |
| 263 | + right_button_pressed = False |
| 264 | + |
| 265 | + # Update button states |
| 266 | + last_left_button_state = left_button |
| 267 | + last_right_button_state = right_button |
| 268 | + |
| 269 | + mouse_coords = (mouse_tg.x, mouse_tg.y) |
| 270 | + |
| 271 | + if waiting_for_release and not left_button and not right_button: |
| 272 | + # If both buttons are released, we can process the next click |
| 273 | + waiting_for_release = False |
| 274 | + |
321 | 275 | if not message_dialog.hidden:
|
322 | 276 | if message_button.handle_mouse(mouse_coords, left_button, waiting_for_release):
|
323 | 277 | waiting_for_release = True
|
|
0 commit comments