Last active
July 24, 2026 01:16
-
-
Save qwerty12/4b3f41eb61724cd9e8f2bb5cc15c33c2 to your computer and use it in GitHub Desktop.
BrightnessSetter: set laptop brightness and show Windows 10's native brightness OSD (https://github.com/qwerty12/AutoHotkeyScripts/tree/master/LaptopBrightnessSetter)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class BrightnessSetter { | |
| ; qwerty12 - 27/05/17 | |
| ; https://github.com/qwerty12/AutoHotkeyScripts/tree/master/LaptopBrightnessSetter | |
| static _WM_POWERBROADCAST := 0x218, _osdHwnd := 0, hPowrprofMod := DllCall("LoadLibrary", "Str", "powrprof.dll", "Ptr") | |
| __New() { | |
| if (BrightnessSetter.IsOnAc(AC)) | |
| this._AC := AC | |
| if ((this.pwrAcNotifyHandle := DllCall("RegisterPowerSettingNotification", "Ptr", A_ScriptHwnd, "Ptr", BrightnessSetter._GUID_ACDC_POWER_SOURCE(), "UInt", DEVICE_NOTIFY_WINDOW_HANDLE := 0x00000000, "Ptr"))) ; Sadly the callback passed to *PowerSettingRegister*Notification runs on a new threadl | |
| OnMessage(this._WM_POWERBROADCAST, ((this.pwrBroadcastFunc := ObjBindMethod(this, "_On_WM_POWERBROADCAST")))) | |
| } | |
| __Delete() { | |
| if (this.pwrAcNotifyHandle) { | |
| OnMessage(BrightnessSetter._WM_POWERBROADCAST, this.pwrBroadcastFunc, 0) | |
| ,DllCall("UnregisterPowerSettingNotification", "Ptr", this.pwrAcNotifyHandle) | |
| ,this.pwrAcNotifyHandle := 0 | |
| ,this.pwrBroadcastFunc := "" | |
| } | |
| } | |
| SetBrightness(increment, jump := False, showOSD := True, autoDcOrAc := -1, ptrAnotherScheme := 0) | |
| { | |
| static PowerGetActiveScheme := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerGetActiveScheme", "Ptr") | |
| ,PowerSetActiveScheme := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerSetActiveScheme", "Ptr") | |
| ,PowerWriteACValueIndex := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerWriteACValueIndex", "Ptr") | |
| ,PowerWriteDCValueIndex := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerWriteDCValueIndex", "Ptr") | |
| ,PowerApplySettingChanges := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerApplySettingChanges", "Ptr") | |
| if (increment == 0 && !jump) { | |
| if (showOSD) | |
| BrightnessSetter._ShowBrightnessOSD() | |
| return | |
| } | |
| if (!ptrAnotherScheme ? DllCall(PowerGetActiveScheme, "Ptr", 0, "Ptr*", currSchemeGuid, "UInt") == 0 : DllCall("powrprof\PowerDuplicateScheme", "Ptr", 0, "Ptr", ptrAnotherScheme, "Ptr*", currSchemeGuid, "UInt") == 0) { | |
| if (autoDcOrAc == -1) { | |
| if (this != BrightnessSetter) { | |
| AC := this._AC | |
| } else { | |
| if (!BrightnessSetter.IsOnAc(AC)) { | |
| DllCall("LocalFree", "Ptr", currSchemeGuid, "Ptr") | |
| return | |
| } | |
| } | |
| } else { | |
| AC := !!autoDcOrAc | |
| } | |
| currBrightness := 0 | |
| if (jump || BrightnessSetter._GetCurrentBrightness(currSchemeGuid, AC, currBrightness)) { | |
| maxBrightness := BrightnessSetter.GetMaxBrightness() | |
| ,minBrightness := BrightnessSetter.GetMinBrightness() | |
| if (jump || !((currBrightness == maxBrightness && increment > 0) || (currBrightness == minBrightness && increment < minBrightness))) { | |
| if (currBrightness + increment > maxBrightness) | |
| increment := maxBrightness | |
| else if (currBrightness + increment < minBrightness) | |
| increment := minBrightness | |
| else | |
| increment += currBrightness | |
| if (DllCall(AC ? PowerWriteACValueIndex : PowerWriteDCValueIndex, "Ptr", 0, "Ptr", currSchemeGuid, "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt", increment, "UInt") == 0) { | |
| ; PowerApplySettingChanges is undocumented and exists only in Windows 8+. Since both the Power control panel and the brightness slider use this, we'll do the same, but fallback to PowerSetActiveScheme if on Windows 7 or something | |
| if (!PowerApplySettingChanges || DllCall(PowerApplySettingChanges, "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt") != 0) | |
| DllCall(PowerSetActiveScheme, "Ptr", 0, "Ptr", currSchemeGuid, "UInt") | |
| } | |
| } | |
| if (showOSD) | |
| BrightnessSetter._ShowBrightnessOSD() | |
| } | |
| DllCall("LocalFree", "Ptr", currSchemeGuid, "Ptr") | |
| } | |
| } | |
| IsOnAc(ByRef acStatus) | |
| { | |
| static SystemPowerStatus | |
| if (!VarSetCapacity(SystemPowerStatus)) | |
| VarSetCapacity(SystemPowerStatus, 12) | |
| if (DllCall("GetSystemPowerStatus", "Ptr", &SystemPowerStatus)) { | |
| acStatus := NumGet(SystemPowerStatus, 0, "UChar") == 1 | |
| return True | |
| } | |
| return False | |
| } | |
| GetDefaultBrightnessIncrement() | |
| { | |
| static ret := 10 | |
| DllCall("powrprof\PowerReadValueIncrement", "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt*", ret, "UInt") | |
| return ret | |
| } | |
| GetMinBrightness() | |
| { | |
| static ret := -1 | |
| if (ret == -1) | |
| if (DllCall("powrprof\PowerReadValueMin", "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt*", ret, "UInt")) | |
| ret := 0 | |
| return ret | |
| } | |
| GetMaxBrightness() | |
| { | |
| static ret := -1 | |
| if (ret == -1) | |
| if (DllCall("powrprof\PowerReadValueMax", "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt*", ret, "UInt")) | |
| ret := 100 | |
| return ret | |
| } | |
| _GetCurrentBrightness(schemeGuid, AC, ByRef currBrightness) | |
| { | |
| static PowerReadACValueIndex := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerReadACValueIndex", "Ptr") | |
| ,PowerReadDCValueIndex := DllCall("GetProcAddress", "Ptr", BrightnessSetter.hPowrprofMod, "AStr", "PowerReadDCValueIndex", "Ptr") | |
| return DllCall(AC ? PowerReadACValueIndex : PowerReadDCValueIndex, "Ptr", 0, "Ptr", schemeGuid, "Ptr", BrightnessSetter._GUID_VIDEO_SUBGROUP(), "Ptr", BrightnessSetter._GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS(), "UInt*", currBrightness, "UInt") == 0 | |
| } | |
| _ShowBrightnessOSD() | |
| { | |
| static PostMessagePtr := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr"), "AStr", A_IsUnicode ? "PostMessageW" : "PostMessageA", "Ptr") | |
| ,WM_SHELLHOOK := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK", "UInt") | |
| if A_OSVersion in WIN_VISTA,WIN_7 | |
| return | |
| BrightnessSetter._RealiseOSDWindowIfNeeded() | |
| ; Thanks to YashMaster @ https://github.com/YashMaster/Tweaky/blob/master/Tweaky/BrightnessHandler.h for realising this could be done: | |
| if (BrightnessSetter._osdHwnd) | |
| DllCall(PostMessagePtr, "Ptr", BrightnessSetter._osdHwnd, "UInt", WM_SHELLHOOK, "Ptr", 0x37, "Ptr", 0) | |
| } | |
| _RealiseOSDWindowIfNeeded() | |
| { | |
| static IsWindow := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr"), "AStr", "IsWindow", "Ptr") | |
| if (!DllCall(IsWindow, "Ptr", BrightnessSetter._osdHwnd) && !BrightnessSetter._FindAndSetOSDWindow()) { | |
| BrightnessSetter._osdHwnd := 0 | |
| try if ((shellProvider := ComObjCreate("{C2F03A33-21F5-47FA-B4BB-156362A2F239}", "{00000000-0000-0000-C000-000000000046}"))) { | |
| try if ((flyoutDisp := ComObjQuery(shellProvider, "{41f9d2fb-7834-4ab6-8b1b-73e74064b465}", "{41f9d2fb-7834-4ab6-8b1b-73e74064b465}"))) { | |
| DllCall(NumGet(NumGet(flyoutDisp+0)+3*A_PtrSize), "Ptr", flyoutDisp, "Int", 0, "UInt", 0) | |
| ,ObjRelease(flyoutDisp) | |
| } | |
| ObjRelease(shellProvider) | |
| if (BrightnessSetter._FindAndSetOSDWindow()) | |
| return | |
| } | |
| ; who knows if the SID & IID above will work for future versions of Windows 10 (or Windows 8). Fall back to this if needs must | |
| Loop 2 { | |
| SendEvent {Volume_Mute 2} | |
| if (BrightnessSetter._FindAndSetOSDWindow()) | |
| return | |
| Sleep 100 | |
| } | |
| } | |
| } | |
| _FindAndSetOSDWindow() | |
| { | |
| static FindWindow := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr"), "AStr", A_IsUnicode ? "FindWindowW" : "FindWindowA", "Ptr") | |
| return !!((BrightnessSetter._osdHwnd := DllCall(FindWindow, "Str", "NativeHWNDHost", "Str", "", "Ptr"))) | |
| } | |
| _On_WM_POWERBROADCAST(wParam, lParam) | |
| { | |
| ;OutputDebug % &this | |
| if (wParam == 0x8013 && lParam && NumGet(lParam+0, 0, "UInt") == NumGet(BrightnessSetter._GUID_ACDC_POWER_SOURCE()+0, 0, "UInt")) { ; PBT_POWERSETTINGCHANGE and a lazy comparison | |
| this._AC := NumGet(lParam+0, 20, "UChar") == 0 | |
| return True | |
| } | |
| } | |
| _GUID_VIDEO_SUBGROUP() | |
| { | |
| static GUID_VIDEO_SUBGROUP__ | |
| if (!VarSetCapacity(GUID_VIDEO_SUBGROUP__)) { | |
| VarSetCapacity(GUID_VIDEO_SUBGROUP__, 16) | |
| ,NumPut(0x7516B95F, GUID_VIDEO_SUBGROUP__, 0, "UInt"), NumPut(0x4464F776, GUID_VIDEO_SUBGROUP__, 4, "UInt") | |
| ,NumPut(0x1606538C, GUID_VIDEO_SUBGROUP__, 8, "UInt"), NumPut(0x99CC407F, GUID_VIDEO_SUBGROUP__, 12, "UInt") | |
| } | |
| return &GUID_VIDEO_SUBGROUP__ | |
| } | |
| _GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS() | |
| { | |
| static GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__ | |
| if (!VarSetCapacity(GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__)) { | |
| VarSetCapacity(GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__, 16) | |
| ,NumPut(0xADED5E82, GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__, 0, "UInt"), NumPut(0x4619B909, GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__, 4, "UInt") | |
| ,NumPut(0xD7F54999, GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__, 8, "UInt"), NumPut(0xCB0BAC1D, GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__, 12, "UInt") | |
| } | |
| return &GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS__ | |
| } | |
| _GUID_ACDC_POWER_SOURCE() | |
| { | |
| static GUID_ACDC_POWER_SOURCE_ | |
| if (!VarSetCapacity(GUID_ACDC_POWER_SOURCE_)) { | |
| VarSetCapacity(GUID_ACDC_POWER_SOURCE_, 16) | |
| ,NumPut(0x5D3E9A59, GUID_ACDC_POWER_SOURCE_, 0, "UInt"), NumPut(0x4B00E9D5, GUID_ACDC_POWER_SOURCE_, 4, "UInt") | |
| ,NumPut(0x34FFBDA6, GUID_ACDC_POWER_SOURCE_, 8, "UInt"), NumPut(0x486551FF, GUID_ACDC_POWER_SOURCE_, 12, "UInt") | |
| } | |
| return &GUID_ACDC_POWER_SOURCE_ | |
| } | |
| } | |
| BrightnessSetter_new() { | |
| return new BrightnessSetter() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Arora-Sir yes of course I can test it, however it may have to wait a few days as I'm currently on vacation and only have my mac with me so I don't have access to my windows pc, but I will indeed test it :D