Skip to content

Commit c3f3ccb

Browse files
authored
Merge pull request #3173 from RetiredWizard/match3trackpad
Metro2350_Match3: Add support for HID multi device keyboards/trackpads
2 parents e66e3c6 + cee3e99 commit c3f3ccb

File tree

2 files changed

+102
-54
lines changed

2 files changed

+102
-54
lines changed

Metro/Metro_RP2350_Match3/match3_game/code.py

Lines changed: 95 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,15 @@
185185
# transparent pixels in the corners for the rounded corner effect
186186
exit_btn_bmp.pixel_shader.make_transparent(0)
187187

188-
# centered within the display, offset to the right
189-
exit_btn.x = display.width // scale_factor // 2 - (exit_btn_bmp.width) // 2 + 30
190-
191-
# inside the bounds of the game over label, so it looks like a dialog visually
192-
exit_btn.y = 100
193-
194188
# add the play again and exit buttons to the game over group
195189
game_over_group.append(play_again_btn)
196-
game_over_group.append(exit_btn)
197190
main_group.append(game_over_group)
198191

192+
# Along right border
193+
exit_btn.x = display.width // scale_factor - (exit_btn_bmp.width)
194+
exit_btn.y = 100
195+
main_group.append(exit_btn)
196+
199197
# wait a second for USB devices to be ready
200198
time.sleep(1)
201199

@@ -247,7 +245,7 @@
247245
# USB info lists
248246
mouse_interface_indexes = []
249247
mouse_endpoint_addresses = []
250-
kernel_driver_active_flags = []
248+
detached_interfaces = []
251249
# USB device object instance list
252250
mice = []
253251
# buffers list for mouse packet data
@@ -257,37 +255,69 @@
257255
mouse_sync = []
258256

259257
# scan for connected USB devices
260-
for device in usb.core.find(find_all=True):
261-
# check if current device is has a boot mouse endpoint
262-
try:
263-
mouse_interface_index, mouse_endpoint_address = (
264-
adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device)
265-
)
266-
if mouse_interface_index is not None and mouse_endpoint_address is not None:
267-
# if it does have a boot mouse endpoint then add information to the
268-
# usb info lists
269-
mouse_interface_indexes.append(mouse_interface_index)
270-
mouse_endpoint_addresses.append(mouse_endpoint_address)
271-
272-
# add the mouse device instance to list
273-
mice.append(device)
274-
print(
275-
f"mouse interface: {mouse_interface_index} "
276-
+ f"endpoint_address: {hex(mouse_endpoint_address)}"
277-
)
278-
mouse_sync.append(0)
279-
280-
# detach kernel driver if needed
281-
kernel_driver_active_flags.append(device.is_kernel_driver_active(0))
282-
if device.is_kernel_driver_active(0):
283-
device.detach_kernel_driver(0)
284-
285-
# set the mouse configuration so it can be used
286-
device.set_configuration()
287-
288-
except usb.core.USBError as e:
289-
# The mouse might have glitched and may not be detected but at least we don't crash
290-
print(e)
258+
for find_endpoint, default_sync in [
259+
(adafruit_usb_host_descriptors.find_boot_mouse_endpoint, 0),
260+
(adafruit_usb_host_descriptors.find_report_mouse_endpoint, -1)
261+
]:
262+
263+
for device in usb.core.find(find_all=True):
264+
if device in mice:
265+
print('found device twice')
266+
continue
267+
# check if current device is has a boot mouse endpoint
268+
try:
269+
mouse_interface_index, mouse_endpoint_address = (find_endpoint(device))
270+
if mouse_interface_index is not None and mouse_endpoint_address is not None:
271+
if (
272+
mouse_interface_index in mouse_interface_indexes and
273+
mouse_endpoint_address in mouse_endpoint_addresses
274+
):
275+
print('found index/address twice')
276+
continue
277+
# if it does have a mouse endpoint then add information to the
278+
# usb info lists
279+
mouse_interface_indexes.append(mouse_interface_index)
280+
mouse_endpoint_addresses.append(mouse_endpoint_address)
281+
282+
# add the mouse device instance to list
283+
mice.append(device)
284+
print(
285+
f"{default_sync} mouse interface: {mouse_interface_index} "
286+
+ f"endpoint_address: {hex(mouse_endpoint_address)}"
287+
)
288+
mouse_sync.append(default_sync)
289+
290+
# detach kernel driver if needed
291+
detached = []
292+
293+
# Typically HID devices have interfaces 0,1,2
294+
for intf in range(3):
295+
print(f'interface: {intf} ',end="")
296+
try:
297+
if device.is_kernel_driver_active(intf):
298+
device.detach_kernel_driver(intf)
299+
detached.append(intf)
300+
print(f"Detached kernel driver from interface {intf}")
301+
else:
302+
print("not active")
303+
except usb.core.USBError as e:
304+
print(e)
305+
306+
detached_interfaces.append(detached)
307+
308+
except usb.core.USBError as e:
309+
# The mouse might have glitched and may not be detected but at least we don't crash
310+
print(e)
311+
312+
if len(mice) >= 2:
313+
break
314+
315+
if len(mice) >= 2:
316+
break
317+
318+
# set the mouse configuration on any detected mice so they can be used
319+
for device in mice:
320+
device.set_configuration()
291321

292322
def is_mouse1_left_clicked():
293323
"""
@@ -356,7 +386,11 @@ def get_mouse_deltas(buffer, read_count, sync):
356386
:param read_count: the number of bytes read from the mouse
357387
:return: tuple containing x and y delta values
358388
"""
359-
if read_count == 4 or (read_count == 8 and sync > 50):
389+
390+
if read_count == 6 and sync == -1:
391+
delta_x = buffer[2]
392+
delta_y = buffer[3]
393+
elif read_count == 4 or (read_count == 8 and sync > 50):
360394
delta_x = buffer[1]
361395
delta_y = buffer[2]
362396
elif read_count == 8:
@@ -378,9 +412,16 @@ def atexit_callback():
378412
:return:
379413
"""
380414
for _i, _mouse in enumerate(mice):
381-
if kernel_driver_active_flags[_i]:
382-
if not _mouse.is_kernel_driver_active(0):
383-
_mouse.attach_kernel_driver(0)
415+
detached_from_device = detached_interfaces[_i]
416+
417+
if detached_from_device:
418+
for _intf in detached_from_device:
419+
if not _mouse.is_kernel_driver_active(_intf):
420+
_mouse.attach_kernel_driver(_intf)
421+
print(f'#{_i} Index: {_intf} (reattaching)')
422+
else:
423+
print(f'#{_i} Index: {_intf} (Not Attaching)')
424+
384425
supervisor.runtime.autoreload = original_autoreload_val
385426

386427

@@ -407,6 +448,8 @@ def atexit_callback():
407448
)
408449
mouse_deltas = get_mouse_deltas(mouse_bufs[i], data_len, mouse_sync[i])
409450
mouse_sync[i] = mouse_deltas[2]
451+
if mouse_sync[i] == -1:
452+
mouse_bufs[i][0] = mouse_bufs[i][1]
410453
# if we got data, then update the mouse cursor on the display
411454
# using min and max to keep it within the bounds of the display
412455
mouse_tg.x = max(
@@ -445,6 +488,11 @@ def atexit_callback():
445488
# get the current mouse coordinates
446489
coords = (mouse_tg.x, mouse_tg.y, 0)
447490

491+
# if the mouse point is within the exit
492+
# button bounding box
493+
if exit_btn.contains(coords):
494+
supervisor.reload()
495+
448496
# if the current state is GAMEOVER
449497
if match3_game.cur_state != STATE_GAMEOVER:
450498
# let the game object handle the click event
@@ -458,11 +506,6 @@ def atexit_callback():
458506
# reload
459507
supervisor.reload()
460508

461-
# if the mouse point is within the exit
462-
# button bounding box
463-
if exit_btn.contains(coords):
464-
supervisor.reload()
465-
466509
# if the game is over
467510
except GameOverException:
468511
# check for a winner
@@ -483,6 +526,10 @@ def atexit_callback():
483526
# show a tie game message
484527
message = "\nGame Over\nTie Game Everyone Wins!"
485528

529+
# centered within the display, offset to the right
530+
# inside the bounds of the game over label, so it looks like a dialog visually
531+
exit_btn.x = display.width // scale_factor // 2 - (exit_btn_bmp.width) // 2 + 30
532+
exit_btn.y = 100
486533
# make the gameover group visible
487534
game_over_group.hidden = False
488535

Metro/Metro_RP2350_Match3/match3_game/match3_game_helpers.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,13 @@ def handle_left_click(self, player_index, coords):
663663
and self.title_screen.resume_btn.contains(coords)
664664
):
665665

666-
# load the game from the given game state
667-
self.load_from_game_state(self.game_state)
668-
# hide the title screen
669-
self.title_screen.hidden = True
670-
# set the current state to open play
671-
self.cur_state = STATE_PLAYING_OPEN
666+
if self.game_state is not None:
667+
# load the game from the given game state
668+
self.load_from_game_state(self.game_state)
669+
# hide the title screen
670+
self.title_screen.hidden = True
671+
# set the current state to open play
672+
self.cur_state = STATE_PLAYING_OPEN
672673

673674
# if the new game button was clicked
674675
elif self.title_screen.new_game_btn.contains(coords):

0 commit comments

Comments
 (0)