Last active
September 23, 2023 16:16
-
-
Save bitboy85/cdcd0e7e04082db414b5f1d23ab09005 to your computer and use it in GitHub Desktop.
Circuit python 7 absolute mouse example
This file contains 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
import usb_hid | |
# https://stackoverflow.com/questions/36750287/two-byte-report-count-for-hid-report-descriptor | |
absolute_mouse = usb_hid.Device( | |
report_descriptor=bytes( | |
# Absolute mouse | |
(0x05, 0x01) # Usage Page (Generic Desktop) | |
+ (0x09, 0x02) # Usage (Mouse) | |
+ (0xA1, 0x01) # Collection (Application) | |
+ (0x09, 0x01) # Usage (Pointer) | |
+ (0xA1, 0x00) # Collection (Physical) | |
+ (0x85, 0x0B) # Report ID [11 is SET at RUNTIME] | |
# Buttons | |
+ (0x05, 0x09) # Usage Page (Button) | |
+ (0x19, 0x01) # Usage Minimum (0x01) | |
+ (0x29, 0x05) # Usage Maximum (0x05) | |
+ (0x15, 0x00) # Logical Minimum (0) | |
+ (0x25, 0x01) # Logical Maximum (1) | |
+ (0x95, 0x05) # Report Count (5) | |
+ (0x75, 0x01) # Report Size (1) | |
+ (0x81, 0x02) # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
+ (0x75, 0x03) # Report Size (3) | |
+ (0x95, 0x01) # Report Count (1) | |
+ (0x81, 0x03) # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
# Movement | |
+ (0x05, 0x01) # Usage Page (Generic Desktop Ctrls) | |
+ (0x09, 0x30) # Usage (X) | |
+ (0x09, 0x31) # Usage (Y) | |
+ (0x15, 0x00) # LOGICAL_MINIMUM (0) ; Note: 0x15 = 1 Byte; 0x16 = 2 Byte; 0x17 = 4 Byte | |
+ (0x26, 0xFF, 0x7F) # LOGICAL_MAXIMUM (32767) ; Note: 0x25 = 1 Byte, 0x26 = 2 Byte; 0x27 = 4 Byte Report | |
#+ (0x35, 0x00) # Physical Minimum (0) | |
#+ (0x46, 0xff, 0x7f) # Physical Maximum (32767) | |
+ (0x75, 0x10) # REPORT_SIZE (16) | |
+ (0x95, 0x02) # REPORT_COUNT (2) | |
+ (0x81, 0x02) # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) | |
# Wheel | |
+ (0x09, 0x38) # Usage (Wheel) | |
+ (0x15, 0x81) # Logical Minimum (-127) | |
+ (0x25, 0x7F) # Logical Maximum (127) | |
#+ (0x35, 0x81) # Physical Minimum (same as logical) | |
#+ (0x45, 0x7f) # Physical Maximum (same as logical) | |
+ (0x75, 0x08) # Report Size (8) | |
+ (0x95, 0x01) # Report Count (1) | |
+ (0x81, 0x06) # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) | |
+ (0xC0,) # End Collection | |
+ (0xC0,) # End Collection | |
), | |
usage_page=1, | |
usage=2, | |
in_report_lengths=(6,), # Number of bytes in the send report = 1 byte for buttons, 2 bytes for x, 2 bytes for y, 1 byte for wheel | |
out_report_lengths=(0,), | |
report_ids=(11,), | |
) | |
usb_hid.enable((usb_hid.Device.KEYBOARD,), boot_device=1) | |
usb_hid.enable((absolute_mouse,), boot_device=0) |
This file contains 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
# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries | |
# | |
# SPDX-License-Identifier: MIT | |
""" | |
`adafruit_hid.mouse.Mouse` | |
==================================================== | |
* Author(s): Dan Halbert, Bitboy | |
""" | |
import time | |
from . import find_device | |
class Mouse: | |
"""Send USB HID mouse reports.""" | |
LEFT_BUTTON = 1 | |
"""Left mouse button.""" | |
RIGHT_BUTTON = 2 | |
"""Right mouse button.""" | |
MIDDLE_BUTTON = 4 | |
"""Middle mouse button.""" | |
def __init__(self, devices): | |
"""Create a Mouse object that will send USB mouse HID reports. | |
Devices can be a list of devices that includes a keyboard device or a keyboard device | |
itself. A device is any object that implements ``send_report()``, ``usage_page`` and | |
``usage``. | |
""" | |
self._mouse_device = find_device(devices, usage_page=0x1, usage=0x02) | |
#print(dir(devices)) | |
# Reuse this bytearray to send mouse reports. | |
# report[0] buttons pressed (LEFT, MIDDLE, RIGHT) | |
# report[1] x1 movement | |
# report[2] x2 movement | |
# report[3] y1 movement | |
# report[4] y2 movement | |
# report[5] wheel movement | |
self.report = bytearray(6) | |
# Do a no-op to test if HID device is ready. | |
# If not, wait a bit and try once more. | |
try: | |
self._send_no_move() | |
except OSError: | |
time.sleep(1) | |
self._send_no_move() | |
def press(self, buttons): | |
"""Press the given mouse buttons. | |
:param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``, | |
``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``. | |
Examples:: | |
# Press the left button. | |
m.press(Mouse.LEFT_BUTTON) | |
# Press the left and right buttons simultaneously. | |
m.press(Mouse.LEFT_BUTTON | Mouse.RIGHT_BUTTON) | |
""" | |
self.report[0] |= buttons | |
self._send_no_move() | |
def release(self, buttons): | |
"""Release the given mouse buttons. | |
:param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``, | |
``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``. | |
""" | |
self.report[0] &= ~buttons | |
self._send_no_move() | |
def release_all(self): | |
"""Release all the mouse buttons.""" | |
self.report[0] = 0 | |
self._send_no_move() | |
def click(self, buttons): | |
"""Press and release the given mouse buttons. | |
:param buttons: a bitwise-or'd combination of ``LEFT_BUTTON``, | |
``MIDDLE_BUTTON``, and ``RIGHT_BUTTON``. | |
Examples:: | |
# Click the left button. | |
m.click(Mouse.LEFT_BUTTON) | |
# Double-click the left button. | |
m.click(Mouse.LEFT_BUTTON) | |
m.click(Mouse.LEFT_BUTTON) | |
""" | |
self.press(buttons) | |
self.release(buttons) | |
def move(self, x=0, y=0, wheel=0): | |
"""Move the mouse and turn the wheel as directed. | |
:param x: Set pointer on x axis. 32767 = 100% to the right | |
:param y: Set pointer on y axis. 32767 = 100% to the bottom | |
:param wheel: Rotate the wheel this amount. Negative is toward the user, positive | |
is away from the user. The scrolling effect depends on the host. | |
Examples:: | |
# Move 100 to the left. Do not move up and down. Do not roll the scroll wheel. | |
m.move(1000, 3000, 0) | |
# Same, with keyword arguments. | |
m.move(x=1000, y=3000, wheel=0) | |
# Roll the mouse wheel away from the user. | |
m.move(wheel=1) | |
""" | |
# Wheel | |
while wheel != 0: | |
partial_wheel = self._limit(wheel) | |
print(wheel) | |
self.report[5] = partial_wheel & 0xFF | |
self._mouse_device.send_report(self.report) | |
wheel -= partial_wheel | |
# Coordinates | |
x = self._limit_coord(x) | |
y = self._limit_coord(y) | |
# HID reports use little endian | |
x1, x2 = (x & 0xFFFFFFFF).to_bytes(2, 'little') | |
y1, y2 = (y & 0xFFFFFFFF).to_bytes(2, 'little') | |
#print(x1) | |
#print(x2) | |
#print(y1) | |
#print(y2) | |
self.report[1] = x1 | |
self.report[2] = x2 | |
self.report[3] = y1 | |
self.report[4] = y2 | |
self._mouse_device.send_report(self.report) | |
def _send_no_move(self): | |
"""Send a button-only report.""" | |
self.report[1] = 0 | |
self.report[2] = 0 | |
self.report[3] = 0 | |
self.report[4] = 0 | |
self._mouse_device.send_report(self.report) | |
@staticmethod | |
def _limit(dist): | |
return min(127, max(-127, dist)) | |
@staticmethod | |
def _limit_coord(coord): | |
return min(32767, max(0, coord)) |
This file contains 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
import usb_hid | |
from adafruit_hid.mouse_abs import Mouse | |
mouse = Mouse(usb_hid.devices) | |
# Note: Values are NOT pixels! 32767 = 100% (to right or to bottom) | |
mouse.move(x=20000, y=2000) |
A fork of my library is now accepted in CircuitPython Community Bundle and can be found here: https://github.com/Neradoc/CircuitPython_Absolute_Mouse
There is a nice very simple example code there.
Nice! Thanks for mentioning my example :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would like to confirm that this "Buffer incorrect size." is occuring when you change the boot.py without powercycling the board.
You need the board to re-negotiate with the host at USB level... unplugging and replugging is the best way to garantee that.
Also I have used your code for this demo: https://github.com/dglaude/CircuitPython_udraw_Absolute_Mouse