diff --git a/NativeDisplayBrightness.xcodeproj/project.pbxproj b/NativeDisplayBrightness.xcodeproj/project.pbxproj index ba50f8d..134cbaf 100644 --- a/NativeDisplayBrightness.xcodeproj/project.pbxproj +++ b/NativeDisplayBrightness.xcodeproj/project.pbxproj @@ -12,6 +12,9 @@ 9DBE37561DB7990900ABE422 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9DBE37551DB7990900ABE422 /* Assets.xcassets */; }; 9DBE37591DB7990900ABE422 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9DBE37571DB7990900ABE422 /* MainMenu.xib */; }; 9DBE37621DB7996100ABE422 /* DDC.m in Sources */ = {isa = PBXBuildFile; fileRef = 9DBE37601DB7996100ABE422 /* DDC.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + E20E58922648360200C1F30B /* config.json in Resources */ = {isa = PBXBuildFile; fileRef = E20E58902648360200C1F30B /* config.json */; }; + E20E58932648360200C1F30B /* macOSKeyCodes.json in Resources */ = {isa = PBXBuildFile; fileRef = E20E58912648360200C1F30B /* macOSKeyCodes.json */; }; + E20E58952648362800C1F30B /* ButtonControl.m in Sources */ = {isa = PBXBuildFile; fileRef = E20E58942648362800C1F30B /* ButtonControl.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,6 +32,10 @@ 9DBE37631DB79A4000ABE422 /* BezelServices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BezelServices.h; sourceTree = ""; }; 9DBE37641DB7A87200ABE422 /* Readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = ""; }; 9DBE37661DB7A9D600ABE422 /* License.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = License.txt; sourceTree = ""; }; + E20E58902648360200C1F30B /* config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = config.json; sourceTree = ""; }; + E20E58912648360200C1F30B /* macOSKeyCodes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = macOSKeyCodes.json; sourceTree = ""; }; + E20E58942648362800C1F30B /* ButtonControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ButtonControl.m; sourceTree = ""; }; + E20E58962648363300C1F30B /* ButtonControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonControl.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +68,8 @@ 9DBE374E1DB7990900ABE422 /* NativeDisplayBrightness */ = { isa = PBXGroup; children = ( + E20E58902648360200C1F30B /* config.json */, + E20E58912648360200C1F30B /* macOSKeyCodes.json */, 9DBE374F1DB7990900ABE422 /* AppDelegate.h */, 9DBE37501DB7990900ABE422 /* AppDelegate.m */, 9DBE37551DB7990900ABE422 /* Assets.xcassets */, @@ -74,6 +83,8 @@ 9DBE37631DB79A4000ABE422 /* BezelServices.h */, 9D1F75421DBD44310039345A /* OSD.h */, 9D1F75431DBD48310039345A /* CoreGraphicsPriv.h */, + E20E58942648362800C1F30B /* ButtonControl.m */, + E20E58962648363300C1F30B /* ButtonControl.h */, ); path = NativeDisplayBrightness; sourceTree = ""; @@ -126,6 +137,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -144,8 +156,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E20E58932648360200C1F30B /* macOSKeyCodes.json in Resources */, 9DBE37561DB7990900ABE422 /* Assets.xcassets in Resources */, 9DBE37591DB7990900ABE422 /* MainMenu.xib in Resources */, + E20E58922648360200C1F30B /* config.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -159,6 +173,7 @@ 9DBE37621DB7996100ABE422 /* DDC.m in Sources */, 9DBE37541DB7990900ABE422 /* main.m in Sources */, 9DBE37511DB7990900ABE422 /* AppDelegate.m in Sources */, + E20E58952648362800C1F30B /* ButtonControl.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcuserdata/ivan_alone.xcuserdatad/UserInterfaceState.xcuserstate b/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcuserdata/ivan_alone.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..ce6fbcc Binary files /dev/null and b/NativeDisplayBrightness.xcodeproj/project.xcworkspace/xcuserdata/ivan_alone.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/NativeDisplayBrightness.xcodeproj/xcuserdata/ivan_alone.xcuserdatad/xcschemes/xcschememanagement.plist b/NativeDisplayBrightness.xcodeproj/xcuserdata/ivan_alone.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..dbf9a3e --- /dev/null +++ b/NativeDisplayBrightness.xcodeproj/xcuserdata/ivan_alone.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + NativeDisplayBrightness.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/NativeDisplayBrightness/AppDelegate.h b/NativeDisplayBrightness/AppDelegate.h index 249e960..25ae257 100644 --- a/NativeDisplayBrightness/AppDelegate.h +++ b/NativeDisplayBrightness/AppDelegate.h @@ -5,8 +5,12 @@ // Created by Benno Krauss on 19.10.16. // Copyright © 2016 Benno Krauss. All rights reserved. // +// Updated by Ivan_Alone on 09.05.21 +// Made with GNU GPL v3 permission +// #import +#import "ButtonControl.h" @interface AppDelegate : NSObject diff --git a/NativeDisplayBrightness/AppDelegate.m b/NativeDisplayBrightness/AppDelegate.m index 34d7721..5ec98e5 100644 --- a/NativeDisplayBrightness/AppDelegate.m +++ b/NativeDisplayBrightness/AppDelegate.m @@ -5,6 +5,9 @@ // Created by Benno Krauss on 19.10.16. // Copyright © 2016 Benno Krauss. All rights reserved. // +// Updated by Ivan_Alone on 09.05.21 +// Made with GNU GPL v3 permission +// #import "AppDelegate.h" #import "DDC.h" @@ -21,6 +24,8 @@ #pragma mark - variables void *(*_BSDoGraphicWithMeterAndTimeout)(CGDirectDisplayID arg0, BSGraphic arg1, int arg2, float v, int timeout) = NULL; +ButtonControl *globalButtonBrightnessUp = NULL, *globalButtonBrightnessDown = NULL; +NSDictionary* keyCodesAll = NULL; #pragma mark - functions @@ -45,7 +50,9 @@ CGEventRef keyboardCGEventCallback(CGEventTapProxy proxy, if (type == NX_KEYDOWN || type == NX_KEYUP || type == NX_FLAGSCHANGED) { int64_t keyCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); - if (keyCode == kVK_F2 || keyCode == kVK_F1) + int64_t modifierFlags = CGEventGetFlags(event); + + if ([globalButtonBrightnessDown verifyKey:keyCode arg2: modifierFlags] || [globalButtonBrightnessUp verifyKey:keyCode arg2: modifierFlags]) { return NULL; } @@ -102,7 +109,7 @@ - (void)_registerGlobalKeyboardEvents { [NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown | NSEventMaskKeyUp handler:^(NSEvent *_Nonnull event) { //NSLog(@"event!!"); - if (event.keyCode == kVK_F1) + if ([globalButtonBrightnessDown verifyKey:event.keyCode arg2: event.modifierFlags]) { if (event.type == NSEventTypeKeyDown) { @@ -111,7 +118,7 @@ - (void)_registerGlobalKeyboardEvents }); } } - else if (event.keyCode == kVK_F2) + else if ([globalButtonBrightnessUp verifyKey:event.keyCode arg2: event.modifierFlags]) { if (event.type == NSEventTypeKeyDown) { @@ -152,6 +159,7 @@ - (void)_loadBrightness - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + [self loadSettings]; if (![self _loadBezelServices]) { [self _loadOSDFramework]; @@ -239,5 +247,88 @@ - (void)decreaseBrightness self.brightness = MAX(self.brightness-brightnessStep,0); } +- (int) parseKeyCode: (NSString*) candidate { + if (keyCodesAll == NULL) { + keyCodesAll = [self JSONFromFile:@"macOSKeyCodes"]; + } + + candidate = candidate.uppercaseString; + + if (candidate.length < 3 || ![[candidate substringToIndex: 3] isEqualToString:@"VK_"] ) { + candidate = [NSString stringWithFormat:@"%@%@", @"VK_", candidate]; + } + + if (keyCodesAll != NULL && keyCodesAll[candidate]) { + return [[keyCodesAll valueForKey:candidate] intValue ]; + } + + return 0; +} + +- (ButtonControl*) parseButtonData: (NSDictionary*) jsonButton { + ButtonControl* btn = [ButtonControl new]; + + NSString* keyCode = [jsonButton objectForKey:@"keyCode"]; + + if (keyCode != NULL) { + int keyCodeInt = keyCode.intValue; + NSString* recomp = [NSString stringWithFormat:@"%d", keyCodeInt]; + + if (keyCode != recomp) { + keyCodeInt = [self parseKeyCode: keyCode]; + } + + btn.keyCode = keyCodeInt; + + btn.isShift = [[jsonButton valueForKey:@"isShift"] boolValue]; + btn.isAlt = [[jsonButton valueForKey:@"isAlt" ] boolValue]; + btn.isCmd = [[jsonButton valueForKey:@"isCmd" ] boolValue]; + btn.isCtrl = [[jsonButton valueForKey:@"isCtrl" ] boolValue]; + btn.isCaps = [[jsonButton valueForKey:@"isCaps" ] boolValue]; + btn.isFN = [[jsonButton valueForKey:@"isFN" ] boolValue]; + + return btn; + } + return NULL; +} + +- (void)loadSettings +{ + NSDictionary *dict = [self JSONFromFile: @"config"]; + + NSDictionary* buttonBrightnessUp = [dict objectForKey:@"buttonBrightnessUp"]; + NSDictionary* buttonBrightnessDown = [dict objectForKey:@"buttonBrightnessDown"]; + + globalButtonBrightnessUp = [ButtonControl new]; + globalButtonBrightnessUp.keyCode = kVK_F2; + + globalButtonBrightnessDown = [ButtonControl new]; + globalButtonBrightnessDown.keyCode = kVK_F1; + + if (buttonBrightnessUp != NULL) { + ButtonControl* btn = [self parseButtonData: buttonBrightnessUp]; + + if (btn && btn.keyCode) { + globalButtonBrightnessUp = btn; + } + } + + if (buttonBrightnessDown != NULL) { + ButtonControl* btn = [self parseButtonData: buttonBrightnessDown]; + + if (btn && btn.keyCode) { + globalButtonBrightnessDown = btn; + } + } + + NSLog(@"Config loaded!"); +} + +- (NSDictionary *)JSONFromFile: (NSString*) filename +{ + NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"json"]; + NSData *data = [NSData dataWithContentsOfFile:path]; + return [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; +} @end diff --git a/NativeDisplayBrightness/ButtonControl.h b/NativeDisplayBrightness/ButtonControl.h new file mode 100644 index 0000000..351f5c2 --- /dev/null +++ b/NativeDisplayBrightness/ButtonControl.h @@ -0,0 +1,29 @@ +// +// ButtonControl.h +// NativeDisplayBrightness +// +// Created by Ivan_Alone on 09.05.21. +// Copyright © 2021 Ivan_Alone. All rights reserved. +// + +#ifndef ButtonControl_h +#define ButtonControl_h + +#import + +@interface ButtonControl : NSObject + +@property int keyCode; + +@property bool isShift; +@property bool isAlt; +@property bool isCmd; +@property bool isCtrl; +@property bool isCaps; +@property bool isFN; + +- (bool)verifyKey: (int64_t)keyCode arg2: (int64_t)modifierFlags; + +@end + +#endif /* ButtonControl_h */ diff --git a/NativeDisplayBrightness/ButtonControl.m b/NativeDisplayBrightness/ButtonControl.m new file mode 100644 index 0000000..007b68c --- /dev/null +++ b/NativeDisplayBrightness/ButtonControl.m @@ -0,0 +1,30 @@ +// +// ButtonControl.m +// NativeDisplayBrightness +// +// Created by Ivan_Alone on 09.05.21. +// Copyright © 2021 Ivan_Alone. All rights reserved. +// + +#import "ButtonControl.h" + +@implementation ButtonControl + +- (bool)xorCheckFor: (bool)a And: (bool)b +{ + return (a && b) || (!a && !b); +} + +- (bool)verifyKey: (int64_t)keyCode arg2: (int64_t)modifierFlags +{ + return keyCode == self.keyCode && + [self xorCheckFor: self.isShift And: (modifierFlags & NSEventModifierFlagShift )] && + [self xorCheckFor: self.isCmd And: (modifierFlags & NSEventModifierFlagCommand )] && + [self xorCheckFor: self.isAlt And: (modifierFlags & NSEventModifierFlagOption )] && + [self xorCheckFor: self.isCtrl And: (modifierFlags & NSEventModifierFlagControl )] && + (self.isCaps ? (modifierFlags & NSEventModifierFlagCapsLock) : true) && + (self.isFN ? (modifierFlags & NSEventModifierFlagFunction) : true); +} + + +@end diff --git a/NativeDisplayBrightness/Info.plist b/NativeDisplayBrightness/Info.plist index 2dab834..895a757 100644 --- a/NativeDisplayBrightness/Info.plist +++ b/NativeDisplayBrightness/Info.plist @@ -19,13 +19,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 0.0.6 CFBundleVersion - 1 + 0.0.6 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2016 Benno Krauss. All rights reserved. + Copyright © 2016 Benno Krauss. Updated by Ivan_Alone, 2021. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass diff --git a/NativeDisplayBrightness/config.json b/NativeDisplayBrightness/config.json new file mode 100644 index 0000000..0f8be53 --- /dev/null +++ b/NativeDisplayBrightness/config.json @@ -0,0 +1,30 @@ +{ + "info": "Config for editing by user", + + "buttonBrightnessUp": { + "comment": "Key combination for brightness increase", + "keyCode": "VK_F2" + }, + "buttonBrightnessDown": { + "comment": "Key combination for brightness decrease", + "keyCode": "VK_F1" + }, + + "example": { + "buttonDefinition": { + "keyCode": "VK_F5", + "isShift": false, + "isAlt": false, + "isCmd": true, + "isCtrl": true, + "isCaps": false, + "isFN": false + }, + "info": { + "text0": "Definition before means Ctrl+Cmd+F5 key combination", + "text1": "You can check keys codess in 'macOSKeyCodes.json'. Also you can write just F5 instead VK_F5, for more convenience", + "text2": "'false' values can be skipped", + "text3": "Be care about 'isCaps' and 'isFN' - thats working as trigger, not key-combo. So that 'true' means 'true', 'false' means 'does not matter'" + } + } +} diff --git a/NativeDisplayBrightness/macOSKeyCodes.json b/NativeDisplayBrightness/macOSKeyCodes.json new file mode 100644 index 0000000..202d257 --- /dev/null +++ b/NativeDisplayBrightness/macOSKeyCodes.json @@ -0,0 +1,123 @@ +{ + "comment": { + "Warning0": "DO NOT EDIT THIS FILE if you do not understand this data!", + "Warning1": "Key codes must begin from VK_, and be in uppercase!", + "Warning2": "Key codes taken from [macOS] / Frameworks / Carbon / HIToolbox / Events.h" + }, + + + "VK_KEY_A": 0, + "VK_KEY_B": 11, + "VK_KEY_C": 8, + "VK_KEY_D": 2, + "VK_KEY_E": 14, + "VK_KEY_F": 3, + "VK_KEY_G": 5, + "VK_KEY_H": 4, + "VK_KEY_I": 34, + "VK_KEY_J": 38, + "VK_KEY_K": 40, + "VK_KEY_L": 37, + "VK_KEY_M": 46, + "VK_KEY_N": 45, + "VK_KEY_O": 31, + "VK_KEY_P": 35, + "VK_KEY_Q": 12, + "VK_KEY_R": 15, + "VK_KEY_S": 1, + "VK_KEY_T": 17, + "VK_KEY_U": 32, + "VK_KEY_V": 9, + "VK_KEY_W": 13, + "VK_KEY_X": 7, + "VK_KEY_Y": 16, + "VK_KEY_Z": 6, + + "VK_KEY_1": 18, + "VK_KEY_2": 19, + "VK_KEY_3": 20, + "VK_KEY_4": 21, + "VK_KEY_5": 23, + "VK_KEY_6": 22, + "VK_KEY_7": 26, + "VK_KEY_8": 28, + "VK_KEY_9": 25, + "VK_KEY_0": 29, + + "VK_KEY_GRAVE": 50, + + "VK_KEY_MINUS": 27, + "VK_KEY_EQUAL": 24, + + "VK_KEY_LEFTBRACKET": 33, + "VK_KEY_RIGHTBRACKET": 30, + + "VK_KEY_SEMICOLON": 41, + "VK_KEY_QUOTE": 39, + "VK_KEY_BACKSLASH": 42, + + "VK_KEY_COMMA": 43, + "VK_KEY_PERIOD": 47, + "VK_KEY_SLASH": 44, + + "VK_KEYPAD_CLEAR": 71, + "VK_KEYPAD_DIVIDE": 75, + "VK_KEYPAD_MULTIPLY": 67, + "VK_KEYPAD_MINUS": 78, + "VK_KEYPAD_PLUS": 69, + "VK_KEYPAD_ENTER": 76, + "VK_KEYPAD_DECIMAL": 65, + "VK_KEYPAD_EQUALS": 81, + + "VK_KEYPAD_0": 82, + "VK_KEYPAD_1": 83, + "VK_KEYPAD_2": 84, + "VK_KEYPAD_3": 85, + "VK_KEYPAD_4": 86, + "VK_KEYPAD_5": 87, + "VK_KEYPAD_6": 88, + "VK_KEYPAD_7": 89, + "VK_KEYPAD_8": 91, + "VK_KEYPAD_9": 92, + + "VK_RETURN": 36, + "VK_TAB": 48, + "VK_SPACE": 49, + "VK_BACKWARDDELETE": 51, + "VK_ESCAPE": 53, + + "VK_F1": 122, + "VK_F2": 120, + "VK_F3": 99, + "VK_F4": 118, + "VK_F5": 96, + "VK_F6": 97, + "VK_F7": 98, + "VK_F8": 100, + "VK_F9": 101, + "VK_F10": 109, + "VK_F11": 103, + "VK_F12": 111, + "VK_F13": 105, + "VK_F14": 107, + "VK_F15": 113, + "VK_F16": 106, + "VK_F17": 64, + "VK_F18": 79, + "VK_F19": 80, + "VK_F20": 90, + + "VK_INSERT": 114, + "VK_DELETE": 117, + + "VK_HOME": 115, + "VK_END": 119, + + "VK_PAGEUP": 116, + "VK_PAGEDOWN": 121, + + "VK_ARROW_UP": 126, + "VK_ARROW_DOWN": 125, + "VK_ARROW_LEFT": 123, + "VK_ARROW_RIGHT": 124 +} diff --git a/Readme.md b/Readme.md index 05c461b..238ba20 100644 --- a/Readme.md +++ b/Readme.md @@ -2,14 +2,39 @@ *Control your desktop monitor brightness just like on a MacBook!* -![native brightness UI](https://raw.githubusercontent.com/Bensge/NativeDisplayBrightness/master/nativeUI.png) +![native brightness UI](https://raw.githubusercontent.com/Ivan-Alone/NativeDisplayBrightness/master/nativeUI_Dark.png) -This a utility application to control monitor brightness with the F1, F2 keys. It utilizes DDC/CI, but this app doesn't have the freezing issues that similar aplications tend to suffer from. +This a utility application to control monitor brightness with the F1, F2 keys (**configurable now!**). It utilizes DDC/CI, but this app doesn't have the freezing issues that similar aplications tend to suffer from. This app also shows the **native** system UI when changing brightness! It uses the private `BezelServices` framework for this. Needless to say, your monitor needs to support DDC/CI for this app to work. +## Configuration + +If you want to change brightness buttons layout, just edit `NativeDisplayBrightness.app/Contents/Resources/config.json` config file. + +Open downloaded application with RMB -> Show Package Contents, go to this path, open `config.json` with TextEdit (or text editor you prefer) and map your own keys layout to increase/decrease brightness. + +For example, this configuration means that brightness will increase/decrease by pressing Cmd+ArrowUp / Cmd+ArrowDown: + +```json +{ + "buttonBrightnessUp": { + "keyCode": "VK_ARROW_UP", + "isCmd": true + }, + "buttonBrightnessDown": { + "keyCode": "VK_ARROW_DOWN", + "isCmd": true + } +} +``` + +You can find more information about key combinations in the same `config.json` file. In `macOSKeyCodes.json` contains all mostly supported keys constants. You can edit it if you understand what you doing, at one's own risk. + +Also you can write `keyCode` as simple integer value, but text IDs is more readable. + ## License This application uses code borrowed from [ddcctl](https://github.com/kfix/ddcctl) which uses code from [DDC-CI-Tools](https://github.com/jontaylor/DDC-CI-Tools-for-OS-X) diff --git a/nativeUI_Dark.png b/nativeUI_Dark.png new file mode 100644 index 0000000..15057bc Binary files /dev/null and b/nativeUI_Dark.png differ