package main import ( "fmt" "strings" "time" "github.com/AvengeMedia/DankMaterialShell/core/internal/log" "github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness" "github.com/spf13/cobra" ) var brightnessCmd = &cobra.Command{ Use: "brightness", Short: "Control device brightness", Long: "Control brightness for backlight and LED devices (use --ddc to include DDC/I2C monitors)", } var brightnessListCmd = &cobra.Command{ Use: "list", Short: "List all brightness devices", Long: "List all available brightness devices with their current values", Run: runBrightnessList, } var brightnessSetCmd = &cobra.Command{ Use: "set ", Short: "Set brightness for a device", Long: "Set brightness percentage (0-100) for a specific device", Args: cobra.ExactArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } includeDDC, _ := cmd.Flags().GetBool("ddc") return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp }, Run: runBrightnessSet, } var brightnessGetCmd = &cobra.Command{ Use: "get ", Short: "Get brightness for a device", Long: "Get current brightness percentage for a specific device", Args: cobra.ExactArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } includeDDC, _ := cmd.Flags().GetBool("ddc") return getBrightnessDevices(includeDDC), cobra.ShellCompDirectiveNoFileComp }, Run: runBrightnessGet, } func init() { brightnessListCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") brightnessSetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") brightnessSetCmd.Flags().Bool("exponential", false, "Use exponential brightness scaling") brightnessSetCmd.Flags().Float64("exponent", 1.2, "Exponent for exponential scaling (default 1.2)") brightnessGetCmd.Flags().Bool("ddc", false, "Include DDC/I2C monitors (slower)") brightnessCmd.SetHelpTemplate(`{{.Long}} Usage: {{.UseLine}}{{if .HasAvailableSubCommands}} Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} {{rpad .Name .NamePadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} `) brightnessListCmd.SetHelpTemplate(`{{.Long}} Usage: {{.UseLine}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} `) brightnessSetCmd.SetHelpTemplate(`{{.Long}} Usage: {{.UseLine}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} `) brightnessGetCmd.SetHelpTemplate(`{{.Long}} Usage: {{.UseLine}}{{if .HasAvailableLocalFlags}} Flags: {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}} `) brightnessCmd.AddCommand(brightnessListCmd, brightnessSetCmd, brightnessGetCmd) } func getAllBrightnessDevices(includeDDC bool) []brightness.Device { allDevices := []brightness.Device{} sysfs, err := brightness.NewSysfsBackend() if err != nil { log.Debugf("Failed to initialize sysfs backend: %v", err) } else { devices, err := sysfs.GetDevices() if err != nil { log.Debugf("Failed to get sysfs devices: %v", err) } else { allDevices = append(allDevices, devices...) } } if includeDDC { ddc, err := brightness.NewDDCBackend() if err != nil { fmt.Printf("Warning: Failed to initialize DDC backend: %v\n", err) } else { time.Sleep(100 * time.Millisecond) devices, err := ddc.GetDevices() if err != nil { fmt.Printf("Warning: Failed to get DDC devices: %v\n", err) } else { allDevices = append(allDevices, devices...) } ddc.Close() } } return allDevices } func runBrightnessList(cmd *cobra.Command, args []string) { includeDDC, _ := cmd.Flags().GetBool("ddc") allDevices := getAllBrightnessDevices(includeDDC) if len(allDevices) == 0 { fmt.Println("No brightness devices found") return } maxIDLen := len("Device") maxNameLen := len("Name") for _, dev := range allDevices { if len(dev.ID) > maxIDLen { maxIDLen = len(dev.ID) } if len(dev.Name) > maxNameLen { maxNameLen = len(dev.Name) } } idPad := maxIDLen + 2 namePad := maxNameLen + 2 fmt.Printf("%-*s %-12s %-*s %s\n", idPad, "Device", "Class", namePad, "Name", "Brightness") sepLen := idPad + 2 + 12 + 2 + namePad + 2 + 15 for range sepLen { fmt.Print("─") } fmt.Println() for _, device := range allDevices { fmt.Printf("%-*s %-12s %-*s %3d%%\n", idPad, device.ID, device.Class, namePad, device.Name, device.CurrentPercent, ) } } func runBrightnessSet(cmd *cobra.Command, args []string) { deviceID := args[0] var percent int if _, err := fmt.Sscanf(args[1], "%d", &percent); err != nil { log.Fatalf("Invalid percent value: %s", args[1]) } if percent < 0 || percent > 100 { log.Fatalf("Percent must be between 0 and 100") } includeDDC, _ := cmd.Flags().GetBool("ddc") exponential, _ := cmd.Flags().GetBool("exponential") exponent, _ := cmd.Flags().GetFloat64("exponent") parts := strings.SplitN(deviceID, ":", 2) if len(parts) == 2 && (parts[0] == "backlight" || parts[0] == "leds") { if ok := tryLogindBrightness(parts[0], parts[1], deviceID, percent, exponential, exponent); ok { return } } sysfs, err := brightness.NewSysfsBackend() if err == nil { if err := sysfs.SetBrightnessWithExponent(deviceID, percent, exponential, exponent); err == nil { fmt.Printf("Set %s to %d%%\n", deviceID, percent) return } log.Debugf("sysfs.SetBrightness failed: %v", err) } else { log.Debugf("NewSysfsBackend failed: %v", err) } // Try DDC if requested if includeDDC { ddc, err := brightness.NewDDCBackend() if err == nil { defer ddc.Close() time.Sleep(100 * time.Millisecond) if err := ddc.SetBrightnessWithExponent(deviceID, percent, exponential, exponent, nil); err == nil { fmt.Printf("Set %s to %d%%\n", deviceID, percent) return } log.Debugf("ddc.SetBrightness failed: %v", err) } else { log.Debugf("NewDDCBackend failed: %v", err) } } log.Fatalf("Failed to set brightness for device: %s", deviceID) } func tryLogindBrightness(subsystem, name, deviceID string, percent int, exponential bool, exponent float64) bool { sysfs, err := brightness.NewSysfsBackend() if err != nil { log.Debugf("NewSysfsBackend failed: %v", err) return false } logind, err := brightness.NewLogindBackend() if err != nil { log.Debugf("NewLogindBackend failed: %v", err) return false } defer logind.Close() dev, err := sysfs.GetDevice(deviceID) if err != nil { log.Debugf("sysfs.GetDeviceByID failed: %v", err) return false } value := sysfs.PercentToValueWithExponent(percent, dev, exponential, exponent) if err := logind.SetBrightness(subsystem, name, uint32(value)); err != nil { log.Debugf("logind.SetBrightness failed: %v", err) return false } log.Debugf("set %s to %d%% (%d) via logind", deviceID, percent, value) fmt.Printf("Set %s to %d%%\n", deviceID, percent) return true } func getBrightnessDevices(includeDDC bool) []string { allDevices := getAllBrightnessDevices(includeDDC) var deviceIDs []string for _, device := range allDevices { deviceIDs = append(deviceIDs, device.ID) } return deviceIDs } func runBrightnessGet(cmd *cobra.Command, args []string) { deviceID := args[0] includeDDC, _ := cmd.Flags().GetBool("ddc") allDevices := getAllBrightnessDevices(includeDDC) for _, device := range allDevices { if device.ID == deviceID { fmt.Printf("%s: %d%% (%d/%d)\n", device.ID, device.CurrentPercent, device.Current, device.Max, ) return } } log.Fatalf("Device not found: %s", deviceID) }