Support multiple configuration profiles. (#8)

Adds a `--config` command-line option to specify a config directory.

Reviewed-on: #8
Co-authored-by: Anna Rose Wiggins <annabunches@gmail.com>
Co-committed-by: Anna Rose Wiggins <annabunches@gmail.com>
This commit is contained in:
Anna Rose Wiggins 2025-07-18 18:28:11 +00:00 committed by Anna Rose Wiggins
parent 238faa9082
commit 5b9dfe0967
2 changed files with 35 additions and 22 deletions

View file

@ -1,9 +1,10 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"os" "os"
"path/filepath" "strings"
"sync" "sync"
"git.annabunches.net/annabunches/joyful/internal/config" "git.annabunches.net/annabunches/joyful/internal/config"
@ -13,12 +14,17 @@ import (
"github.com/holoplot/go-evdev" "github.com/holoplot/go-evdev"
) )
func readConfig() *config.ConfigParser { func getConfigDir() string {
configFlag := flag.String("config", "~/.config/joyful", "Directory to read configuration from.")
flag.Parse()
configDir := strings.ReplaceAll(*configFlag, "~", "${HOME}")
return os.ExpandEnv(configDir)
}
func readConfig(configDir string) *config.ConfigParser {
parser := &config.ConfigParser{} parser := &config.ConfigParser{}
homeDir, err := os.UserHomeDir() err := parser.Parse(configDir)
logger.FatalIfError(err, "Can't get user home directory, so can't find configuration.") logger.FatalIfError(err, "Failed to parse config")
err = parser.Parse(filepath.Join(homeDir, ".config/joyful"))
logger.FatalIfError(err, "")
return parser return parser
} }
@ -56,7 +62,8 @@ func initPhysicalDevices(config *config.ConfigParser) map[string]*evdev.InputDev
func main() { func main() {
// parse configs // parse configs
config := readConfig() configDir := getConfigDir()
config := readConfig(configDir)
// Initialize virtual devices with event buffers // Initialize virtual devices with event buffers
vBuffersByName, vBuffersByDevice := initVirtualBuffers(config) vBuffersByName, vBuffersByDevice := initVirtualBuffers(config)
@ -112,8 +119,9 @@ func main() {
fmt.Println("Waiting for existing listeners to exit. Provide input from each of your devices.") fmt.Println("Waiting for existing listeners to exit. Provide input from each of your devices.")
wg.Wait() wg.Wait()
fmt.Println("Listeners exited. Parsing config.") fmt.Println("Listeners exited. Parsing config.")
config := readConfig() // reload the config config := readConfig(configDir) // reload the config
rules, eventChannel, doneChannel, wg = loadRules(config, pDevices, getVirtualDevices(vBuffersByName)) rules, eventChannel, doneChannel, wg = loadRules(config, pDevices, getVirtualDevices(vBuffersByName))
fmt.Println("Config re-loaded. Only rule changes applied. Device and Mode changes require restart.")
} }
} }
} }

View file

@ -8,26 +8,27 @@ Joyful is ideal for Linux gamers who enjoy space and flight sims and miss the fe
## Features ## Features
### Current Features - try them today! ### Current Features
* Create virtual devices with up to 8 axes and 56 buttons. * Create virtual devices with up to 8 axes and 74 buttons.
* Make simple 1:1 mappings of buttons and axes: Button1 -> VirtualButtonA * Flexible rule system that allows several different types of rules, including:
* Make combination mappings: Button1 + Button2 -> VirtualButtonA * Simple 1:1 mappings of buttons and axes: Button1 -> VirtualButtonA
* Define multiple modes with per-mode behavior. * Combination mappings: Button1 + Button2 -> VirtualButtonA
* "Split" axis mapping: map sections of an axis to different outputs. * "Split" axis mapping: map sections of an axis to different outputs using deadzones.
* Configure per-mapping configurable deadzones for axes.
* Axis -> button mapping with optional "proportional" repeat speed (i.e. repeat faster as the axis is engaged further) * Axis -> button mapping with optional "proportional" repeat speed (i.e. repeat faster as the axis is engaged further)
* Axis -> Relative Axis mapping, for converting a joystick axis to mouse movement and scrollwheel events. * Axis -> Relative Axis mapping, for converting a joystick axis to mouse movement and scrollwheel events.
* Define multiple modes with per-mode behavior.
* Configure per-rule configurable deadzones for axes.
### Future Features - try them at an unspecified point in the future! ### Possible Future Features
* Macros - have a single input produce a sequence of button presses with configurable pauses. * Macros - have a single input produce a sequence of button presses with configurable pauses.
* Sequence combos - Button1, Button2, Button3 -> VirtualButtonA * Sequence combos - Button1, Button2, Button3 -> VirtualButtonA
* Output keyboard button presses * Output keyboard button presses
* Explicit input and output from gamepad-like devices. * Hat support
* HIDRAW support for more button options. * HIDRAW support for more button options.
* Specify different config directories for multiple sets of mappings. * Percentage-based deadzones.
* Positional and percentage-based deadzones. * Sensitivity Curves.
## Configuration ## Configuration
@ -37,11 +38,15 @@ A configuration guide and examples can be found in the `docs/` directory.
Configuration can be fairly complicated and repetitive. If anyone wants to create a graphical interface to configure Joyful, we would love to link to it here. Configuration can be fairly complicated and repetitive. If anyone wants to create a graphical interface to configure Joyful, we would love to link to it here.
## Usage
After building (see below) and writing your configuration (see above), just run `joyful`. (Feel free to move this somewhere in your path. You can use `--config <directory>` to specify different configuration profiles.
## Technical details ## Technical details
Joyful is written in golang, and uses evdev/uinput to manage devices. Joyful is written in golang, and uses evdev/uinput to manage devices.
### Building ### Build & Install
To build joyful, install `go` via your package manager, then run: To build joyful, install `go` via your package manager, then run:
@ -49,7 +54,7 @@ To build joyful, install `go` via your package manager, then run:
CGO_ENABLED=0 go build -o build/ ./... CGO_ENABLED=0 go build -o build/ ./...
``` ```
Look for binaries in the `build/` directory. Copy the binaries in the `build/` directory to somewhere in your `$PATH`. (details depend on your setup, but typically somewhere like `/usr/local/bin` or `~/bin`)
### Contributing ### Contributing