Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy-web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
with:
python-version: "3.12"
- name: Install Hatch
run: pip install hatch==1.15.1
run: pip install hatch
- uses: actions/cache@v4
with:
key: mkdocs-${{ github.ref }}
Expand Down
3 changes: 0 additions & 3 deletions .sourcery.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Once your device works correctly:

1. Create a branch: `git checkout -b add-device-<name>`
2. Add your device entry to `devices.toml`
3. Test thoroughly with the examples in `examples/`
3. Test thoroughly with the examples in `examples/`. If you add a new example, update the README and `docs/mouseApi/examples.md`.
4. Submit a PR with your device name and any notes about testing

### Using Custom Configuration (Without Modifying Library)
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ See the [examples/](https://github.com/JakubAndrysek/PySpaceMouse/tree/master/ex
| `06_axis_callbacks.py` | Per-axis callbacks with filtering |
| `07_led.py` | LED control |
| `08_buttons.py` | Button names and handling |
| `09_custom_config.py` | Custom axis mappings |
| `09_invert_rotations.py` | Invert rotations |
| `10_custom_config_unity.py` | A totally custom device config using the Unity axis convention |

## Dependencies

Expand Down Expand Up @@ -260,8 +261,9 @@ This project includes a `Makefile` with commands for creating a virtual environm
You will need `hatch` and `pre-commit` for this.
You can get these by using

```
pipx install hatch==1.15.1 pre-commit
```bash
# Most recently tested with hatch 1.17.0
pipx install hatch pre-commit
```

If you're not familiar with pipx, it lets you install python tools into isolated environments in `~/.local`.
Expand Down
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Once your device works correctly:

1. Create a branch: `git checkout -b add-device-<name>`
2. Add your device entry to `devices.toml`
3. Test thoroughly with the examples in `examples/`
3. Test thoroughly with the examples in `examples/`. If you add a new example, update the README and `docs/mouseApi/examples.md`.
4. Submit a PR with your device name and any notes about testing

### Using Custom Configuration (Without Modifying Library)
Expand Down
10 changes: 6 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device:
```

<p align="center">
<img src="./assets/hid_axes.svg" alt="Raw HID axis convention" width="220">
<img src="./assets/hid_z_up_axes.svg" alt="HID Z-up axis convention" width="220">
<img src="./assets/hid_axes.svg" alt="Raw HID axis convention" width="220">
<img src="./assets/legacy_axis.svg" alt="Legacy PySpaceMouse axis convention" width="220">
</p>

Expand Down Expand Up @@ -225,7 +225,8 @@ See the [examples/](https://github.com/JakubAndrysek/PySpaceMouse/tree/master/ex
| `06_axis_callbacks.py` | Per-axis callbacks with filtering |
| `07_led.py` | LED control |
| `08_buttons.py` | Button names and handling |
| `09_custom_config.py` | Custom axis mappings |
| `09_invert_rotations.py` | Invert rotations |
| `10_custom_config_unity.py` | A totally custom device config using the Unity axis convention |

## Dependencies

Expand Down Expand Up @@ -260,8 +261,9 @@ This project includes a `Makefile` with commands for creating a virtual environm
You will need `hatch` and `pre-commit` for this.
You can get these by using

```
pipx install hatch==1.15.1 pre-commit
```bash
# Most recently tested with hatch 1.17.0
pipx install hatch pre-commit
```

If you're not familiar with pipx, it lets you install python tools into isolated environments in `~/.local`.
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/hid_axes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/assets/hid_z_up_axes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/assets/legacy_axis.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
135 changes: 70 additions & 65 deletions docs/mouseApi/examples.md
Original file line number Diff line number Diff line change
@@ -1,96 +1,101 @@
# Examples

## 01. Basic

## Basic usage
[basicExample.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/basicExample.py)
````py
import pyspacemouse
import time
- File: [01_basic.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/01_basic.py)
- Summary: Basic example: Read SpaceMouse input with context manager.
- Run: `python examples/01_basic.py`

success = pyspacemouse.open()
if success:
while 1:
state = pyspacemouse.read()
print(state.x, state.y, state.z)
time.sleep(0.01)
````
```py title="examples/01_basic.py"
--8<-- "examples/01_basic.py"
```

## 02. Callbacks

## Usage with callback
[callbackExample.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/callbackExample.py)
````py
import pyspacemouse
import time
- File: [02_callbacks.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/02_callbacks.py)
- Summary: Callbacks example: React to button presses and axis movements.
- Run: `python examples/02_callbacks.py`

```py title="examples/02_callbacks.py"
--8<-- "examples/02_callbacks.py"
```

def button_0(state, buttons, pressed_buttons):
print("Button:", pressed_buttons)
## 03. Multi Device

- File: [03_multi_device.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/03_multi_device.py)
- Summary: Multi-device example: Connect to multiple SpaceMouse devices.
- Run: `python examples/03_multi_device.py`

def button_0_1(state, buttons, pressed_buttons):
print("Buttons:", pressed_buttons)
```py title="examples/03_multi_device.py"
--8<-- "examples/03_multi_device.py"
```

## 04. Open By Path

def someButton(state, buttons):
print("Some button")
- File: [04_open_by_path.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/04_open_by_path.py)
- Summary: Open by path example: Connect to a specific HID device by filesystem path.
- Run: `python examples/04_open_by_path.py`

```py title="examples/04_open_by_path.py"
--8<-- "examples/04_open_by_path.py"
```

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), ]
## 05. Discovery

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)
- File: [05_discovery.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/05_discovery.py)
- Summary: Device discovery example: List and inspect available devices.
- Run: `python examples/05_discovery.py`

```py title="examples/05_discovery.py"
--8<-- "examples/05_discovery.py"
```

if __name__ == '__main__':
callback()
````
## 06. Axis Callbacks

- File: [06_axis_callbacks.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/06_axis_callbacks.py)
- Summary: Axis callbacks example: React to specific axis movements.
- Run: `python examples/06_axis_callbacks.py`

### Callback: print_state
```py title="examples/06_axis_callbacks.py"
--8<-- "examples/06_axis_callbacks.py"
```

Print all axis states
## 07. Led

x +0.00 y +0.00 z +0.00 roll +0.00 pitch +0.00 yaw +0.00 t +0.0
- File: [07_led.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/07_led.py)
- Summary: LED control example: Blink the SpaceMouse LED.
- Run: `python examples/07_led.py`

### Callback: print_buttons
```py title="examples/07_led.py"
--8<-- "examples/07_led.py"
```

Print all buttons states
## 08. Buttons

[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]
- File: [08_buttons.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/08_buttons.py)
- Summary: Button names example: Show button names when pressed.
- Run: `python examples/08_buttons.py`

```py title="examples/08_buttons.py"
--8<-- "examples/08_buttons.py"
```

## Custom Device Configuration
## 09. Invert Rotations

[09_custom_config.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/09_custom_config.py)
- File: [09_invert_rotations.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/09_invert_rotations.py)
- Summary: Example: Invert rotation axes
- Run: `python examples/09_invert_rotations.py`

Customize axis mappings for different coordinate conventions (ROS, OpenGL, etc.):
```py title="examples/09_invert_rotations.py"
--8<-- "examples/09_invert_rotations.py"
```

````py
import pyspacemouse
## 10. Custom Config Unity

# Get existing device spec and modify it
specs = pyspacemouse.get_device_specs()
base = specs["SpaceNavigator"]
- File: [10_custom_config_unity.py](https://github.com/JakubAndrysek/PySpaceMouse/blob/master/examples/10_custom_config_unity.py)
- Summary: Example: Custom device configuration with axis remapping.
- Run: `python examples/10_custom_config_unity.py`

# 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}")
````

See also: `create_device_info()` for creating completely custom device specs.
```py title="examples/10_custom_config_unity.py"
--8<-- "examples/10_custom_config_unity.py"
```
3 changes: 2 additions & 1 deletion examples/01_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
"""

import pyspacemouse
from pyspacemouse import AxisConvention

# Using context manager (recommended)
with pyspacemouse.open() as device:
with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device:
print(f"Connected to: {device.name}")
print("Move the SpaceMouse to see values (Ctrl+C to exit)")

Expand Down
2 changes: 2 additions & 0 deletions examples/02_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import time

import pyspacemouse
from pyspacemouse import AxisConvention


# Button callbacks receive (state, buttons, pressed_buttons)
Expand Down Expand Up @@ -39,6 +40,7 @@ def on_any_button(state, buttons):

# Open with callbacks
with pyspacemouse.open(
axis_convention=AxisConvention.HID_Z_UP,
dof_callback=pyspacemouse.print_state, # Built-in DOF printer
button_callback=on_any_button,
button_callbacks=button_callbacks,
Expand Down
7 changes: 5 additions & 2 deletions examples/03_multi_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import time

import pyspacemouse
from pyspacemouse import AxisConvention


def main():
Expand All @@ -24,8 +25,10 @@ def main():
path1 = list(connected.keys())[1]

# Open two devices by path
with pyspacemouse.open_by_path(path0) as left_hand:
with pyspacemouse.open_by_path(path1) as right_hand:
with pyspacemouse.open_by_path(path0, axis_convention=AxisConvention.HID_Z_UP) as left_hand:
with pyspacemouse.open_by_path(
path1, axis_convention=AxisConvention.HID_Z_UP
) as right_hand:
print(f"Left hand: {left_hand.name}")
print(f"Right hand: {right_hand.name}")
print()
Expand Down
6 changes: 5 additions & 1 deletion examples/04_open_by_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

import pyspacemouse
from pyspacemouse import AxisConvention


def main():
Expand All @@ -25,7 +26,10 @@ def main():
device_path = "/dev/hidraw0"

try:
with pyspacemouse.open_by_path(device_path) as device:
with pyspacemouse.open_by_path(
device_path,
axis_convention=AxisConvention.HID_Z_UP,
) as device:
print(f"Connected to: {device.name} at {device_path}")
print("Move the device (Ctrl+C to exit)")
print()
Expand Down
6 changes: 5 additions & 1 deletion examples/06_axis_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import time

import pyspacemouse
from pyspacemouse import AxisConvention


def on_x_positive(state, value):
Expand Down Expand Up @@ -46,7 +47,10 @@ def on_z_move(state, value):
),
]

with pyspacemouse.open(dof_callbacks=dof_callbacks) as device:
with pyspacemouse.open(
dof_callbacks=dof_callbacks,
axis_convention=AxisConvention.HID_Z_UP,
) as device:
print(f"Connected to: {device.name}")
print("Move X axis (left/right) or Z axis (up/down)")
print("Ctrl+C to exit")
Expand Down
3 changes: 2 additions & 1 deletion examples/07_led.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import time

import pyspacemouse
from pyspacemouse import AxisConvention

# Using context manager (recommended)
with pyspacemouse.open() as device:
with pyspacemouse.open(axis_convention=AxisConvention.HID_Z_UP) as device:
print(f"Connected to: {device.name}")
print("LED will blink every 0.5 seconds (Ctrl+C to exit)")
print()
Expand Down
6 changes: 5 additions & 1 deletion examples/08_buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import time

import pyspacemouse
from pyspacemouse import AxisConvention


def on_button_change(state, buttons):
Expand All @@ -21,7 +22,10 @@ def on_button_change(state, buttons):


# Open device
with pyspacemouse.open(button_callback=on_button_change) as device:
with pyspacemouse.open(
button_callback=on_button_change,
axis_convention=AxisConvention.HID_Z_UP,
) as device:
print(f"Connected to: {device.name}")
print(f"Device has {len(device.info.button_names)} buttons:")
for i, name in enumerate(device.info.button_names):
Expand Down
Loading
Loading