Change Laptop and External Monitor Brightness based on cursor position

Post your working scripts, libraries and tools.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 26 Sep 2022, 13:47

Based on where your mouse is, this script will change the brightness of that monitor.
Works with laptop and external monitors.
If you have a laptop monitor, the flyout will also be displayed.

Credits to everyone, because I must have used 5-6+ sources for code. W stands for Window and M stands for mouse. The OSD has been disabled, since it doesn't seem to work on Windows 11 (it just brings up the volume slider)

Code: Select all

; Use strings "+1" or "-1"
XButton2 & WheelUp :: BrightnessOSDM "+1" ; Cursor Position
XButton2 & WheelDown:: BrightnessOSDM "-1" ; Cursor Position

^Up::                 BrightnessOSDW "+1"  ; Current Active Window
^Down::               BrightnessOSDW "-1"  ; Current Active Window

BrightnessOSDW(b) { ; Use current active window
   hMon := DllCall("MonitorFromWindow", "ptr", WinExist("A"), "uint", 0, "ptr")
   return BrightnessOSD(hMon, b)
}

BrightnessOSDM(b) { ; Use cursor position
   DllCall("GetCursorPos", "uint64*", &point:=0)
   hMon := DllCall("MonitorFromPoint", "uint64", point, "uint", 0x2, "ptr")
   return BrightnessOSD(hMon, b)
}

BrightnessOSD(hMon, b) { ; https://www.reddit.com/r/AutoHotkey/comments/uvykvk/comment/i9orgso/



      MIEX := Buffer(40 + 64)
         NumPut("uint", MIEX.size, MIEX)

   if DllCall("GetMonitorInfo", "ptr", hMon, "ptr", MIEX)
      MonName := StrGet(MIEX.ptr + 40, 32)









   ; https://stackoverflow.com/a/42351543
   ; https://social.msdn.microsoft.com/Forums/windows/en-US/d940a189-58e8-48e5-a3f0-0ca0f66f1cb1/howto-get-handle-of-a-display-device-from-displaydevicedevicename?forum=vcgeneral

   ; struct DISPLAY_DEVICEW - https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-display_devicew
   ddAdapter := Buffer(840, 0)
      NumPut("uint", ddAdapter.size, ddAdapter)

   while DllCall("EnumDisplayDevicesW", "ptr", 0, "uint", A_Index-1, "ptr", ddAdapter, "uint", 0) {

      ; Useful DISPLAY_DEVICE.StateFlags:
      ;   #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
      ;   #define DISPLAY_DEVICE_PRIMARY_DEVICE      0x00000004
      ;   #define DISPLAY_DEVICE_MIRRORING_DRIVER    0x00000008

      StateFlags := NumGet(ddAdapter, 324, "uint")

      if ((StateFlags & 0x9) == 0x1) {

         DeviceName := StrGet(ddAdapter.ptr + 4, 32+2, "UTF-16")
         DeviceString := StrGet(ddAdapter.ptr + 68, 128+2, "UTF-16")

         ddMonitor := Buffer(840, 0)
            NumPut("uint", ddMonitor.size, ddMonitor)

         if (DeviceName != MonName)
            continue

         while DllCall("EnumDisplayDevicesW", "str", DeviceName, "uint", A_Index-1, "ptr", ddMonitor, "uint", 1) { ; EDD_GET_DEVICE_INTERFACE_NAME

            ; Child Device state
            ; #define DISPLAY_DEVICE_ACTIVE              0x00000001
            ; #define DISPLAY_DEVICE_ATTACHED            0x00000002

            StateFlags := NumGet(ddMonitor, 324, "uint")

            if (StateFlags & 0x1)
            {

              ;DeviceName := StrGet(ddMonitor.ptr + 4, 32+2, "UTF-16")
              ;DeviceString := StrGet(ddMonitor.ptr + 68, 128+2, "UTF-16")
               DeviceID := StrGet(ddMonitor.ptr + 328, 128+2, "UTF-16")

























   SupportedBrightness := Buffer(256, 0)
   Brightness := Buffer(3, 0)

   hLCD := DllCall("CreateFile"
         , "str", DeviceID ; !!!!!!!!!
         , "uint", 0x80000000 | 0x40000000 ;Read | Write
         , "uint", 0x1 | 0x2  ; File Read | File Write
         , "ptr", 0
         , "uint", 0x3  ; open any existing file
         , "uint", 0
         , "ptr", 0
         , "ptr")

   if hLCD = -1
      throw OSError()

   DevVideo := 0x00000023, BuffMethod := 0, Fileacces := 0
         NumPut("UChar", 0x03, Brightness, 0)   ; 0x01 = Set AC, 0x02 = Set DC, 0x03 = Set both
         NumPut("UChar", 0x00, Brightness, 1)      ; The AC brightness level
         NumPut("UChar", 0x00, Brightness, 2)      ; The DC brightness level

   DllCall("DeviceIoControl"
         , "ptr", hLCD
         , "uint", (DevVideo<<16 | 0x126<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS
         , "ptr", 0
         , "uint", 0
         , "ptr", Brightness
         , "uint", 3
         , "uint*", &BrightnessSize:=0
         , "ptr", 0)

   DllCall("DeviceIoControl"
         , "ptr", hLCD
         , "uint", (DevVideo<<16 | 0x125<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS
         , "ptr", 0
         , "uint", 0
         , "ptr", SupportedBrightness
         , "uint", 256
         , "uint*", &SupportedBrightnessSize:=0
         , "ptr", 0)

   ACBrightness := NumGet(Brightness, 1, "UChar")
   ACIndex := 0
   DCBrightness := NumGet(Brightness, 2, "UChar")
   DCIndex := 0
   BufferSize := SupportedBrightnessSize
   MaxIndex := SupportedBrightnessSize-1

   Loop BufferSize
   {
      ThisIndex := A_Index-1
      ThisBrightness := NumGet(SupportedBrightness, ThisIndex, "UChar")
      if (ACBrightness = ThisBrightness)
         ACIndex := ThisIndex
      if (DCBrightness = ThisBrightness)
         DCIndex := ThisIndex
   }

   if (DCIndex >= ACIndex)
      BrightnessIndex := DCIndex
   else
      BrightnessIndex := ACIndex

   BrightnessIndex += b
   BrightnessIndex := Min(MaxIndex, BrightnessIndex)
   BrightnessIndex := Max(0, BrightnessIndex)

   NewBrightness := NumGet(SupportedBrightness, BrightnessIndex, "UChar")
      NumPut("UChar", 0x03, Brightness, 0)   ; 0x01 = Set AC, 0x02 = Set DC, 0x03 = Set both
      NumPut("UChar", NewBrightness, Brightness, 1)      ; The AC brightness level
      NumPut("UChar", NewBrightness, Brightness, 2)      ; The DC brightness level

   ; will set A_LastError to ERROR_INVALID_HANDLE (0x6) if not a built in LCD.
   check := DllCall("DeviceIoControl"
      , "ptr", hLCD
      , "uint", (DevVideo<<16 | 0x127<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
      , "ptr", Brightness
      , "uint", 3
      , "ptr", 0
      , "uint", 0
      , "ptr", 0
      , "ptr", 0)

   DllCall("CloseHandle", "ptr", hLCD)      










   if not check {




static stored := Map()




      DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR"
         ,    "ptr", hMon
         ,  "uint*", &PhysMons:=0)
      DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR"
         ,    "ptr", hMon
         ,   "uint", PhysMons
         ,    "ptr", PHYS_MONITORS := Buffer((A_PtrSize + 256) * PhysMons, 0))
      hPhysMon := NumGet(PHYS_MONITORS, 0, "ptr")
start := A_TickCount
; Occasionaly fails to communicate with the monitor, setting current brightness to zero.
; fails if not external

      if ! stored.has(MonName) {
            ; fixes a bug where the call randomly fails :(
            while !DllCall("dxva2\GetVCPFeatureAndVCPFeatureReply"
                  , "Ptr",   hPhysMon
                  ,"uchar", 0x10
                  , "ptr", 0
                  , "uint*", &BrightnessCur:=0
                  , "uint*", &BrightnessMax:=0)
               if A_Index >= 6
                  throw OSError()

b := Max(0, Min(BrightnessMax, BrightnessCur + b))
            stored[MonName] := [0, b, BrightnessMax]
} else {
BrightnessMax := stored[MonName][3]
BrightnessCur := stored[MonName][2]
b := stored[MonName][2] := Max(0, Min(BrightnessMax, BrightnessCur + b))
}


   ; lmao you need to create a named function, and use named_func.bind or else SetTimer will just reset the timer!
   set_brightness(b, bref, xd2) {
      if (b == %bref%)
         DllCall("dxva2\SetVCPFeature", "Ptr",hPhysMon, "uchar", 0x10, "UInt", b)
      DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysMons, "ptr", xd2)
   }

   ; Sending a reference to b in case it changes is pretty important, as it allows updating the timer's function queue
   ; by discarding the unnecessary changes. For example, when going from 30 → 50, it's not necessary to set 31, 32, 33,
   ; if the current value of b is already at 50. Instead it may set 31, return, and see a new value of 50, skip 32-49 and set 50.
   SetTimer set_brightness.bind(b, &b, PHYS_MONITORS), -1









    }





   ; Cause you used createfile
   else {

/*
      ; Show the Brightness OSD
      static WM_SHELLHOOK := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK", "UInt")
      static hwnd := 0
      if !hwnd
         try if shellProvider := ComObject("{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}")
               if !ComCall(3, flyoutDisp, "int", 0, "uint", 0)
                  hwnd := DllCall("FindWindow", "Str", "NativeHWNDHost", "Str", "", "Ptr")
      DllCall("PostMessage", "ptr", hwnd, "uint", WM_SHELLHOOK, "uptr", 0x37, "ptr", 0)
*/
   }



























            }
         }

      }
   }















}
Old Code
Windows has too many monitor APIs, and this approach combines all of them.
  • EnumDisplayDevices - Reliable, yet also broken. Most of the symlinks it purports to create are not actually created, however, I managed to get this working.
  • EnumDisplayMonitors - Works, except cannot be used with CreateFile to open the device. Only returns an hMonitor
  • CreateFile - Can open a monitor device and returns a device handle compatible with DeviceIoControl.
  • DeviceIoControl - Extremely fast. Only works with laptop monitors.
  • GetPhysicalMonitorsFromHMONITOR - Uses the Physical Monitor API in combination with VCP codes.
  • SetVCPFeature - Slow. Only works with external monitors. Has a delay of about 50-100 ms, as it actually communicates with hardware.
  • PowerWriteACValueIndex - Indirectly sets the laptop brightness through the power plan.
  • ComObjGet( "winmgmts:\\.\root\WMI" ).ExecQuery("SELECT * FROM WmiMonitorBrightnessMethods") - Indirect. Executes a SQL Query, the absolute slowest. Extremely reliable however.
TwinkleTray - I recommend using https://twinkletray.com/ for a nice GUI.
  • Clean up code
  • Optimize - SetVCP is already optimized, the 40ms delay cannot be reduced any further, as I've tested it against TwinkleTray. TwinkleTray uses a delay to send only the latest VCP command, so it seems faster, this function seems slower, because every value from 80 → 40 is sent.
Last edited by iseahound on 19 Jun 2023, 11:44, edited 3 times in total.

o000u
Posts: 5
Joined: 09 May 2023, 20:35

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by o000u » 06 Jun 2023, 22:58

Hi! iseahound. Great code! It works perfect on my desktop monitor, and it is very sensitive to adjust the brightness, almost without delay! Thank you very much for sharing! The question now is, can it be converted to a v1 version of the code to use? I want to integrate it with the v1 code I used before. I am a novice to ahk and don't know much about v2, so I wonder if you can help? Thank you!

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 08 Jun 2023, 09:46

Hi! I suggest sticking with this v2 code, unless someone else decides to translate it back to v1. It's not small, and frankly, needs some work as you can probably see the fact that I was experimenting with different methods.

In case you or anyone else was wondering: The code to change the brightness of an external monitor is really fast and "snappy" because it queues up "+1" and "-1" commands. If you make it so the monitor goes from 100 to 0, it doesn't send 99, 98, etc. because any queued commands are overridden with the latest user input. I had to implement this because changing the monitor brightness for an external monitor is rather slow at around 30 milliseconds per command.

o000u
Posts: 5
Joined: 09 May 2023, 20:35

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by o000u » 08 Jun 2023, 10:38

iseahound wrote:
08 Jun 2023, 09:46
Hi! I suggest sticking with this v2 code, unless someone else decides to translate it back to v1. It's not small, and frankly, needs some work as you can probably see the fact that I was experimenting with different methods.

In case you or anyone else was wondering: The code to change the brightness of an external monitor is really fast and "snappy" because it queues up "+1" and "-1" commands. If you make it so the monitor goes from 100 to 0, it doesn't send 99, 98, etc. because any queued commands are overridden with the latest user input. I had to implement this because changing the monitor brightness for an external monitor is rather slow at around 30 milliseconds per command.
Oh, I see. In fact, I also want to use the v2 version, but the v1 library I am using is so large that it is difficult to switch to v2, so I can only stay at v1 for now, but I don't want to install both v1 and v2. Anyway, thank you very much for your reply and suggestion. I will continue to look for a solution. Once again, thank you for the magic code, they are really great!

Krd
Posts: 405
Joined: 10 Mar 2020, 02:46

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by Krd » 12 Jun 2023, 04:38

Can you please make a simple GUI for changing brightness instead of hotkeys?

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 12 Jun 2023, 08:56

https://twinkletray.com/ would be that nice GUI you were asking for - there's no need for me to reinvent the wheel.

Krd
Posts: 405
Joined: 10 Mar 2020, 02:46

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by Krd » 13 Jun 2023, 03:06

While I want to use this in my job.
If
only I had permission to install any exe.
else
'Please do it in AHK way' :)

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 19 Jun 2023, 11:40

Fixed a bug where sometimes the function would fail to capture a monitors brightness. It will now retry 6 times before throwing an error.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 05 Oct 2023, 15:56

@Krd
I too use this for work, and this is the GUI that I use:
image.png
image.png (125.64 KiB) Viewed 1956 times
Obviously if you don't like pink you can change the color. It's a completely random color, so its very rare that it'll end up pink.

Brightness.ahk

Code: Select all

#include *i TextRender.ahk

BrightnessOSDW(b) { ; Use current active window
   hMon := DllCall("MonitorFromWindow", "ptr", WinExist("A"), "uint", 0, "ptr")
   return BrightnessOSD(hMon, b)
}

BrightnessOSDM(b) { ; Use cursor position
   DllCall("GetCursorPos", "uint64*", &point:=0)
   hMon := DllCall("MonitorFromPoint", "uint64", point, "uint", 0x2, "ptr")
   return BrightnessOSD(hMon, b)
}

BrightnessOSD(hMon, b) { ; https://www.reddit.com/r/AutoHotkey/comments/uvykvk/comment/i9orgso/



   MIEX := Buffer(40 + 64)
      NumPut("uint", MIEX.size, MIEX)

   if DllCall("GetMonitorInfo", "ptr", hMon, "ptr", MIEX)
      MonName := StrGet(MIEX.ptr + 40, 32)









   ; https://stackoverflow.com/a/42351543
   ; https://social.msdn.microsoft.com/Forums/windows/en-US/d940a189-58e8-48e5-a3f0-0ca0f66f1cb1/howto-get-handle-of-a-display-device-from-displaydevicedevicename?forum=vcgeneral

   ; struct DISPLAY_DEVICEW - https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-display_devicew
   ddAdapter := Buffer(840, 0)
      NumPut("uint", ddAdapter.size, ddAdapter)

   while DllCall("EnumDisplayDevicesW", "ptr", 0, "uint", A_Index-1, "ptr", ddAdapter, "uint", 0) {

      ; Useful DISPLAY_DEVICE.StateFlags:
      ;   #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
      ;   #define DISPLAY_DEVICE_PRIMARY_DEVICE      0x00000004
      ;   #define DISPLAY_DEVICE_MIRRORING_DRIVER    0x00000008

      StateFlags := NumGet(ddAdapter, 324, "uint")

      if ((StateFlags & 0x9) == 0x1) {

         DeviceName := StrGet(ddAdapter.ptr + 4, 32+2, "UTF-16")
         DeviceString := StrGet(ddAdapter.ptr + 68, 128+2, "UTF-16")

         ddMonitor := Buffer(840, 0)
            NumPut("uint", ddMonitor.size, ddMonitor)

         if (DeviceName != MonName)
            continue

         while DllCall("EnumDisplayDevicesW", "str", DeviceName, "uint", A_Index-1, "ptr", ddMonitor, "uint", 1) { ; EDD_GET_DEVICE_INTERFACE_NAME

            ; Child Device state
            ; #define DISPLAY_DEVICE_ACTIVE              0x00000001
            ; #define DISPLAY_DEVICE_ATTACHED            0x00000002

            StateFlags := NumGet(ddMonitor, 324, "uint")

            if (StateFlags & 0x1) {

              ;DeviceName := StrGet(ddMonitor.ptr + 4, 32+2, "UTF-16")
              ;DeviceString := StrGet(ddMonitor.ptr + 68, 128+2, "UTF-16")
               DeviceID := StrGet(ddMonitor.ptr + 328, 128+2, "UTF-16")




   SupportedBrightness := Buffer(256, 0)
   Brightness := Buffer(3, 0)

   hLCD := DllCall("CreateFile"
         , "str", DeviceID ; !!!!!!!!!
         , "uint", 0x80000000 | 0x40000000 ;Read | Write
         , "uint", 0x1 | 0x2  ; File Read | File Write
         , "ptr", 0
         , "uint", 0x3  ; open any existing file
         , "uint", 0
         , "ptr", 0
         , "ptr")

   if hLCD = -1
      throw OSError()

   DevVideo := 0x00000023, BuffMethod := 0, Fileacces := 0
         NumPut("UChar", 0x03, Brightness, 0)   ; 0x01 = Set AC, 0x02 = Set DC, 0x03 = Set both
         NumPut("UChar", 0x00, Brightness, 1)      ; The AC brightness level
         NumPut("UChar", 0x00, Brightness, 2)      ; The DC brightness level

   DllCall("DeviceIoControl"
         , "ptr", hLCD
         , "uint", (DevVideo<<16 | 0x126<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_QUERY_DISPLAY_BRIGHTNESS
         , "ptr", 0
         , "uint", 0
         , "ptr", Brightness
         , "uint", 3
         , "uint*", &BrightnessSize:=0
         , "ptr", 0)

   DllCall("DeviceIoControl"
         , "ptr", hLCD
         , "uint", (DevVideo<<16 | 0x125<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_QUERY_SUPPORTED_BRIGHTNESS
         , "ptr", 0
         , "uint", 0
         , "ptr", SupportedBrightness
         , "uint", 256
         , "uint*", &SupportedBrightnessSize:=0
         , "ptr", 0)

   ACBrightness := NumGet(Brightness, 1, "UChar")
   ACIndex := 0
   DCBrightness := NumGet(Brightness, 2, "UChar")
   DCIndex := 0
   BufferSize := SupportedBrightnessSize
   MaxIndex := SupportedBrightnessSize-1

   Loop BufferSize
   {
      ThisIndex := A_Index-1
      ThisBrightness := NumGet(SupportedBrightness, ThisIndex, "UChar")
      if (ACBrightness = ThisBrightness)
         ACIndex := ThisIndex
      if (DCBrightness = ThisBrightness)
         DCIndex := ThisIndex
   }

   if (DCIndex >= ACIndex)
      BrightnessIndex := DCIndex
   else
      BrightnessIndex := ACIndex

   BrightnessIndex += b
   BrightnessIndex := Min(MaxIndex, BrightnessIndex)
   BrightnessIndex := Max(0, BrightnessIndex)

   ; Absolute value now???
   ; b := BrightnessIndex

   NewBrightness := NumGet(SupportedBrightness, BrightnessIndex, "UChar")
      NumPut("UChar", 0x03, Brightness, 0)   ; 0x01 = Set AC, 0x02 = Set DC, 0x03 = Set both
      NumPut("UChar", NewBrightness, Brightness, 1)      ; The AC brightness level
      NumPut("UChar", NewBrightness, Brightness, 2)      ; The DC brightness level

   ; will set A_LastError to ERROR_INVALID_HANDLE (0x6) if not a built in LCD.
   check := DllCall("DeviceIoControl"
      , "ptr", hLCD
      , "uint", (DevVideo<<16 | 0x127<<2 | BuffMethod<<14 | Fileacces) ; IOCTL_VIDEO_SET_DISPLAY_BRIGHTNESS
      , "ptr", Brightness
      , "uint", 3
      , "ptr", 0
      , "uint", 0
      , "ptr", 0
      , "ptr", 0)

   DllCall("CloseHandle", "ptr", hLCD)      









   ; This is an external monitor.
   if not check {

      static stored := Map()

      DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR"
         ,    "ptr", hMon
         ,  "uint*", &PhysMons:=0)
      DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR"
         ,    "ptr", hMon
         ,   "uint", PhysMons
         ,    "ptr", PHYS_MONITORS := Buffer((A_PtrSize + 256) * PhysMons, 0))
      hPhysMon := NumGet(PHYS_MONITORS, 0, "ptr")

      start := A_TickCount
      ; Occasionaly fails to communicate with the monitor, setting current brightness to zero.
      ; fails if not external


      if ! stored.has(MonName) {
         ; fixes a bug where the call randomly fails :(
         while !DllCall("dxva2\GetVCPFeatureAndVCPFeatureReply"
               , "Ptr",   hPhysMon
               ,"uchar", 0x10
               , "ptr", 0
               , "uint*", &BrightnessCur:=0
               , "uint*", &BrightnessMax:=0)
            if A_Index >= 6
               throw OSError()

         b := Max(0, Min(BrightnessMax, BrightnessCur + b))
         stored[MonName] := [0, b, BrightnessMax]
      } 
      else {
         BrightnessMax := stored[MonName][3]
         BrightnessCur := stored[MonName][2]
         b := stored[MonName][2] := Max(0, Min(BrightnessMax, BrightnessCur + b))
      }

      ; Somehow b goes from a relative to a fixed value...

      ; lmao you need to create a named function, and use named_func.bind or else SetTimer will just reset the timer!
      set_brightness(b, bref, xd2) {
         if (b == %bref%)
            DllCall("dxva2\SetVCPFeature", "Ptr",hPhysMon, "uchar", 0x10, "UInt", b)
         DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysMons, "ptr", xd2)
      }

      ; Sending a reference to b in case it changes is pretty important, as it allows updating the timer's function queue
      ; by discarding the unnecessary changes. For example, when going from 30 → 50, it's not necessary to set 31, 32, 33,
      ; if the current value of b is already at 50. Instead it may set 31, return, and see a new value of 50, skip 32-49 and set 50.
      SetTimer set_brightness.bind(b, &b, PHYS_MONITORS), -1
   }




   ; Doesn't work on windows 11 for some reason.
   else {

/*
      ; Show the Brightness OSD
      static WM_SHELLHOOK := DllCall("RegisterWindowMessage", "Str", "SHELLHOOK", "UInt")
      static hwnd := 0
      if !hwnd
         try if shellProvider := ComObject("{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}")
               if !ComCall(3, flyoutDisp, "int", 0, "uint", 0)
                  hwnd := DllCall("FindWindow", "Str", "NativeHWNDHost", "Str", "", "Ptr")
      DllCall("PostMessage", "ptr", hwnd, "uint", WM_SHELLHOOK, "uptr", 0x37, "ptr", 0)
*/
   }

            }
         }

      }
   }

   ; Render here I guess.
   static color := Format("{:x}", Random(0, 0xFFFFFF))
   static tr := TextRender()
   func := () => (check) 
      ? tr.Render(BrightnessIndex, "t:750 a:bottom-left x:8vmin y:92vmin c:0xEE" color " screen:" hMon, "s:12vmin") 
      : tr.Render(b, "t:750 a:bottom-left x:8vmin y:92vmin c:0xEE" color " screen:" hMon, "s:12vmin")
   SetTimer func, -1
}

TextRender.ahk
https://github.com/iseahound/TextRender/blob/main/TextRender.ahk

Also don't complain that TextRender.ahk is like 3000 lines of code. It's the fastest text rendering engine in AutoHotkey, capable of 1000+ fps easily. In addition, when you change the brightness of different monitors, the GUI will show on that monitor with the correct scale and distance from the edge of the screen.

Krd
Posts: 405
Joined: 10 Mar 2020, 02:46

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by Krd » 07 Oct 2023, 07:47

This is weird!

I see the GUI displaying values from 0 to 100 but no effect on any screen!

What is wrong here? How to debug? That is why I saw notting before you provided the GUI.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 07 Oct 2023, 12:43

Don't know. It works on my laptop, my work laptop and their corresponding external monitors. I'm not buying additional monitors to test what works perfectly for me. You can read through my code, and the 7 different methods of changing monitor brightness.

Krd
Posts: 405
Joined: 10 Mar 2020, 02:46

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by Krd » 09 Oct 2023, 04:50

BrightnessOSDM only works on the laptop screen and not on external monitors.
Does it make a difference which type of screens are connected or how they are connected (using a dock here)?

Could you please share the steps to switch to the next 5 method? It seems that the Pro doesn't know how to do it.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by iseahound » 20 Oct 2023, 10:26

I'll be honest with you—I've tested plenty of monitors and this seems to work. You're very likely working in a virtualized environment, such as citrix workspace.

Krd
Posts: 405
Joined: 10 Mar 2020, 02:46

Re: Change Laptop and External Monitor Brightness based on cursor position

Post by Krd » 27 Oct 2023, 08:59

Nope, other than the docking station!

We let this be as it is. :)

Post Reply

Return to “Scripts and Functions (v2)”