
I think I’ve finally done it — written an application for a “total addressable market” size of 1, namely me.
Usually, I keep the backlight on my Realforce GX1 keyboard on the lowest of its 3 brightness settings. But sometimes the sun gets a bit bright outside, and I go up a notch or two.
This app automates that process by reading the Apple Pro Display XDR’s ambient light sensors (ALS), computing a user-driven average, and then flexibly mapping that to the 3 keyboard backlight brightness levels. It also turns off the backlight if you want when the display goes dark or the Mac sleeps, since otherwise it will still be lit up during dark wake (or not yet asleep) time.
I had written the core of the RealforceControl library last year, since Realforce only provides Windows software for interacting with the non-core features of the keyboard. It was a fun experiment in reversing the USB commands the official software uses for configuring the keyboard.
Then, this summer, sun happened a fair bit, and I was minorly annoyed at having to push a button during the day for keyboard brightness up, and in the evening again for keyboard brightness down. And then realized that I was thankful for Apple’s automatic display brightness working so well on the Pro Display XDR that I didn’t have to deal with that aspect at all.
And so, I looked into whether one could access the data from the ambient light sensor of the display, and it also happens to be exposed as a USB HID device (the relevant info I could find was for a Windows-based app for it, of all things). That worked quite well (other than an annoying CoreHID warning I cannot seem to get rid of when requesting an explicit element update), and so now I have an AmbientLight library for reading this sensor data.
And now, there’s KeyLight, which is a small macOS app that glues the two together, and now regulates the brightness of the keyboard. 🥳
Note: I used a locally hosted Qwen 3.8 27B for the later parts of these developments: I’m not sure I want to learn SwiftUI, and Swift’s actor model really has a lot of sharp edges; and as usual, Apple’s documentation leaves me wanting. The LLM has been a mostly competent aid, and I’m not sure I would have persisted with it otherwise… It was an interesting learning experience.
