| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- package rgb
- import (
- "fmt"
- "math"
- )
- // Effect defines an RGB lighting effect.
- type Effect uint8
- const (
- Static Effect = 0
- Breathing Effect = 1
- EffectAlmond Effect = 2
- BandSat Effect = 3
- BandVal Effect = 4
- BandHue Effect = 5
- Chroma Effect = 6
- Rainbow Effect = 7
- RainbowWave Effect = 8
- Dance Effect = 9
- RainbowDance Effect = 10
- ChromaDance Effect = 11
- Snake Effect = 12
- Tail Effect = 13
- Split Effect = 14
- Heartbeat Effect = 15
- Blink Effect = 16
- BlinkStatic Effect = 17
- Gradient Effect = 18
- Testing Effect = 19
- )
- // EffectName returns the human-readable name of an effect.
- func (e Effect) String() string {
- names := map[Effect]string{
- Static: "static",
- Breathing: "breathing",
- EffectAlmond: "almond",
- BandSat: "band_sat",
- BandVal: "band_val",
- BandHue: "band_hue",
- Chroma: "chroma",
- Rainbow: "rainbow",
- RainbowWave: "rainbow_wave",
- Dance: "dance",
- RainbowDance: "rainbow_dance",
- ChromaDance: "chroma_dance",
- Snake: "snake",
- Tail: "tail",
- Split: "split",
- Heartbeat: "heartbeat",
- Blink: "blink",
- BlinkStatic: "blink_static",
- Gradient: "gradient",
- Testing: "testing",
- }
- if name, ok := names[e]; ok {
- return name
- }
- return "unknown"
- }
- // ParseEffect converts a string name to an Effect.
- func ParseEffect(name string) (Effect, error) {
- switch name {
- case "static":
- return Static, nil
- case "breathing":
- return Breathing, nil
- case "almond":
- return EffectAlmond, nil
- case "band_sat":
- return BandSat, nil
- case "band_val":
- return BandVal, nil
- case "band_hue":
- return BandHue, nil
- case "chroma":
- return Chroma, nil
- case "rainbow":
- return Rainbow, nil
- case "rainbow_wave":
- return RainbowWave, nil
- case "dance":
- return Dance, nil
- case "rainbow_dance":
- return RainbowDance, nil
- case "chroma_dance":
- return ChromaDance, nil
- case "snake":
- return Snake, nil
- case "tail":
- return Tail, nil
- case "split":
- return Split, nil
- case "heartbeat":
- return Heartbeat, nil
- case "blink":
- return Blink, nil
- case "blink_static":
- return BlinkStatic, nil
- case "gradient":
- return Gradient, nil
- case "testing":
- return Testing, nil
- default:
- return 0, fmt.Errorf("unknown effect: %s", name)
- }
- }
- // LEDParam defines QMK rgblight parameter indices.
- type LEDParam uint8
- const (
- Mode LEDParam = 0
- Brightness LEDParam = 1
- Speed LEDParam = 2
- Enable LEDParam = 3
- Hue LEDParam = 26
- Saturation LEDParam = 27
- EffectID LEDParam = 48
- EffectSwitch LEDParam = 49
- BrightSet LEDParam = 50
- )
- // Color represents an RGB color.
- type Color struct {
- R uint8
- G uint8
- B uint8
- }
- // ParseHexColor parses a 6-digit hex color string (e.g. "ff0000").
- func ParseHexColor(s string) (Color, error) {
- if len(s) != 6 {
- return Color{}, fmt.Errorf("invalid hex color: %s", s)
- }
- r := hexDigit(s[0])<<4 + hexDigit(s[1])
- g := hexDigit(s[2])<<4 + hexDigit(s[3])
- b := hexDigit(s[4])<<4 + hexDigit(s[5])
- return Color{R: r, G: g, B: b}, nil
- }
- func hexDigit(c byte) uint8 {
- switch {
- case c >= '0' && c <= '9':
- return c - '0'
- case c >= 'a' && c <= 'f':
- return c - 'a' + 10
- case c >= 'A' && c <= 'F':
- return c - 'A' + 10
- default:
- return 0
- }
- }
- // State represents the current RGB state from the keyboard.
- type State struct {
- Enabled bool
- Mode Effect
- Brightness uint8
- Speed uint8
- Color Color
- }
- // HSV converts the color to HSV (QMK rgblight uses 0-255 ranges for H, S, V).
- func (c Color) HSV() (h, s, v uint8) {
- r, g, b := float64(c.R), float64(c.G), float64(c.B)
- max := math.Max(r, math.Max(g, b))
- min := math.Min(r, math.Min(g, b))
- v = uint8(max)
- d := max - min
- if d == 0 {
- return 0, 0, v
- }
- if max > 0 {
- s = uint8((d / max) * 255)
- } else {
- return 0, 0, 0
- }
- var hFloat float64
- switch {
- case max == r:
- hFloat = ((g - b) / d) * 60.0
- case max == g:
- hFloat = ((b-r)/d)*60.0 + 120.0
- case max == b:
- hFloat = ((r-g)/d)*60.0 + 240.0
- }
- if hFloat < 0 {
- hFloat += 360.0
- }
- h = uint8((hFloat / 360.0) * 255.0)
- if h >= 255 {
- h = 254
- }
- return h, s, v
- }
|