Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hs.brightness.get() returns nil on M1 #2668

Closed
limakzi opened this issue Jan 30, 2021 · 13 comments
Closed

hs.brightness.get() returns nil on M1 #2668

limakzi opened this issue Jan 30, 2021 · 13 comments

Comments

@limakzi
Copy link

limakzi commented Jan 30, 2021

I have found an issue on Apple Silicon M1. hs.brightness returns nil and returns false on each function execution.
I think this is related to: #2663.

> hs.brightness.get()
nil

> hs.brightness.set(20)
false

> hs.brightness.set(50)
false
@cmsj
Copy link
Member

cmsj commented Feb 9, 2021

See also #2663 - the display Subsystem on M1 macs seems to be completely different and the old APIs for getting brightness and screen names don't work. Hopefully we'll be able to figure out replacements at some point!

@cmsj cmsj closed this as completed in cededda Feb 14, 2021
@cmsj
Copy link
Member

cmsj commented Feb 14, 2021

For now I've added a note to the docs for hs.brightness, to indicate that the module is not working on M1 Macs.

@limakzi
Copy link
Author

limakzi commented Feb 15, 2021

@cmsj Closing not resolved issue is passé. 😢

@latenitefilms
Copy link
Contributor

@limakzi - Unfortunately there's not much that can be done, unless someone in the open source community can work out how Apple's doing it, and track down a hidden API or workaround.

Hopefully one of these issues on other repos will come up with a fix:

@jtbandes
Copy link

jtbandes commented Feb 21, 2021

I found that these private APIs from the DisplayServices framework work for getting and setting brightness on my M1 MacBook Air's built-in display:

extern int DisplayServicesGetBrightness(int display, float *brightness);
extern int DisplayServicesSetBrightness(int display, float brightness);

// Change brightness
float brightness = 0.8;
int err = DisplayServicesSetBrightness(1, brightness);

// Get current brightness
err = DisplayServicesGetBrightness(1, &brightness);

@asmagill
Copy link
Member

Can anyone try these out on an intel mac, and ideally as far back as Mojave?

@asmagill
Copy link
Member

Ok, it works on the M1 MacBook, but doesn't on an Intel iMac running Catalina (the previous method did work on it) or an intel MacBook running Big Sur. I need to figure out how to determine architecture at runtime (which should be easy, just haven't had to do it yet) and select the method based on that. I should have a pull request up later today.

This still doesn't make hs.brightness.ambient work... any luck finding something to address that?

@jtbandes
Copy link

jtbandes commented Feb 21, 2021

I believe the ambient brightness can be read with: /usr/libexec/corebrightnessdiag status-info | grep AggregatedLux

I'm looking into whether there's a way to get this using a private API instead of parsing log output, although I think parsing the plist produced by corebrightnessdiag is not a terrible solution (for some applications—not sure about the hammerspoon project). Example of parsing the output here.

@asmagill
Copy link
Member

@jtbandes where did you come across DisplayServicesSetBrightness and DisplayServicesGetBrightness? Is there a link you can share that has more information?

I can get it to work in hs.brightness but not in hs.screen. As far as I can tell, hs.screen is loaded before whatever framework that contains these functions is loaded (hs.screen and hs.window are loaded pretty early during application launch) , so even with weak linking, hs.screen can't resolve them and leaves the weak links Null. If I can figure out which framework they belong to (or at least which framework forces the framework they belong to) to load, I can link the screen library directly to it.

The other possibilities I'm considering are to muck around with dlsym and try to validate them that way (annoying, tedious, and may hit the same wall) or more likely convert hs.screen:getBrightness and hs.screen:setBrightness into wrappers that actually use hs.brightness but make sure not to load the actual brightness module until the methods are invoked.


Further crappy news... apparently even hs.brightness fails if the console hasn't been opened first... so unless I can figure out a framework to link to, it looks like I'll have to muck around with dlsym anyways...

@latenitefilms
Copy link
Contributor

Open up /usr/libexec/corebrightnessdiag in Hopper?

Interestingly, I don't have corebrightnessdiag on Mojave, but I do have corebrightnessd.

@jtbandes
Copy link

This seems to work and give the same result as the corebrightnessdiag command I showed above:

// Link with /System/Library/PrivateFrameworks/CoreBrightness.framework
NSNumber* lux = [[NSClassFromString(@"DisplayServicesClient") new] copyPropertyForKey:@"AggregatedLux"];

It also works if you use BrightnessSystemClient instead of DisplayServicesClient. I don't really understand the differences here, just poking around private APIs 😉

It looks like these classes use XPC to communicate with com.apple.backlightd, but I haven't found which process actually provides that service so I don't know where to dig for a non-XPC way of getting the lux info. Anyway, this should work well enough

@jtbandes
Copy link

jtbandes commented Feb 21, 2021

where did you come across DisplayServicesSetBrightness and DisplayServicesGetBrightness?

I've been looking around to try and find a way to read brightness and this was the best I could find. I've been using Hopper to look at DisplayServices, CoreBrightness, and CoreDisplay frameworks. These functions seemed like the most direct and low-level ones to get brightness. There are also lots of other functions in DisplayServices that may be useful for various purposes. The ambient lighting stuff (and much other functionality) looks like it's implemented in some CBModule subclasses in CoreBrightness, however I don't really know how to correctly instantiate these classes and that's why I took the approach of using the BrightnessSystemClient (I think I got this idea from disassembling corebrightnessdiag).

FYI, there is a man page for corebrightnessdiag that says "Collects Night Shift Information for sysdiagnose".

image


If I can figure out which framework they belong to (or at least which framework forces the framework they belong to) to load, I can link the screen library directly to it.

Does DisplayServices or CoreBrightness not work? It's been working in my simple tests (a standalone Obj-C program).

(BTW, apologies if I say irrelevant things here — I'm not actually familiar with the hammerspoon project, just wanted to share my discoveries about Big Sur brightness APIs with others who've been struggling with them!)

@asmagill
Copy link
Member

Ok, adding package.loadlib("/System/Library/PrivateFrameworks/DisplayServices.framework/Versions/Current/DisplayServices", "*") to the head of hs.screen's init.lua file seems to do the trick, at least in initial tests...

I think I have some consistent behaviors now that I can try and wrap up into a pull request that you guys can test, hopefully later tonight or tomorrow at the latest.

As to the ambient stuff... I'll take a closer look after I get the brightness stuff working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants