Browse Source

add keyboard list, effect --list, and --version commands

- wobkey keyboard list: print supported keyboards from keyboards.json
- wobkey rgb effect --list: list all effects per zone (JSON)
- wobkey rgb effect (no args): list effects without argument
- wobkey --version: show CLI version (set via -ldflags at build time)
- Fix skipped zone message to use comma-separated names
Paul-Dieter Klumpp 2 tuần trước cách đây
mục cha
commit
9856f3bef4
3 tập tin đã thay đổi với 123 bổ sung và 32 xóa
  1. 32 0
      cmd/wobkey/main.go
  2. 71 32
      cmd/wobkey/rgb/effect.go
  3. 20 0
      internal/rgb/impact80.go

+ 32 - 0
cmd/wobkey/main.go

@@ -10,6 +10,9 @@ import (
 	"github.com/wobkey/rgb/internal/device"
 )
 
+// version is set at build time via -ldflags.
+var version = "dev"
+
 func newRootCommand() *cobra.Command {
 	return &cobra.Command{
 		Use:           "wobkey",
@@ -69,9 +72,36 @@ var keyboardInfoCmd = &cobra.Command{
 	},
 }
 
+var keyboardListCmd = &cobra.Command{
+	Use:   "list",
+	Short: "List supported keyboards",
+	Long:  "Print all keyboards from keyboards.json as JSON.",
+	Run: func(cmd *cobra.Command, args []string) {
+		keyboards, err := device.LoadKeyboards()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+			os.Exit(1)
+		}
+
+		if len(keyboards) == 0 {
+			fmt.Println(`{"keyboards":[]}`)
+			return
+		}
+
+		type Info struct {
+			Keyboards []device.Keyboard `json:"keyboards"`
+			Total     int               `json:"total"`
+		}
+		out := Info{Keyboards: keyboards, Total: len(keyboards)}
+		data, _ := json.MarshalIndent(out, "", "  ")
+		fmt.Println(string(data))
+	},
+}
+
 func init() {
 	rootCmd.AddCommand(keyboardCmd)
 	keyboardCmd.AddCommand(keyboardInfoCmd)
+	keyboardCmd.AddCommand(keyboardListCmd)
 	rgbCmd := rgb.Init()
 	rgbCmd.AddCommand(
 		rgb.NewEffectCmd(),
@@ -84,4 +114,6 @@ func init() {
 		rgb.NewInfoCmd(),
 	)
 	rootCmd.AddCommand(rgbCmd)
+	rootCmd.Version = version
+	rootCmd.SetVersionTemplate("wobkey {{.Version}}\n")
 }

+ 71 - 32
cmd/wobkey/rgb/effect.go

@@ -1,6 +1,7 @@
 package rgb
 
 import (
+	"encoding/json"
 	"fmt"
 	"strings"
 
@@ -9,6 +10,8 @@ import (
 	"github.com/wobkey/rgb/internal/via"
 )
 
+var listEffects bool
+
 func resolveEffectTargets(name string, zones []intrgb.Zone) ([]intrgb.EffectTarget, []intrgb.Zone, error) {
 	if name == "static" {
 		name = "solid"
@@ -17,42 +20,78 @@ func resolveEffectTargets(name string, zones []intrgb.Zone) ([]intrgb.EffectTarg
 }
 
 func NewEffectCmd() *cobra.Command {
-	return &cobra.Command{
-		Use:   "effect <name>",
-		Short: "Set RGB effect",
-		Long:  "Set the RGB lighting effect on the connected keyboard.",
-		Args:  cobra.ExactArgs(1),
+	cmd := &cobra.Command{
+		Use:   "effect [name]",
+		Short: "Set or list RGB effects",
+		Long:  "Set the RGB lighting effect on the connected keyboard. Without an argument, lists all effects.",
+		Args:  cobra.MaximumNArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			zones, err := selectedZones()
-			if err != nil {
-				return err
-			}
-			targets, skipped, err := resolveEffectTargets(args[0], zones)
-			if err != nil {
-				return err
-			}
-			if len(skipped) > 0 {
-				skippedNames := make([]string, len(skipped))
-				for i, zone := range skipped {
-					skippedNames[i] = string(zone)
-				}
-				fmt.Fprintf(cmd.ErrOrStderr(), "Warning: effect not supported on zone(s): %s\n", strings.Join(skippedNames, ", "))
+			if listEffects || len(args) == 0 {
+				return listAllEffects(cmd)
 			}
+			return runEffectSet(cmd, args)
+		},
+	}
+	cmd.Flags().BoolVar(&listEffects, "list", false, "List all available effects per zone")
+	return cmd
+}
 
-			proto, err := openRGBProtocol()
-			if err != nil {
-				return err
-			}
-			defer proto.Close()
+func listAllEffects(cmd *cobra.Command) error {
+	type ZoneEffectList struct {
+		Zone   string `json:"zone"`
+		Effect string `json:"effect"`
+		ID     uint8  `json:"id"`
+	}
+	type EffectList struct {
+		Zones []ZoneEffectList `json:"zones"`
+	}
 
-			for _, target := range targets {
-				if err := proto.SetValue(via.LEDType(target.Zone.Channel()), uint8(intrgb.EffectID), target.ID); err != nil {
-					return fmt.Errorf("set effect on %s: %w", target.Zone, err)
-				}
-			}
+	var list EffectList
+	for _, zone := range intrgb.AllZones() {
+		names := intrgb.ZoneEffects(zone)
+		for id, name := range names {
+			list.Zones = append(list.Zones, ZoneEffectList{
+				Zone:   string(zone),
+				Effect: name,
+				ID:     uint8(id),
+			})
+		}
+	}
 
-			fmt.Fprintf(cmd.OutOrStdout(), "Effect set to %q\n", args[0])
-			return nil
-		},
+	data, _ := json.MarshalIndent(list.Zones, "", "  ")
+	fmt.Fprintf(cmd.OutOrStdout(), "%s\n", string(data))
+	return nil
+}
+
+func runEffectSet(cmd *cobra.Command, args []string) error {
+	zones, err := selectedZones()
+	if err != nil {
+		return err
+	}
+	targets, skipped, err := resolveEffectTargets(args[0], zones)
+	if err != nil {
+		return err
+	}
+	if len(skipped) > 0 {
+		skippedNames := make([]string, len(skipped))
+		for i, zone := range skipped {
+			skippedNames[i] = string(zone)
+		}
+		fmt.Fprintf(cmd.ErrOrStderr(), "Warning: effect not supported on zone(s): %s\n", strings.Join(skippedNames, ", "))
 	}
+
+	proto, err := openRGBProtocol()
+	if err != nil {
+		return err
+	}
+	defer proto.Close()
+
+	for _, target := range targets {
+		if err := proto.SetValue(via.LEDType(target.Zone.Channel()), uint8(intrgb.EffectID), target.ID); err != nil {
+			return fmt.Errorf("set effect on %s: %w", target.Zone, err)
+		}
+	}
+
+	fmt.Fprintf(cmd.OutOrStdout(), "Effect set to %q\n", args[0])
+	return nil
 }

+ 20 - 0
internal/rgb/impact80.go

@@ -227,3 +227,23 @@ func ParseImpact80Effect(name string) (uint8, error) {
 	}
 	return targets[0].ID, nil
 }
+
+// AllLogoEffects returns the effect names for the logo zone.
+func AllLogoEffects() []string {
+	return impact80LogoEffects[:]
+}
+
+// AllBacklightEffects returns the effect names for the backlight zone.
+func AllBacklightEffects() []string {
+	return impact80BacklightEffects[:]
+}
+
+// AllSideEffects returns the effect names for the side zone.
+func AllSideEffects() []string {
+	return impact80SideEffects[:]
+}
+
+// ZoneEffects returns the effect names for a zone.
+func ZoneEffects(zone Zone) []string {
+	return impact80EffectNames(zone)
+}