Upload files to "lib/adafruit_hid"
This commit is contained in:
@@ -0,0 +1,191 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
__version__ = "6.1.1"
|
||||||
|
__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, delay: float = None) -> 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.
|
||||||
|
:param float delay: Optional delay in seconds between key presses.
|
||||||
|
: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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if delay is not None:
|
||||||
|
sleep(delay)
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
"""
|
||||||
|
`adafruit_hid.keycode.Keycode`
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
* Author(s): Scott Shawcroft, Dan Halbert
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 Dan Halbert for Adafruit Industries
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
"""
|
||||||
|
`adafruit_hid.mouse.Mouse`
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
* Author(s): Dan Halbert
|
||||||
|
"""
|
||||||
|
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."""
|
||||||
|
BACK_BUTTON = 8
|
||||||
|
"""Back mouse button."""
|
||||||
|
FORWARD_BUTTON = 16
|
||||||
|
"""Forward mouse button."""
|
||||||
|
|
||||||
|
def __init__(self, devices: Sequence[usb_hid.Device], timeout: int = None) -> None:
|
||||||
|
"""Create a Mouse object that will send USB mouse HID reports.
|
||||||
|
|
||||||
|
:param timeout: Time in seconds to wait for USB to become ready before timing out.
|
||||||
|
Defaults to None to wait indefinitely.
|
||||||
|
|
||||||
|
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, timeout=timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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))
|
||||||
Reference in New Issue
Block a user