### Install PySpaceMouse Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Install the library using pip. No additional drivers are required. ```bash pip install pyspacemouse ``` -------------------------------- ### Install hidapi on Linux Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Install the hidapi C library development files on Debian-based Linux systems using apt-get. ```bash sudo apt-get install libhidapi-dev ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Install necessary packages for development, including 'doxygen'. ```bash make install-dev ``` -------------------------------- ### Install Development Tools Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Install necessary development tools like hatch and pre-commit using pipx. These tools are used for managing virtual environments and pre-commit hooks in the project. ```bash pipx install hatch==1.15.1 pre-commit ``` -------------------------------- ### Quick Start with Context Manager Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Use the context manager for recommended device handling, which automatically closes the device. Reads and prints translation (x, y, z) axes in a loop. ```python import pyspacemouse # Context manager (recommended) - automatically closes device with pyspacemouse.open() as device: while True: state = device.read() print(state.x, state.y, state.z) ``` -------------------------------- ### Example lsusb Output Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/troubleshooting.md Example output from `lsusb` showing a SpaceMouse device. The Vendor ID and Product ID are highlighted for use in udev rules. ```text Bus 001 Device 013: ID 256f:c652 3Dconnexion Universal Receiver ``` -------------------------------- ### Install PySpaceMouse Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Install the PySpaceMouse library using pip. Platform dependencies for hidapi are also listed. ```bash pip install pyspacemouse ``` ```bash # Linux sudo apt-get install libhidapi-dev ``` ```bash # macOS brew install hidapi ``` ```bash # Linux udev permissions (run once) echo 'KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"' | \ sudo tee /etc/udev/rules.d/99-hidraw-permissions.rules sudo usermod -aG plugdev $USER && newgrp plugdev ``` -------------------------------- ### Install hidapi on macOS Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Install the hidapi C library on macOS using the Homebrew package manager. ```bash brew install hidapi ``` -------------------------------- ### Test SpaceMouse Connection Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Run this command to test the connection to your SpaceMouse device and view its live state. It's useful for initial setup and verification. ```bash pyspacemouse --test ``` -------------------------------- ### Show PySpaceMouse Version with CLI Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md This command displays the currently installed version of the PySpaceMouse library. ```bash pyspacemouse --version # Show version ``` -------------------------------- ### Show Installed PySpaceMouse Version Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Check the installed version of the PySpaceMouse library using this command. Ensure you are running a compatible version for your project. ```bash pyspacemouse --version ``` -------------------------------- ### List All HID Devices for Debugging Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Get a comprehensive list of all connected HID devices, useful for debugging purposes. Returns product name, manufacturer, vendor ID, and product ID. ```python # List ALL HID devices (for debugging) pyspacemouse.get_all_hid_devices() # Returns: [(product, manufacturer, vid, pid), ...] ``` -------------------------------- ### Troubleshoot OSError: cannot load library 'hidapi.dll' Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md This traceback indicates that the 'hidapi.dll' library, required by easyhid, could not be loaded. This often occurs on Windows if the library is not installed or not accessible in the system's PATH. ```bash Traceback (most recent call last): File "C:\Users\Student\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\easyhid\easyhid.py", line 53, in hidapi = ffi.dlopen('hidapi.dll') File "C:\Users\Student\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\cffi\api.py", line 150, in dlopen lib, function_cache = _make_ffi_library(self, name, flags) File "C:\Users\Student\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\cffi\api.py", line 832, in _make_ffi_library backendlib = _load_backend_lib(backend, libname, flags) File "C:\Users\Student\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\cffi\api.py", line 827, in _load_backend_lib raise OSError(msg) OSError: cannot load library 'hidapi.dll': error 0x7e. Additionally, ctypes.util.find_library() did not manage to locate a library called 'hidapi.dll ``` -------------------------------- ### Open Specific Device by Index Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Opens a specific SpaceMouse device when multiple identical devices are connected, using their index (starting from 0). The context manager ensures proper closing. ```python # Open second device when multiple identical devices are connected with pyspacemouse.open(device_index=1) as device: state = device.read() ``` -------------------------------- ### Build Documentation Locally Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Serve the documentation locally using mkdocs to preview changes before deployment. ```bash make docs-serve ``` -------------------------------- ### Create and Edit udev Rules File Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md Navigate to the udev rules directory and create a new rules file (e.g., `99-spacemouse.rules`) using `sudo touch` and edit it with `sudo nano`. ```bash cd /etc/udev/rules.d sudo touch 99-spacemouse.rules sudo nano 99-spacemouse.rules ``` -------------------------------- ### Basic SpaceMouse Reading with Context Manager Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Demonstrates how to open and read data from a SpaceMouse device using a context manager for proper resource handling. ```python from pyspacemouse import SpaceMouse with SpaceMouse() as sm: print(sm.read_data()) ``` -------------------------------- ### Basic PySpaceMouse Usage Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/examples.md Demonstrates how to open a connection, read device states, and print axis values. Ensure a spacemouse device is connected before running. ```python import pyspacemouse import time success = pyspacemouse.open() if success: while 1: state = pyspacemouse.read() print(state.x, state.y, state.z) time.sleep(0.01) ``` -------------------------------- ### OSError: cannot load library 'hidapi.dll' Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/troubleshooting.md This error occurs when the hidapi.dll library cannot be found or loaded by the system. Ensure the library is correctly installed and accessible via the system's PATH. ```bash Traceback (most recent call last): File "C:\\Users\\Student\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python312\\site-packages\\easyhid\\easyhid.py", line 53, in hidapi = ffi.dlopen('hidapi.dll') File "C:\\Users\\Student\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python312\\site-packages\\cffi\\api.py", line 150, in dlopen lib, function_cache = _make_ffi_library(self, name, flags) File "C:\\Users\\Student\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python312\\site-packages\\cffi\\api.py", line 832, in _make_ffi_library backendlib = _load_backend_lib(backend, libname, flags) File "C:\\Users\\Student\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python312\\site-packages\\cffi\\api.py", line 827, in _load_backend_lib raise OSError(msg) OSError: cannot load library 'hidapi.dll': error 0x7e. Additionally, ctypes.util.find_library() did not manage to locate a library called 'hidapi.dll ``` -------------------------------- ### Device Discovery Functions Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Query available hardware using get_connected_devices(), get_supported_devices(), and get_all_hid_devices(). Also demonstrates loading device specifications. ```python import pyspacemouse # Connected SpaceMouse devices (supported + plugged in) connected = pyspacemouse.get_connected_devices() print(f"Connected: {connected}") # e.g. ['SpaceNavigator', 'SpaceMouse Pro'] # All device types known to the library supported = pyspacemouse.get_supported_devices() for name, vid, pid in supported: status = "✓" if name in connected else " " print(f" [{status}] {name} VID={vid:#06x} PID={pid:#06x}") # Every HID device on the system (for troubleshooting) all_hid = pyspacemouse.get_all_hid_devices() for product, manufacturer, vid, pid in all_hid: print(f" {product or 'Unknown'} by {manufacturer or 'Unknown'} " f"({vid:#06x}/{pid:#06x})") # Load raw device specifications from devices.toml specs = pyspacemouse.get_device_specs() print(f"{len(specs)} device types loaded") nav_spec = specs["SpaceNavigator"] print(f"SpaceNavigator axis_scale={nav_spec.axis_scale}, " f"buttons={nav_spec.button_names}") ``` -------------------------------- ### CLI: List Supported Devices Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Command-line interface command to display all device types supported by the pyspacemouse library. ```bash pyspacemouse --list-supported ``` -------------------------------- ### Create Custom Device Info Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/index.md Use `create_device_info` to define a completely custom device configuration, specifying mappings for axes and buttons. ```python custom = pyspacemouse.create_device_info( name="MyDevice", vendor_id=0x256F, product_id=0xC635, mappings={ "x": (1, 1, 2, 1), # (channel, byte1, byte2, scale) "y": (1, 3, 4, -1), # Inverted "z": (1, 5, 6, -1), "pitch": (2, 1, 2, -1), "roll": (2, 3, 4, -1), "yaw": (2, 5, 6, 1), }, buttons={"LEFT": (3, 1, 0), "RIGHT": (3, 1, 1)}, ) ``` -------------------------------- ### create_device_info() Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Define a fully custom device configuration. Builds a DeviceInfo from scratch using Python dicts — no TOML editing required. Each axis mapping is a (channel, byte1, byte2, scale) tuple; each button is (channel, byte, bit). Use this for unsupported devices or complete HID remapping. ```APIDOC ## `create_device_info()` — Define a fully custom device configuration Builds a `DeviceInfo` from scratch using Python dicts — no TOML editing required. Each axis mapping is a `(channel, byte1, byte2, scale)` tuple; each button is `(channel, byte, bit)`. Use this for unsupported devices or complete HID remapping. ```python import pyspacemouse custom = pyspacemouse.create_device_info( name="CustomSpaceMouse", vendor_id=0x256F, # 3Dconnexion vendor ID product_id=0xC635, # SpaceMouse Compact product ID axis_scale=350.0, # Raw HID value that maps to 1.0 mappings={ # (channel, byte1, byte2, scale) scale=-1 inverts the axis "x": (1, 1, 2, 1), "y": (1, 3, 4, -1), # Inverted "z": (1, 5, 6, -1), # Inverted "pitch": (2, 1, 2, -1), "roll": (2, 3, 4, -1), "yaw": (2, 5, 6, 1), }, buttons={ # (channel, byte, bit) "LEFT": (3, 1, 0), "RIGHT": (3, 1, 1), }, led_id=(4, 0x01), # Optional: (report_id, on_value) ) print(f"Device: {custom.name}") print(f"VID/PID: {custom.vendor_id:#06x} / {custom.product_id:#06x}") print(f"Axes: {list(custom.mappings.keys())}") print(f"Buttons: {custom.button_names}") # Use with open() or open_by_path() with pyspacemouse.open(device_spec=custom) as device: state = device.read() print(f"x={state.x}, y={state.y}, z={state.z}") ``` ``` -------------------------------- ### Create Device Info: Define Custom Device Configuration Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Builds a DeviceInfo from scratch using Python dicts for unsupported devices or complete HID remapping. Each axis mapping is a (channel, byte1, byte2, scale) tuple; each button is a (channel, byte, bit). ```python import pyspacemouse custom = pyspacemouse.create_device_info( name="CustomSpaceMouse", vendor_id=0x256F, # 3Dconnexion vendor ID product_id=0xC635, # SpaceMouse Compact product ID axis_scale=350.0, # Raw HID value that maps to 1.0 mappings={ # (channel, byte1, byte2, scale) scale=-1 inverts the axis "x": (1, 1, 2, 1), "y": (1, 3, 4, -1), # Inverted "z": (1, 5, 6, -1), # Inverted "pitch": (2, 1, 2, -1), "roll": (2, 3, 4, -1), "yaw": (2, 5, 6, 1), }, buttons={ # (channel, byte, bit) "LEFT": (3, 1, 0), "RIGHT": (3, 1, 1), }, led_id=(4, 0x01), # Optional: (report_id, on_value) ) print(f"Device: {custom.name}") print(f"VID/PID: {custom.vendor_id:#06x} / {custom.product_id:#06x}") print(f"Axes: {list(custom.mappings.keys())}") print(f"Buttons: {custom.button_names}") # Use with open() or open_by_path() with pyspacemouse.open(device_spec=custom) as device: state = device.read() print(f"x={state.x}, y={state.y}, z={state.z}") ``` -------------------------------- ### Create Custom Device Info Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Dynamically create a device information object for use with pyspacemouse without modifying 'devices.toml'. ```python import pyspacemouse device_spec = pyspacemouse.create_device_info({ "name": "MyCustomDevice", "hid_id": [0x256F, 0xC652], "axis_scale": 350.0, "mappings": { "x": [1, 1, 2, 1], "y": [1, 3, 4, -1], "z": [1, 5, 6, -1], "pitch": [2, 1, 2, -1], "roll": [2, 3, 4, -1], "yaw": [2, 5, 6, 1], }, "buttons": { "LEFT": [3, 1, 0], "RIGHT": [3, 1, 1], }, }) with pyspacemouse.open(device_spec=device_spec) as device: state = device.read() ``` -------------------------------- ### Add New Device Configuration Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Define a new device in 'devices.toml' with its HID IDs, LED control, axis scaling, and axis/button mappings. ```toml [YourDeviceName] hid_id = [0xVID, 0xPID] # Vendor ID and Product ID in hex led_id = [0x04, 0x01] # Optional: [report_id, on_value] for LED control axis_scale = 350.0 # Scaling factor (adjust based on device sensitivity) # Axis mappings: [channel, byte1, byte2, scale] # - channel: HID report number (1, 2, or 3) # - byte1, byte2: Byte positions for the 16-bit value # - scale: 1 for normal, -1 for inverted axis mappings.x = [1, 1, 2, 1] mappings.y = [1, 3, 4, -1] mappings.z = [1, 5, 6, -1] pitch = [2, 1, 2, -1] mappings.roll = [2, 3, 4, -1] mappings.yaw = [2, 5, 6, 1] # Button mappings: [channel, byte, bit] [YourDeviceName.buttons] LEFT = [3, 1, 0] # Channel 3, byte 1, bit 0 RIGHT = [3, 1, 1] # Channel 3, byte 1, bit 1 ``` -------------------------------- ### Open Specific SpaceMouse Device by Path Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Demonstrates how to open a particular SpaceMouse device by specifying its unique path. ```python from pyspacemouse import SpaceMouse # Replace with the actual device path device_path = "/dev/input/eventX" with SpaceMouse(device_path=device_path) as sm: print(sm.read_data()) ``` -------------------------------- ### Config Object for Bundling All Callbacks Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Organize all callback types (general, axis, button) into a single Config object for passing to open_with_config(). Useful for managing complex configurations or passing settings around. ```python import time import pyspacemouse config = pyspacemouse.Config( callback=lambda s: None, # Every state update dof_callback=pyspacemouse.print_state, # Any axis change dof_callbacks=[ pyspacemouse.DofCallback("yaw", lambda s, v: print(f"Yaw: {v:+.2f}"), filter=0.05), ], button_callback=pyspacemouse.print_buttons, # Built-in button printer button_callbacks=[ pyspacemouse.ButtonCallback(0, lambda s, b, p: print("Button 0!")), ], ) with pyspacemouse.open_with_config(config) as device: print(f"Connected: {device.name}") while True: device.read() time.sleep(0.01) ``` -------------------------------- ### SpaceMouse Button Names and Handling Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Explains how to access button names and handle button events effectively. ```python from pyspacemouse import SpaceMouse def button_callback(pressed, button_id): button_name = sm.get_button_name(button_id) print(f"Button '{button_name}' ({button_id}) {'pressed' if pressed else 'released'}") with SpaceMouse() as sm: sm.register_callback(event='button', callback=button_callback) sm.listen() ``` -------------------------------- ### List HID Devices with PySpaceMouse CLI Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Use this command to display all Human Interface Device (HID) devices connected to your system. ```bash pyspacemouse --list-hid # Show all HID devices ``` -------------------------------- ### List Connected Devices with PySpaceMouse CLI Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Use this command to display a list of all connected SpaceMouse devices recognized by the system. ```bash pyspacemouse --list-connected # Show connected devices ``` -------------------------------- ### List All Supported Device Types Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Retrieve a list of all device types supported by the library, including their names, vendor IDs, and product IDs. ```python # List all supported device types pyspacemouse.get_supported_devices() # Returns: [(name, vendor_id, product_id), ...] ``` -------------------------------- ### Add udev Rules for SpaceMouse Permissions Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md Add these rules to your `99-spacemouse.rules` file to grant necessary permissions for HID devices. Replace `046d` and `c62b` with your device's specific Vendor ID and Product ID. ```bash SUBSYSTEM=="input", GROUP="input", MODE="0660" KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c62b", MODE="0666" ``` -------------------------------- ### CLI: List Connected Devices Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Command-line interface command to display all currently connected SpaceMouse devices. ```bash pyspacemouse --list-connected ``` -------------------------------- ### List USB Devices (Linux/macOS) Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Use 'lsusb' to find your device's Vendor ID (VID) and Product ID (PID). ```bash lsusb # Example output: Bus 001 Device 013: ID 256f:c652 3Dconnexion Universal Receiver # VID = 256f, PID = c652 ``` -------------------------------- ### Open Device with Callbacks Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Opens a SpaceMouse device using a context manager and enables custom button and DOF (Degrees of Freedom) callbacks. The `device.read()` call triggers these callbacks. ```python with pyspacemouse.open( button_callbacks=button_callbacks, dof_callbacks=dof_callbacks, ) as device: while True: device.read() # Triggers callbacks ``` -------------------------------- ### Open First Available Device Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Opens the first detected SpaceMouse device using a context manager for automatic resource management. Reads and returns the device state. ```python # Auto-detect and open first device with pyspacemouse.open() as device: state = device.read() ``` -------------------------------- ### List HID Devices with hidapitester Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/CONTRIBUTING.md Use the `hidapitester` tool to list connected HID devices and their IDs. ```bash ./hidapitester --list # Example: 046D/C626: 3Dconnexion - SpaceNavigator ``` -------------------------------- ### List Supported Device Types with PySpaceMouse CLI Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md This command lists all device types that the PySpaceMouse library supports. ```bash pyspacemouse --list-supported # Show all supported types ``` -------------------------------- ### Custom Device Configuration for PySpaceMouse Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/examples.md Illustrates how to customize axis mappings for different coordinate conventions, such as ROS or OpenGL. This allows for tailored device behavior. ```python import pyspacemouse # Get existing device spec and modify it specs = pyspacemouse.get_device_specs() base = specs["SpaceNavigator"] # Invert axes for ROS conventions ros_spec = pyspacemouse.modify_device_info( base, name="SpaceNavigator (ROS)", invert_axes=["y", "z", "roll", "yaw"], ) # Open with custom configuration with pyspacemouse.open(device_spec=ros_spec) as device: while True: state = device.read() print(f"x={state.x:.2f} y={state.y:.2f} z={state.z:.2f}") ``` -------------------------------- ### PySpaceMouse with Callback Functions Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/examples.md Shows how to use callback functions for handling device events, including button presses and axis movements. Custom callbacks can be defined for specific actions. ```python import pyspacemouse import time def button_0(state, buttons, pressed_buttons): print("Button:", pressed_buttons) def button_0_1(state, buttons, pressed_buttons): print("Buttons:", pressed_buttons) def someButton(state, buttons): print("Some button") def callback(): button_arr = [pyspacemouse.ButtonCallback(0, button_0), pyspacemouse.ButtonCallback([1], lambda state, buttons, pressed_buttons: print("Button: 1")), pyspacemouse.ButtonCallback([0, 1], button_0_1), ] success = pyspacemouse.open(dof_callback=pyspacemouse.print_state, button_callback=someButton, button_callback_arr=button_arr) if success: while True: pyspacemouse.read() time.sleep(0.01) if __name__ == '__main__': callback() ``` -------------------------------- ### Control SpaceMouse LED Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Demonstrates how to turn the LED on the SpaceMouse device on or off. ```python from pyspacemouse import SpaceMouse with SpaceMouse() as sm: sm.set_led(True) # Turn LED on # ... do something ... sm.set_led(False) # Turn LED off ``` -------------------------------- ### List All HID Devices Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Use this command to see all HID devices connected to your system. This can help in identifying the correct device for PySpaceMouse. ```bash pyspacemouse --list-hid ``` -------------------------------- ### Per-Axis Callbacks with Filtering for SpaceMouse Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Shows how to set up callbacks for individual axes with optional filtering to only receive updates when a certain threshold is crossed. ```python from pyspacemouse import SpaceMouse def axis_callback(axis_values): # axis_values is a dictionary like {'x': 0.1, 'y': -0.05, ...} print(axis_values) with SpaceMouse() as sm: # Register callback for 'x' and 'y' axes with a threshold of 0.01 sm.register_callback(event='axis', callback=axis_callback, axis_filter={'x': 0.01, 'y': 0.01}) sm.listen() ``` -------------------------------- ### SpaceMouse Button and DOF Callbacks Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Shows how to register callback functions that are triggered when buttons are pressed or DOF (Degrees of Freedom) data changes. ```python from pyspacemouse import SpaceMouse def button_callback(pressed, button_id): print(f"Button {button_id} {'pressed' if pressed else 'released'}") def dof_callback(x, y, z, rot_x, rot_y, rot_z): print(f"DOF: x={x}, y={y}, z={z}, rx={rot_x}, ry={rot_y}, rz={rot_z}") with SpaceMouse() as sm: sm.register_callback(event='button', callback=button_callback) sm.register_callback(event='dof', callback=dof_callback) sm.listen() ``` -------------------------------- ### Test Connection with PySpaceMouse CLI Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Run this command to test the connection and functionality of your SpaceMouse device. ```bash pyspacemouse --test # Test connection ``` -------------------------------- ### List HID Devices with hidapitester Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Use 'hidapitester --list' to identify connected HID devices and their IDs. ```bash ./hidapitester --list # Example: 046D:C626: 3Dconnexion - SpaceNavigator ``` -------------------------------- ### Open Device with Custom Spec Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/index.md Pass a custom device specification, created with `create_device_info` or `modify_device_info`, to the `pyspacemouse.open()` function. ```python with pyspacemouse.open(device_spec=ros_spec) as device: state = device.read() ``` -------------------------------- ### List and Inspect SpaceMouse Devices Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/README.md Provides a way to discover available SpaceMouse devices and inspect their properties. ```python from pyspacemouse import list_devices devices = list_devices() for device in devices: print(device) ``` -------------------------------- ### Linux hidapi Permissions Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Commands to set up udev rules for hidapi on Linux, ensuring proper permissions for user access to HID devices. This is necessary for PySpaceMouse to function correctly on Linux. ```bash echo 'KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/99-hidraw-permissions.rules sudo usermod -aG plugdev $USER newgrp plugdev ``` -------------------------------- ### Traceback for Failed Device Open Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/troubleshooting.md This traceback indicates a 'Failed to open device' error, typically caused by insufficient permissions for the user to access HID devices on Linux. ```bash Traceback ( File "/home/user/.local/lib/python3.8/site-packages/pyspacemouse/pyspacemouse.py", line 183, in open self.device.open() File "/home/user/.local/lib/python3.8/site-packages/easyhid/easyhid.py", line 134, in open raise HIDException("Failed to open device") easyhid.easyhid.HIDException: Failed to open device ``` -------------------------------- ### Traceback for Failed to Open Device Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md This traceback indicates a 'Failed to open device' error, commonly caused by insufficient user permissions to access HID devices on Linux. ```bash Traceback (most recent call last): File "/home/user/.local/lib/python3.8/site-packages/pyspacemouse/pyspacemouse.py", line 183, in open self.device.open() File "/home/user/.local/lib/python3.8/site-packages/easyhid/easyhid.py", line 134, in open raise HIDException("Failed to open device") easyhid.easyhid.HIDException: Failed to open device ``` -------------------------------- ### Open SpaceMouse Device by Path Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Use `pyspacemouse.open_by_path()` to open a device using its specific HID filesystem path. This is useful for disambiguating devices or when paths are known from udev rules. A custom device specification can be provided for unsupported devices. ```python import pyspacemouse # Open by explicit path with pyspacemouse.open_by_path("/dev/hidraw0") as device: print(f"Opened: {device.name}") state = device.read() print(f"x={state.x:+.2f} y={state.y:+.2f} z={state.z:+.2f}") ``` ```python # Open with a custom spec for an unsupported device at a known path custom = pyspacemouse.create_device_info( name="MyDevice", vendor_id=0x256F, product_id=0xC635, mappings={ "x": (1, 1, 2, 1), "y": (1, 3, 4, -1), "z": (1, 5, 6, -1), "pitch": (2, 1, 2, -1), "roll": (2, 3, 4, -1), "yaw": (2, 5, 6, 1), }, ) with pyspacemouse.open_by_path("/dev/hidraw1", device_spec=custom) as device: state = device.read() print(f"Custom device: {state.x}, {state.y}, {state.z}") ``` -------------------------------- ### SpaceMouseDevice.set_led() Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Control the device LED. Toggles the LED indicator on devices that support it. If DeviceInfo.led_id is None (device has no LED), this call is silently ignored. Failures during the HID write are also silently swallowed. ```APIDOC ## `SpaceMouseDevice.set_led()` — Control the device LED Toggles the LED indicator on devices that support it. If `DeviceInfo.led_id` is `None` (device has no LED), this call is silently ignored. Failures during the HID write are also silently swallowed. ```python import time import pyspacemouse with pyspacemouse.open() as device: print(f"Connected: {device.name}") # Blink LED every 500ms for i in range(10): device.set_led(i % 2 == 0) # True = on, False = off time.sleep(0.5) device.set_led(False) # Ensure LED is off on exit ``` ``` -------------------------------- ### Callbacks Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Setting up custom callback functions for button presses and DOF (Degrees of Freedom) changes, with options for filtering and rate limiting. ```APIDOC ## Callbacks ### Button callback ```python def on_button(state, buttons, pressed): print(f"Button {pressed} pressed!") button_callbacks = [ pyspacemouse.ButtonCallback(0, on_button), # Button 0 pyspacemouse.ButtonCallback([0, 1], on_button), # Both 0 and 1 ] ``` ### DOF callback with filtering ```python dof_callbacks = [ pyspacemouse.DofCallback( axis="x", callback=lambda s, v: print(f"X: {v}"), callback_minus=lambda s, v: print(f"X negative: {v}"), filter=0.1, # Deadzone sleep=0.05, # Rate limit ), ] ``` ### Using callbacks when opening a device ```python with pyspacemouse.open( button_callbacks=button_callbacks, dof_callbacks=dof_callbacks, ) as device: while True: device.read() # Triggers callbacks ``` ``` -------------------------------- ### Module-level API Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/index.md Functions for interacting with the default or currently active space navigator device. ```APIDOC ## Module-level API ### `open(callback=None, button_callback=None, button_callback_arr=None, set_nonblocking_loop=True, device=None)` **Description**: Opens a 3D space navigator device, making it the active device for module-level `read()` and `close()` calls. If multiple devices are present, it's recommended to use the object-oriented API. **Parameters**: - `callback` (callable, optional): Called on each HID update with the current state. - `button_callback` (callable, optional): Called on each button push with `(state_tuple, button_state)`. - `device` (str, optional): The name of the device to open (e.g., "SpaceNavigator"). If `None`, the first supported device is chosen. **Returns**: - A device object if successful, otherwise `None`. ### `read()` **Description**: Returns the current state of the active device. **Returns**: - A namedtuple with state information: `(t, x, y, z, roll, pitch, yaw, button)`. ### `close()` **Description**: Closes the connection to the currently active device. ### `list_devices()` **Description**: Returns a list of supported space navigator devices found on the system. **Returns**: - A list of strings, where each string is a supported device name. Returns an empty list if no devices are found. ``` -------------------------------- ### Open Device by Filesystem Path Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Opens a SpaceMouse device directly using its filesystem path, typically used on Linux systems (e.g., '/dev/hidraw0'). The context manager handles device closure. ```python # Open by filesystem path (Linux: /dev/hidraw0) with pyspacemouse.open_by_path("/dev/hidraw0") as device: state = device.read() ``` -------------------------------- ### pyspacemouse.open() Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Auto-detects and opens the first connected SpaceMouse device. It supports optional callbacks for axis and button events and returns a SpaceMouseDevice object that functions as a context manager for automatic cleanup. It raises RuntimeError if no device is found and ValueError for an unknown device name. ```APIDOC ## pyspacemouse.open() ### Description Auto-detects and opens the first connected SpaceMouse device. Accepts optional callbacks for axis and button events. Returns a `SpaceMouseDevice` that supports the context manager protocol for automatic cleanup. Raises `RuntimeError` if no device is found, `ValueError` for an unknown device name. ### Method `pyspacemouse.open(device=None, device_index=0, **kwargs)` ### Parameters #### Path Parameters - **device** (str, optional): The name of the device to open. Defaults to None. - **device_index** (int, optional): The index of the device to open if multiple devices of the same name are present. Defaults to 0. ### Request Example ```python import time import pyspacemouse # Basic usage: context manager auto-closes the device with pyspacemouse.open() as device: print(f"Connected: {device.name}") # describe_connection() shows product name, vendor, version, serial print(device.describe_connection()) while True: state = device.read() # Non-blocking; returns SpaceMouseState # 6-DOF axes: float in range [-1.0, 1.0] if abs(state.x) > 0.01 or abs(state.z) > 0.01: print( f"x={state.x:+.2f} y={state.y:+.2f} z={state.z:+.2f} " f"roll={state.roll:+.2f} pitch={state.pitch:+.2f} yaw={state.yaw:+.2f} " f"t={state.t:.3f}" ) # Button states: list of 0/1 per button if any(state.buttons): print(f"Buttons: {list(state.buttons)}") time.sleep(0.01) # Open a specific device by name with pyspacemouse.open(device="SpaceNavigator") as device: state = device.read() # Open second of two identical devices with pyspacemouse.open(device="SpaceMouse Pro", device_index=1) as device: state = device.read() ``` ### Response #### Success Response (SpaceMouseDevice) - **name** (str): The name of the connected device. - **describe_connection()**: A method that returns a string describing the device connection details (product name, vendor, version, serial). - **read()**: A method that returns the current state of the device (axes and buttons). #### Response Example ``` Connected: SpaceNavigator Product: SpaceNavigator, Vendor: 0x046d, Product: 0xc62b, Version: 100, Serial: 1234567890 x=+0.01 y=-0.02 z=+0.00 roll=+0.00 pitch=+0.00 yaw=+0.00 t=0.123 Buttons: [0, 1, 0] ``` ``` -------------------------------- ### Open Specific Device by Name Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Opens a specific SpaceMouse device by its name (e.g., 'SpaceNavigator') using a context manager. Ensures the correct device is used when multiple are connected. ```python # Open specific device by name with pyspacemouse.open(device="SpaceNavigator") as device: state = device.read() ``` -------------------------------- ### Multi-Device Usage: Open Two SpaceMice Simultaneously Source: https://context7.com/jakubandrysek/pyspacemouse/llms.txt Opens multiple devices using `device_index` to distinguish between identical devices connected simultaneously. Useful for applications like bimanual robot teleoperation. ```python import time import pyspacemouse connected = pyspacemouse.get_connected_devices() # e.g. ['SpaceMouse Pro', 'SpaceMouse Pro'] device_name = connected[0] with pyspacemouse.open(device=device_name, device_index=0) as left: with pyspacemouse.open(device=device_name, device_index=1) as right: print(f"Left: {left.name} | Right: {right.name}") while True: l = left.read() r = right.read() print( f"L x={l.x:+.2f} y={l.y:+.2f} z={l.z:+.2f} | " f"R x={r.x:+.2f} y={r.y:+.2f} z={r.z:+.2f}" ) time.sleep(0.02) ``` -------------------------------- ### PySpaceMouse CLI Commands Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Common command-line interface commands for interacting with connected SpaceMouse devices. Use these to list devices, test connections, and view version information. ```bash pyspacemouse --list-connected # Show connected devices ``` ```bash pyspacemouse --list-supported # Show all supported types ``` ```bash pyspacemouse --list-hid # Show all HID devices ``` ```bash pyspacemouse --test # Test connection ``` ```bash pyspacemouse --version # Show version ``` -------------------------------- ### Test SpaceMouse Device Recognition and Reading Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/CONTRIBUTING.md Verify if the device is recognized by pyspacemouse and test reading its state (axes and buttons). ```python import pyspacemouse # Check if device is recognized devices = pyspacemouse.get_connected_devices() print(devices) # Should show your device name # Test reading with pyspacemouse.open() as device: while True: state = device.read() print(f"X:{state.x:.2f} Y:{state.y:.2f} Z:{state.z:.2f}") print(f"Roll:{state.roll:.2f} Pitch:{state.pitch:.2f} Yaw:{state.yaw:.2f}") print(f"Buttons: {state.buttons}") ``` -------------------------------- ### Custom Device Configuration Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/mouseApi/index.md Helper functions for creating and modifying device configurations for custom or non-standard devices. ```APIDOC ## Custom Device Configuration ### `create_device_info()` **Description**: Creates a completely custom device configuration. **Example Usage**: ```python custom = pyspacemouse.create_device_info( name="MyDevice", vendor_id=0x256F, product_id=0xC635, mappings={ "x": (1, 1, 2, 1), "y": (1, 3, 4, -1), "z": (1, 5, 6, -1), "pitch": (2, 1, 2, -1), "roll": (2, 3, 4, -1), "yaw": (2, 5, 6, 1), }, buttons={"LEFT": (3, 1, 0), "RIGHT": (3, 1, 1)}, ) ``` ### `modify_device_info()` **Description**: Modifies an existing device specification, for example, to invert axes. **Example Usage**: ```python specs = pyspacemouse.get_device_specs() base = specs["SpaceNavigator"] ros_spec = pyspacemouse.modify_device_info( base, name="SpaceNavigator (ROS)", invert_axes=["y", "z", "roll", "yaw"], ) ``` ### Using Custom Specs Pass the custom device specification to the `open()` function: ```python with pyspacemouse.open(device_spec=ros_spec) as device: state = device.read() ``` ``` -------------------------------- ### List USB Devices Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md Use the `lsusb` command to find your SpaceMouse device and identify its Vendor ID and Product ID, which are necessary for creating udev rules. ```bash lsusb ``` -------------------------------- ### Add User to Input Group Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md Add your current user to the `input` group using `sudo usermod -a -G input $USER` to grant access to input devices. ```bash sudo usermod -a -G input $USER ``` -------------------------------- ### Opening Devices Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/docs/README.md Methods to open a SpaceMouse device, either by auto-detection, specifying a device name or index, or by its filesystem path. ```APIDOC ## Opening Devices ### Auto-detect and open first device ```python import pyspacemouse with pyspacemouse.open() as device: state = device.read() ``` ### Open specific device by name ```python import pyspacemouse with pyspacemouse.open(device="SpaceNavigator") as device: state = device.read() ``` ### Open second device when multiple identical devices are connected ```python import pyspacemouse with pyspacemouse.open(device_index=1) as device: state = device.read() ``` ### Open by filesystem path (Linux: /dev/hidraw0) ```python import pyspacemouse with pyspacemouse.open_by_path("/dev/hidraw0") as device: state = device.read() ``` ``` -------------------------------- ### Set DYLD_LIBRARY_PATH for Hidapi on Mac M1 Source: https://github.com/jakubandrysek/pyspacemouse/blob/master/troubleshooting.md On Mac M1/M2 systems, add the hidapi library path to the DYLD_LIBRARY_PATH environment variable to resolve potential linking issues. This is typically needed for the current session only. ```bash export DYLD_LIBRARY_PATH=/opt/homebrew/Cellar/hidapi//lib:$DYLD_LIBRARY_PATH ```