1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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))
|