Skip to content

Commit

Permalink
Merge pull request #1 from Rambomst/add-config-file
Browse files Browse the repository at this point in the history
Update script to support a config file
  • Loading branch information
RoarkGit authored Jul 18, 2024
2 parents 08d0ee4 + 673492a commit 26b3ad4
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 23 deletions.
92 changes: 86 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Stream Deck Pedal.

There aren't a lot of dependencies, but what you do need are:
- Python
- hidapi
- evdev
- hidapi (https://pypi.org/project/hidapi/)
- evdev (https://pypi.org/project/evdev/)

## How it works

Expand All @@ -19,11 +19,93 @@ one for each button on the pedal, and then run the program. The program then
listens for button presses and sends the mapped keys to `/dev/uinput`.

Run the Python script and press your pedal. You can run it as a `systemd` unit
or equivalent to have it always running in the background.
or equivalent to have it always running in the background. Refer to the "Running as a systemd Service" section for instructions on how to set it up.


You can find a list of all possible keycodes
[here](https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h).

## Configuration

The program now supports reading configuration from JSON files. There are two configuration files:
- `config.default.json`: This file contains the default key mappings and settings.
- `config.json`: This file is optional and can be used to override the default settings with user-specific values.

### Configuration File Format

The config.json file should have the same format as the config.default.json and can be used to specify custom key mappings. For example:
```json
{
"left_keys": [
{
"mods": [],
"keys": ["KEY_F24"]
}
],
"middle_keys": [
{
"mods": ["KEY_RIGHTSHIFT"],
"keys": ["KEY_F24"]
}
],
"right_keys": [
{
"keys": ["KEY_F24"]
}
]
}
```

### How It Works

The program first loads the settings from config.default.json and then overwrites those settings with any values found in config.json. This allows you to maintain a base configuration while making specific customizations as needed.

## Running as a systemd Service

To run this program as a `systemd` service, you can create a service file with the following content:

1. **Create the Service File**:
```
sudo vim /etc/systemd/system/pedalmapper.service
```

2. **Add the Following Content**:
```
[Unit]
Description=Pedal Mapper Startup
After=network.target
[Service]
Type=simple
WorkingDirectory=/working/directory/Pedal-Mapper
ExecStart=/usr/bin/python3 /working/directory/Pedal-Mapper/pedal_mapper.py
User=root
Restart=on-failure
[Install]
WantedBy=multi-user.target
```

3. **Reload the systemd Daemon**:
```
sudo systemctl daemon-reload
```

4. **Enable the Service**:
```
sudo systemctl enable pedalmapper.service
```

5. **Start the Service**:
```
sudo systemctl start pedalmapper.service
```

6. **Check the Status**:
```
sudo systemctl status pedalmapper.service
```

## Possible issues

If you're using Wayland it won't work if your voice chat client isn't focused.
Expand All @@ -41,8 +123,6 @@ never know.
This was just my first pass at implementing this specifically for my needs. The
code sucks, is basic as hell, and isn't very configurable. In no particular
order, things that I may implement in the future if I feel inspired are:
- Reading configuration from a file rather than being hardcoded into the
program.
- Configuring other types of devices.
[input-remapper](https://github.com/sezanzeb/input-remapper) is already a good
general purpose solution, but it's possible there are unsupported devices for
Expand All @@ -61,4 +141,4 @@ but they're here as ideas in case anyone else wants to contribute.
## Contributing

Feel free to submit merge requests. I'm not too scary and would happily accept
contributions.
contributions.
16 changes: 16 additions & 0 deletions config.default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"left_keys": [],
"middle_keys": [
{
"mods": ["KEY_RIGHTMETA"],
"keys": ["KEY_F13"]
}
],
"right_keys": [
{
"mods": ["KEY_RIGHTSHIFT", "KEY_RIGHTMETA"],
"keys": ["KEY_F13"]
}
],
"polling_rate": 10
}
50 changes: 33 additions & 17 deletions pedal_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,31 @@
from enum import Enum
from evdev import UInput, ecodes as e
import hid
import json

# Elgato Stream Deck Pedal Vendor / Product IDs
VENDOR_ID = 0x0FD9
PRODUCT_ID = 0x0086


# Represents a key combination of mods, which are held for the whole
# combination, and keys, which are pressed and released.
KeyCombo = namedtuple("KeyCombo", ["mods", "keys"], defaults=([], []))


# Simple enum that represents the three buttons.
class Button(Enum):
LEFT = 0
MIDDLE = 1
RIGHT = 2


class PedalMapper:
def __init__(self, left_keys=[], middle_keys=[], right_keys=[], polling_rate=10):
self.button_key_mappings = (left_keys, middle_keys, right_keys)
def __init__(self, config):
self.button_key_mappings = (
self.parse_key_combos(config.get("left_keys", [])),
self.parse_key_combos(config.get("middle_keys", [])),
self.parse_key_combos(config.get("right_keys", []))
)
self.button_state = [False, False, False]
self.polling_rate = polling_rate
self.polling_rate = config.get("polling_rate", 10)
self.dev = hid.device()
self.dev.open(VENDOR_ID, PRODUCT_ID)
self.dev.set_nonblocking(1)
Expand All @@ -38,6 +40,14 @@ def __init__(self, left_keys=[], middle_keys=[], right_keys=[], polling_rate=10)
cap = {e.EV_KEY: reg_keys}
self.ui = UInput(cap, name="Pedal Mapper Virtual Input")

def parse_key_combos(self, key_combos):
parsed_combos = []
for combo in key_combos:
mods = [getattr(e, mod) for mod in combo.get("mods", [])]
keys = [getattr(e, key) for key in combo["keys"]]
parsed_combos.append(KeyCombo(mods, keys))
return parsed_combos

def get_event(self):
# We're non-blocking, so wait for a poll. This could just be changed to
# blocking instead without issues, but it is non-blocking in case it's
Expand Down Expand Up @@ -78,22 +88,28 @@ def write_key(self, key, state):
self.ui.write(e.EV_KEY, key, state)
self.ui.syn()

def load_config(default_path="config.default.json", user_path="config.json"):
with open(default_path, "r") as f:
config = json.load(f)

try:
with open(user_path, "r") as f:
user_config = json.load(f)
config.update(user_config)
except FileNotFoundError:
pass

return config

if __name__ == "__main__":
# Load the config
config = load_config()

# Create Pedal
# Example mappings:
# Left: no-op
# Middle: right meta + F13
# Right: shift + right meta + F13
pm = PedalMapper(
middle_keys=[KeyCombo(mods=[e.KEY_RIGHTMETA], keys=[e.KEY_F13])],
right_keys=[
KeyCombo(mods=[e.KEY_RIGHTSHIFT, e.KEY_RIGHTMETA], keys=[e.KEY_F13])
],
)
pm = PedalMapper(config)

# Loop to get events and handle them accordingly.
while True:
ev = pm.get_event()
if ev:
pm.handle_key(ev[0], ev[1])
pm.handle_key(ev[0], ev[1])

0 comments on commit 26b3ad4

Please sign in to comment.