├── .github └── workflows │ └── build.yaml ├── .gitignore ├── BrightnessControl.h ├── BrightnessControl.m ├── KeyboardBrightnessClient.h ├── KeyboardManager.h ├── KeyboardManager.m ├── LICENSE ├── Makefile ├── README.md └── main.m /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | runs-on: macos-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | 12 | - name: Build project 13 | run: | 14 | CC=clang 15 | CFLAGS="-Wall -Wextra -O2" 16 | LDFLAGS="-framework Foundation" 17 | SRC="main.m BrightnessControl.m KeyboardManager.m" 18 | OUT="mac-brightnessctl" 19 | $CC $CFLAGS $LDFLAGS -o $OUT $SRC 20 | - name: Release 21 | uses: softprops/action-gh-release@v1 22 | if: startsWith(github.ref, 'refs/tags/') 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | *.xcodeproj/* 15 | !*.xcodeproj/project.pbxproj 16 | !*.xcworkspace/contents.xcworkspacedata 17 | DerivedData/ 18 | *.moved-aside 19 | *.pbxuser 20 | !default.pbxuser 21 | *.mode1v3 22 | !default.mode1v3 23 | *.mode2v3 24 | !default.mode2v3 25 | *.perspectivev3 26 | !default.perspectivev3 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | 31 | ## App packaging 32 | *.ipa 33 | *.dSYM.zip 34 | *.dSYM 35 | 36 | ## Playgrounds 37 | timeline.xctimeline 38 | playground.xcworkspace 39 | 40 | # Swift Package Manager 41 | # 42 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 43 | Packages/ 44 | Package.pins 45 | Package.resolved 46 | # *.xcodeproj 47 | # 48 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 49 | # hence it is not needed unless you have added a package configuration file to your project 50 | # .swiftpm 51 | 52 | .build/ 53 | 54 | # CocoaPods 55 | # 56 | # We recommend against adding the Pods directory to your .gitignore. However 57 | # you should judge for yourself, the pros and cons are mentioned at: 58 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 59 | # 60 | # Pods/ 61 | # 62 | # Add this line if you want to avoid checking in source code from the Xcode workspace 63 | # *.xcworkspace 64 | 65 | # Carthage 66 | # 67 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 68 | # Carthage/Checkouts 69 | 70 | Carthage/Build/ 71 | 72 | # Accio dependency management 73 | Dependencies/ 74 | .accio/ 75 | 76 | # fastlane 77 | # 78 | # It is recommended to not store the screenshots in the git repo. 79 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 80 | # For more information about the recommended setup visit: 81 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 82 | 83 | fastlane/report.xml 84 | fastlane/Preview.html 85 | fastlane/screenshots/**/*.png 86 | fastlane/test_output 87 | 88 | # Code Injection 89 | # 90 | # After new code Injection tools there's a generated folder /iOSInjectionProject 91 | # https://github.com/johnno1962/injectionforxcode 92 | 93 | iOSInjectionProject/ -------------------------------------------------------------------------------- /BrightnessControl.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface BrightnessControl : NSObject 4 | 5 | + (void)setBrightness:(float)brightness; 6 | + (float)getBrightness; 7 | + (bool)isAutoBrightnessEnabled; 8 | + (bool)isIdleDimmingSuspended; 9 | + (void)setSuspendIdleDimming:(bool)value; 10 | + (void)setIdleDimTime:(double)value; 11 | + (double)idleDimTimeForKeyboard; 12 | + (void)enableAutoBrightness:(bool)value; 13 | + (void)flashKeyboardLights:(int)times 14 | withInterval:(double)interval 15 | andFadeSpeed:(double)fadeSpeed; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /BrightnessControl.m: -------------------------------------------------------------------------------- 1 | #import "BrightnessControl.h" 2 | #import "KeyboardManager.h" 3 | 4 | @implementation BrightnessControl 5 | 6 | + (void)setBrightness:(float)brightness { 7 | [KeyboardManager.brightnessClient setBrightness:brightness forKeyboard:1]; 8 | } 9 | 10 | + (float)getBrightness { 11 | return [KeyboardManager.brightnessClient brightnessForKeyboard:1]; 12 | } 13 | 14 | + (bool)isAutoBrightnessEnabled { 15 | return [KeyboardManager.brightnessClient isAutoBrightnessEnabledForKeyboard:1]; 16 | } 17 | 18 | + (bool)isIdleDimmingSuspended { 19 | return [KeyboardManager.brightnessClient isIdleDimmingSuspendedOnKeyboard:1]; 20 | } 21 | 22 | + (void)setSuspendIdleDimming:(bool)value { 23 | [KeyboardManager.brightnessClient suspendIdleDimming:value forKeyboard:1]; 24 | } 25 | 26 | + (void)setIdleDimTime:(double)value { 27 | [KeyboardManager.brightnessClient setIdleDimTime:value forKeyboard:1]; 28 | } 29 | 30 | + (double)idleDimTimeForKeyboard { 31 | return [KeyboardManager.brightnessClient idleDimTimeForKeyboard:1]; 32 | } 33 | 34 | + (void)enableAutoBrightness:(bool)value { 35 | [KeyboardManager.brightnessClient enableAutoBrightness:value forKeyboard:1]; 36 | } 37 | 38 | + (void)flashKeyboardLights:(int)times withInterval:(double)interval andFadeSpeed:(double)fadeSpeed { 39 | float current = [self getBrightness]; 40 | for (int i = 0; i < times; i++) { 41 | [KeyboardManager.brightnessClient setBrightness:0 fadeSpeed:fadeSpeed commit:true forKeyboard:1]; 42 | [NSThread sleepForTimeInterval:interval]; 43 | [KeyboardManager.brightnessClient setBrightness:1 fadeSpeed:fadeSpeed commit:true forKeyboard:1]; 44 | [NSThread sleepForTimeInterval:interval]; 45 | } 46 | [self setBrightness:current]; 47 | } 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /KeyboardBrightnessClient.h: -------------------------------------------------------------------------------- 1 | @interface KeyboardBrightnessClient : NSObject 2 | 3 | - (void)unregisterKeyboardNotificationBlock; 4 | - (BOOL)isAutoBrightnessEnabledForKeyboard:(unsigned long long)arg1; 5 | - (BOOL)isIdleDimmingSuspendedOnKeyboard:(unsigned long long)arg1; 6 | - (BOOL)suspendIdleDimming:(BOOL)arg1 forKeyboard:(unsigned long long)arg2; 7 | - (BOOL)setIdleDimTime:(double)arg1 forKeyboard:(unsigned long long)arg2; 8 | - (double)idleDimTimeForKeyboard:(unsigned long long)arg1; 9 | - (BOOL)isKeyboardBuiltIn:(unsigned long long)arg1; 10 | - (BOOL)isAmbientFeatureAvailableOnKeyboard:(unsigned long long)arg1; 11 | - (BOOL)enableAutoBrightness:(BOOL)arg1 forKeyboard:(unsigned long long)arg2; 12 | - (BOOL)setBrightness:(float)arg1 fadeSpeed:(int)arg2 commit:(_Bool)arg3 forKeyboard:(unsigned long long)arg4; 13 | - (BOOL)setBrightness:(float)arg1 forKeyboard:(unsigned long long)arg2; 14 | - (float)brightnessForKeyboard:(unsigned long long)arg1; 15 | - (BOOL)isBacklightDimmedOnKeyboard:(unsigned long long)arg1; 16 | - (BOOL)isBacklightSaturatedOnKeyboard:(unsigned long long)arg1; 17 | - (BOOL)isBacklightSuppressedOnKeyboard:(unsigned long long)arg1; 18 | - (id)copyKeyboardBacklightIDs; 19 | - (id)init; 20 | 21 | // Auto-dim speed is 500ms 22 | // manual control fade speed is 350ms 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /KeyboardManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "KeyboardBrightnessClient.h" 3 | 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | @interface KeyboardManager : NSObject 7 | @property(nonatomic,strong) KeyboardBrightnessClient * brightnessClient; 8 | @property(atomic,readwrite) BOOL paused; 9 | +(id)sharedInstance; 10 | +(void)configure; 11 | +(KeyboardBrightnessClient *)brightnessClient; 12 | @end 13 | 14 | NS_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /KeyboardManager.m: -------------------------------------------------------------------------------- 1 | #import "KeyboardManager.h" 2 | 3 | @interface KeyboardManager() 4 | +(void)loadPrivateFrameworks; 5 | @end 6 | 7 | @implementation KeyboardManager 8 | 9 | + (id)sharedInstance { 10 | static KeyboardManager *sharedInstance = nil; 11 | static dispatch_once_t onceToken; 12 | dispatch_once(&onceToken, ^{ 13 | sharedInstance = [[self alloc] init]; 14 | }); 15 | return sharedInstance; 16 | } 17 | 18 | +(void)loadPrivateFrameworks { 19 | [[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/CoreBrightness.framework"] load]; 20 | [KeyboardManager.sharedInstance setBrightnessClient:[[NSClassFromString(@"KeyboardBrightnessClient") alloc] init]]; 21 | } 22 | 23 | +(void)configure { 24 | [self loadPrivateFrameworks]; 25 | } 26 | 27 | +(KeyboardBrightnessClient *)brightnessClient { 28 | return [KeyboardManager.sharedInstance brightnessClient]; 29 | } 30 | 31 | - (id)init { 32 | if (self = [super init]) { 33 | self.paused = false; 34 | } 35 | return self; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 rakalex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | CFLAGS = -Wall -Wextra -O2 3 | LDFLAGS = -framework Foundation 4 | 5 | SRC = main.m BrightnessControl.m KeyboardManager.m 6 | OUT = mac-brightnessctl 7 | 8 | all: $(OUT) 9 | 10 | $(OUT): $(SRC) 11 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ 12 | 13 | clean: 14 | rm -f $(OUT) 15 | 16 | .PHONY: all clean 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mac-brightnessctl 2 | mac-brightnessctl is a command line tool for controlling the keyboard backlight brightness on macOS. 3 | ## Usage 4 | ```bash 5 | mac-brightnessctl [