Merge pull request #1 from WoodardDigital/Dotfiles-installation
Dotfiles installation
This commit is contained in:
21
Makefile
21
Makefile
@@ -22,23 +22,10 @@ build-helper:
|
|||||||
|
|
||||||
# ── Install ───────────────────────────────────────────────────────────────────
|
# ── Install ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
install: build udev _install-user
|
# Interactive install — prompts for dotfiles directory, creates symlink,
|
||||||
@echo ""
|
# installs binary + udev rule + systemd user service.
|
||||||
@echo "Done. Edit $(CONFIG_DIR)/config.yaml to configure your keys."
|
install:
|
||||||
@echo "To enable privileged commands (suspend, reboot, etc): make install-helper"
|
@bash install.sh
|
||||||
|
|
||||||
_install-user:
|
|
||||||
install -Dm755 $(BINARY) $(BIN_DIR)/$(BINARY)
|
|
||||||
mkdir -p $(CONFIG_DIR)/icons
|
|
||||||
@if [ ! -f $(CONFIG_DIR)/config.yaml ]; then \
|
|
||||||
install -Dm644 config.example.yaml $(CONFIG_DIR)/config.yaml; \
|
|
||||||
echo "Default config written to $(CONFIG_DIR)/config.yaml"; \
|
|
||||||
else \
|
|
||||||
echo "Config already exists — not overwriting"; \
|
|
||||||
fi
|
|
||||||
install -Dm644 systemd/streamdeck-go.service $(SYSTEMD_USER)/streamdeck-go.service
|
|
||||||
systemctl --user daemon-reload
|
|
||||||
systemctl --user enable --now streamdeck-go.service
|
|
||||||
|
|
||||||
# Install the privileged helper (requires sudo).
|
# Install the privileged helper (requires sudo).
|
||||||
# Creates a 'streamdeck' group, adds the current user to it, installs the
|
# Creates a 'streamdeck' group, adds the current user to it, installs the
|
||||||
|
|||||||
55
README.md
55
README.md
@@ -98,8 +98,8 @@ interleave partial image data across keys.
|
|||||||
|
|
||||||
### Option A — `make install` (recommended)
|
### Option A — `make install` (recommended)
|
||||||
|
|
||||||
Builds the binary, installs the systemd user service, and writes a default config
|
An interactive installer that handles everything, including optional dotfiles
|
||||||
if one doesn't already exist.
|
directory integration.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
@@ -110,22 +110,55 @@ cd streamdeck-go
|
|||||||
make install
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
`make install` does the following automatically:
|
The installer walks you through the whole setup:
|
||||||
|
|
||||||
1. Installs the udev rule (`/etc/udev/rules.d/99-streamdeck.rules`) so the device is accessible without root
|
```
|
||||||
2. Builds the binary and copies it to `~/.local/bin/streamdeck-go`
|
❯ Building streamdeck-go...
|
||||||
3. Creates `~/.config/streamdeck-go/` and `~/.config/streamdeck-go/icons/`
|
✓ Build complete
|
||||||
4. Writes a starter `~/.config/streamdeck-go/config.yaml` (only if one doesn't exist)
|
|
||||||
5. Installs and enables the systemd user service — starts now and on every login
|
|
||||||
|
|
||||||
After install, edit your config:
|
❯ Checking udev rule...
|
||||||
|
✓ udev rule already installed — skipping
|
||||||
|
|
||||||
|
Config location
|
||||||
|
─────────────────────────────────────────────
|
||||||
|
|
||||||
|
· streamdeck-go stores its config and icons in a single directory.
|
||||||
|
· You can keep that directory inside your dotfiles repo and symlink it
|
||||||
|
· into ~/.config — the same pattern used by Hyprland, Waybar, etc.
|
||||||
|
|
||||||
|
❯ Use a dotfiles directory? [Y/n]
|
||||||
|
❯ Path to dotfiles repo [~/dotfiles]:
|
||||||
|
|
||||||
|
· Will create:
|
||||||
|
· ~/dotfiles/.config/streamdeck-go/
|
||||||
|
· ~/dotfiles/.config/streamdeck-go/config.yaml
|
||||||
|
· ~/dotfiles/.config/streamdeck-go/icons/
|
||||||
|
|
||||||
|
· Will symlink:
|
||||||
|
· ~/.config/streamdeck-go
|
||||||
|
· └─▶ ~/dotfiles/.config/streamdeck-go
|
||||||
|
|
||||||
|
❯ Confirm? [Y/n]
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting structure inside your dotfiles repo mirrors everything else in `.config`:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/dotfiles/
|
||||||
|
└── .config/
|
||||||
|
├── hypr/
|
||||||
|
├── waybar/
|
||||||
|
└── streamdeck-go/ ← lives here, symlinked to ~/.config/streamdeck-go
|
||||||
|
├── config.yaml
|
||||||
|
└── icons/
|
||||||
|
```
|
||||||
|
|
||||||
|
After install, edit and save `config.yaml` — the deck reloads live, no restart needed:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$EDITOR ~/.config/streamdeck-go/config.yaml
|
$EDITOR ~/.config/streamdeck-go/config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Changes are picked up automatically — no need to restart anything.
|
|
||||||
|
|
||||||
To remove:
|
To remove:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
356
install.sh
Executable file
356
install.sh
Executable file
@@ -0,0 +1,356 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# streamdeck-go installer
|
||||||
|
# Handles dotfiles-aware installation with interactive prompts.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BINARY="streamdeck-go"
|
||||||
|
BIN_DIR="${HOME}/.local/bin"
|
||||||
|
SYSTEMD_USER="${HOME}/.config/systemd/user"
|
||||||
|
UDEV_RULE="/etc/udev/rules.d/99-streamdeck.rules"
|
||||||
|
XDG_CONFIG="${HOME}/.config"
|
||||||
|
DEFAULT_DOTFILES="${HOME}/dotfiles"
|
||||||
|
|
||||||
|
# ── Colours ────────────────────────────────────────────────────────────────────
|
||||||
|
if [[ -t 1 ]]; then
|
||||||
|
BOLD='\033[1m'; DIM='\033[2m'
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'; CYAN='\033[0;36m'; MAGENTA='\033[0;35m'
|
||||||
|
NC='\033[0m'
|
||||||
|
else
|
||||||
|
BOLD=''; DIM=''; RED=''; GREEN=''; YELLOW=''
|
||||||
|
BLUE=''; CYAN=''; MAGENTA=''; NC=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
CHECK="${GREEN}✓${NC}"
|
||||||
|
CROSS="${RED}✗${NC}"
|
||||||
|
ARROW="${CYAN}❯${NC}"
|
||||||
|
WARN="${YELLOW}⚠${NC}"
|
||||||
|
DOT="${DIM}·${NC}"
|
||||||
|
|
||||||
|
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||||
|
nl() { echo ""; }
|
||||||
|
step() { echo -e " ${ARROW} $1"; }
|
||||||
|
ok() { echo -e " ${CHECK} $1"; }
|
||||||
|
warn() { echo -e " ${WARN} $1"; }
|
||||||
|
info() { echo -e " ${DOT} $1"; }
|
||||||
|
error() { echo -e " ${CROSS} ${RED}$1${NC}"; }
|
||||||
|
dim() { echo -e " ${DIM}$1${NC}"; }
|
||||||
|
|
||||||
|
prompt_yn() {
|
||||||
|
local msg="$1" default="${2:-y}"
|
||||||
|
local opts; [[ $default == "y" ]] && opts="Y/n" || opts="y/N"
|
||||||
|
echo -ne " ${ARROW} ${msg} ${DIM}[${opts}]${NC} "
|
||||||
|
read -r _answer </dev/tty
|
||||||
|
_answer="${_answer:-$default}"
|
||||||
|
[[ $_answer =~ ^[Yy] ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_input() {
|
||||||
|
# echo-ne goes to /dev/tty so it isn't captured when called inside $()
|
||||||
|
local msg="$1" default="$2"
|
||||||
|
echo -ne " ${ARROW} ${msg} ${DIM}[${default}]${NC}: " >/dev/tty
|
||||||
|
read -r _input </dev/tty
|
||||||
|
echo "${_input:-$default}"
|
||||||
|
}
|
||||||
|
|
||||||
|
pick_directory() {
|
||||||
|
local default="$1"
|
||||||
|
local result=""
|
||||||
|
|
||||||
|
if command -v fzf &>/dev/null; then
|
||||||
|
echo -e "\n ${DIM}arrow keys to navigate · enter to select · ctrl-c to type path manually${NC}\n" >/dev/tty
|
||||||
|
result=$(
|
||||||
|
find "$HOME" -maxdepth 4 -type d 2>/dev/null | sort |
|
||||||
|
fzf --height=50% \
|
||||||
|
--reverse \
|
||||||
|
--border=rounded \
|
||||||
|
--prompt=" ❯ " \
|
||||||
|
--header=" Select dotfiles directory" \
|
||||||
|
--preview="ls -1 {} 2>/dev/null | head -30" \
|
||||||
|
--preview-window="right:35%:border-left" \
|
||||||
|
--query="dotfiles" \
|
||||||
|
--bind="ctrl-c:abort"
|
||||||
|
) || result=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# fzf not available or ctrl-c pressed — fall back to plain text input
|
||||||
|
if [[ -z "$result" ]]; then
|
||||||
|
echo -ne " ${ARROW} Path to dotfiles repo ${DIM}[${default}]${NC}: " >/dev/tty
|
||||||
|
read -r result </dev/tty
|
||||||
|
result="${result:-$default}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$result"
|
||||||
|
}
|
||||||
|
|
||||||
|
abspath() {
|
||||||
|
# Expand ~, resolve to absolute path without requiring it to exist yet.
|
||||||
|
local p="${1/#\~/$HOME}"
|
||||||
|
echo "$p"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Dependency detection ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
detect_pkg_manager() {
|
||||||
|
if command -v pacman &>/dev/null; then echo "pacman"
|
||||||
|
elif command -v apt &>/dev/null; then echo "apt"
|
||||||
|
elif command -v dnf &>/dev/null; then echo "dnf"
|
||||||
|
elif command -v zypper &>/dev/null; then echo "zypper"
|
||||||
|
else echo "unknown"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns 0 if hidapi dev headers are present (needed for cgo build).
|
||||||
|
hidapi_present() {
|
||||||
|
pkg-config --exists hidapi-hidraw 2>/dev/null ||
|
||||||
|
pkg-config --exists hidapi 2>/dev/null ||
|
||||||
|
ldconfig -p 2>/dev/null | grep -q libhidapi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_pkg() {
|
||||||
|
local pm="$1"; shift
|
||||||
|
local pkgs=("$@")
|
||||||
|
case "$pm" in
|
||||||
|
pacman) sudo pacman -S --needed --noconfirm "${pkgs[@]}" ;;
|
||||||
|
apt) sudo apt-get install -y "${pkgs[@]}" ;;
|
||||||
|
dnf) sudo dnf install -y "${pkgs[@]}" ;;
|
||||||
|
zypper) sudo zypper install -y "${pkgs[@]}" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Header ─────────────────────────────────────────────────────────────────────
|
||||||
|
nl
|
||||||
|
echo -e " ${BOLD}${CYAN}streamdeck-go${NC} ${DIM}installer${NC}"
|
||||||
|
echo -e " ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 1. System dependencies ─────────────────────────────────────────────────────
|
||||||
|
step "Checking system dependencies..."
|
||||||
|
PM="$(detect_pkg_manager)"
|
||||||
|
|
||||||
|
# Go
|
||||||
|
if ! command -v go &>/dev/null; then
|
||||||
|
warn "Go not found."
|
||||||
|
if [[ "$PM" == "unknown" ]]; then
|
||||||
|
error "Could not detect a package manager — install Go manually: https://go.dev/dl/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if prompt_yn "Install Go now?" "y"; then
|
||||||
|
case "$PM" in
|
||||||
|
pacman) install_pkg pacman go ;;
|
||||||
|
apt) install_pkg apt golang-go ;;
|
||||||
|
dnf) install_pkg dnf golang ;;
|
||||||
|
zypper) install_pkg zypper go ;;
|
||||||
|
esac
|
||||||
|
ok "Go installed: $(go version)"
|
||||||
|
else
|
||||||
|
error "Go is required to build — aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ok "Go found: $(go version | awk '{print $3}')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# hidapi (C library + dev headers required for cgo)
|
||||||
|
if hidapi_present; then
|
||||||
|
ok "hidapi found"
|
||||||
|
else
|
||||||
|
warn "hidapi not found (required for USB HID communication)."
|
||||||
|
if [[ "$PM" == "unknown" ]]; then
|
||||||
|
warn "Could not detect a package manager — install hidapi manually, then re-run."
|
||||||
|
warn " Arch: sudo pacman -S hidapi"
|
||||||
|
warn " Debian: sudo apt install libhidapi-dev libhidapi-hidraw0"
|
||||||
|
warn " Fedora: sudo dnf install hidapi-devel"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if prompt_yn "Install hidapi now?" "y"; then
|
||||||
|
case "$PM" in
|
||||||
|
pacman) install_pkg pacman hidapi ;;
|
||||||
|
apt) install_pkg apt libhidapi-dev libhidapi-hidraw0 ;;
|
||||||
|
dnf) install_pkg dnf hidapi hidapi-devel ;;
|
||||||
|
zypper) install_pkg zypper hidapi-devel ;;
|
||||||
|
esac
|
||||||
|
ok "hidapi installed"
|
||||||
|
else
|
||||||
|
error "hidapi is required — aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 2. Build ───────────────────────────────────────────────────────────────────
|
||||||
|
step "Building ${BOLD}${BINARY}${NC}..."
|
||||||
|
if go build -o "${BINARY}" ./cmd/streamdeck/ 2>&1; then
|
||||||
|
ok "Build complete"
|
||||||
|
else
|
||||||
|
error "Build failed — aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 3. udev rule ───────────────────────────────────────────────────────────────
|
||||||
|
step "Checking udev rule..."
|
||||||
|
if [[ -f "${UDEV_RULE}" ]]; then
|
||||||
|
ok "udev rule already installed — skipping"
|
||||||
|
else
|
||||||
|
info "Installing udev rule (requires sudo):"
|
||||||
|
dim " ${UDEV_RULE}"
|
||||||
|
echo 'KERNEL=="hidraw*", ATTRS{idVendor}=="0fd9", MODE="0666"' \
|
||||||
|
| sudo tee "${UDEV_RULE}" >/dev/null
|
||||||
|
sudo udevadm control --reload
|
||||||
|
sudo udevadm trigger
|
||||||
|
ok "udev rule installed — device accessible without root"
|
||||||
|
fi
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 4. Binary ──────────────────────────────────────────────────────────────────
|
||||||
|
step "Installing binary to ${BOLD}${BIN_DIR}/${BINARY}${NC}..."
|
||||||
|
mkdir -p "${BIN_DIR}"
|
||||||
|
install -Dm755 "${BINARY}" "${BIN_DIR}/${BINARY}"
|
||||||
|
ok "Binary installed"
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 5. Dotfiles ────────────────────────────────────────────────────────────────
|
||||||
|
echo -e " ${BOLD}Config location${NC}"
|
||||||
|
echo -e " ${DIM}─────────────────────────────────────────────${NC}"
|
||||||
|
nl
|
||||||
|
info "streamdeck-go stores its config and icons in a single directory."
|
||||||
|
info "You can keep that directory inside your dotfiles repo and symlink it"
|
||||||
|
info "into ~/.config — the same pattern used by Hyprland, Waybar, etc."
|
||||||
|
nl
|
||||||
|
|
||||||
|
USE_DOTFILES=false
|
||||||
|
CONFIG_DIR=""
|
||||||
|
|
||||||
|
if prompt_yn "Use a dotfiles directory?" "y"; then
|
||||||
|
nl
|
||||||
|
DOTFILES_RAW="$(pick_directory "${DEFAULT_DOTFILES}")"
|
||||||
|
DOTFILES="$(abspath "${DOTFILES_RAW}")"
|
||||||
|
|
||||||
|
if [[ ! -d "${DOTFILES}" ]]; then
|
||||||
|
warn "Directory ${DOTFILES} does not exist — it will be created."
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_DIR="${DOTFILES}/.config/streamdeck-go"
|
||||||
|
SYMLINK_TARGET="${XDG_CONFIG}/streamdeck-go"
|
||||||
|
|
||||||
|
nl
|
||||||
|
echo -e " ${DIM}─────────────────────────────────────────────${NC}"
|
||||||
|
info "${BOLD}Will create:${NC}"
|
||||||
|
dim " ${CONFIG_DIR}/"
|
||||||
|
dim " ${CONFIG_DIR}/config.yaml ${DIM}(if absent)${NC}"
|
||||||
|
dim " ${CONFIG_DIR}/icons/"
|
||||||
|
nl
|
||||||
|
info "${BOLD}Will symlink:${NC}"
|
||||||
|
dim " ${SYMLINK_TARGET}"
|
||||||
|
dim " └─▶ ${CONFIG_DIR}"
|
||||||
|
echo -e " ${DIM}─────────────────────────────────────────────${NC}"
|
||||||
|
nl
|
||||||
|
|
||||||
|
if ! prompt_yn "Confirm?" "y"; then
|
||||||
|
nl
|
||||||
|
warn "Aborted — nothing written."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
USE_DOTFILES=true
|
||||||
|
else
|
||||||
|
nl
|
||||||
|
CONFIG_DIR="${XDG_CONFIG}/streamdeck-go"
|
||||||
|
info "Config will go directly in ${CONFIG_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
nl
|
||||||
|
|
||||||
|
# ── 6. Create config directory ─────────────────────────────────────────────────
|
||||||
|
step "Setting up config directory..."
|
||||||
|
mkdir -p "${CONFIG_DIR}/icons"
|
||||||
|
ok "Created ${CONFIG_DIR}/icons/"
|
||||||
|
|
||||||
|
if [[ ! -f "${CONFIG_DIR}/config.yaml" ]]; then
|
||||||
|
install -Dm644 config.example.yaml "${CONFIG_DIR}/config.yaml"
|
||||||
|
ok "Default config written to config.yaml"
|
||||||
|
else
|
||||||
|
ok "config.yaml already exists — not overwritten"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy bundled icons (never overwrite existing ones the user may have customised).
|
||||||
|
if [[ -d "icons" ]]; then
|
||||||
|
copied=0
|
||||||
|
for f in icons/*; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
dest="${CONFIG_DIR}/icons/$(basename "$f")"
|
||||||
|
if [[ ! -f "$dest" ]]; then
|
||||||
|
cp "$f" "$dest"
|
||||||
|
(( copied++ )) || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if (( copied > 0 )); then
|
||||||
|
ok "Copied ${copied} bundled icon(s) to ${CONFIG_DIR}/icons/"
|
||||||
|
else
|
||||||
|
ok "Bundled icons already present — not overwritten"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 7. Symlink (dotfiles mode only) ───────────────────────────────────────────
|
||||||
|
if [[ "${USE_DOTFILES}" == "true" ]]; then
|
||||||
|
nl
|
||||||
|
step "Creating symlink..."
|
||||||
|
SYMLINK_TARGET="${XDG_CONFIG}/streamdeck-go"
|
||||||
|
|
||||||
|
if [[ -L "${SYMLINK_TARGET}" ]]; then
|
||||||
|
existing="$(readlink -f "${SYMLINK_TARGET}")"
|
||||||
|
if [[ "${existing}" == "${CONFIG_DIR}" ]]; then
|
||||||
|
ok "Symlink already correct — skipping"
|
||||||
|
else
|
||||||
|
warn "Symlink exists but points to ${existing}"
|
||||||
|
if prompt_yn "Replace it?" "y"; then
|
||||||
|
rm "${SYMLINK_TARGET}"
|
||||||
|
ln -s "${CONFIG_DIR}" "${SYMLINK_TARGET}"
|
||||||
|
ok "Symlink updated → ${CONFIG_DIR}"
|
||||||
|
else
|
||||||
|
warn "Symlink not updated — you may need to fix this manually."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [[ -d "${SYMLINK_TARGET}" ]]; then
|
||||||
|
warn "${SYMLINK_TARGET} is a real directory (not a symlink)."
|
||||||
|
info "Move its contents to ${CONFIG_DIR} first, then re-run install."
|
||||||
|
warn "Skipping symlink — config will work from ${CONFIG_DIR} but is not linked."
|
||||||
|
else
|
||||||
|
mkdir -p "${XDG_CONFIG}"
|
||||||
|
ln -s "${CONFIG_DIR}" "${SYMLINK_TARGET}"
|
||||||
|
ok "Symlinked ${SYMLINK_TARGET} → ${CONFIG_DIR}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 8. Systemd user service ────────────────────────────────────────────────────
|
||||||
|
nl
|
||||||
|
step "Installing systemd user service..."
|
||||||
|
mkdir -p "${SYSTEMD_USER}"
|
||||||
|
install -Dm644 systemd/streamdeck-go.service "${SYSTEMD_USER}/streamdeck-go.service"
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable --now streamdeck-go.service
|
||||||
|
ok "Service enabled and started"
|
||||||
|
|
||||||
|
# ── Done ───────────────────────────────────────────────────────────────────────
|
||||||
|
nl
|
||||||
|
echo -e " ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
|
echo -e " ${GREEN}${BOLD}All done.${NC}"
|
||||||
|
nl
|
||||||
|
|
||||||
|
if [[ "${USE_DOTFILES}" == "true" ]]; then
|
||||||
|
info "Your config lives in your dotfiles repo:"
|
||||||
|
dim " ${CONFIG_DIR}/config.yaml"
|
||||||
|
dim " ${CONFIG_DIR}/icons/"
|
||||||
|
else
|
||||||
|
info "Your config:"
|
||||||
|
dim " ${CONFIG_DIR}/config.yaml"
|
||||||
|
dim " ${CONFIG_DIR}/icons/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
nl
|
||||||
|
info "Edit and save config.yaml — the deck reloads automatically."
|
||||||
|
info "For privileged commands (suspend, reboot, etc): ${BOLD}make install-helper${NC}"
|
||||||
|
nl
|
||||||
|
info "Logs: ${DIM}journalctl --user -u streamdeck-go -f${NC}"
|
||||||
|
nl
|
||||||
@@ -49,5 +49,11 @@ func Load(path string) (*Config, error) {
|
|||||||
return nil, fmt.Errorf("parse config: %w", err)
|
return nil, fmt.Errorf("parse config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve relative icons_dir against the config file's directory so the
|
||||||
|
// binary works regardless of the working directory (e.g. as a systemd service).
|
||||||
|
if !filepath.IsAbs(cfg.IconsDir) {
|
||||||
|
cfg.IconsDir = filepath.Join(filepath.Dir(path), cfg.IconsDir)
|
||||||
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sstallion/go-hid"
|
"github.com/sstallion/go-hid"
|
||||||
@@ -152,6 +153,12 @@ func (sd *StreamDeck) ReadButtons() ([]bool, error) {
|
|||||||
data := make([]byte, readReportSize)
|
data := make([]byte, readReportSize)
|
||||||
n, err := sd.dev.ReadWithTimeout(data, 250)
|
n, err := sd.dev.ReadWithTimeout(data, 250)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// hidraw on Linux returns errors rather than (0, nil) for non-fatal
|
||||||
|
// conditions: timeout waiting for data, or EINTR (signal interrupted).
|
||||||
|
msg := strings.ToLower(err.Error())
|
||||||
|
if strings.Contains(msg, "timeout") || strings.Contains(msg, "interrupted") {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user