|
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