2020import terminalio
2121import usb .core
2222from adafruit_fruitjam .peripherals import request_display_config
23+ from adafruit_usb_host_mouse import find_and_init_boot_mouse , find_and_init_report_mouse
2324import adafruit_usb_host_descriptors
2425from adafruit_pathlib import Path
2526
@@ -223,6 +224,20 @@ def update_score_text():
223224# add the game over group to the main group
224225main_group .append (game_over_group )
225226
227+ # add the Exit Game button to game screen
228+ exit_game = TextBox (
229+ terminalio .FONT ,
230+ text = "Exit" ,
231+ color = 0xFFFFFF ,
232+ background_color = 0xFF0000 ,
233+ width = 30 ,
234+ height = 15 ,
235+ align = TextBox .ALIGN_CENTER ,
236+ )
237+ exit_game .x = display .width - 30
238+ exit_game .y = display .height - 15
239+ main_group .append (exit_game )
240+
226241# create score label for each player
227242for i in range (2 ):
228243 # create a new label to hold score
@@ -268,78 +283,46 @@ def update_score_text():
268283# add it to the main group
269284main_group .append (title_screen_tg )
270285
271- # load the mouse bitmap
272- mouse_bmp = OnDiskBitmap ("mouse_cursor.bmp" )
273-
274- # make the background pink pixels transparent
275- mouse_bmp .pixel_shader .make_transparent (0 )
276-
277- # create a TileGrid for the mouse
278- mouse_tg = TileGrid (mouse_bmp , pixel_shader = mouse_bmp .pixel_shader )
279-
280- # place it in the center of the display
281- mouse_tg .x = display .width // 2
282- mouse_tg .y = display .height // 2
283-
284- # add the mouse to the main group
285- main_group .append (mouse_tg )
286-
287286# variable for the mouse USB device instance
288287mouse = None
289288
290289# wait a second for USB devices to be ready
291290time .sleep (1 )
292291
293- mouse_interface_index , mouse_endpoint_address = None , None
294- mouse = None
295-
296292# scan for connected USB devices
297- for device in usb .core .find (find_all = True ):
298- # print information about the found devices
299- print (f"{ device .idVendor :04x} :{ device .idProduct :04x} " )
300- print (device .manufacturer , device .product )
301- print (device .serial_number )
302- mouse_interface_index , mouse_endpoint_address = (
303- adafruit_usb_host_descriptors .find_boot_mouse_endpoint (device ))
304-
305- if mouse_interface_index is not None and mouse_endpoint_address is not None :
306- mouse = device
307- print (
308- f"mouse interface: { mouse_interface_index } "
309- + f"endpoint_address: { hex (mouse_endpoint_address )} "
310- )
311-
312- break
293+ mouse_ptr = find_and_init_boot_mouse ("mouse_cursor.bmp" )
294+ if mouse_ptr is None :
295+ mouse_ptr = find_and_init_report_mouse ("mouse_cursor.bmp" )
296+ sensitivity = 1
297+ if mouse_ptr is None :
298+ print ("No mouse found." )
299+ mouse = mouse_ptr .device
313300
301+ mouse_tg = mouse_ptr .tilegrid
314302
315- mouse_was_attached = None
316- if mouse is not None :
317- # detach the kernel driver if needed
318- if mouse .is_kernel_driver_active (0 ):
319- mouse_was_attached = True
320- mouse .detach_kernel_driver (0 )
321- else :
322- mouse_was_attached = False
303+ # place it in the center of the display
304+ mouse_tg .x = display .width // 2
305+ mouse_tg .y = display .height // 2
323306
324- # set configuration on the mouse so we can use it
325- mouse . set_configuration ( )
307+ # add the mouse to the main group
308+ main_group . append ( mouse_tg )
326309
327310def atexit_callback ():
328311 """
329312 re-attach USB devices to kernel if needed.
330313 :return:
331314 """
332315 print ("inside atexit callback" )
333- if mouse_was_attached and not mouse .is_kernel_driver_active (0 ):
334- mouse .attach_kernel_driver (0 )
335-
316+ if mouse is not None :
317+ if mouse_ptr .was_attached and not mouse_ptr .device .is_kernel_driver_active (0 ):
318+ mouse .attach_kernel_driver (0 )
319+ # The keyboard buffer seems to have data left over from when it was detached
320+ # This clears it before the next process starts
321+ while supervisor .runtime .serial_bytes_available :
322+ sys .stdin .read (1 )
336323
337324atexit .register (atexit_callback )
338325
339- # Buffer to hold data read from the mouse
340- # Boot mice have 4 byte reports
341- buf = array .array ("b" , [0 ] * 4 )
342-
343326# timestamp in the future to wait until before
344327# awarding points for a pair, or flipping cards
345328# back over and changing turns
@@ -352,36 +335,40 @@ def atexit_callback():
352335waiting_to_reset = False
353336
354337# main loop
338+ last_left_button_state = None
339+ left_button_pressed = False
355340while True :
356341 # timestamp of the current time
357342 now = ticks_ms ()
358343
359344 # attempt mouse read
360- try :
361- # try to read data from the mouse, small timeout so the code will move on
362- # quickly if there is no data
363- data_len = mouse .read (mouse_endpoint_address , buf , timeout = 20 )
345+ buttons = mouse_ptr .update ()
346+
347+ # Extract button states
348+ if buttons is None or last_left_button_state is None :
349+ current_left_button_state = 0
350+ else :
351+ current_left_button_state = 1 if 'left' in buttons else 0
364352
365- # if there was data, then update the mouse cursor on the display
366- # using min and max to keep it within the bounds of the display
367- mouse_tg .x = max (0 , min (display .width - 1 , mouse_tg .x + buf [1 ] // 2 ))
368- mouse_tg .y = max (0 , min (display .height - 1 , mouse_tg .y + buf [2 ] // 2 ))
353+ # Detect button presses
354+ if current_left_button_state == 1 and last_left_button_state == 0 :
355+ left_button_pressed = True
356+ elif current_left_button_state == 0 and last_left_button_state == 1 :
357+ left_button_pressed = False
369358
370- # timeout error is raised if no data was read within the allotted timeout
371- except usb .core .USBTimeoutError :
372- # no problem, just go on
373- pass
359+ # Update button states
360+ last_left_button_state = current_left_button_state
374361
375362 # if the current state is title screen
376363 if CUR_STATE == STATE_TITLE :
377364 # if the left mouse button was clicked
378- if buf [ 0 ] & ( 1 << 0 ) != 0 :
365+ if left_button_pressed :
379366 # change the current state to playing
380367 CUR_STATE = STATE_PLAYING
381368 # hide the title screen
382369 title_screen_tg .hidden = True
383370 # change the mouse cursor color to match the current player
384- mouse_bmp .pixel_shader [2 ] = colors [current_turn_index ]
371+ mouse_tg .pixel_shader [2 ] = colors [current_turn_index ]
385372
386373 # if the current state is playing
387374 elif CUR_STATE == STATE_PLAYING :
@@ -455,15 +442,20 @@ def atexit_callback():
455442 current_player_lbl .color = colors [current_turn_index ]
456443
457444 # update the color of the mouse cursor
458- mouse_bmp .pixel_shader [2 ] = colors [current_turn_index ]
445+ mouse_tg .pixel_shader [2 ] = colors [current_turn_index ]
459446
460447 # empty out the cards flipped this turn list
461448 cards_flipped_this_turn = []
462449
463450 # ignore any clicks while the code is waiting to take reset cards
464451 if now >= WAIT_UNTIL :
465452 # left btn pressed
466- if buf [0 ] & (1 << 0 ) != 0 :
453+ if left_button_pressed :
454+ # if the mouse point is within the exit button
455+ if (mouse_tg .x >= display .width - 30 and
456+ mouse_tg .y >= display .height - 15 ):
457+ # restart back to code.py
458+ supervisor .reload ()
467459
468460 # loop over all cards
469461 for card_index , card in enumerate (card_tgs ):
@@ -491,7 +483,7 @@ def atexit_callback():
491483 # if the current state is gameover
492484 elif CUR_STATE == STATE_GAMEOVER :
493485 # left btn pressed
494- if buf [ 0 ] & ( 1 << 0 ) != 0 :
486+ if left_button_pressed :
495487 # get the coordinates of the mouse cursor point
496488 coords = (mouse_tg .x , mouse_tg .y , 0 )
497489
@@ -500,7 +492,7 @@ def atexit_callback():
500492 if play_again_btn .contains (coords ):
501493 # set next code file to this one
502494 supervisor .set_next_code_file (__file__ ,
503- working_directory = Path (__file__ ).parent .absolute ())
495+ working_directory = Path (__file__ ).parent .absolute ())
504496 # reload
505497 supervisor .reload ()
506498
0 commit comments