1 /*****************************************************************************
2 * VLCKeyboardBlacklightControl.m: MacBook keyboard backlight control for VLC
3 *****************************************************************************
4 * Copyright (C) 2015 VLC authors and VideoLAN
7 * Authors: Maxime Mouchet <max@maxmouchet.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #import "VLCKeyboardBacklightControl.h"
25 #import <IOKit/IOKitLib.h>
28 kGetSensorReadingID = 0, // getSensorReading(int *, int *)
29 kGetLEDBrightnessID = 1, // getLEDBrightness(int, int *)
30 kSetLEDBrightnessID = 2, // setLEDBrightness(int, int, int *)
31 kSetLEDFadeID = 3 // setLEDFade(int, int, int, int *)
34 @implementation VLCKeyboardBacklightControl {
35 io_connect_t dataPort;
38 static float lastBrightnessLevel;
41 dataPort = [self getDataPort];
42 lastBrightnessLevel = [self getBrightness];
48 IOServiceClose(dataPort);
51 - (io_connect_t)getDataPort {
52 if (dataPort) return dataPort;
54 io_service_t serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
56 if (!serviceObject) return 0;
58 kern_return_t kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &dataPort);
59 IOObjectRelease(serviceObject);
61 if (kr != KERN_SUCCESS) return 0;
66 - (void)setBrightness:(float)brightness {
67 if (!dataPort) return;
69 UInt32 inputCount = 2;
70 UInt64 inputValues[2] = { 0, brightness * 0xfff };
72 UInt32 outputCount = 1;
73 UInt64 outputValues[1];
75 kern_return_t kr = IOConnectCallScalarMethod(dataPort,
82 if (kr != KERN_SUCCESS) return;
85 - (float)getBrightness {
86 if (!dataPort) return 0.0;
88 uint32_t inputCount = 1;
89 uint64_t inputValues[1] = { 0 };
91 uint32_t outputCount = 1;
92 uint64_t outputValues[1];
94 kern_return_t kr = IOConnectCallScalarMethod(dataPort,
101 float brightness = -1.0;
102 if (kr == KERN_SUCCESS) {
103 brightness = (float)outputValues[0] / 0xfff;
110 if (!dataPort) return;
112 @synchronized(self) {
113 float start = [self getBrightness];
114 float target = lastBrightnessLevel;
116 // Don't do anything if the user has put
117 // backlight on again during playback.
118 if (start != 0) return;
120 for (float i = start; i <= target; i += 0.08) {
121 [self setBrightness:i];
122 [NSThread sleepForTimeInterval:0.05];
125 [self setBrightness:target];
130 if (!dataPort) return;
132 @synchronized(self) {
133 float start = [self getBrightness];
136 lastBrightnessLevel = start;
138 for (float i = start; i >= target; i -= 0.08) {
139 [self setBrightness:i];
140 [NSThread sleepForTimeInterval:0.05];
143 [self setBrightness:target];
147 - (void)switchLightsAsync:(BOOL)on {
149 [NSThread detachNewThreadSelector:@selector(lightsUp) toTarget:self withObject:nil];
151 [NSThread detachNewThreadSelector:@selector(lightsDown) toTarget:self withObject:nil];
155 - (void)switchLightsInstantly:(BOOL)on {
157 // Don't do anything if the user has put backlight on again during playback.
158 if ([self getBrightness] == 0) {
159 [self setBrightness:lastBrightnessLevel];
162 [self setBrightness:0];