Created
December 30, 2024 20:38
-
-
Save Jan-Zeiseweis/98cd18ecc5d4fe6da981d02ee795249d to your computer and use it in GitHub Desktop.
usb-device-mouse interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# MicroPython USB Mouse module with Scroll Wheel | |
# MIT license; Copyright (c) 2023-2024 Angus Gratton | |
from micropython import const | |
import struct | |
import machine | |
from usb.device.hid import HIDInterface | |
_INTERFACE_PROTOCOL_MOUSE = const(0x02) | |
class MouseInterface(HIDInterface): | |
# A USB mouse HID interface with 3 buttons and a scroll wheel | |
def __init__(self, interface_str="MicroPython Mouse with Scroll Wheel"): | |
super().__init__( | |
_MOUSE_REPORT_DESC, | |
protocol=_INTERFACE_PROTOCOL_MOUSE, | |
interface_str=interface_str, | |
) | |
self._l = False # Left button | |
self._m = False # Middle button | |
self._r = False # Right button | |
self._buf = bytearray(4) # Updated to 4 bytes: buttons, X, Y, wheel | |
def send_report(self, dx=0, dy=0, wheel=0): | |
b = 0 | |
if self._l: | |
b |= 1 << 0 | |
if self._r: | |
b |= 1 << 1 | |
if self._m: | |
b |= 1 << 2 | |
# Wait for any pending report to be sent to the host | |
while self.busy(): | |
machine.idle() | |
struct.pack_into("Bbbb", self._buf, 0, b, dx, dy, wheel) | |
return super().send_report(self._buf) | |
def click_left(self, down=True): | |
self._l = down | |
return self.send_report() | |
def click_middle(self, down=True): | |
self._m = down | |
return self.send_report() | |
def click_right(self, down=True): | |
self._r = down | |
return self.send_report() | |
def move_by(self, dx, dy): | |
if not -127 <= dx <= 127: | |
raise ValueError("dx") | |
if not -127 <= dy <= 127: | |
raise ValueError("dy") | |
return self.send_report(dx, dy) | |
def scroll(self, wheel): | |
if not -127 <= wheel <= 127: | |
raise ValueError("wheel") | |
return self.send_report(wheel=wheel) | |
# Updated HID Report Descriptor to include scroll wheel | |
# Based on Appendix E.10 of the HID v1.11 document. | |
# fmt: off | |
_MOUSE_REPORT_DESC = ( | |
b'\x05\x01' # Usage Page (Generic Desktop) | |
b'\x09\x02' # Usage (Mouse) | |
b'\xA1\x01' # Collection (Application) | |
b'\x09\x01' # Usage (Pointer) | |
b'\xA1\x00' # Collection (Physical) | |
b'\x05\x09' # Usage Page (Buttons) | |
b'\x19\x01' # Usage Minimum (01), | |
b'\x29\x03' # Usage Maximum (03), | |
b'\x15\x00' # Logical Minimum (0), | |
b'\x25\x01' # Logical Maximum (1), | |
b'\x95\x03' # Report Count (3), | |
b'\x75\x01' # Report Size (1), | |
b'\x81\x02' # Input (Data, Variable, Absolute), ;3 button bits | |
b'\x95\x01' # Report Count (1), | |
b'\x75\x05' # Report Size (5), | |
b'\x81\x01' # Input (Constant), ;5 bit padding | |
b'\x05\x01' # Usage Page (Generic Desktop), | |
b'\x09\x30' # Usage (X), | |
b'\x09\x31' # Usage (Y), | |
b'\x15\x81' # Logical Minimum (-127), | |
b'\x25\x7F' # Logical Maximum (127), | |
b'\x75\x08' # Report Size (8), | |
b'\x95\x02' # Report Count (2), | |
b'\x81\x06' # Input (Data, Variable, Relative), ;2 position bytes (X & Y) | |
b'\x09\x38' # Usage (Wheel), | |
b'\x15\x81' # Logical Minimum (-127), | |
b'\x25\x7F' # Logical Maximum (127), | |
b'\x75\x08' # Report Size (8), | |
b'\x95\x01' # Report Count (1), | |
b'\x81\x06' # Input (Data, Variable, Relative), ;1 wheel byte | |
b'\xC0' # End Collection | |
b'\xC0' # End Collection | |
) | |
# fmt: on |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment