micropython-lib/micropython/usb/usb-device-mouse/usb/device/mouse.py

101 wiersze
3.3 KiB
Python

# MicroPython USB Mouse module
#
# 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 basic three button USB mouse HID interface
def __init__(self, interface_str="MicroPython Mouse"):
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(3)
def send_report(self, dx=0, dy=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
# before updating contents of _buf.
#
# This loop can be removed if you don't care about possibly missing a
# transient report, the final report buffer contents will always be the
# last one sent to the host (it just might lose one of the ones in the
# middle).
while self.busy():
machine.idle()
struct.pack_into("Bbb", self._buf, 0, b, dx, dy)
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)
# Basic 3-button mouse HID Report Descriptor.
# This is 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 Maximun (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'\xC0' # End Collection
b'\xC0' # End Collection
)
# fmt: on