From 95cfdff2237c19af3e8fd963ffe63e2f8334906b Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Mon, 1 Dec 2025 22:48:13 -0500 Subject: [PATCH 01/18] add interface index to BOOTMOUSE class --- adafruit_usb_host_mouse/__init__.py | 57 ++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 0e68546..1fc2cef 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -95,9 +95,9 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 mouse_was_attached = None if mouse_device is not None: # detach the kernel driver if needed - if mouse_device.is_kernel_driver_active(0): + if mouse_device.is_kernel_driver_active(mouse_interface_index): mouse_was_attached = True - mouse_device.detach_kernel_driver(0) + mouse_device.detach_kernel_driver(mouse_interface_index) else: mouse_was_attached = False @@ -117,7 +117,13 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 else: mouse_tg = None - return BootMouse(mouse_device, mouse_endpoint_address, mouse_was_attached, mouse_tg) + return BootMouse( + mouse_device, + mouse_interface_index, + mouse_endpoint_address, + mouse_was_attached, + mouse_tg + ) # if no mouse found return None @@ -174,9 +180,9 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 mouse_was_attached = None if mouse_device is not None: # detach the kernel driver if needed - if mouse_device.is_kernel_driver_active(0): + if mouse_device.is_kernel_driver_active(mouse_interface_index): mouse_was_attached = True - mouse_device.detach_kernel_driver(0) + mouse_device.detach_kernel_driver(mouse_interface_index) else: mouse_was_attached = False @@ -196,7 +202,13 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 else: mouse_tg = None - return ReportMouse(mouse_device, mouse_endpoint_address, mouse_was_attached, mouse_tg) + return ReportMouse( + mouse_device, + mouse_interface_index, + mouse_endpoint_address, + mouse_was_attached, + mouse_tg + ) # if no mouse found return None @@ -209,6 +221,7 @@ class BootMouse: were pressed. :param device: The usb device instance for the mouse + :param interface_index: The USB interface index of the mouse :param endpoint_address: The address of the mouse endpoint :param was_attached: Whether the usb device was attached to the kernel :param tilegrid: The TileGrid that holds the visible mouse cursor @@ -216,12 +229,22 @@ class BootMouse: Needed in order to properly clamp the mouse to the display bounds """ - def __init__(self, device, endpoint_address, was_attached, tilegrid=None, scale=1): # noqa: PLR0913, too many args + def __init__( + self, + device, + interface_index, + endpoint_address, + was_attached, + tilegrid=None, + scale=1 + ): # noqa: PLR0913, too many args + self.device = device self.tilegrid = tilegrid """TileGrid containing the Mouse cursor graphic.""" + self.interface = interface_index self.endpoint = endpoint_address self.buffer = array.array("b", [0] * 4) self.was_attached = was_attached @@ -337,8 +360,24 @@ def update(self): class ReportMouse(BootMouse): - def __init__(self, device, endpoint_address, was_attached, tilegrid=None, scale=1): # noqa: PLR0913, too many args - super().__init__(device, endpoint_address, was_attached, tilegrid, scale) + def __init__( + self, + device, + interface_index, + endpoint_address, + was_attached, + tilegrid=None, + scale=1 + ): # noqa: PLR0913, too many args + + super().__init__( + device, + interface_index, + endpoint_address, + was_attached, + tilegrid, + scale + ) def update(self): """ From 8fe13cad16a00e4b209571a819bdc0f504a7360d Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 2 Dec 2025 01:59:54 -0500 Subject: [PATCH 02/18] ruff updates --- adafruit_usb_host_mouse/__init__.py | 37 +++++++---------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 1fc2cef..5ec44c5 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -122,7 +122,7 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 mouse_interface_index, mouse_endpoint_address, mouse_was_attached, - mouse_tg + tilegrid=mouse_tg, ) # if no mouse found @@ -207,7 +207,7 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 mouse_interface_index, mouse_endpoint_address, mouse_was_attached, - mouse_tg + tilegrid=mouse_tg, ) # if no mouse found @@ -229,16 +229,9 @@ class BootMouse: Needed in order to properly clamp the mouse to the display bounds """ - def __init__( - self, - device, - interface_index, - endpoint_address, - was_attached, - tilegrid=None, - scale=1 - ): # noqa: PLR0913, too many args - + def __init__( # noqa: PLR0913, too many args + self, device, interface_index, endpoint_address, was_attached, *, tilegrid=None, scale=1 + ): self.device = device self.tilegrid = tilegrid @@ -360,23 +353,11 @@ def update(self): class ReportMouse(BootMouse): - def __init__( - self, - device, - interface_index, - endpoint_address, - was_attached, - tilegrid=None, - scale=1 - ): # noqa: PLR0913, too many args - + def __init__( # noqa: PLR0913, too many args + self, device, interface_index, endpoint_address, was_attached, *, tilegrid=None, scale=1 + ): super().__init__( - device, - interface_index, - endpoint_address, - was_attached, - tilegrid, - scale + device, interface_index, endpoint_address, was_attached, tilegrid=tilegrid, scale=scale ) def update(self): From 39bca08f6bb9de2778bd6bebc4721ccfa0ad5405 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 2 Dec 2025 04:19:52 -0500 Subject: [PATCH 03/18] detach all interface belonging to HID config --- adafruit_usb_host_mouse/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 5ec44c5..0b191b4 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -177,14 +177,15 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 except usb.core.USBError as e: print_exception(e, e, None) - mouse_was_attached = None + mouse_was_attached = False if mouse_device is not None: # detach the kernel driver if needed - if mouse_device.is_kernel_driver_active(mouse_interface_index): - mouse_was_attached = True - mouse_device.detach_kernel_driver(mouse_interface_index) - else: - mouse_was_attached = False + # Typically HID devices have interfaces 0,1,2 + # Trying 0..mouse_iface is safe and sufficient + for intf in range(mouse_interface_index + 1): + if mouse_device.is_kernel_driver_active(intf): + mouse_was_attached = True + mouse_device.detach_kernel_driver(intf) # set configuration on the mouse so we can use it mouse_device.set_configuration() From 916116c2c5de6bf5fa2fbfedd4d31dbbb169f3d7 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 2 Dec 2025 17:18:57 -0500 Subject: [PATCH 04/18] Check first three interfaces for report mice --- adafruit_usb_host_mouse/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 0b191b4..14a3152 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -181,8 +181,7 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 if mouse_device is not None: # detach the kernel driver if needed # Typically HID devices have interfaces 0,1,2 - # Trying 0..mouse_iface is safe and sufficient - for intf in range(mouse_interface_index + 1): + for intf in range(3): if mouse_device.is_kernel_driver_active(intf): mouse_was_attached = True mouse_device.detach_kernel_driver(intf) From 5e232c310a1f4961b91d5feef7645b5d0a4d6f26 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 4 Dec 2025 15:47:55 -0500 Subject: [PATCH 05/18] return list of interface in was_attached --- adafruit_usb_host_mouse/__init__.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 14a3152..c4a618f 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -92,14 +92,12 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 except usb.core.USBError as e: print_exception(e, e, None) - mouse_was_attached = None + mouse_was_attached = [] if mouse_device is not None: # detach the kernel driver if needed if mouse_device.is_kernel_driver_active(mouse_interface_index): - mouse_was_attached = True + mouse_was_attached = [[mouse_interface_index]] mouse_device.detach_kernel_driver(mouse_interface_index) - else: - mouse_was_attached = False # set configuration on the mouse so we can use it mouse_device.set_configuration() @@ -177,15 +175,19 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 except usb.core.USBError as e: print_exception(e, e, None) - mouse_was_attached = False + mouse_was_attached = [] + _attach_list = [] if mouse_device is not None: # detach the kernel driver if needed # Typically HID devices have interfaces 0,1,2 for intf in range(3): if mouse_device.is_kernel_driver_active(intf): - mouse_was_attached = True + _attach_list.append(intf) mouse_device.detach_kernel_driver(intf) + if len(_attach_list) > 0: + mouse_was_attached = [_attach_list] + # set configuration on the mouse so we can use it mouse_device.set_configuration() @@ -299,8 +301,12 @@ def release(self): Release the mouse cursor and re-attach it to the kernel if it was attached previously. """ - if self.was_attached and not self.device.is_kernel_driver_active(0): - self.device.attach_kernel_driver(0) + # was_attached is an empty list if no interfaces were detached from the kernel + if self.was_attached: + # the first element of the was_attached list is a list of detached interfaces + for intf in self.was_attached[0]: + if not self.device.is_kernel_driver_active(intf): + self.device.attach_kernel_driver(intf) def update(self): """ From 5f4288f58ec752a6aa7ecade235c0607ac060d53 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 4 Dec 2025 16:05:50 -0500 Subject: [PATCH 06/18] run pre-commit --- adafruit_usb_host_mouse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index c4a618f..36a0557 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -304,7 +304,7 @@ def release(self): # was_attached is an empty list if no interfaces were detached from the kernel if self.was_attached: # the first element of the was_attached list is a list of detached interfaces - for intf in self.was_attached[0]: + for intf in self.was_attached[0]: if not self.device.is_kernel_driver_active(intf): self.device.attach_kernel_driver(intf) From 6044f2c95e524a85c817377e58327428e48f860b Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Thu, 4 Dec 2025 16:18:01 -0500 Subject: [PATCH 07/18] simplify was_attached attribute --- adafruit_usb_host_mouse/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 36a0557..a7dc1d0 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -96,7 +96,7 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 if mouse_device is not None: # detach the kernel driver if needed if mouse_device.is_kernel_driver_active(mouse_interface_index): - mouse_was_attached = [[mouse_interface_index]] + mouse_was_attached = [mouse_interface_index] mouse_device.detach_kernel_driver(mouse_interface_index) # set configuration on the mouse so we can use it @@ -186,7 +186,7 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 mouse_device.detach_kernel_driver(intf) if len(_attach_list) > 0: - mouse_was_attached = [_attach_list] + mouse_was_attached = _attach_list # set configuration on the mouse so we can use it mouse_device.set_configuration() @@ -304,7 +304,7 @@ def release(self): # was_attached is an empty list if no interfaces were detached from the kernel if self.was_attached: # the first element of the was_attached list is a list of detached interfaces - for intf in self.was_attached[0]: + for intf in self.was_attached: if not self.device.is_kernel_driver_active(intf): self.device.attach_kernel_driver(intf) From 3bb117da90f9f16a8e9e29b51cb960c875edbf90 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 5 Dec 2025 15:22:25 -0500 Subject: [PATCH 08/18] update class DOC strings --- adafruit_usb_host_mouse/__init__.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index a7dc1d0..db7a626 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -225,7 +225,7 @@ class BootMouse: :param device: The usb device instance for the mouse :param interface_index: The USB interface index of the mouse :param endpoint_address: The address of the mouse endpoint - :param was_attached: Whether the usb device was attached to the kernel + :param was_attached: A list of the usb devices detached from the kernel. :param tilegrid: The TileGrid that holds the visible mouse cursor :param scale: The scale of the group that the Mouse TileGrid will be put into. Needed in order to properly clamp the mouse to the display bounds @@ -359,6 +359,20 @@ def update(self): class ReportMouse(BootMouse): + """ + Helpler class that encapsulates the objects needed to interact with a non-Boot + mouse (Report), show a visible cursor on the display, and determine when buttons + were pressed. The class is a subclass of BootMouse that overrides the update method. + + :param device: The usb device instance for the mouse + :param interface_index: The USB interface index of the mouse + :param endpoint_address: The address of the mouse endpoint + :param was_attached: A list of the usb devices detached from the kernel. + :param tilegrid: The TileGrid that holds the visible mouse cursor + :param scale: The scale of the group that the Mouse TileGrid will be put into. + Needed in order to properly clamp the mouse to the display bounds + """ + def __init__( # noqa: PLR0913, too many args self, device, interface_index, endpoint_address, was_attached, *, tilegrid=None, scale=1 ): From 92e7c762211b97d4e8905326d760c09bc8d33973 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 5 Dec 2025 15:24:03 -0500 Subject: [PATCH 09/18] remove periods from DOC string lists --- adafruit_usb_host_mouse/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index db7a626..fdcb7e0 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -225,9 +225,9 @@ class BootMouse: :param device: The usb device instance for the mouse :param interface_index: The USB interface index of the mouse :param endpoint_address: The address of the mouse endpoint - :param was_attached: A list of the usb devices detached from the kernel. + :param was_attached: A list of the usb devices detached from the kernel :param tilegrid: The TileGrid that holds the visible mouse cursor - :param scale: The scale of the group that the Mouse TileGrid will be put into. + :param scale: The scale of the group that the Mouse TileGrid will be put into Needed in order to properly clamp the mouse to the display bounds """ @@ -367,9 +367,9 @@ class ReportMouse(BootMouse): :param device: The usb device instance for the mouse :param interface_index: The USB interface index of the mouse :param endpoint_address: The address of the mouse endpoint - :param was_attached: A list of the usb devices detached from the kernel. + :param was_attached: A list of the usb devices detached from the kernel :param tilegrid: The TileGrid that holds the visible mouse cursor - :param scale: The scale of the group that the Mouse TileGrid will be put into. + :param scale: The scale of the group that the Mouse TileGrid will be put into Needed in order to properly clamp the mouse to the display bounds """ From 0847184a5947948decb33f1b58908fc4ad7b450f Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 5 Dec 2025 16:18:57 -0500 Subject: [PATCH 10/18] Combine find_and_init functions --- adafruit_usb_host_mouse/__init__.py | 113 +++++++--------------------- 1 file changed, 26 insertions(+), 87 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index fdcb7e0..a6fe402 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -43,8 +43,11 @@ BUTTONS = ["left", "right", "middle"] DEFAULT_CURSOR = "/".join(__file__.split("/")[:-1]) + "/mouse_cursor.bmp" +SUBCLASS_BOOT = 0x01 +SUBCLASS_RESERVED = 0x00 -def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 + +def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # noqa: PLR0912 """ Scan for an attached boot mouse connected via USB host. If one is found initialize an instance of :class:`BootMouse` class @@ -56,9 +59,17 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 """ mouse_interface_index, mouse_endpoint_address = None, None mouse_device = None + if subclass == SUBCLASS_BOOT: + deviceType = "boot" + find_endpoint = adafruit_usb_host_descriptors.find_boot_mouse_endpoint + returnClass = BootMouse + else: + deviceType = "report" + find_endpoint = adafruit_usb_host_descriptors.find_report_mouse_endpoint + returnClass = ReportMouse # scan for connected USB device and loop over any found - print("scanning usb (boot)") + print(f"scanning usb ({deviceType})") for device in usb.core.find(find_all=True): # print device info try: @@ -76,9 +87,7 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 ) print(config_descriptor) - _possible_interface_index, _possible_endpoint_address = ( - adafruit_usb_host_descriptors.find_boot_mouse_endpoint(device) - ) + _possible_interface_index, _possible_endpoint_address = find_endpoint(device) if _possible_interface_index is not None and _possible_endpoint_address is not None: mouse_device = device mouse_interface_index = _possible_interface_index @@ -88,16 +97,22 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 + f"endpoint_address: {hex(mouse_endpoint_address)}" ) break - print("was not a boot mouse") + print(f"was not a {deviceType} mouse") except usb.core.USBError as e: print_exception(e, e, None) mouse_was_attached = [] if mouse_device is not None: # detach the kernel driver if needed - if mouse_device.is_kernel_driver_active(mouse_interface_index): - mouse_was_attached = [mouse_interface_index] - mouse_device.detach_kernel_driver(mouse_interface_index) + if subclass == SUBCLASS_BOOT: + possible_interfaces = [mouse_interface_index] + else: + possible_interfaces = [0, 1, 2] + + for intf in possible_interfaces: + if mouse_device.is_kernel_driver_active(intf): + mouse_was_attached.append(intf) + mouse_device.detach_kernel_driver(intf) # set configuration on the mouse so we can use it mouse_device.set_configuration() @@ -115,7 +130,7 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 else: mouse_tg = None - return BootMouse( + return returnClass( mouse_device, mouse_interface_index, mouse_endpoint_address, @@ -137,83 +152,7 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 `None`, the :class:`ReportMouse` will not control a :class:`displayio.TileGrid` object. :return: The :class:`ReportMouse` instance or None if no mouse was found. """ - mouse_interface_index, mouse_endpoint_address = None, None - mouse_device = None - - # scan for connected USB device and loop over any found - print("scanning usb (report)") - for device in usb.core.find(find_all=True): - # print device info - try: - try: - print(f"{device.idVendor:04x}:{device.idProduct:04x}") - except usb.core.USBError as e: - print_exception(e, e, None) - try: - print(device.manufacturer, device.product) - except usb.core.USBError as e: - print_exception(e, e, None) - print() - config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor( - device, 0 - ) - print(config_descriptor) - - _possible_interface_index, _possible_endpoint_address = ( - adafruit_usb_host_descriptors.find_report_mouse_endpoint(device) - ) - if _possible_interface_index is not None and _possible_endpoint_address is not None: - mouse_device = device - mouse_interface_index = _possible_interface_index - mouse_endpoint_address = _possible_endpoint_address - print( - f"mouse interface: {mouse_interface_index} " - + f"endpoint_address: {hex(mouse_endpoint_address)}" - ) - break - print("was not a report mouse") - except usb.core.USBError as e: - print_exception(e, e, None) - - mouse_was_attached = [] - _attach_list = [] - if mouse_device is not None: - # detach the kernel driver if needed - # Typically HID devices have interfaces 0,1,2 - for intf in range(3): - if mouse_device.is_kernel_driver_active(intf): - _attach_list.append(intf) - mouse_device.detach_kernel_driver(intf) - - if len(_attach_list) > 0: - mouse_was_attached = _attach_list - - # set configuration on the mouse so we can use it - mouse_device.set_configuration() - - # load the mouse cursor bitmap - if isinstance(cursor_image, str): - mouse_bmp = OnDiskBitmap(cursor_image) - - # make the background pink pixels transparent - mouse_bmp.pixel_shader.make_transparent(0) - - # create a TileGrid for the mouse, using its bitmap and pixel_shader - mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) - - else: - mouse_tg = None - - return ReportMouse( - mouse_device, - mouse_interface_index, - mouse_endpoint_address, - mouse_was_attached, - tilegrid=mouse_tg, - ) - - # if no mouse found - return None + return find_and_init_boot_mouse(cursor_image, SUBCLASS_RESERVED) class BootMouse: From bd42fcc922ce05c7f7d0c680a19d13b7a5081781 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 5 Dec 2025 23:28:56 -0500 Subject: [PATCH 11/18] Use more symetric function design --- adafruit_usb_host_mouse/__init__.py | 62 +++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index a6fe402..da1b6d1 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -47,26 +47,33 @@ SUBCLASS_RESERVED = 0x00 -def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # noqa: PLR0912 +def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, scale=1, subclass=SUBCLASS_BOOT): # noqa: PLR0912 """ - Scan for an attached boot mouse connected via USB host. - If one is found initialize an instance of :class:`BootMouse` class - and return it. + Scan for an attached mouse connected via USB host. + If one is found return a tuple containing the parameters needed to initalize an + instance of :class: `BootMouse` or :class: `ReportMouse` depending on the value of + the subclass parameter. :param cursor_image: Provide the absolute path to the desired cursor bitmap image. If set as - `None`, the :class:`BootMouse` instance will not control a :class:`displayio.TileGrid` object. - :return: The :class:`BootMouse` instance or None if no mouse was found. + `None`, the object instance created using the returned tuple will not control + a :class:`displayio.TileGrid` object. + :param scale: The scale of the group that the Mouse TileGrid will be put into + Needed in order to properly clamp the mouse to the display bounds + :param subclass: Defines whether to search for boot or non-boot mice. + `0x01`, a boot mouse will be searched for + `0x02`, a non-boot (report) mouse will be searched for + :return: A tupple cotaining the arguments needed to inialize a :class:`BootMouse` + or `ReportMouse` instance depending on the value of subclass. If no mouse is found + None is returned. """ mouse_interface_index, mouse_endpoint_address = None, None mouse_device = None if subclass == SUBCLASS_BOOT: deviceType = "boot" find_endpoint = adafruit_usb_host_descriptors.find_boot_mouse_endpoint - returnClass = BootMouse else: deviceType = "report" find_endpoint = adafruit_usb_host_descriptors.find_report_mouse_endpoint - returnClass = ReportMouse # scan for connected USB device and loop over any found print(f"scanning usb ({deviceType})") @@ -130,19 +137,36 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT else: mouse_tg = None - return returnClass( - mouse_device, - mouse_interface_index, - mouse_endpoint_address, - mouse_was_attached, - tilegrid=mouse_tg, + return ( + (mouse_device, mouse_interface_index, mouse_endpoint_address, mouse_was_attached), + mouse_tg, + scale, ) # if no mouse found return None -def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 +def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR0912 + """ + Scan for an attached boot mouse connected via USB host. + If one is found initialize an instance of :class:`BootMouse` class + and return it. + + :param cursor_image: Provide the absolute path to the desired cursor bitmap image. If set as + `None`, the :class:`BootMouse` instance will not control a :class:`displayio.TileGrid` object + :param scale: The scale of the group that the Mouse TileGrid will be put into + Needed in order to properly clamp the mouse to the display bounds + :return: The :class:`BootMouse` instance or None if no mouse was found. + """ + found_mouse = find_and_init_mouse(cursor_image, scale, SUBCLASS_BOOT) + if found_mouse is not None: + return BootMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=found_mouse[2]) + else: + return None + + +def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR0912 """ Scan for an attached report mouse connected via USB host. If one is found initialize an instance of :class:`ReportMouse` class @@ -150,9 +174,15 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR): # noqa: PLR0912 :param cursor_image: Provide the absolute path to the desired cursor bitmap image. If set as `None`, the :class:`ReportMouse` will not control a :class:`displayio.TileGrid` object. + :param scale: The scale of the group that the Mouse TileGrid will be put into + Needed in order to properly clamp the mouse to the display bounds :return: The :class:`ReportMouse` instance or None if no mouse was found. """ - return find_and_init_boot_mouse(cursor_image, SUBCLASS_RESERVED) + found_mouse = find_and_init_mouse(cursor_image, scale, SUBCLASS_RESERVED) + if found_mouse is not None: + return ReportMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=found_mouse[2]) + else: + return None class BootMouse: From 762accf39bfd876ee7e3710032e0455ab113486c Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Fri, 5 Dec 2025 23:43:56 -0500 Subject: [PATCH 12/18] generic find_and_init doesn't need to pass scale --- adafruit_usb_host_mouse/__init__.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index da1b6d1..41c3a58 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -47,7 +47,7 @@ SUBCLASS_RESERVED = 0x00 -def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, scale=1, subclass=SUBCLASS_BOOT): # noqa: PLR0912 +def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # noqa: PLR0912 """ Scan for an attached mouse connected via USB host. If one is found return a tuple containing the parameters needed to initalize an @@ -57,8 +57,6 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, scale=1, subclass=SUBCLASS_ :param cursor_image: Provide the absolute path to the desired cursor bitmap image. If set as `None`, the object instance created using the returned tuple will not control a :class:`displayio.TileGrid` object. - :param scale: The scale of the group that the Mouse TileGrid will be put into - Needed in order to properly clamp the mouse to the display bounds :param subclass: Defines whether to search for boot or non-boot mice. `0x01`, a boot mouse will be searched for `0x02`, a non-boot (report) mouse will be searched for @@ -140,7 +138,6 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, scale=1, subclass=SUBCLASS_ return ( (mouse_device, mouse_interface_index, mouse_endpoint_address, mouse_was_attached), mouse_tg, - scale, ) # if no mouse found @@ -159,9 +156,9 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR Needed in order to properly clamp the mouse to the display bounds :return: The :class:`BootMouse` instance or None if no mouse was found. """ - found_mouse = find_and_init_mouse(cursor_image, scale, SUBCLASS_BOOT) + found_mouse = find_and_init_mouse(cursor_image, SUBCLASS_BOOT) if found_mouse is not None: - return BootMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=found_mouse[2]) + return BootMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=scale) else: return None @@ -178,9 +175,9 @@ def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: P Needed in order to properly clamp the mouse to the display bounds :return: The :class:`ReportMouse` instance or None if no mouse was found. """ - found_mouse = find_and_init_mouse(cursor_image, scale, SUBCLASS_RESERVED) + found_mouse = find_and_init_mouse(cursor_image, SUBCLASS_RESERVED) if found_mouse is not None: - return ReportMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=found_mouse[2]) + return ReportMouse(*found_mouse[0], tilegrid=found_mouse[1], scale=scale) else: return None From af73dce25e197f6de1276a8fd7e4a4f00fec1c89 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 6 Dec 2025 00:16:20 -0500 Subject: [PATCH 13/18] Use conditional statements to reduce number of branches --- adafruit_usb_host_mouse/__init__.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 41c3a58..ec41b00 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -47,7 +47,7 @@ SUBCLASS_RESERVED = 0x00 -def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # noqa: PLR0912 +def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): """ Scan for an attached mouse connected via USB host. If one is found return a tuple containing the parameters needed to initalize an @@ -66,12 +66,11 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # """ mouse_interface_index, mouse_endpoint_address = None, None mouse_device = None - if subclass == SUBCLASS_BOOT: - deviceType = "boot" - find_endpoint = adafruit_usb_host_descriptors.find_boot_mouse_endpoint - else: - deviceType = "report" - find_endpoint = adafruit_usb_host_descriptors.find_report_mouse_endpoint + deviceType, find_endpoint = ( + ("boot", adafruit_usb_host_descriptors.find_boot_mouse_endpoint) + if subclass == SUBCLASS_BOOT + else ("report", adafruit_usb_host_descriptors.find_report_mouse_endpoint) + ) # scan for connected USB device and loop over any found print(f"scanning usb ({deviceType})") @@ -109,10 +108,7 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # mouse_was_attached = [] if mouse_device is not None: # detach the kernel driver if needed - if subclass == SUBCLASS_BOOT: - possible_interfaces = [mouse_interface_index] - else: - possible_interfaces = [0, 1, 2] + possible_interfaces = [mouse_interface_index] if subclass == SUBCLASS_BOOT else [0, 1, 2] for intf in possible_interfaces: if mouse_device.is_kernel_driver_active(intf): @@ -123,6 +119,7 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # mouse_device.set_configuration() # load the mouse cursor bitmap + mouse_tg = None if isinstance(cursor_image, str): mouse_bmp = OnDiskBitmap(cursor_image) @@ -132,9 +129,6 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # # create a TileGrid for the mouse, using its bitmap and pixel_shader mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) - else: - mouse_tg = None - return ( (mouse_device, mouse_interface_index, mouse_endpoint_address, mouse_was_attached), mouse_tg, @@ -144,7 +138,7 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): # return None -def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR0912 +def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, scale=1): """ Scan for an attached boot mouse connected via USB host. If one is found initialize an instance of :class:`BootMouse` class @@ -163,7 +157,7 @@ def find_and_init_boot_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR return None -def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR, scale=1): # noqa: PLR0912 +def find_and_init_report_mouse(cursor_image=DEFAULT_CURSOR, scale=1): """ Scan for an attached report mouse connected via USB host. If one is found initialize an instance of :class:`ReportMouse` class From 875b0b457e57cd2902eb39f111e528d6e8da1212 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 6 Dec 2025 00:18:47 -0500 Subject: [PATCH 14/18] Try to fix DOC string syntax --- adafruit_usb_host_mouse/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index ec41b00..4e785f1 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -58,8 +58,8 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): `None`, the object instance created using the returned tuple will not control a :class:`displayio.TileGrid` object. :param subclass: Defines whether to search for boot or non-boot mice. - `0x01`, a boot mouse will be searched for - `0x02`, a non-boot (report) mouse will be searched for + `SUBCLASS_BOOT` (0X01), a boot mouse will be searched for + `SUBCLASS_RESERVED` (0x02), a non-boot (report) mouse will be searched for :return: A tupple cotaining the arguments needed to inialize a :class:`BootMouse` or `ReportMouse` instance depending on the value of subclass. If no mouse is found None is returned. From 37c48c9ab0bfa695a48e21693bed731dfccb68b0 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 6 Dec 2025 00:21:36 -0500 Subject: [PATCH 15/18] Try to fix DOC string syntax --- adafruit_usb_host_mouse/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index 4e785f1..fae1549 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -58,8 +58,8 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): `None`, the object instance created using the returned tuple will not control a :class:`displayio.TileGrid` object. :param subclass: Defines whether to search for boot or non-boot mice. - `SUBCLASS_BOOT` (0X01), a boot mouse will be searched for - `SUBCLASS_RESERVED` (0x02), a non-boot (report) mouse will be searched for + SUBCLASS_BOOT (0X01), a boot mouse will be searched for + SUBCLASS_RESERVED (0x02), a non-boot (report) mouse will be searched for :return: A tupple cotaining the arguments needed to inialize a :class:`BootMouse` or `ReportMouse` instance depending on the value of subclass. If no mouse is found None is returned. From cf6d286aed65167cce09a5c5000577f0bf3a2fb2 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Sat, 6 Dec 2025 00:42:10 -0500 Subject: [PATCH 16/18] Fix old comment --- adafruit_usb_host_mouse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index fae1549..e6923a8 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -263,7 +263,7 @@ def release(self): """ # was_attached is an empty list if no interfaces were detached from the kernel if self.was_attached: - # the first element of the was_attached list is a list of detached interfaces + # was_attached is a list of detached interfaces for intf in self.was_attached: if not self.device.is_kernel_driver_active(intf): self.device.attach_kernel_driver(intf) From e37e192b8125b1d372a0f2f298c4e953f272dc6c Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 9 Dec 2025 10:57:47 -0500 Subject: [PATCH 17/18] clean up comments and redudant test in release method --- adafruit_usb_host_mouse/__init__.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index e6923a8..a700a35 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -59,10 +59,9 @@ def find_and_init_mouse(cursor_image=DEFAULT_CURSOR, subclass=SUBCLASS_BOOT): a :class:`displayio.TileGrid` object. :param subclass: Defines whether to search for boot or non-boot mice. SUBCLASS_BOOT (0X01), a boot mouse will be searched for - SUBCLASS_RESERVED (0x02), a non-boot (report) mouse will be searched for - :return: A tupple cotaining the arguments needed to inialize a :class:`BootMouse` - or `ReportMouse` instance depending on the value of subclass. If no mouse is found - None is returned. + SUBCLASS_RESERVED (0x00), a non-boot (report) mouse will be searched for + :return: A tupple cotaining the arguments needed by the calling find and init helper + function. If no mouse is found None is returned. """ mouse_interface_index, mouse_endpoint_address = None, None mouse_device = None @@ -261,12 +260,11 @@ def release(self): Release the mouse cursor and re-attach it to the kernel if it was attached previously. """ - # was_attached is an empty list if no interfaces were detached from the kernel - if self.was_attached: - # was_attached is a list of detached interfaces - for intf in self.was_attached: - if not self.device.is_kernel_driver_active(intf): - self.device.attach_kernel_driver(intf) + # was_attached is a list of interfaces detached from the kernel or + # an empty list if no interfaces were detached + for intf in self.was_attached: + if not self.device.is_kernel_driver_active(intf): + self.device.attach_kernel_driver(intf) def update(self): """ From f725500b1fb690e47b5a3847e7d4d158fd992a25 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 9 Dec 2025 11:01:49 -0500 Subject: [PATCH 18/18] run pre-commit :/ --- adafruit_usb_host_mouse/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_usb_host_mouse/__init__.py b/adafruit_usb_host_mouse/__init__.py index a700a35..011241c 100644 --- a/adafruit_usb_host_mouse/__init__.py +++ b/adafruit_usb_host_mouse/__init__.py @@ -260,7 +260,7 @@ def release(self): Release the mouse cursor and re-attach it to the kernel if it was attached previously. """ - # was_attached is a list of interfaces detached from the kernel or + # was_attached is a list of interfaces detached from the kernel or # an empty list if no interfaces were detached for intf in self.was_attached: if not self.device.is_kernel_driver_active(intf):