diff --git a/README.md b/README.md index d83ea53..4258b2d 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Note: You should connect the data usb port (left one) to the raspberry, and NOT from zero_hid import Mouse m = Mouse() for i in range(5): - m.move_relative(10, 10) + m.move(10, 10) ``` - Control keyboard ```python @@ -37,6 +37,9 @@ k = Keyboard() k.type('Hello world!') ``` +## Examples +see [examples](examples) + ## Tests | Raspberry Pi Model | Raspbian Version | Kernel Version | |---------------------|-------------------|----------------| diff --git a/examples/absolute_mouse.py b/examples/absolute_mouse.py new file mode 100644 index 0000000..a9ecb27 --- /dev/null +++ b/examples/absolute_mouse.py @@ -0,0 +1,5 @@ +from zero_hid import Mouse + +m = Mouse(absolute=True) +m.move(50,50) +m.close() \ No newline at end of file diff --git a/examples/mouse_example.py b/examples/mouse_example.py index b148400..8013821 100644 --- a/examples/mouse_example.py +++ b/examples/mouse_example.py @@ -1,8 +1,6 @@ from zero_hid import Mouse - - m = Mouse() for i in range(5): - m.move_relative(5,5) + m.move(5,5) m.close() \ No newline at end of file diff --git a/tests/mouse_test.py b/tests/mouse_test.py index abde3b4..906baf0 100644 --- a/tests/mouse_test.py +++ b/tests/mouse_test.py @@ -15,7 +15,7 @@ def test_left_click(): def test_move(): with open(random_file(), 'ab+') as f: m = Mouse(f) - m.move_relative(100, 100) + m.move(100, 100) f.seek(0) data = f.read() f.close() diff --git a/usb_gadget/init_usb_gadget b/usb_gadget/init_usb_gadget index b990938..46ce26f 100644 --- a/usb_gadget/init_usb_gadget +++ b/usb_gadget/init_usb_gadget @@ -74,12 +74,12 @@ D=$(mktemp) } >> "$D" cp "$D" "${KEYBOARD_FUNCTIONS_DIR}/report_desc" -# Mouse -MOUSE_FUNCTIONS_DIR="functions/hid.mouse" -mkdir -p "$MOUSE_FUNCTIONS_DIR" -echo 0 > "${MOUSE_FUNCTIONS_DIR}/protocol" -echo 0 > "${MOUSE_FUNCTIONS_DIR}/subclass" -echo 7 > "${MOUSE_FUNCTIONS_DIR}/report_length" +# Mouse Relative +MOUSE_RELATIVE_FUNCTIONS_DIR="functions/hid.mouse_relative" +mkdir -p "$MOUSE_RELATIVE_FUNCTIONS_DIR" +echo 0 > "${MOUSE_RELATIVE_FUNCTIONS_DIR}/protocol" +echo 0 > "${MOUSE_RELATIVE_FUNCTIONS_DIR}/subclass" +echo 7 > "${MOUSE_RELATIVE_FUNCTIONS_DIR}/report_length" # Write the report descriptor D=$(mktemp) { @@ -95,15 +95,69 @@ echo -ne \\x25\\x01 # LOGICAL_MAXIMUM (1) echo -ne \\x95\\x08 # REPORT_COUNT (8) echo -ne \\x75\\x01 # REPORT_SIZE (1) echo -ne \\x81\\x02 # INPUT (Data,Var,Abs) + # x,y relative coordinates echo -ne \\x05\\x01 # USAGE_PAGE (Generic Desktop) echo -ne \\x09\\x30 # USAGE (X) echo -ne \\x09\\x31 # USAGE (Y) -echo -ne \\x15\\x81 # LOGICAL_MINIMUM (-127) -echo -ne \\x25\\x7f # LOGICAL_MAXIMUM (127) +echo -ne \\x15\\x81 # LOGICAL_MINIMUM (-127) +echo -ne \\x25\\x7f # LOGICAL_MAXIMUM (127) echo -ne \\x75\\x08 # REPORT_SIZE (16) echo -ne \\x95\\x02 # REPORT_COUNT (2) echo -ne \\x81\\x06 # INPUT (Data,Var,Rel) + + # vertical wheel +echo -ne \\x09\\x38 # USAGE (wheel) +echo -ne \\x15\\x81 # LOGICAL_MINIMUM (-127) +echo -ne \\x25\\x7F # LOGICAL_MAXIMUM (127) +echo -ne \\x75\\x08 # REPORT_SIZE (8) +echo -ne \\x95\\x01 # REPORT_COUNT (1) +echo -ne \\x81\\x06 # INPUT (Data,Var,Rel) + # horizontal wheel +echo -ne \\x05\\x0C # USAGE_PAGE (Consumer Devices) +echo -ne \\x0A\\x38\\x02 # USAGE (AC Pan) +echo -ne \\x15\\x81 # LOGICAL_MINIMUM (-127) +echo -ne \\x25\\x7F # LOGICAL_MAXIMUM (127) +echo -ne \\x75\\x08 # REPORT_SIZE (8) +echo -ne \\x95\\x01 # REPORT_COUNT (1) +echo -ne \\x81\\x06 # INPUT (Data,Var,Rel) +echo -ne \\xC0 # END_COLLECTION +} >> "$D" +cp "$D" "${MOUSE_RELATIVE_FUNCTIONS_DIR}/report_desc" + +# Mouse Absolute +MOUSE_ABSOLUTE_FUNCTIONS_DIR="functions/hid.mouse_absolute" +mkdir -p "$MOUSE_ABSOLUTE_FUNCTIONS_DIR" +echo 0 > "${MOUSE_ABSOLUTE_FUNCTIONS_DIR}/protocol" +echo 0 > "${MOUSE_ABSOLUTE_FUNCTIONS_DIR}/subclass" +echo 7 > "${MOUSE_ABSOLUTE_FUNCTIONS_DIR}/report_length" +# Write the report descriptor +D=$(mktemp) +{ +echo -ne \\x05\\x01 # USAGE_PAGE (Generic Desktop) +echo -ne \\x09\\x02 # USAGE (Mouse) +echo -ne \\xA1\\x01 # COLLECTION (Application) + # 8-buttons +echo -ne \\x05\\x09 # USAGE_PAGE (Button) +echo -ne \\x19\\x01 # USAGE_MINIMUM (Button 1) +echo -ne \\x29\\x08 # USAGE_MAXIMUM (Button 8) +echo -ne \\x15\\x00 # LOGICAL_MINIMUM (0) +echo -ne \\x25\\x01 # LOGICAL_MAXIMUM (1) +echo -ne \\x95\\x08 # REPORT_COUNT (8) +echo -ne \\x75\\x01 # REPORT_SIZE (1) +echo -ne \\x81\\x02 # INPUT (Data,Var,Abs) + + + # x,y absolute coordinates +echo -ne \\x05\\x01 # USAGE_PAGE (Generic Desktop) +echo -ne \\x09\\x30 # USAGE (X) +echo -ne \\x09\\x31 # USAGE (Y) +echo -ne \\x15\\x00 # LOGICAL_MINIMUM (0) +echo -ne \\x26\\xff\\x7f # LOGICAL_MAXIMUM (65535) +echo -ne \\x75\\x10 # REPORT_SIZE (16) +echo -ne \\x95\\x02 # REPORT_COUNT (2) +echo -ne \\x81\\x02 # INPUT (Data,Var,RAbs) + # vertical wheel echo -ne \\x09\\x38 # USAGE (wheel) echo -ne \\x15\\x81 # LOGICAL_MINIMUM (-127) @@ -121,7 +175,7 @@ echo -ne \\x95\\x01 # REPORT_COUNT (1) echo -ne \\x81\\x06 # INPUT (Data,Var,Rel) echo -ne \\xC0 # END_COLLECTION } >> "$D" -cp "$D" "${MOUSE_FUNCTIONS_DIR}/report_desc" +cp "$D" "${MOUSE_ABSOLUTE_FUNCTIONS_DIR}/report_desc" CONFIG_INDEX=1 CONFIGS_DIR="configs/c.${CONFIG_INDEX}" @@ -133,8 +187,11 @@ mkdir -p "$CONFIGS_STRINGS_DIR" echo "Config ${CONFIG_INDEX}: ECM network" > "${CONFIGS_STRINGS_DIR}/configuration" ln -s "$KEYBOARD_FUNCTIONS_DIR" "${CONFIGS_DIR}/" -ln -s "$MOUSE_FUNCTIONS_DIR" "${CONFIGS_DIR}/" +ln -s "$MOUSE_RELATIVE_FUNCTIONS_DIR" "${CONFIGS_DIR}/" +ln -s "$MOUSE_ABSOLUTE_FUNCTIONS_DIR" "${CONFIGS_DIR}/" ls /sys/class/udc > UDC -chmod 777 /dev/hidg0 -chmod 777 /dev/hidg1 +chmod 777 /dev/hidg0 # Keyboard +chmod 777 /dev/hidg1 # Mouse Relative +chmod 777 /dev/hidg2 # Mouse Absolute + diff --git a/zero_hid/Keyboard.py b/zero_hid/Keyboard.py index 3a10279..fec8e4a 100644 --- a/zero_hid/Keyboard.py +++ b/zero_hid/Keyboard.py @@ -2,6 +2,7 @@ from .hid.keyboard import send_keystroke, release_keys from .hid.keycodes import KeyCodes +from . import defaults from time import sleep import json import operator @@ -12,7 +13,7 @@ class Keyboard: - def __init__(self, dev='/dev/hidg0') -> None: + def __init__(self, dev=defaults.KEYBOARD_PATH) -> None: if not hasattr(dev, 'write'): # check if file like object self.dev = open(dev, 'ab+') else: diff --git a/zero_hid/Mouse.py b/zero_hid/Mouse.py index 7d8477d..ef0bff7 100644 --- a/zero_hid/Mouse.py +++ b/zero_hid/Mouse.py @@ -1,13 +1,16 @@ -from .hid.mouse import send_mouse_event +from . import defaults +from .hid.mouse import relative_mouse_event, absolute_mouse_event from typing import SupportsInt - class RelativeMoveRangeError(Exception): pass - class Mouse: - def __init__(self, dev='/dev/hidg1') -> None: + def __init__(self, dev = None, absolute = False) -> None: + if dev is None: + dev = defaults.ABSOLUTE_MOUSE_PATH if absolute else defaults.RELATIVE_MOUSE_PATH + self.move = self.__move_absolute if absolute else self.__move_relative # dynamic move method + self.__send_mouse_event = absolute_mouse_event if absolute else relative_mouse_event # dynamic mouse event method if not hasattr(dev, 'write'): # check if file like object self.dev = open(dev, 'ab+') else: @@ -15,14 +18,14 @@ def __init__(self, dev='/dev/hidg1') -> None: def left_click(self): - send_mouse_event(self.dev, 0x1, 0, 0, 0, 0) - send_mouse_event(self.dev, 0x0, 0, 0, 0, 0) + self.__send_mouse_event(self.dev, 0x1, 0, 0, 0, 0) + self.__send_mouse_event(self.dev, 0x0, 0, 0, 0, 0) def right_click(self): - send_mouse_event(self.dev, 0x1, 0, 0, 0, 0) - send_mouse_event(self.dev, 0x2, 0, 0, 0, 0) - - def move_relative(self, x, y): + self.__send_mouse_event(self.dev, 0x2, 0, 0, 0, 0) + self.__send_mouse_event(self.dev, 0x0, 0, 0, 0, 0) + + def __move_relative(self, x, y): """ move the mouse in relative mode x,y should be in range of -127 to 127 @@ -30,9 +33,15 @@ def move_relative(self, x, y): if not -127 <= x <= 127: raise RelativeMoveRangeError(f"Value of x: {x} out of range (-127 - 127)") if not -127 <= y <= 127: - RelativeMoveRangeError(f"Value of x: {y} out of range (-127 - 127)") - send_mouse_event(self.dev, 0x0, x, y, 0, 0) + RelativeMoveRangeError(f"Value of y: {y} out of range (-127 - 127)") + self.__send_mouse_event(self.dev, 0x0, x, y, 0, 0) + def __move_absolute(self, x, y): + if not 0 <= x <= 65535: + raise RelativeMoveRangeError(f"Value of x: {x} out of range (0 - 65535)") + if not 0 <= y <= 65535: + RelativeMoveRangeError(f"Value of y: {y} out of range (0 - 65535)") + self.__send_mouse_event(self.dev, 0x0, x, y, 0, 0) def __enter__(self): diff --git a/zero_hid/__init__.py b/zero_hid/__init__.py index 988a8f9..0ef92a7 100644 --- a/zero_hid/__init__.py +++ b/zero_hid/__init__.py @@ -1,5 +1,11 @@ from .Mouse import Mouse from .Keyboard import Keyboard from .hid.keycodes import KeyCodes +from . import defaults -__all__ = ['Mouse', 'Keyboard', 'KeyCodes'] +__all__ = [ + 'Mouse', + 'Keyboard', + 'KeyCodes', + 'defaults' +] diff --git a/zero_hid/defaults.py b/zero_hid/defaults.py new file mode 100644 index 0000000..7a2731a --- /dev/null +++ b/zero_hid/defaults.py @@ -0,0 +1,3 @@ +KEYBOARD_PATH = '/dev/hidg0' +RELATIVE_MOUSE_PATH = '/dev/hidg1' +ABSOLUTE_MOUSE_PATH = '/dev/hidg2' \ No newline at end of file diff --git a/zero_hid/hid/mouse.py b/zero_hid/hid/mouse.py index 3a321a4..e06b704 100644 --- a/zero_hid/hid/mouse.py +++ b/zero_hid/hid/mouse.py @@ -1,13 +1,26 @@ from . import write as hid_write -def send_mouse_event(dev, buttons, relative_x, relative_y, - vertical_wheel_delta, horizontal_wheel_delta): +def relative_mouse_event(dev, buttons, x, y, + vertical_wheel_delta, horizontal_wheel_delta, absolute = False): buf = [ buttons, - relative_x & 0xff, - relative_y & 0xff, + x & 0xff, + y & 0xff, vertical_wheel_delta & 0xff, horizontal_wheel_delta & 0xff ] hid_write.write_to_hid_interface(dev, buf) - \ No newline at end of file + + +def absolute_mouse_event(dev, buttons, x, y, + vertical_wheel_delta, horizontal_wheel_delta): + buf = [ + buttons, + x & 0xff, + (x >> 8) & 0xff, # Extract the upper byte of x + y & 0xff, + (y >> 8) & 0xff, # Extract the upper byte of y + vertical_wheel_delta & 0xff, + horizontal_wheel_delta & 0xff + ] + hid_write.write_to_hid_interface(dev, buf) \ No newline at end of file