mac-keyboard-brightness icon indicating copy to clipboard operation
mac-keyboard-brightness copied to clipboard

Keyboard brightness API removed by Apple on Macs after 2016 ๐Ÿ˜ญ (If you know of any new one, plz help๐Ÿ™)

Open DylanVolz opened this issue 6 years ago โ€ข 30 comments

macOS sierra version: 10.12.5 (16F73) mbp 15-in, 2016

Display controls work fine but keyboard read and write operations fail:

$ ./dbrightness 0.650391 $ ./dbrightness .8 $ ./kbrightness getLightSensors() error: failed to find ambient light sensor getKeyboardBrightness() error 0.000000 $ ./kbrightness 1.0 getLightSensors() error: failed to find ambient light sensor setKeyboardBrightness() error

I will update with more info when I have some time to debug this evening (and will pr if I find the issue).

DylanVolz avatar Jul 14 '17 21:07 DylanVolz

Thanks, you're not the only one to report this, but I haven't been able to fix it since it's not reproducible on my 2013 MacBook Pro.

pirate avatar Jul 14 '17 21:07 pirate

Ok, well I will see if I can get anywhere with it this weekend.

DylanVolz avatar Jul 14 '17 22:07 DylanVolz

Actually I think I fixed it 1d1daf1, pull master and give it a shot when you get a chance.

The binaries were just out of date from the c code (where I had removed getLightSensors), so I just recompiled them and pushed.

pirate avatar Jul 14 '17 22:07 pirate

Still having an issue, but got a new error message: $ ./kbrightness 1.0 Failed to connect to AppleLMUController setKeyboardBrightness() error $ ./kbrightness Failed to connect to AppleLMUController getKeyboardBrightness() error

DylanVolz avatar Jul 14 '17 22:07 DylanVolz

Hmm the IOKit methods I'm using are all deprecated, it's possible Apple removed support for them when it added upgraded hardware in the 2015+ MBP models.

I can try copying over this newer swift code instead for krightness: https://github.com/bhoeting/DiscoKeyboard/blob/b50d1722007aadba1059e5324cc0a572419dfd54/DiscoKeyboard/Backlight.swift

pirate avatar Jul 14 '17 22:07 pirate

Same is happening with DiscoKeyboard any leads on how to read KeyboardBrightness ?

I have a work around to set it by sending keystrokes but I can't read the value. I'll post it here soon.

Alex293 avatar Aug 16 '17 13:08 Alex293

Does ./dbrightness from the latest commit work? If so I think I have a fix for you @Alex293.

pirate avatar Aug 16 '17 21:08 pirate

Yes it does work,

./kbrightness give Failed to connect to AppleLMUController getKeyboardBrightness() error

Edit : Also it would be awesome to be able to set the value as for now the only thing I managed to get working is to send the keystrokes that increase the value by steps.

Alex293 avatar Aug 16 '17 21:08 Alex293

Hello! For me dbrightness works beautifully. However kbrightness always returns 0.000000%

Now if I run blink, it gives me this error: setKeyboardBrightness() error

I am on a 2017 MacBook pro nTB

tymscar avatar Aug 26 '17 03:08 tymscar

They changed the driver for the keyboard I'll post here soon how to read the value. But they didn't implemented the set function so we can't set the value without simulating the keyboard keys.

Alex293 avatar Aug 26 '17 17:08 Alex293

Got it!

Can we somehow implement the "simulating keyboard keys" part? I would love to have the keyboard flash when I get a notification for example :)

tymscar avatar Aug 26 '17 17:08 tymscar

I haven't figured out how to do it by simulating key presses yet, but if you find a way, do post back!

This article says there isn't an easy way to do it via AppleScript, and I don't know Swift/ObjC well enough to do it there.

fn + F6 on my keyboard is keyboard brightness up, does it vary between macs?

pirate avatar Aug 26 '17 18:08 pirate

import IOKit

static func readKeyboardBrigthness() -> Float?
    {
        let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleHIDKeyboardEventDriverV2"))
        defer
        {
            IOObjectRelease(service)
        }
        let ser: CFTypeRef = IORegistryEntryCreateCFProperty(service, "KeyboardBacklightBrightness" as CFString, kCFAllocatorDefault,0).takeUnretainedValue()
        if let result = ser as? Float {
            return result
        }


        return nil
    }

Alex293 avatar Aug 28 '17 11:08 Alex293

// Simulate illumination up
let code = NX_KEYTYPE_ILLUMINATION_UP
let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1)
event1?.cgEvent?.post(tap: .cghidEventTap)
let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1)
event2?.cgEvent?.post(tap: .cghidEventTap)



// Simulate illumination down
let code = NX_KEYTYPE_ILLUMINATION_DOWN
let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1)
event1?.cgEvent?.post(tap: .cghidEventTap)
let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1)
event2?.cgEvent?.post(tap: .cghidEventTap)

My previous comment give you the value. Good thing to note is that this is kinda slow. I tried to implement a slider and its too slow for nice results. If you can make something from this please keep me updated.

@tymscar here it is !

Alex293 avatar Aug 28 '17 11:08 Alex293

@pirate the is no way to simulate key press for keyboard illumination but you can simulate nsevent sent when those keys are pressed.

Alex293 avatar Aug 28 '17 12:08 Alex293

Also now that I'm thinking about this, you may actually be able to listen to quicks change by listening to those events (in my second comment). Like first you read the value with the driver to get the initial value then you only listen to the events. I don't have time to experiment those days this but I will when I can.

Alex293 avatar Aug 28 '17 12:08 Alex293

Here is the start of an observer for IOKit. I does not work but I think its not so far :

import IOKit
import Foundation

let IOKitListenerNewDataNotificationIdentifier: NSNotification.Name = NSNotification.Name("IOKitListenerNewDataNotification")
let IOKitListenerNewDataNotificationKeyboardBrightnessIdentifier = "IOKitListenerNewDataNotificationKeyboardBrightness"

class IOKitListener: NSObject
{
    //var masterPort : mach_port_t?
    var isListenerActive : Bool = false
    var service : io_registry_entry_t
    var notificationPort : IONotificationPortRef?
    //var notificationRunLoopSource : CFRunLoopSource?

    //var info : Dictionary?

    private override init()
    {
        service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleHIDKeyboardEventDriverV2"))
    }

    //MARK: Shared Instance

    static let shared: IOKitListener = IOKitListener()

    func start()
    {
        guard !isListenerActive else { return }
        notificationPort = IONotificationPortCreate(kIOMasterPortDefault)
        //let notificationObject : io_object_t
        IOServiceAddInterestNotification(notificationPort, service, kIOGeneralInterest, { (_, _, _, _) in IOKitListener.shared.didRefresh() }, nil, nil)
        IONotificationPortSetDispatchQueue(notificationPort, DispatchQueue.main)
        isListenerActive = true
    }

    func did (arg1 : UnsafeMutableRawPointer?, arg2 : io_service_t, arg3 : UInt32, arg4 : UnsafeMutableRawPointer?)
    {
        didRefresh()
    }

    func stop()
    {
        guard isListenerActive else { return }
        IONotificationPortDestroy(notificationPort)
    }

    func request()
    {
        didRefresh()
    }

    func didRefresh()
    {
        guard let result = IORegistryEntryCreateCFProperty(service, "KeyboardBacklightBrightness" as CFString, kCFAllocatorDefault,0).takeUnretainedValue() as? Float else { return }
        NotificationCenter.default.post(name: IOKitListenerNewDataNotificationIdentifier, object: nil, userInfo: [IOKitListenerNewDataNotificationKeyboardBrightnessIdentifier: result])
    }
}

Alex293 avatar Aug 28 '17 12:08 Alex293

That looks awesome @Alex293 ! I've however never done macOS dev so I'm not sure how to execute it :(

I opened up a new Xcode project and made a cocoa app but it doesn't seem to play well with the code.

tymscar avatar Aug 28 '17 23:08 tymscar

Look for a quick tutorial on the net with just a simple button in a controller then add one of the two part of my second comment.

Alex293 avatar Aug 29 '17 12:08 Alex293

Works nicely! :D

tymscar avatar Sep 08 '17 02:09 tymscar

This didn't match my requirements but I'm happy that it still useful to someone !

Alex293 avatar Sep 08 '17 17:09 Alex293

As mentioned in https://github.com/pirate/mac-keyboard-brightness/issues/8 I now have a new mac to test this on, so I can hopefully get this working again sometime in the next few weeks. Post any tips here if you have them.

pirate avatar Dec 02 '19 18:12 pirate

Related issue: https://github.com/maxmouchet/LightKit/issues/1

pirate avatar Dec 03 '19 21:12 pirate

As far as I can tell, the keyboard brightness is not present in the IORegistry at all :/

ioreg > before.txt
# changed keyboard brightness via touchbar
ioreg > after.txt
diff before.txt after.txt
# no indication of keyboard-brightness related changes in the difff

This means it's either controlled via some other secret API or is not accessible at all. I'll keep investigating, but if I don't find anything we may have to resort to faking the key events as @Alex293 showed above.

pirate avatar Dec 03 '19 22:12 pirate

I just reproduced the issue on my Machine:

$ ./brightness 0.85
Failed to connect to AppleLMUController
setKeyboardBrightness() error
$ neofetch
               .OMMMMo           OS: macOS 10.15.3 19D76 x86_64
               OMMM0,            Host: MacBookPro15,1
     .;loddo:' loolloddol;.      Kernel: 19.3.0
   cKMMMMMMMMMMNWMMMMMMMMMM0:    Uptime: 1 day, 19 hours, 21 mins
 .KMMMMMMMMMMMMMMMMMMMMMMMWd.    Packages: 123 (brew)
 XMMMMMMMMMMMMMMMMMMMMMMMX.      Shell: zsh 5.7.1
;MMMMMMMMMMMMMMMMMMMMMMMM:       Resolution: 1920x1200@2x, 3840x1600@2x
:MMMMMMMMMMMMMMMMMMMMMMMM:       DE: Aqua
.MMMMMMMMMMMMMMMMMMMMMMMMX.      WM: Quartz Compositor
 kMMMMMMMMMMMMMMMMMMMMMMMMWd.    WM Theme: Blue (Dark)
 .XMMMMMMMMMMMMMMMMMMMMMMMMMMk   Terminal: iTerm2
  .XMMMMMMMMMMMMMMMMMMMMMMMMK.   Terminal Font: HackNerdFontComplete-Regular 12
    kMMMMMMMMMMMMMMMMMMMMMMd     CPU: Intel i7-8850H (12) @ 2.60GHz
     ;KMMMMMMMWXXWMMMMMMMk.      GPU: Intel UHD Graphics 630, Radeon Pro 560X
       .cooc,.    .,coo:.        Memory: 11195MiB / 16384MiB

tbrodbeck avatar Mar 27 '20 17:03 tbrodbeck

Yeah there's no known fix unfortunately, the registry options that were used to control it in the past are no longer available on new machines.

pirate avatar Mar 31 '20 03:03 pirate

Any news on this? I have the same issue.

cotfas:mac-keyboard-brightness work$ ./kbrightness Failed to connect to AppleLMUController getKeyboardBrightness() error 0.000000 cotfas:mac-keyboard-brightness work$

cotfas avatar May 17 '20 20:05 cotfas

@cotfas

there's no known fix unfortunately

pirate avatar May 18 '20 01:05 pirate

Just to clarify, there's no way to take command line control of the keyboard backlight for MacBook with Touch Bar?

daisy-spec avatar Aug 07 '22 01:08 daisy-spec

Maybe https://github.com/EthanRDoesMC/KBPulse

JamesEthan261 avatar Jun 27 '23 04:06 JamesEthan261