aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid
diff options
context:
space:
mode:
Diffstat (limited to 'circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid')
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py45
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py106
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py47
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py189
-rwxr-xr-xcircuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py186
-rwxr-xr-xcircuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py166
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py312
-rw-r--r--circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py152
8 files changed, 1203 insertions, 0 deletions
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py
new file mode 100644
index 0000000..518817d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/__init__.py
@@ -0,0 +1,45 @@
+# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid`
+====================================================
+
+This driver simulates USB HID devices.
+
+* Author(s): Scott Shawcroft, Dan Halbert
+
+Implementation Notes
+--------------------
+**Software and Dependencies:**
+* Adafruit CircuitPython firmware for the supported boards:
+ https://github.com/adafruit/circuitpython/releases
+"""
+
+# imports
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HID.git"
+
+
+def find_device(
+ devices: Sequence[usb_hid.Device], *, usage_page: int, usage: int
+) -> usb_hid.Device:
+ """Search through the provided sequence of devices to find the one with the matching
+ usage_page and usage."""
+ if hasattr(devices, "send_report"):
+ devices = [devices]
+ for device in devices:
+ if (
+ device.usage_page == usage_page
+ and device.usage == usage
+ and hasattr(device, "send_report")
+ ):
+ return device
+ raise ValueError("Could not find matching HID device.")
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py
new file mode 100644
index 0000000..d26f116
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control.py
@@ -0,0 +1,106 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.consumer_control.ConsumerControl`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+
+import sys
+
+if sys.implementation.version[0] < 3:
+ raise ImportError(
+ "{0} is not supported in CircuitPython 2.x or lower".format(__name__)
+ )
+
+# pylint: disable=wrong-import-position
+import struct
+import time
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+
+class ConsumerControl:
+ """Send ConsumerControl code reports, used by multimedia keyboards, remote controls, etc."""
+
+ def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
+ """Create a ConsumerControl object that will send Consumer Control Device HID reports.
+
+ Devices can be a sequence of devices that includes a Consumer Control device or a CC device
+ itself. A device is any object that implements ``send_report()``, ``usage_page`` and
+ ``usage``.
+ """
+ self._consumer_device = find_device(devices, usage_page=0x0C, usage=0x01)
+
+ # Reuse this bytearray to send consumer reports.
+ self._report = bytearray(2)
+
+ # Do a no-op to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.send(0x0)
+ except OSError:
+ time.sleep(1)
+ self.send(0x0)
+
+ def send(self, consumer_code: int) -> None:
+ """Send a report to do the specified consumer control action,
+ and then stop the action (so it will not repeat).
+
+ :param consumer_code: a 16-bit consumer control code.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume.
+ consumer_control.send(ConsumerControlCode.VOLUME_INCREMENT)
+
+ # Advance to next track (song).
+ consumer_control.send(ConsumerControlCode.SCAN_NEXT_TRACK)
+ """
+ self.press(consumer_code)
+ self.release()
+
+ def press(self, consumer_code: int) -> None:
+ """Send a report to indicate that the given key has been pressed.
+ Only one consumer control action can be pressed at a time, so any one
+ that was previously pressed will be released.
+
+ :param consumer_code: a 16-bit consumer control code.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume for 0.5 seconds
+ consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
+ time.sleep(0.5)
+ consumer_control.release()
+ """
+ struct.pack_into("<H", self._report, 0, consumer_code)
+ self._consumer_device.send_report(self._report)
+
+ def release(self) -> None:
+ """Send a report indicating that the consumer control key has been
+ released. Only one consumer control key can be pressed at a time.
+
+ Examples::
+
+ from adafruit_hid.consumer_control_code import ConsumerControlCode
+
+ # Raise volume for 0.5 seconds
+ consumer_control.press(ConsumerControlCode.VOLUME_INCREMENT)
+ time.sleep(0.5)
+ consumer_control.release()
+ """
+ self._report[0] = self._report[1] = 0x0
+ self._consumer_device.send_report(self._report)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py
new file mode 100644
index 0000000..e49137e
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/consumer_control_code.py
@@ -0,0 +1,47 @@
+# SPDX-FileCopyrightText: 2018 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.consumer_control_code.ConsumerControlCode`
+========================================================
+
+* Author(s): Dan Halbert
+"""
+
+
+class ConsumerControlCode:
+ """USB HID Consumer Control Device constants.
+
+ This list includes a few common consumer control codes from
+ https://www.usb.org/sites/default/files/hut1_21_0.pdf#page=118.
+ """
+
+ # pylint: disable-msg=too-few-public-methods
+
+ RECORD = 0xB2
+ """Record"""
+ FAST_FORWARD = 0xB3
+ """Fast Forward"""
+ REWIND = 0xB4
+ """Rewind"""
+ SCAN_NEXT_TRACK = 0xB5
+ """Skip to next track"""
+ SCAN_PREVIOUS_TRACK = 0xB6
+ """Go back to previous track"""
+ STOP = 0xB7
+ """Stop"""
+ EJECT = 0xB8
+ """Eject"""
+ PLAY_PAUSE = 0xCD
+ """Play/Pause toggle"""
+ MUTE = 0xE2
+ """Mute"""
+ VOLUME_DECREMENT = 0xEA
+ """Decrease volume"""
+ VOLUME_INCREMENT = 0xE9
+ """Increase volume"""
+ BRIGHTNESS_DECREMENT = 0x70
+ """Decrease Brightness"""
+ BRIGHTNESS_INCREMENT = 0x6F
+ """Increase Brightness"""
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py
new file mode 100644
index 0000000..f1240c3
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard.py
@@ -0,0 +1,189 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard.Keyboard`
+====================================================
+
+* Author(s): Scott Shawcroft, Dan Halbert
+"""
+
+import time
+from micropython import const
+
+from .keycode import Keycode
+
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+_MAX_KEYPRESSES = const(6)
+
+
+class Keyboard:
+ """Send HID keyboard reports."""
+
+ LED_NUM_LOCK = 0x01
+ """LED Usage ID for Num Lock"""
+ LED_CAPS_LOCK = 0x02
+ """LED Usage ID for Caps Lock"""
+ LED_SCROLL_LOCK = 0x04
+ """LED Usage ID for Scroll Lock"""
+ LED_COMPOSE = 0x08
+ """LED Usage ID for Compose"""
+
+ # No more than _MAX_KEYPRESSES regular keys may be pressed at once.
+
+ def __init__(self, devices: Sequence[usb_hid.Device]) -> None:
+ """Create a Keyboard object that will send keyboard HID reports.
+
+ Devices can be a sequence 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._keyboard_device = find_device(devices, usage_page=0x1, usage=0x06)
+
+ # Reuse this bytearray to send keyboard reports.
+ self.report = bytearray(8)
+
+ # report[0] modifiers
+ # report[1] unused
+ # report[2:8] regular key presses
+
+ # View onto byte 0 in report.
+ self.report_modifier = memoryview(self.report)[0:1]
+
+ # List of regular keys currently pressed.
+ # View onto bytes 2-7 in report.
+ self.report_keys = memoryview(self.report)[2:]
+
+ # Do a no-op to test if HID device is ready.
+ # If not, wait a bit and try once more.
+ try:
+ self.release_all()
+ except OSError:
+ time.sleep(1)
+ self.release_all()
+
+ def press(self, *keycodes: int) -> None:
+ """Send a report indicating that the given keys have been pressed.
+
+ :param keycodes: Press these keycodes all at once.
+ :raises ValueError: if more than six regular keys are pressed.
+
+ Keycodes may be modifiers or regular keys.
+ No more than six regular keys may be pressed simultaneously.
+
+ Examples::
+
+ from adafruit_hid.keycode import Keycode
+
+ # Press ctrl-x.
+ kbd.press(Keycode.LEFT_CONTROL, Keycode.X)
+
+ # Or, more conveniently, use the CONTROL alias for LEFT_CONTROL:
+ kbd.press(Keycode.CONTROL, Keycode.X)
+
+ # Press a, b, c keys all at once.
+ kbd.press(Keycode.A, Keycode.B, Keycode.C)
+ """
+ for keycode in keycodes:
+ self._add_keycode_to_report(keycode)
+ self._keyboard_device.send_report(self.report)
+
+ def release(self, *keycodes: int) -> None:
+ """Send a USB HID report indicating that the given keys have been released.
+
+ :param keycodes: Release these keycodes all at once.
+
+ If a keycode to be released was not pressed, it is ignored.
+
+ Example::
+
+ # release SHIFT key
+ kbd.release(Keycode.SHIFT)
+ """
+ for keycode in keycodes:
+ self._remove_keycode_from_report(keycode)
+ self._keyboard_device.send_report(self.report)
+
+ def release_all(self) -> None:
+ """Release all pressed keys."""
+ for i in range(8):
+ self.report[i] = 0
+ self._keyboard_device.send_report(self.report)
+
+ def send(self, *keycodes: int) -> None:
+ """Press the given keycodes and then release all pressed keys.
+
+ :param keycodes: keycodes to send together
+ """
+ self.press(*keycodes)
+ self.release_all()
+
+ def _add_keycode_to_report(self, keycode: int) -> None:
+ """Add a single keycode to the USB HID report."""
+ modifier = Keycode.modifier_bit(keycode)
+ if modifier:
+ # Set bit for this modifier.
+ self.report_modifier[0] |= modifier
+ else:
+ # Don't press twice.
+ # (I'd like to use 'not in self.report_keys' here, but that's not implemented.)
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == keycode:
+ # Already pressed.
+ return
+ # Put keycode in first empty slot.
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == 0:
+ self.report_keys[i] = keycode
+ return
+ # All slots are filled.
+ raise ValueError("Trying to press more than six keys at once.")
+
+ def _remove_keycode_from_report(self, keycode: int) -> None:
+ """Remove a single keycode from the report."""
+ modifier = Keycode.modifier_bit(keycode)
+ if modifier:
+ # Turn off the bit for this modifier.
+ self.report_modifier[0] &= ~modifier
+ else:
+ # Check all the slots, just in case there's a duplicate. (There should not be.)
+ for i in range(_MAX_KEYPRESSES):
+ if self.report_keys[i] == keycode:
+ self.report_keys[i] = 0
+
+ @property
+ def led_status(self) -> bytes:
+ """Returns the last received report"""
+ return self._keyboard_device.last_received_report
+
+ def led_on(self, led_code: int) -> bool:
+ """Returns whether an LED is on based on the led code
+
+ Examples::
+
+ import usb_hid
+ from adafruit_hid.keyboard import Keyboard
+ from adafruit_hid.keycode import Keycode
+ import time
+
+ # Initialize Keybaord
+ kbd = Keyboard(usb_hid.devices)
+
+ # Press and release CapsLock.
+ kbd.press(Keycode.CAPS_LOCK)
+ time.sleep(.09)
+ kbd.release(Keycode.CAPS_LOCK)
+
+ # Check status of the LED_CAPS_LOCK
+ print(kbd.led_on(Keyboard.LED_CAPS_LOCK))
+
+ """
+ return bool(self.led_status[0] & led_code)
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py
new file mode 100755
index 0000000..54de33d
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_base.py
@@ -0,0 +1,186 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard_layout_base.KeyboardLayoutBase`
+=======================================================
+
+* Author(s): Dan Halbert, AngainorDev, Neradoc
+"""
+
+
+try:
+ from typing import Tuple
+ from .keyboard import Keyboard
+except ImportError:
+ pass
+
+
+__version__ = "0.0.0-auto.0"
+__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_HID.git"
+
+
+class KeyboardLayoutBase:
+ """Base class for keyboard layouts. Uses the tables defined in the subclass
+ to map UTF-8 characters to appropriate keypresses.
+
+ Non-supported characters and most control characters will raise an exception.
+ """
+
+ SHIFT_FLAG = 0x80
+ """Bit set in any keycode byte if the shift key is required for the character."""
+ ALTGR_FLAG = 0x80
+ """Bit set in the combined keys table if altgr is required for the first key."""
+ SHIFT_CODE = 0xE1
+ """The SHIFT keycode, to avoid dependency to the Keycode class."""
+ RIGHT_ALT_CODE = 0xE6
+ """The ALTGR keycode, to avoid dependency to the Keycode class."""
+ ASCII_TO_KEYCODE = ()
+ """Bytes string of keycodes for low ASCII characters, indexed by the ASCII value.
+ Keycodes use the `SHIFT_FLAG` if needed.
+ Dead keys are excluded by assigning the keycode 0."""
+ HIGHER_ASCII = {}
+ """Dictionary that associates the ord() int value of high ascii and utf8 characters
+ to their keycode. Keycodes use the `SHIFT_FLAG` if needed."""
+ NEED_ALTGR = ""
+ """Characters in `ASCII_TO_KEYCODE` and `HIGHER_ASCII` that need
+ the ALTGR key pressed to type."""
+ COMBINED_KEYS = {}
+ """
+ Dictionary of characters (indexed by ord() value) that can be accessed by typing first
+ a dead key followed by a regular key, like ``ñ`` as ``~ + n``. The value is a 2-bytes int:
+ the high byte is the dead-key keycode (including SHIFT_FLAG), the low byte is the ascii code
+ of the second character, with ALTGR_FLAG set if the dead key (the first key) needs ALTGR.
+
+ The combined-key codes bits are: ``0b SDDD DDDD AKKK KKKK``:
+ ``S`` is the shift flag for the **first** key,
+ ``DDD DDDD`` is the keycode for the **first** key,
+ ``A`` is the altgr flag for the **first** key,
+ ``KKK KKKK`` is the (low) ASCII code for the second character.
+ """
+
+ def __init__(self, keyboard: Keyboard) -> None:
+ """Specify the layout for the given keyboard.
+
+ :param keyboard: a Keyboard object. Write characters to this keyboard when requested.
+
+ Example::
+
+ kbd = Keyboard(usb_hid.devices)
+ layout = KeyboardLayout(kbd)
+ """
+ self.keyboard = keyboard
+
+ def _write(self, keycode: int, altgr: bool = False) -> None:
+ """Type a key combination based on shift bit and altgr bool
+
+ :param keycode: int value of the keycode, with the shift bit.
+ :param altgr: bool indicating if the altgr key should be pressed too.
+ """
+ # Add altgr modifier if needed
+ if altgr:
+ self.keyboard.press(self.RIGHT_ALT_CODE)
+ # If this is a shifted char, clear the SHIFT flag and press the SHIFT key.
+ if keycode & self.SHIFT_FLAG:
+ keycode &= ~self.SHIFT_FLAG
+ self.keyboard.press(self.SHIFT_CODE)
+ self.keyboard.press(keycode)
+ self.keyboard.release_all()
+
+ def write(self, string: str) -> None:
+ """Type the string by pressing and releasing keys on my keyboard.
+
+ :param string: A string of UTF-8 characters to convert to key presses and send.
+ :raises ValueError: if any of the characters has no keycode
+ (such as some control characters).
+
+ Example::
+
+ # Write abc followed by Enter to the keyboard
+ layout.write('abc\\n')
+ """
+ for char in string:
+ # find easy ones first
+ keycode = self._char_to_keycode(char)
+ if keycode > 0:
+ self._write(keycode, char in self.NEED_ALTGR)
+ # find combined keys
+ elif ord(char) in self.COMBINED_KEYS:
+ # first key (including shift bit)
+ cchar = self.COMBINED_KEYS[ord(char)]
+ self._write(cchar >> 8, cchar & self.ALTGR_FLAG)
+ # second key (removing the altgr bit)
+ char = chr(cchar & 0xFF & (~self.ALTGR_FLAG))
+ keycode = self._char_to_keycode(char)
+ # assume no altgr needed for second key
+ self._write(keycode, False)
+ else:
+ raise ValueError(
+ "No keycode available for character {letter} ({num}/0x{num:02x}).".format(
+ letter=repr(char), num=ord(char)
+ )
+ )
+
+ def keycodes(self, char: str) -> Tuple[int, ...]:
+ """Return a tuple of keycodes needed to type the given character.
+
+ :param char: A single UTF8 character in a string.
+ :type char: str of length one.
+ :returns: tuple of Keycode keycodes.
+ :raises ValueError: if there is no keycode for ``char``.
+
+ Examples::
+
+ # Returns (Keycode.TAB,)
+ keycodes('\t')
+ # Returns (Keycode.A,)
+ keycode('a')
+ # Returns (Keycode.SHIFT, Keycode.A)
+ keycode('A')
+ # Raises ValueError with a US layout because it's an unknown character
+ keycode('é')
+ """
+ keycode = self._char_to_keycode(char)
+ if keycode == 0:
+ raise ValueError(
+ "No keycode available for character {letter} ({num}/0x{num:02x}).".format(
+ letter=repr(char), num=ord(char)
+ )
+ )
+
+ codes = []
+ if char in self.NEED_ALTGR:
+ codes.append(self.RIGHT_ALT_CODE)
+ if keycode & self.SHIFT_FLAG:
+ codes.extend((self.SHIFT_CODE, keycode & ~self.SHIFT_FLAG))
+ else:
+ codes.append(keycode)
+
+ return codes
+
+ def _above128char_to_keycode(self, char: str) -> int:
+ """Return keycode for above 128 utf8 codes.
+
+ A character can be indexed by the char itself or its int ord() value.
+
+ :param char_val: char value
+ :return: keycode, with modifiers if needed
+ """
+ if ord(char) in self.HIGHER_ASCII:
+ return self.HIGHER_ASCII[ord(char)]
+ if char in self.HIGHER_ASCII:
+ return self.HIGHER_ASCII[char]
+ return 0
+
+ def _char_to_keycode(self, char: str) -> int:
+ """Return the HID keycode for the given character, with the SHIFT_FLAG possibly set.
+
+ If the character requires pressing the Shift key, the SHIFT_FLAG bit is set.
+ You must clear this bit before passing the keycode in a USB report.
+ """
+ char_val = ord(char)
+ if char_val > len(self.ASCII_TO_KEYCODE):
+ return self._above128char_to_keycode(char)
+ keycode = self.ASCII_TO_KEYCODE[char_val]
+ return keycode
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py
new file mode 100755
index 0000000..35b163b
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keyboard_layout_us.py
@@ -0,0 +1,166 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keyboard_layout_us.KeyboardLayoutUS`
+=======================================================
+
+* Author(s): Dan Halbert
+"""
+
+from .keyboard_layout_base import KeyboardLayoutBase
+
+
+class KeyboardLayoutUS(KeyboardLayoutBase):
+ """Map ASCII characters to appropriate keypresses on a standard US PC keyboard.
+
+ Non-ASCII characters and most control characters will raise an exception.
+ """
+
+ # The ASCII_TO_KEYCODE bytes object is used as a table to maps ASCII 0-127
+ # to the corresponding # keycode on a US 104-key keyboard.
+ # The user should not normally need to use this table,
+ # but it is not marked as private.
+ #
+ # Because the table only goes to 127, we use the top bit of each byte (ox80) to indicate
+ # that the shift key should be pressed. So any values 0x{8,9,a,b}* are shifted characters.
+ #
+ # The Python compiler will concatenate all these bytes literals into a single bytes object.
+ # Micropython/CircuitPython will store the resulting bytes constant in flash memory
+ # if it's in a .mpy file, so it doesn't use up valuable RAM.
+ #
+ # \x00 entries have no keyboard key and so won't be sent.
+ ASCII_TO_KEYCODE = (
+ b"\x00" # NUL
+ b"\x00" # SOH
+ b"\x00" # STX
+ b"\x00" # ETX
+ b"\x00" # EOT
+ b"\x00" # ENQ
+ b"\x00" # ACK
+ b"\x00" # BEL \a
+ b"\x2a" # BS BACKSPACE \b (called DELETE in the usb.org document)
+ b"\x2b" # TAB \t
+ b"\x28" # LF \n (called Return or ENTER in the usb.org document)
+ b"\x00" # VT \v
+ b"\x00" # FF \f
+ b"\x00" # CR \r
+ b"\x00" # SO
+ b"\x00" # SI
+ b"\x00" # DLE
+ b"\x00" # DC1
+ b"\x00" # DC2
+ b"\x00" # DC3
+ b"\x00" # DC4
+ b"\x00" # NAK
+ b"\x00" # SYN
+ b"\x00" # ETB
+ b"\x00" # CAN
+ b"\x00" # EM
+ b"\x00" # SUB
+ b"\x29" # ESC
+ b"\x00" # FS
+ b"\x00" # GS
+ b"\x00" # RS
+ b"\x00" # US
+ b"\x2c" # SPACE
+ b"\x9e" # ! x1e|SHIFT_FLAG (shift 1)
+ b"\xb4" # " x34|SHIFT_FLAG (shift ')
+ b"\xa0" # # x20|SHIFT_FLAG (shift 3)
+ b"\xa1" # $ x21|SHIFT_FLAG (shift 4)
+ b"\xa2" # % x22|SHIFT_FLAG (shift 5)
+ b"\xa4" # & x24|SHIFT_FLAG (shift 7)
+ b"\x34" # '
+ b"\xa6" # ( x26|SHIFT_FLAG (shift 9)
+ b"\xa7" # ) x27|SHIFT_FLAG (shift 0)
+ b"\xa5" # * x25|SHIFT_FLAG (shift 8)
+ b"\xae" # + x2e|SHIFT_FLAG (shift =)
+ b"\x36" # ,
+ b"\x2d" # -
+ b"\x37" # .
+ b"\x38" # /
+ b"\x27" # 0
+ b"\x1e" # 1
+ b"\x1f" # 2
+ b"\x20" # 3
+ b"\x21" # 4
+ b"\x22" # 5
+ b"\x23" # 6
+ b"\x24" # 7
+ b"\x25" # 8
+ b"\x26" # 9
+ b"\xb3" # : x33|SHIFT_FLAG (shift ;)
+ b"\x33" # ;
+ b"\xb6" # < x36|SHIFT_FLAG (shift ,)
+ b"\x2e" # =
+ b"\xb7" # > x37|SHIFT_FLAG (shift .)
+ b"\xb8" # ? x38|SHIFT_FLAG (shift /)
+ b"\x9f" # @ x1f|SHIFT_FLAG (shift 2)
+ b"\x84" # A x04|SHIFT_FLAG (shift a)
+ b"\x85" # B x05|SHIFT_FLAG (etc.)
+ b"\x86" # C x06|SHIFT_FLAG
+ b"\x87" # D x07|SHIFT_FLAG
+ b"\x88" # E x08|SHIFT_FLAG
+ b"\x89" # F x09|SHIFT_FLAG
+ b"\x8a" # G x0a|SHIFT_FLAG
+ b"\x8b" # H x0b|SHIFT_FLAG
+ b"\x8c" # I x0c|SHIFT_FLAG
+ b"\x8d" # J x0d|SHIFT_FLAG
+ b"\x8e" # K x0e|SHIFT_FLAG
+ b"\x8f" # L x0f|SHIFT_FLAG
+ b"\x90" # M x10|SHIFT_FLAG
+ b"\x91" # N x11|SHIFT_FLAG
+ b"\x92" # O x12|SHIFT_FLAG
+ b"\x93" # P x13|SHIFT_FLAG
+ b"\x94" # Q x14|SHIFT_FLAG
+ b"\x95" # R x15|SHIFT_FLAG
+ b"\x96" # S x16|SHIFT_FLAG
+ b"\x97" # T x17|SHIFT_FLAG
+ b"\x98" # U x18|SHIFT_FLAG
+ b"\x99" # V x19|SHIFT_FLAG
+ b"\x9a" # W x1a|SHIFT_FLAG
+ b"\x9b" # X x1b|SHIFT_FLAG
+ b"\x9c" # Y x1c|SHIFT_FLAG
+ b"\x9d" # Z x1d|SHIFT_FLAG
+ b"\x2f" # [
+ b"\x31" # \ backslash
+ b"\x30" # ]
+ b"\xa3" # ^ x23|SHIFT_FLAG (shift 6)
+ b"\xad" # _ x2d|SHIFT_FLAG (shift -)
+ b"\x35" # `
+ b"\x04" # a
+ b"\x05" # b
+ b"\x06" # c
+ b"\x07" # d
+ b"\x08" # e
+ b"\x09" # f
+ b"\x0a" # g
+ b"\x0b" # h
+ b"\x0c" # i
+ b"\x0d" # j
+ b"\x0e" # k
+ b"\x0f" # l
+ b"\x10" # m
+ b"\x11" # n
+ b"\x12" # o
+ b"\x13" # p
+ b"\x14" # q
+ b"\x15" # r
+ b"\x16" # s
+ b"\x17" # t
+ b"\x18" # u
+ b"\x19" # v
+ b"\x1a" # w
+ b"\x1b" # x
+ b"\x1c" # y
+ b"\x1d" # z
+ b"\xaf" # { x2f|SHIFT_FLAG (shift [)
+ b"\xb1" # | x31|SHIFT_FLAG (shift \)
+ b"\xb0" # } x30|SHIFT_FLAG (shift ])
+ b"\xb5" # ~ x35|SHIFT_FLAG (shift `)
+ b"\x4c" # DEL DELETE (called Forward Delete in usb.org document)
+ )
+
+
+KeyboardLayout = KeyboardLayoutUS
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py
new file mode 100644
index 0000000..14c8aa1
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/keycode.py
@@ -0,0 +1,312 @@
+# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.keycode.Keycode`
+====================================================
+
+* Author(s): Scott Shawcroft, Dan Halbert
+"""
+
+try:
+ import typing # pylint: disable=unused-import
+except ImportError:
+ pass
+
+
+class Keycode:
+ """USB HID Keycode constants.
+
+ This list is modeled after the names for USB keycodes defined in
+ https://usb.org/sites/default/files/hut1_21_0.pdf#page=83.
+ This list does not include every single code, but does include all the keys on
+ a regular PC or Mac keyboard.
+
+ Remember that keycodes are the names for key *positions* on a US keyboard, and may
+ not correspond to the character that you mean to send if you want to emulate non-US keyboard.
+ For instance, on a French keyboard (AZERTY instead of QWERTY),
+ the keycode for 'q' is used to indicate an 'a'. Likewise, 'y' represents 'z' on
+ a German keyboard. This is historical: the idea was that the keycaps could be changed
+ without changing the keycodes sent, so that different firmware was not needed for
+ different variations of a keyboard.
+ """
+
+ # pylint: disable-msg=invalid-name
+ A = 0x04
+ """``a`` and ``A``"""
+ B = 0x05
+ """``b`` and ``B``"""
+ C = 0x06
+ """``c`` and ``C``"""
+ D = 0x07
+ """``d`` and ``D``"""
+ E = 0x08
+ """``e`` and ``E``"""
+ F = 0x09
+ """``f`` and ``F``"""
+ G = 0x0A
+ """``g`` and ``G``"""
+ H = 0x0B
+ """``h`` and ``H``"""
+ I = 0x0C
+ """``i`` and ``I``"""
+ J = 0x0D
+ """``j`` and ``J``"""
+ K = 0x0E
+ """``k`` and ``K``"""
+ L = 0x0F
+ """``l`` and ``L``"""
+ M = 0x10
+ """``m`` and ``M``"""
+ N = 0x11
+ """``n`` and ``N``"""
+ O = 0x12
+ """``o`` and ``O``"""
+ P = 0x13
+ """``p`` and ``P``"""
+ Q = 0x14
+ """``q`` and ``Q``"""
+ R = 0x15
+ """``r`` and ``R``"""
+ S = 0x16
+ """``s`` and ``S``"""
+ T = 0x17
+ """``t`` and ``T``"""
+ U = 0x18
+ """``u`` and ``U``"""
+ V = 0x19
+ """``v`` and ``V``"""
+ W = 0x1A
+ """``w`` and ``W``"""
+ X = 0x1B
+ """``x`` and ``X``"""
+ Y = 0x1C
+ """``y`` and ``Y``"""
+ Z = 0x1D
+ """``z`` and ``Z``"""
+
+ ONE = 0x1E
+ """``1`` and ``!``"""
+ TWO = 0x1F
+ """``2`` and ``@``"""
+ THREE = 0x20
+ """``3`` and ``#``"""
+ FOUR = 0x21
+ """``4`` and ``$``"""
+ FIVE = 0x22
+ """``5`` and ``%``"""
+ SIX = 0x23
+ """``6`` and ``^``"""
+ SEVEN = 0x24
+ """``7`` and ``&``"""
+ EIGHT = 0x25
+ """``8`` and ``*``"""
+ NINE = 0x26
+ """``9`` and ``(``"""
+ ZERO = 0x27
+ """``0`` and ``)``"""
+ ENTER = 0x28
+ """Enter (Return)"""
+ RETURN = ENTER
+ """Alias for ``ENTER``"""
+ ESCAPE = 0x29
+ """Escape"""
+ BACKSPACE = 0x2A
+ """Delete backward (Backspace)"""
+ TAB = 0x2B
+ """Tab and Backtab"""
+ SPACEBAR = 0x2C
+ """Spacebar"""
+ SPACE = SPACEBAR
+ """Alias for SPACEBAR"""
+ MINUS = 0x2D
+ """``-` and ``_``"""
+ EQUALS = 0x2E
+ """``=` and ``+``"""
+ LEFT_BRACKET = 0x2F
+ """``[`` and ``{``"""
+ RIGHT_BRACKET = 0x30
+ """``]`` and ``}``"""
+ BACKSLASH = 0x31
+ r"""``\`` and ``|``"""
+ POUND = 0x32
+ """``#`` and ``~`` (Non-US keyboard)"""
+ SEMICOLON = 0x33
+ """``;`` and ``:``"""
+ QUOTE = 0x34
+ """``'`` and ``"``"""
+ GRAVE_ACCENT = 0x35
+ r""":literal:`\`` and ``~``"""
+ COMMA = 0x36
+ """``,`` and ``<``"""
+ PERIOD = 0x37
+ """``.`` and ``>``"""
+ FORWARD_SLASH = 0x38
+ """``/`` and ``?``"""
+
+ CAPS_LOCK = 0x39
+ """Caps Lock"""
+
+ F1 = 0x3A
+ """Function key F1"""
+ F2 = 0x3B
+ """Function key F2"""
+ F3 = 0x3C
+ """Function key F3"""
+ F4 = 0x3D
+ """Function key F4"""
+ F5 = 0x3E
+ """Function key F5"""
+ F6 = 0x3F
+ """Function key F6"""
+ F7 = 0x40
+ """Function key F7"""
+ F8 = 0x41
+ """Function key F8"""
+ F9 = 0x42
+ """Function key F9"""
+ F10 = 0x43
+ """Function key F10"""
+ F11 = 0x44
+ """Function key F11"""
+ F12 = 0x45
+ """Function key F12"""
+
+ PRINT_SCREEN = 0x46
+ """Print Screen (SysRq)"""
+ SCROLL_LOCK = 0x47
+ """Scroll Lock"""
+ PAUSE = 0x48
+ """Pause (Break)"""
+
+ INSERT = 0x49
+ """Insert"""
+ HOME = 0x4A
+ """Home (often moves to beginning of line)"""
+ PAGE_UP = 0x4B
+ """Go back one page"""
+ DELETE = 0x4C
+ """Delete forward"""
+ END = 0x4D
+ """End (often moves to end of line)"""
+ PAGE_DOWN = 0x4E
+ """Go forward one page"""
+
+ RIGHT_ARROW = 0x4F
+ """Move the cursor right"""
+ LEFT_ARROW = 0x50
+ """Move the cursor left"""
+ DOWN_ARROW = 0x51
+ """Move the cursor down"""
+ UP_ARROW = 0x52
+ """Move the cursor up"""
+
+ KEYPAD_NUMLOCK = 0x53
+ """Num Lock (Clear on Mac)"""
+ KEYPAD_FORWARD_SLASH = 0x54
+ """Keypad ``/``"""
+ KEYPAD_ASTERISK = 0x55
+ """Keypad ``*``"""
+ KEYPAD_MINUS = 0x56
+ """Keyapd ``-``"""
+ KEYPAD_PLUS = 0x57
+ """Keypad ``+``"""
+ KEYPAD_ENTER = 0x58
+ """Keypad Enter"""
+ KEYPAD_ONE = 0x59
+ """Keypad ``1`` and End"""
+ KEYPAD_TWO = 0x5A
+ """Keypad ``2`` and Down Arrow"""
+ KEYPAD_THREE = 0x5B
+ """Keypad ``3`` and PgDn"""
+ KEYPAD_FOUR = 0x5C
+ """Keypad ``4`` and Left Arrow"""
+ KEYPAD_FIVE = 0x5D
+ """Keypad ``5``"""
+ KEYPAD_SIX = 0x5E
+ """Keypad ``6`` and Right Arrow"""
+ KEYPAD_SEVEN = 0x5F
+ """Keypad ``7`` and Home"""
+ KEYPAD_EIGHT = 0x60
+ """Keypad ``8`` and Up Arrow"""
+ KEYPAD_NINE = 0x61
+ """Keypad ``9`` and PgUp"""
+ KEYPAD_ZERO = 0x62
+ """Keypad ``0`` and Ins"""
+ KEYPAD_PERIOD = 0x63
+ """Keypad ``.`` and Del"""
+ KEYPAD_BACKSLASH = 0x64
+ """Keypad ``\\`` and ``|`` (Non-US)"""
+
+ APPLICATION = 0x65
+ """Application: also known as the Menu key (Windows)"""
+ POWER = 0x66
+ """Power (Mac)"""
+ KEYPAD_EQUALS = 0x67
+ """Keypad ``=`` (Mac)"""
+ F13 = 0x68
+ """Function key F13 (Mac)"""
+ F14 = 0x69
+ """Function key F14 (Mac)"""
+ F15 = 0x6A
+ """Function key F15 (Mac)"""
+ F16 = 0x6B
+ """Function key F16 (Mac)"""
+ F17 = 0x6C
+ """Function key F17 (Mac)"""
+ F18 = 0x6D
+ """Function key F18 (Mac)"""
+ F19 = 0x6E
+ """Function key F19 (Mac)"""
+
+ F20 = 0x6F
+ """Function key F20"""
+ F21 = 0x70
+ """Function key F21"""
+ F22 = 0x71
+ """Function key F22"""
+ F23 = 0x72
+ """Function key F23"""
+ F24 = 0x73
+ """Function key F24"""
+
+ LEFT_CONTROL = 0xE0
+ """Control modifier left of the spacebar"""
+ CONTROL = LEFT_CONTROL
+ """Alias for LEFT_CONTROL"""
+ LEFT_SHIFT = 0xE1
+ """Shift modifier left of the spacebar"""
+ SHIFT = LEFT_SHIFT
+ """Alias for LEFT_SHIFT"""
+ LEFT_ALT = 0xE2
+ """Alt modifier left of the spacebar"""
+ ALT = LEFT_ALT
+ """Alias for LEFT_ALT; Alt is also known as Option (Mac)"""
+ OPTION = ALT
+ """Labeled as Option on some Mac keyboards"""
+ LEFT_GUI = 0xE3
+ """GUI modifier left of the spacebar"""
+ GUI = LEFT_GUI
+ """Alias for LEFT_GUI; GUI is also known as the Windows key, Command (Mac), or Meta"""
+ WINDOWS = GUI
+ """Labeled with a Windows logo on Windows keyboards"""
+ COMMAND = GUI
+ """Labeled as Command on Mac keyboards, with a clover glyph"""
+ RIGHT_CONTROL = 0xE4
+ """Control modifier right of the spacebar"""
+ RIGHT_SHIFT = 0xE5
+ """Shift modifier right of the spacebar"""
+ RIGHT_ALT = 0xE6
+ """Alt modifier right of the spacebar"""
+ RIGHT_GUI = 0xE7
+ """GUI modifier right of the spacebar"""
+
+ # pylint: enable-msg=invalid-name
+ @classmethod
+ def modifier_bit(cls, keycode: int) -> int:
+ """Return the modifer bit to be set in an HID keycode report if this is a
+ modifier key; otherwise return 0."""
+ return (
+ 1 << (keycode - 0xE0) if cls.LEFT_CONTROL <= keycode <= cls.RIGHT_GUI else 0
+ )
diff --git a/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py
new file mode 100644
index 0000000..3b324db
--- /dev/null
+++ b/circuitpython/frozen/Adafruit_CircuitPython_HID/adafruit_hid/mouse.py
@@ -0,0 +1,152 @@
+# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+`adafruit_hid.mouse.Mouse`
+====================================================
+
+* Author(s): Dan Halbert
+"""
+import time
+
+from . import find_device
+
+try:
+ from typing import Sequence
+ import usb_hid
+except ImportError:
+ pass
+
+
+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: Sequence[usb_hid.Device]):
+ """Create a Mouse object that will send USB mouse HID reports.
+
+ Devices can be a sequence 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)
+
+ # Reuse this bytearray to send mouse reports.
+ # report[0] buttons pressed (LEFT, MIDDLE, RIGHT)
+ # report[1] x movement
+ # report[2] y movement
+ # report[3] wheel movement
+ self.report = bytearray(4)
+
+ # 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: int) -> None:
+ """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: int) -> None:
+ """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) -> None:
+ """Release all the mouse buttons."""
+ self.report[0] = 0
+ self._send_no_move()
+
+ def click(self, buttons: int) -> None:
+ """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: int = 0, y: int = 0, wheel: int = 0) -> None:
+ """Move the mouse and turn the wheel as directed.
+
+ :param x: Move the mouse along the x axis. Negative is to the left, positive
+ is to the right.
+ :param y: Move the mouse along the y axis. Negative is upwards on the display,
+ positive is downwards.
+ :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(-100, 0, 0)
+ # Same, with keyword arguments.
+ m.move(x=-100)
+
+ # Move diagonally to the upper right.
+ m.move(50, 20)
+ # Same.
+ m.move(x=50, y=-20)
+
+ # Roll the mouse wheel away from the user.
+ m.move(wheel=1)
+ """
+ # Send multiple reports if necessary to move or scroll requested amounts.
+ while x != 0 or y != 0 or wheel != 0:
+ partial_x = self._limit(x)
+ partial_y = self._limit(y)
+ partial_wheel = self._limit(wheel)
+ self.report[1] = partial_x & 0xFF
+ self.report[2] = partial_y & 0xFF
+ self.report[3] = partial_wheel & 0xFF
+ self._mouse_device.send_report(self.report)
+ x -= partial_x
+ y -= partial_y
+ wheel -= partial_wheel
+
+ def _send_no_move(self) -> None:
+ """Send a button-only report."""
+ self.report[1] = 0
+ self.report[2] = 0
+ self.report[3] = 0
+ self._mouse_device.send_report(self.report)
+
+ @staticmethod
+ def _limit(dist: int) -> int:
+ return min(127, max(-127, dist))