Multi-action keys with tap/long-press/double-tap/hold, gesture timing, display output colors, global font, and display output JSON/color parsing

- Multi-action system: each key supports multiple actions with different triggers
  (tap, long_press, double_tap, hold_start, hold_end)
- GestureEngine: timing-based gesture detection with configurable thresholds
- New config types: KeyAction, TimingConfig, DisplayOutput
- Display output now supports JSON format (text/background/text_color) and
  first-line-as-hex-color format for dynamic key backgrounds
- Display background colors are reflected in the web UI on the grid
- renderUnicodeText/renderUnicodeTextOnImage accept custom text color (fg)
- Global font setting (medium/regular) in Settings UI
- PageManager.defaultFont used as fallback for per-key font
- Alpine.js bundled locally (no CDN dependency)
- Web UI: action tabs (Tap/Long Press/Double Tap/Hold), unified More section
  with appearance + display settings, gesture timing sliders in Settings
- Grid: subtle action type icons in top-left corner matching display indicator style
- Backward compatible: old config 'action' field auto-migrated to 'actions' array
- M+ 1m font files in assets/ for reference
- Updated config.example.json and README with all new features
This commit is contained in:
Maksim Totmin
2026-06-17 00:09:48 +07:00
parent e536f97b18
commit 9f85cbddd9
14 changed files with 1037 additions and 284 deletions
+3 -1
View File
@@ -7,6 +7,7 @@ import (
"image/draw"
"log/slog"
"sync"
"time"
"github.com/bearsh/hid"
"github.com/dh1tw/streamdeck"
@@ -83,6 +84,7 @@ func toStreamDeckConfig(dc DeckConfig) *streamdeck.Config {
type Event struct {
Kind int
Index int
At time.Time
}
const (
@@ -137,7 +139,7 @@ func OpenDeck(serial string) (*Deck, error) {
return
}
select {
case d.events <- Event{Kind: kind, Index: e.Which}:
case d.events <- Event{Kind: kind, Index: e.Which, At: time.Now()}:
default:
slog.Warn("event channel full, dropping event", "kind", e.Kind, "index", e.Which)
}