@@ -436,10 +436,10 @@ def brightness(self) -> Optional[int]:
436
436
if self ._iokit is None :
437
437
self ._iokit , self ._cf , self ._ioservice = _loadIOKit (self .handle )
438
438
if self ._iokit is not None and self ._cf is not None and self ._ioservice is not None :
439
- var_name = CF .CFStringCreateWithCString (None , b"brightness" , 0 )
439
+ kDisplayBrightnessKey = CF .CFStringCreateWithCString (None , b"brightness" , 0 )
440
440
value = ctypes .c_float ()
441
441
try :
442
- ret = self ._iokit .IODisplayGetFloatParameter (self ._ioservice , 0 , var_name , ctypes .byref (value ))
442
+ ret = self ._iokit .IODisplayGetFloatParameter (self ._ioservice , 0 , kDisplayBrightnessKey , ctypes .byref (value ))
443
443
except :
444
444
ret = 1
445
445
if ret == 0 :
@@ -488,10 +488,10 @@ def setBrightness(self, brightness: Optional[int]):
488
488
if self ._iokit is None :
489
489
self ._iokit , self ._cf , self ._ioservice = _loadIOKit (self .handle )
490
490
if self ._iokit is not None and self ._cf is not None and self ._ioservice is not None :
491
- var_name = CF .CFStringCreateWithCString (None , b"brightness" , 0 )
491
+ kDisplayBrightnessKey = CF .CFStringCreateWithCString (None , b"brightness" , 0 )
492
492
value = ctypes .c_float (brightness / 100 )
493
493
try :
494
- ret = self ._iokit .IODisplaySetFloatParameter (self ._ioservice , 0 , var_name , value )
494
+ ret = self ._iokit .IODisplaySetFloatParameter (self ._ioservice , 0 , kDisplayBrightnessKey , value )
495
495
except :
496
496
ret = 1
497
497
if ret != 0 :
@@ -706,7 +706,6 @@ def _NSgetAllMonitorsDict():
706
706
# https://stackoverflow.com/questions/30816183/iokit-ioservicegetmatchingservices-broken-under-python3
707
707
# https://stackoverflow.com/questions/65150131/iodisplayconnect-is-gone-in-big-sur-of-apple-silicon-what-is-the-replacement
708
708
# https://alexdelorenzo.dev/programming/2018/08/16/reverse_engineering_private_apple_apis
709
- # https://github.com/nriley/brightness/blob/master/brightness.c
710
709
711
710
def _loadDisplayServices ():
712
711
# Display Services Framework can be used in modern systems. It takes A LOT to load
@@ -733,57 +732,71 @@ def _loadCoreDisplay():
733
732
734
733
def _loadIOKit (displayID = Quartz .CGMainDisplayID ()):
735
734
# In other systems, we can try to use IOKit
735
+ # https://github.com/nriley/brightness/blob/master/brightness.c
736
736
# https://stackoverflow.com/questions/22841741/calling-functions-with-arguments-from-corefoundation-using-ctypes
737
737
738
- try :
739
- class _CFString (ctypes .Structure ):
740
- pass
741
-
742
- CFStringRef = ctypes .POINTER (_CFString )
743
-
744
- lib = ctypes .util .find_library ("CoreFoundation" )
745
- if not lib :
746
- return None , None , None
747
- CF : ctypes .CDLL = ctypes .cdll .LoadLibrary (lib )
748
- CF .CFStringCreateWithCString .argtypes = [ctypes .c_void_p , ctypes .c_char_p , ctypes .c_uint32 ]
749
- CF .CFStringCreateWithCString .restype = CFStringRef
750
-
751
- lib = ctypes .util .find_library ('IOKit' )
752
- if not lib :
753
- return None , None , None
754
- iokit : ctypes .CDLL = ctypes .cdll .LoadLibrary (lib )
755
- iokit .IODisplayGetFloatParameter .argtypes = [ctypes .c_void_p , ctypes .c_uint , CFStringRef , ctypes .POINTER (ctypes .c_float )]
756
- iokit .IODisplayGetFloatParameter .restype = ctypes .c_int
757
- iokit .IODisplaySetFloatParameter .argtypes = [ctypes .c_void_p , ctypes .c_uint , CFStringRef , ctypes .c_float ]
758
- iokit .IODisplaySetFloatParameter .restype = ctypes .c_int
759
- iokit .IOServiceRequestProbe .argtypes = [ctypes .c_void_p , ctypes .c_uint ]
760
- iokit .IOServiceRequestProbe .restype = ctypes .c_int
761
-
762
- try :
763
- service : int = Quartz .CGDisplayIOServicePort (displayID )
764
- except :
765
- service = 0
766
-
767
- if not service :
768
-
769
- iokit .IOServiceMatching .restype = ctypes .c_void_p
770
- iokit .IOServiceGetMatchingService .argtypes = [ctypes .c_void_p , ctypes .c_void_p ]
771
- iokit .IOServiceGetMatchingService .restype = ctypes .c_void_p
772
-
773
- try :
774
- kIOMasterPortDefault = ctypes .c_void_p .in_dll (iokit , "kIOMasterPortDefault" )
738
+ class _CFString (ctypes .Structure ):
739
+ pass
775
740
776
- service = iokit .IOServiceGetMatchingService (
777
- kIOMasterPortDefault ,
778
- iokit .IOServiceMatching (b'IODisplayConnect' )
779
- )
780
- except :
781
- service = 0
741
+ CFStringRef = ctypes .POINTER (_CFString )
742
+
743
+ lib = ctypes .util .find_library ("CoreFoundation" )
744
+ if not lib :
745
+ return None , None , None
746
+ CF : ctypes .CDLL = ctypes .cdll .LoadLibrary (lib )
747
+ CF .CFStringCreateWithCString .argtypes = [ctypes .c_void_p , ctypes .c_char_p , ctypes .c_uint32 ]
748
+ CF .CFStringCreateWithCString .restype = CFStringRef
749
+ CF .CFDictionaryGetValue .argtypes = [ctypes .c_void_p , CFStringRef ]
750
+ CF .CFDictionaryGetValue .restype = ctypes .c_void_p
751
+
752
+ lib = ctypes .util .find_library ('IOKit' )
753
+ if not lib :
754
+ return None , None , None
755
+ iokit : ctypes .CDLL = ctypes .cdll .LoadLibrary (lib )
756
+ iokit .IODisplayGetFloatParameter .argtypes = [ctypes .c_void_p , ctypes .c_uint , CFStringRef , ctypes .POINTER (ctypes .c_float )]
757
+ iokit .IODisplayGetFloatParameter .restype = ctypes .c_int
758
+ iokit .IODisplaySetFloatParameter .argtypes = [ctypes .c_void_p , ctypes .c_uint , CFStringRef , ctypes .c_float ]
759
+ iokit .IODisplaySetFloatParameter .restype = ctypes .c_int
760
+ iokit .IOServiceRequestProbe .argtypes = [ctypes .c_void_p , ctypes .c_uint ]
761
+ iokit .IOServiceRequestProbe .restype = ctypes .c_int
762
+ # iokit.IODisplayCreateInfoDictionary.argtypes = [ctypes.c_void_p, ctypes.c_uint]
763
+ # iokit.IODisplayCreateInfoDictionary.restype = ctypes.Structure
782
764
783
- if service :
784
- return iokit , CF , service
765
+ try :
766
+ # CGDisplayIOServicePort is deprecated as of 10.9
767
+ service : int = Quartz .CGDisplayIOServicePort (displayID )
785
768
except :
786
- pass
769
+ service = 0
770
+
771
+ # Check if this works in an actual macOS (preferably in several versions)
772
+ if not service :
773
+
774
+ iokit .IOServiceMatching .restype = ctypes .c_void_p
775
+ iokit .IOServiceGetMatchingServices .argtypes = [ctypes .c_void_p , ctypes .c_void_p , ctypes .c_void_p ]
776
+ iokit .IOServiceGetMatchingServices .restype = ctypes .c_void_p
777
+ iokit .IODisplayCreateInfoDictionary .restype = ctypes .c_void_p
778
+
779
+ kIOMasterPortDefault = ctypes .c_void_p .in_dll (iokit , "kIOMasterPortDefault" )
780
+ iterator = ctypes .c_void_p ()
781
+ ret = iokit .IOServiceGetMatchingServices (
782
+ kIOMasterPortDefault ,
783
+ iokit .IOServiceMatching (b'IODisplayConnect' ),
784
+ ctypes .byref (iterator )
785
+ )
786
+
787
+ kIODisplayNoProductName = 0x00000400
788
+ kDisplaySerialNumber = CF .CFStringCreateWithCString (None , b"DisplaySerialNumber" , 0 )
789
+ while True :
790
+ service = iokit .IOIteratorNext (iterator )
791
+ if not service :
792
+ break
793
+ info = iokit .IODisplayCreateInfoDictionary (service , kIODisplayNoProductName )
794
+ serialNumber = CF .CFDictionaryGetValue (info , kDisplaySerialNumber )
795
+ if serialNumber == Quartz .CGDisplaySerialNumber (displayID ):
796
+ break
797
+
798
+ if service :
799
+ return iokit , CF , service
787
800
788
801
return None , None , None
789
802
0 commit comments