(原) golang实现Win下的显示器亮度调整

原创文章,请后转载,并注明出处。
package main

import (
	"fmt"
	"log"
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

// 定义 Windows API 所需的常量和结构
const (
	MONITOR_DEFAULTTONULL    = 0x00000000
	MONITOR_DEFAULTTOPRIMARY = 0x00000001
	MONITOR_DEFAULTTONEAREST = 0x00000002

	MC_CAPS_HORIZONTAL_POSITION            = 0x00000001
	MC_CAPS_VERTICAL_POSITION              = 0x00000002
	MC_CAPS_BRIGHTNESS                     = 0x00000004
	MC_CAPS_CONTRAST                       = 0x00000008
	MC_CAPS_COLOR_PRESET                   = 0x00000010
	MC_CAPS_RED_GREEN_BLUE_GAIN            = 0x00000020
	MC_CAPS_RED_GREEN_BLUE_DRIVE           = 0x00000040
	MC_CAPS_DEGAUSS                        = 0x00000080
	MC_CAPS_RESTORE_FACTORY_DEFAULTS       = 0x00000100
	MC_CAPS_RESTORE_FACTORY_COLOR_DEFAULTS = 0x00000200
	MC_CAPS_MONITOR_TECHNOLOGY_TYPE        = 0x00000400
	MC_CAPS_DISPLAY_AREA_SIZE              = 0x00000800
)

// 定义 PHYSICAL_MONITOR 结构
type PHYSICAL_MONITOR struct {
	hPhysicalMonitor             windows.Handle
	szPhysicalMonitorDescription [128]uint16
}

// 加载所需的 DLL 和函数
var (
	dxva2  = windows.NewLazySystemDLL("dxva2.dll")
	user32 = windows.NewLazySystemDLL("user32.dll")

	// 显示设备枚举函数
	procEnumDisplayMonitors = user32.NewProc("EnumDisplayMonitors")
	procGetMonitorInfoW     = user32.NewProc("GetMonitorInfoW")

	procGetNumberOfPhysicalMonitorsFromHMONITOR = dxva2.NewProc("GetNumberOfPhysicalMonitorsFromHMONITOR")
	procGetPhysicalMonitorsFromHMONITOR         = dxva2.NewProc("GetPhysicalMonitorsFromHMONITOR")
	procDestroyPhysicalMonitor                  = dxva2.NewProc("DestroyPhysicalMonitor")

	// DDC/CI 控制函数
	procGetMonitorCapabilities = dxva2.NewProc("GetMonitorCapabilities")
	procGetMonitorBrightness   = dxva2.NewProc("GetMonitorBrightness")
	procSetMonitorBrightness   = dxva2.NewProc("SetMonitorBrightness")
)

type HMONITOR uintptr
type HDC uintptr

// 回调函数类型,用于 EnumDisplayMonitors
type MonitorEnumProc func(hMonitor HMONITOR, hdcMonitor HDC, lprcMonitor *RECT, dwData uintptr) uintptr

// RECT 结构定义
type RECT struct {
	Left   int32
	Top    int32
	Right  int32
	Bottom int32
}

// 枚举所有显示器并设置亮度
func SetBrightnessForAllMonitors(brightness uint32) error {
	// 确保亮度值在有效范围内(0-100)
	if brightness > 100 {
		brightness = 100
	} else if brightness < 0 {
		brightness = 0
	}

	// 存储物理监视器的切片
	var physicalMonitors []PHYSICAL_MONITOR

	// 枚举显示器的回调函数
	callback := func(hMonitor HMONITOR, hdcMonitor HDC, lprcMonitor *RECT, dwData uintptr) uintptr {
		// 获取物理监视器数量
		var monitorCount uint32
		_, _, err := procGetNumberOfPhysicalMonitorsFromHMONITOR.Call(
			uintptr(hMonitor),
			uintptr(unsafe.Pointer(&monitorCount)))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取物理监视器数量失败: %v", err)
			return 1 // 继续枚举其他显示器
		}

		// 分配物理监视器数组
		monitors := make([]PHYSICAL_MONITOR, monitorCount)
		_, _, err = procGetPhysicalMonitorsFromHMONITOR.Call(
			uintptr(hMonitor),
			uintptr(monitorCount),
			uintptr(unsafe.Pointer(&monitors[0])))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取物理监视器信息失败: %v", err)
			return 1 // 继续枚举其他显示器
		}

		// 添加到物理监视器列表
		physicalMonitors = append(physicalMonitors, monitors...)

		return 1 // 继续枚举其他显示器
	}

	// 枚举所有显示器
	_, _, err := procEnumDisplayMonitors.Call(
		0,
		0,
		uintptr(syscall.NewCallback(MonitorEnumProc(callback))),
		0)
	if err != nil && err.(syscall.Errno) != 0 {
		return fmt.Errorf("枚举显示器失败: %v", err)
	}

	// 为每个物理监视器设置亮度
	for _, monitor := range physicalMonitors {
		// 获取显示器功能
		var capabilities DWORD
		var supportedColorTemperatures DWORD
		_, _, err := procGetMonitorCapabilities.Call(
			uintptr(monitor.hPhysicalMonitor),
			uintptr(unsafe.Pointer(&capabilities)),
			uintptr(unsafe.Pointer(&supportedColorTemperatures)))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取显示器功能失败: %v", err)
			continue
		}

		// 检查显示器是否支持亮度调节
		if capabilities&MC_CAPS_BRIGHTNESS == 0 {
			log.Println("此显示器不支持亮度调节")
			continue
		}

		// 获取当前亮度范围
		var minimumBrightness, currentBrightness, maximumBrightness uint32
		_, _, err = procGetMonitorBrightness.Call(
			uintptr(monitor.hPhysicalMonitor),
			uintptr(unsafe.Pointer(&minimumBrightness)),
			uintptr(unsafe.Pointer(&currentBrightness)),
			uintptr(unsafe.Pointer(&maximumBrightness)))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取亮度范围失败: %v", err)
			continue
		}

		// 计算实际亮度值(将0-100映射到显示器的最小-最大范围)
		actualBrightness := minimumBrightness + (brightness * (maximumBrightness - minimumBrightness) / 100)

		// 设置亮度
		_, _, err = procSetMonitorBrightness.Call(
			uintptr(monitor.hPhysicalMonitor),
			uintptr(actualBrightness))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("设置亮度失败: %v", err)
			continue
		}

		fmt.Printf("成功将显示器 %s 的亮度设置为 %d%%\n",
			windows.UTF16ToString(monitor.szPhysicalMonitorDescription[:]), brightness)

		// 关闭物理监视器句柄
		procDestroyPhysicalMonitor.Call(uintptr(monitor.hPhysicalMonitor))
	}

	return nil
}

// DWORD 类型定义
type DWORD uint32

func GetCurrentBrightnessForAllMonitors() error {
	var physicalMonitors []PHYSICAL_MONITOR

	callback := func(hMonitor HMONITOR, hdcMonitor HDC, lprcMonitor *RECT, dwData uintptr) uintptr {
		var monitorCount uint32
		_, _, err := procGetNumberOfPhysicalMonitorsFromHMONITOR.Call(
			uintptr(hMonitor),
			uintptr(unsafe.Pointer(&monitorCount)))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取物理监视器数量失败: %v", err)
			return 1
		}
		monitors := make([]PHYSICAL_MONITOR, monitorCount)
		_, _, err = procGetPhysicalMonitorsFromHMONITOR.Call(
			uintptr(hMonitor),
			uintptr(monitorCount),
			uintptr(unsafe.Pointer(&monitors[0])))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取物理监视器信息失败: %v", err)
			return 1
		}
		physicalMonitors = append(physicalMonitors, monitors...)
		return 1
	}

	_, _, err := procEnumDisplayMonitors.Call(
		0,
		0,
		uintptr(syscall.NewCallback(MonitorEnumProc(callback))),
		0)
	if err != nil && err.(syscall.Errno) != 0 {
		return fmt.Errorf("枚举显示器失败: %v", err)
	}

	for _, monitor := range physicalMonitors {
		var minimumBrightness, currentBrightness, maximumBrightness uint32
		_, _, err := procGetMonitorBrightness.Call(
			uintptr(monitor.hPhysicalMonitor),
			uintptr(unsafe.Pointer(&minimumBrightness)),
			uintptr(unsafe.Pointer(&currentBrightness)),
			uintptr(unsafe.Pointer(&maximumBrightness)))
		if err != nil && err.(syscall.Errno) != 0 {
			log.Printf("获取亮度范围失败: %v", err)
			continue
		}
		percent := 0
		if maximumBrightness > minimumBrightness {
			percent = int((currentBrightness - minimumBrightness) * 100 / (maximumBrightness - minimumBrightness))
		}
		fmt.Printf("显示器 %s 当前亮度为 %d%%(原始值: %d)\n",
			windows.UTF16ToString(monitor.szPhysicalMonitorDescription[:]), percent, currentBrightness)
		procDestroyPhysicalMonitor.Call(uintptr(monitor.hPhysicalMonitor))
	}
	return nil
}

func main() {
	GetCurrentBrightnessForAllMonitors()  // 获取当前亮度
	// 设置亮度为 25%
	err := SetBrightnessForAllMonitors(25)
	if err != nil {
		log.Fatalf("设置亮度时出错: %v", err)
	}
}

相关文章