# PiController
This is a project to connect a nintendo pro controller to a raspberry pi.
I initially did this with pygame [here](https://github.com/PreciousFood/pro_controller), but this is better suited for the pi. That project is multiplatform though, whereas this makes use of evdev, which is only available on linux.
# Documentation
## Overview
The `ProController` module provides an abstraction for interfacing with a Nintendo Switch Pro Controller via the `evdev` library in Python. It includes classes and utilities for handling buttons, joysticks, and events, as well as support for vibration feedback.
---
## Table of Contents
1. [Installation](#installation)
2. [Classes](#classes)
- [ProController](#1-procontroller)
- [RawJoystick](#2-rawjoystick)
- [Joystick](#3-joystick)
- [Key](#1-key)
3. [Additional Functions](#additional-functions)
4. [Usage](#usage)
5. [Examples](#examples)
6. [Requirements](#requirements)
---
## Installation
1. Install the python development headers, a dependency for evdev, the one and only dependency of this library.
```bash
sudo apt install python3-dev
```
2. Install pi_controller (inside a virtual environment is recomended)
```bash
pip install pi_controller
```
or clone from github
```bash
git clone https://github.com/PreciousFood/pi_controller.git
```
## Classes
### 1. `ProController`
Represents the Nintendo Switch Pro Controller. Handles button and joystick inputs, event processing, and vibration feedback.
#### Initialization:
```python
ProController(index: int, check_controller: bool = True, min_pause_time: float = 0)
```
- `index`: Index of the controller in the list of devices. See [list_devices](#1-list_devices) to figure out what the correct index is.
- `check_controller`: If `True`, validates the controller as a Pro Controller.
- `min_pause_time`: Minimum time between event loops.
#### Attributes:
- `BUTTONS`: Tuple of button names.
- `JOYSTICKS`: Tuple of joystick names.
- `buttons`: List of `Key` objects representing controller buttons.
- `raw_joysticks`: List of `RawJoystick` objects for joystick axes.
- `joysticks`: List of `Joystick` objects for grouped joystick axes.
#### Methods:
- `run()`: Starts the event loop to process input.
- `stop()`: Stops the event loop.
- `button_from_code(code: int) -> Key`: Maps a hardware code to a `Key`.
- `raw_joystick_from_code(code: int) -> RawJoystick`: Maps a hardware code to a `RawJoystick`.
#### Event Handlers:
- `on_key_press(func: Callable[[Key], None])`: Adds a callback for button press events.
- `on_key_release(func: Callable[[Key], None])`: Adds a callback for button release events.
- `on_v_key_press(key: str)`: Adds a callback for a specific button press.
- `on_v_key_release(key: str)`: Adds a callback for a specific button release.
- `on_every_loop(func: Callable)`: Adds a callback for every event loop iteration.
- `on_abs_event(func: Callable[[RawJoystick, int], None])`: Adds a callback for joystick movement events.
- `on_v_abs_event(joystick: str)`: Adds a callback for a specific joystick movement.
#### Vibration:
> Experimental feature, not fully implemented yet
- `rumble(duration: int, strong: int, weak: int, repeat: int = 1)`: Triggers vibration feedback.
#### Properties:
- Button aliases (`a`, `b`, `x`, etc.).
- Joystick aliases (`left_joystick`, `right_joystick`, `dpad).
- D-pad directional properties (`dpad_up`, `dpad_down`, etc.).
>Note: Because of how evdev handles the dpad, it is technically a joystick with values of -1, 0, or 1. The D-pad directional properties handle this to be a simple bool
---
### 2. `RawJoystick`
Represents a raw axis of a joystick.
#### Attributes:
- `name` (str): Name of the axis.
- `code` (int): Hardware code for the axis.
- `value` (int): Current raw value of the axis.
- `max_val` (int): Maximum possible value for the axis.
#### Properties:
- `p_val` (float): Normalized value of the axis (`value / max_val`).
#### Methods:
- `__str__()`: Returns the name of the axis.
---
### 3. `Joystick`
Represents a joystick with two axes (X and Y).
#### Attributes:
- `name` (str): Name of the joystick.
- `x` (`RawJoystick`): X-axis of the joystick.
- `y` (`RawJoystick`): Y-axis of the joystick.
#### Properties:
- `value` (tuple[int, int]): Tuple of raw X and Y values.
- `p_val` (tuple[float, float]): Tuple of normalized X and Y values.
#### Methods:
- `__str__()`: Returns the joystick name.
---
### 1. `Key`
Represents a single button on the controller.
#### Attributes:
- `name` (str): Name of the button.
- `code` (int): Hardware code for the button.
- `pressed` (bool): State of the button (`True` if pressed, `False` otherwise).
#### Methods:
- `__str__()`: Returns the name of the button and whether it is pressed.
- `__bool__()`: Returns the `pressed` state.
## Additional Functions
### 1. list_devices
Lists the names of all available devices, the index of the device you want is the index to pass to `ProController`.
Returns a list of strings.
## Usage
1. **Initialize the Controller:**
```python
from pro_controller import ProController
pro = ProController(index=0)
```
2. **Register Event Handlers:**
```python
@pro.on_key_press
def on_button_press(key):
print(f"{key} pressed")
```
3. **Start the Event Loop:**
```python
pro.run()
```
4. **Stop the Controller:**
```python
pro.stop()
```
---
## Examples
### Button Press Example:
```python
pro = ProController(0)
@pro.on_key_press
def handle_press(button):
print(f"Button {button.name} was pressed!")
pro.run()
```
### Joystick Movement Example:
```python
pro = ProController(0)
@pro.on_abs_event
def handle_joystick(joystick, value):
print(f"{joystick.name} moved to {value}")
pro.run()
```
Raw data
{
"_id": null,
"home_page": null,
"name": "pi-controller",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "pi, raspberry pi, controller, pro controller",
"author": "PreciousFood",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/f2/0f/ef8ba98166050f34492cc3a3aa66bb4c44f120ef808f5885b67ecbb9e413/pi_controller-1.0.0.tar.gz",
"platform": null,
"description": "# PiController\nThis is a project to connect a nintendo pro controller to a raspberry pi. \nI initially did this with pygame [here](https://github.com/PreciousFood/pro_controller), but this is better suited for the pi. That project is multiplatform though, whereas this makes use of evdev, which is only available on linux. \n\n# Documentation\n\n## Overview\n\nThe `ProController` module provides an abstraction for interfacing with a Nintendo Switch Pro Controller via the `evdev` library in Python. It includes classes and utilities for handling buttons, joysticks, and events, as well as support for vibration feedback.\n\n---\n\n## Table of Contents\n\n1. [Installation](#installation)\n2. [Classes](#classes)\n - [ProController](#1-procontroller)\n - [RawJoystick](#2-rawjoystick)\n - [Joystick](#3-joystick)\n - [Key](#1-key)\n3. [Additional Functions](#additional-functions)\n4. [Usage](#usage)\n5. [Examples](#examples)\n6. [Requirements](#requirements)\n\n---\n\n## Installation\n\n1. Install the python development headers, a dependency for evdev, the one and only dependency of this library.\n ```bash\n sudo apt install python3-dev\n ```\n2. Install pi_controller (inside a virtual environment is recomended)\n ```bash\n pip install pi_controller\n ```\n or clone from github\n ```bash\n git clone https://github.com/PreciousFood/pi_controller.git\n ```\n\n## Classes\n\n### 1. `ProController`\nRepresents the Nintendo Switch Pro Controller. Handles button and joystick inputs, event processing, and vibration feedback.\n\n#### Initialization:\n```python\nProController(index: int, check_controller: bool = True, min_pause_time: float = 0)\n```\n\n- `index`: Index of the controller in the list of devices. See [list_devices](#1-list_devices) to figure out what the correct index is.\n- `check_controller`: If `True`, validates the controller as a Pro Controller.\n- `min_pause_time`: Minimum time between event loops.\n\n#### Attributes:\n- `BUTTONS`: Tuple of button names.\n- `JOYSTICKS`: Tuple of joystick names.\n- `buttons`: List of `Key` objects representing controller buttons.\n- `raw_joysticks`: List of `RawJoystick` objects for joystick axes.\n- `joysticks`: List of `Joystick` objects for grouped joystick axes.\n\n#### Methods:\n- `run()`: Starts the event loop to process input.\n- `stop()`: Stops the event loop.\n- `button_from_code(code: int) -> Key`: Maps a hardware code to a `Key`.\n- `raw_joystick_from_code(code: int) -> RawJoystick`: Maps a hardware code to a `RawJoystick`.\n\n#### Event Handlers:\n- `on_key_press(func: Callable[[Key], None])`: Adds a callback for button press events.\n- `on_key_release(func: Callable[[Key], None])`: Adds a callback for button release events.\n- `on_v_key_press(key: str)`: Adds a callback for a specific button press.\n- `on_v_key_release(key: str)`: Adds a callback for a specific button release.\n- `on_every_loop(func: Callable)`: Adds a callback for every event loop iteration.\n- `on_abs_event(func: Callable[[RawJoystick, int], None])`: Adds a callback for joystick movement events.\n- `on_v_abs_event(joystick: str)`: Adds a callback for a specific joystick movement.\n\n#### Vibration:\n> Experimental feature, not fully implemented yet\n- `rumble(duration: int, strong: int, weak: int, repeat: int = 1)`: Triggers vibration feedback.\n\n#### Properties:\n- Button aliases (`a`, `b`, `x`, etc.).\n- Joystick aliases (`left_joystick`, `right_joystick`, `dpad).\n- D-pad directional properties (`dpad_up`, `dpad_down`, etc.).\n>Note: Because of how evdev handles the dpad, it is technically a joystick with values of -1, 0, or 1. The D-pad directional properties handle this to be a simple bool\n\n---\n\n### 2. `RawJoystick`\nRepresents a raw axis of a joystick.\n\n#### Attributes:\n- `name` (str): Name of the axis.\n- `code` (int): Hardware code for the axis.\n- `value` (int): Current raw value of the axis.\n- `max_val` (int): Maximum possible value for the axis.\n\n#### Properties:\n- `p_val` (float): Normalized value of the axis (`value / max_val`).\n\n#### Methods:\n- `__str__()`: Returns the name of the axis.\n\n---\n\n### 3. `Joystick`\nRepresents a joystick with two axes (X and Y).\n\n#### Attributes:\n- `name` (str): Name of the joystick.\n- `x` (`RawJoystick`): X-axis of the joystick.\n- `y` (`RawJoystick`): Y-axis of the joystick.\n\n#### Properties:\n- `value` (tuple[int, int]): Tuple of raw X and Y values.\n- `p_val` (tuple[float, float]): Tuple of normalized X and Y values.\n\n#### Methods:\n- `__str__()`: Returns the joystick name.\n\n---\n\n### 1. `Key`\nRepresents a single button on the controller.\n\n#### Attributes:\n- `name` (str): Name of the button.\n- `code` (int): Hardware code for the button.\n- `pressed` (bool): State of the button (`True` if pressed, `False` otherwise).\n\n#### Methods:\n- `__str__()`: Returns the name of the button and whether it is pressed.\n- `__bool__()`: Returns the `pressed` state.\n\n\n## Additional Functions\n\n### 1. list_devices\nLists the names of all available devices, the index of the device you want is the index to pass to `ProController`.\n\nReturns a list of strings.\n\n## Usage\n\n1. **Initialize the Controller:**\n ```python\n from pro_controller import ProController\n\n pro = ProController(index=0)\n ```\n\n2. **Register Event Handlers:**\n ```python\n @pro.on_key_press\n def on_button_press(key):\n print(f\"{key} pressed\")\n ```\n\n3. **Start the Event Loop:**\n ```python\n pro.run()\n ```\n\n4. **Stop the Controller:**\n ```python\n pro.stop()\n ```\n\n---\n\n## Examples\n\n### Button Press Example:\n```python\npro = ProController(0)\n\n@pro.on_key_press\ndef handle_press(button):\n print(f\"Button {button.name} was pressed!\")\n\npro.run()\n```\n\n### Joystick Movement Example:\n```python\npro = ProController(0)\n\n@pro.on_abs_event\ndef handle_joystick(joystick, value):\n print(f\"{joystick.name} moved to {value}\")\n\npro.run()\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "A library for nintendo switch pro controller support with raspberry pi.",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/PreciousFood/pi_controller"
},
"split_keywords": [
"pi",
" raspberry pi",
" controller",
" pro controller"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "2192dd5395b56a3ca9033e511c5128af339e32838194bb9317673429e306d4c7",
"md5": "c74d55bed8f1f7f6d7126b63e04e83b2",
"sha256": "5c8f3daa6e62e39594896956274da2999c3dc01549e04eeb429bc5b163b775d0"
},
"downloads": -1,
"filename": "pi_controller-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c74d55bed8f1f7f6d7126b63e04e83b2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 6965,
"upload_time": "2025-01-08T19:34:47",
"upload_time_iso_8601": "2025-01-08T19:34:47.205252Z",
"url": "https://files.pythonhosted.org/packages/21/92/dd5395b56a3ca9033e511c5128af339e32838194bb9317673429e306d4c7/pi_controller-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f20fef8ba98166050f34492cc3a3aa66bb4c44f120ef808f5885b67ecbb9e413",
"md5": "e001802faf5a258f4f2cfd653915a034",
"sha256": "28e70815537a5890343d58efaa38ff35c0f2aa51250c315f6187f70fbaac0b4d"
},
"downloads": -1,
"filename": "pi_controller-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "e001802faf5a258f4f2cfd653915a034",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 7037,
"upload_time": "2025-01-08T19:34:49",
"upload_time_iso_8601": "2025-01-08T19:34:49.560647Z",
"url": "https://files.pythonhosted.org/packages/f2/0f/ef8ba98166050f34492cc3a3aa66bb4c44f120ef808f5885b67ecbb9e413/pi_controller-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-08 19:34:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "PreciousFood",
"github_project": "pi_controller",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "evdev",
"specs": []
}
],
"lcname": "pi-controller"
}