maclight 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/ext/maclight/maclight.c +275 -311
- data/lib/maclight/cli.rb +77 -34
- data/lib/maclight/version.rb +1 -1
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b24508bb26e8dd38759e7ac95fa0ff03f6526a08
|
4
|
+
data.tar.gz: f97b6d155204e429e3c869bd16ec2dc8ccc8cc76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 168125dcb91528fbeeaa03f4861e73a3e3a82265067cfc368a2e221d6fb6f083f2a9777b3d45a43e678bb64c62d3b268f357d46c5a7249758e2f20d1621f0137
|
7
|
+
data.tar.gz: ac5f80babb1f27b4addb159fb95b0ae31cefa2aecbf820d3870499eca7d69cb9ebb4cfbdbf0e10e2d78ee21cbc136aee09e6df0509238ed071cf4805696cb814
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# MacLight [](https://gemnasium.com/busyloop/maclight)
|
2
2
|
|
3
|
-
MacLight lets you control the keyboard
|
3
|
+
MacLight lets you control the keyboard LEDs on your Mac or Macbook.
|
4
4
|
|
5
5
|
## Screenshot
|
6
6
|
|
@@ -17,7 +17,7 @@ $ maclight --help
|
|
17
17
|
|
18
18
|
Usage: maclight <command>
|
19
19
|
|
20
|
-
MacLight
|
20
|
+
MacLight v3.0.0 - LED control utility
|
21
21
|
|
22
22
|
Options:
|
23
23
|
--version: Print version and exit
|
@@ -35,17 +35,17 @@ Commands:
|
|
35
35
|
|
36
36
|
require 'maclight'
|
37
37
|
|
38
|
-
# Turn
|
39
|
-
MacLight.
|
40
|
-
MacLight.numlock(true)
|
38
|
+
# Turn LEDs on
|
39
|
+
MacLight.all_leds(true)
|
41
40
|
|
42
41
|
sleep 2
|
43
42
|
|
44
|
-
# Turn
|
45
|
-
MacLight.
|
46
|
-
MacLight.numlock(false)
|
43
|
+
# Turn LEDs off
|
44
|
+
MacLight.all_leds(false)
|
47
45
|
```
|
48
46
|
|
49
|
-
##
|
47
|
+
## Notice
|
48
|
+
|
49
|
+
MacLight can currently only toggle all LEDs at once
|
50
|
+
and has only been tested on OSX 10.11.3 (El Capitan).
|
50
51
|
|
51
|
-
MacLight is based on HID demonstration code by [Amit Singh](http://googlemac.blogspot.de/2008/04/manipulating-keyboard-leds-through.html).
|
data/ext/maclight/maclight.c
CHANGED
@@ -1,328 +1,288 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
1
|
+
// File: main.c
|
2
|
+
// Abstract: source code for HID LED test tool
|
3
|
+
// Version: 1.3
|
4
|
+
//
|
5
|
+
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
6
|
+
// Inc. ("Apple") in consideration of your agreement to the following
|
7
|
+
// terms, and your use, installation, modification or redistribution of
|
8
|
+
// this Apple software constitutes acceptance of these terms. If you do
|
9
|
+
// not agree with these terms, please do not use, install, modify or
|
10
|
+
// redistribute this Apple software.
|
11
|
+
//
|
12
|
+
// In consideration of your agreement to abide by the following terms, and
|
13
|
+
// subject to these terms, Apple grants you a personal, non-exclusive
|
14
|
+
// license, under Apple's copyrights in this original Apple software (the
|
15
|
+
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
16
|
+
// Software, with or without modifications, in source and/or binary forms;
|
17
|
+
// provided that if you redistribute the Apple Software in its entirety and
|
18
|
+
// without modifications, you must retain this notice and the following
|
19
|
+
// text and disclaimers in all such redistributions of the Apple Software.
|
20
|
+
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
21
|
+
// be used to endorse or promote products derived from the Apple Software
|
22
|
+
// without specific prior written permission from Apple. Except as
|
23
|
+
// expressly stated in this notice, no other rights or licenses, express or
|
24
|
+
// implied, are granted by Apple herein, including but not limited to any
|
25
|
+
// patent rights that may be infringed by your derivative works or by other
|
26
|
+
// works in which the Apple Software may be incorporated.
|
27
|
+
//
|
28
|
+
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
29
|
+
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
30
|
+
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
31
|
+
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
32
|
+
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
33
|
+
//
|
34
|
+
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
35
|
+
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
36
|
+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
37
|
+
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
38
|
+
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
39
|
+
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
40
|
+
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
41
|
+
// POSSIBILITY OF SUCH DAMAGE.
|
42
|
+
//
|
43
|
+
// Copyright (C) 2015 Apple Inc. All Rights Reserved.
|
44
|
+
//
|
45
|
+
// ****************************************************
|
31
46
|
|
32
47
|
/* rubyfied by moe@busyloop.net */
|
48
|
+
#pragma mark -
|
49
|
+
#pragma mark * complation directives *
|
50
|
+
// ----------------------------------------------------
|
51
|
+
/* rubyfied by moe@busyloop.net */
|
52
|
+
|
53
|
+
#ifndef FALSE
|
54
|
+
#define FALSE 0
|
55
|
+
#define TRUE !FALSE
|
56
|
+
#endif
|
33
57
|
|
34
|
-
|
35
|
-
#
|
36
|
-
#
|
37
|
-
|
38
|
-
#include <mach/mach_error.h>
|
58
|
+
// ****************************************************
|
59
|
+
#pragma mark -
|
60
|
+
#pragma mark * includes & imports *
|
61
|
+
// ----------------------------------------------------
|
39
62
|
|
40
|
-
#include <
|
63
|
+
#include <CoreFoundation/CoreFoundation.h>
|
64
|
+
#include <Carbon/Carbon.h>
|
41
65
|
#include <IOKit/hid/IOHIDLib.h>
|
42
|
-
#include <IOKit/hid/IOHIDUsageTables.h>
|
43
66
|
|
44
67
|
#include "ruby.h"
|
45
68
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
io_service_t find_a_keyboard(void);
|
56
|
-
void find_led_cookies(IOHIDDeviceInterface122** handle);
|
57
|
-
void create_hid_interface(io_object_t hidDevice,
|
58
|
-
IOHIDDeviceInterface*** hdi);
|
59
|
-
int manipulate_led(UInt32 whichLED, SInt32 value);
|
60
|
-
|
61
|
-
inline void
|
62
|
-
print_errmsg_if_io_err(int expr, char* msg)
|
69
|
+
// ****************************************************
|
70
|
+
#pragma mark -
|
71
|
+
#pragma mark * typedef's, struct's, enums, defines, etc. *
|
72
|
+
// ----------------------------------------------------
|
73
|
+
// function to create a matching dictionary for usage page & usage
|
74
|
+
static CFMutableDictionaryRef hu_CreateMatchingDictionaryUsagePageUsage( Boolean isDeviceNotElement,
|
75
|
+
UInt32 inUsagePage,
|
76
|
+
UInt32 inUsage )
|
63
77
|
{
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
{
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
78
|
+
// create a dictionary to add usage page / usages to
|
79
|
+
CFMutableDictionaryRef result = CFDictionaryCreateMutable( kCFAllocatorDefault,
|
80
|
+
0,
|
81
|
+
&kCFTypeDictionaryKeyCallBacks,
|
82
|
+
&kCFTypeDictionaryValueCallBacks );
|
83
|
+
|
84
|
+
if ( result ) {
|
85
|
+
if ( inUsagePage ) {
|
86
|
+
// Add key for device type to refine the matching dictionary.
|
87
|
+
CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsagePage );
|
88
|
+
|
89
|
+
if ( pageCFNumberRef ) {
|
90
|
+
if ( isDeviceNotElement ) {
|
91
|
+
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ), pageCFNumberRef );
|
92
|
+
} else {
|
93
|
+
CFDictionarySetValue( result, CFSTR( kIOHIDElementUsagePageKey ), pageCFNumberRef );
|
94
|
+
}
|
95
|
+
CFRelease( pageCFNumberRef );
|
96
|
+
|
97
|
+
// note: the usage is only valid if the usage page is also defined
|
98
|
+
if ( inUsage ) {
|
99
|
+
CFNumberRef usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsage );
|
100
|
+
|
101
|
+
if ( usageCFNumberRef ) {
|
102
|
+
if ( isDeviceNotElement ) {
|
103
|
+
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ), usageCFNumberRef );
|
104
|
+
} else {
|
105
|
+
CFDictionarySetValue( result, CFSTR( kIOHIDElementUsageKey ), usageCFNumberRef );
|
106
|
+
}
|
107
|
+
CFRelease( usageCFNumberRef );
|
108
|
+
} else {
|
109
|
+
fprintf( stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__ );
|
110
|
+
}
|
111
|
+
}
|
112
|
+
} else {
|
113
|
+
fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__ );
|
114
|
+
}
|
115
|
+
}
|
116
|
+
} else {
|
117
|
+
fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__ );
|
118
|
+
}
|
119
|
+
return result;
|
120
|
+
} // hu_CreateMatchingDictionaryUsagePageUsage
|
121
|
+
|
122
|
+
//int main( int argc, const char * argv[] )
|
123
|
+
int manipulate_led( int which_led, int led_value )
|
86
124
|
{
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
if (!(matchingDictRef = IOServiceMatching(kIOHIDDeviceKey))) {
|
94
|
-
return result;
|
95
|
-
}
|
96
|
-
|
97
|
-
UInt32 usagePage = kHIDPage_GenericDesktop;
|
98
|
-
UInt32 usage = kHIDUsage_GD_Keyboard;
|
99
|
-
|
100
|
-
if (!(usagePageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
|
101
|
-
&usagePage))) {
|
102
|
-
goto out;
|
103
|
-
}
|
125
|
+
#pragma unused ( argc, argv )
|
126
|
+
IOHIDDeviceRef * tIOHIDDeviceRefs = nil;
|
127
|
+
|
128
|
+
// create a IO HID Manager reference
|
129
|
+
IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );
|
130
|
+
require( tIOHIDManagerRef, Oops );
|
104
131
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
}
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
if (!(hidService = find_a_keyboard())) {
|
247
|
-
fprintf(stderr, "No keyboard found.\n");
|
248
|
-
return ioReturnValue;
|
249
|
-
}
|
250
|
-
|
251
|
-
hidDevice = (io_object_t)hidService;
|
252
|
-
|
253
|
-
create_hid_interface(hidDevice, &hidDeviceInterface);
|
254
|
-
|
255
|
-
find_led_cookies((IOHIDDeviceInterface122 **)hidDeviceInterface);
|
256
|
-
|
257
|
-
ioReturnValue = IOObjectRelease(hidDevice);
|
258
|
-
if (ioReturnValue != kIOReturnSuccess) {
|
259
|
-
goto out;
|
260
|
-
}
|
261
|
-
|
262
|
-
ioReturnValue = kIOReturnError;
|
263
|
-
|
264
|
-
if (hidDeviceInterface == NULL) {
|
265
|
-
fprintf(stderr, "Failed to create HID device interface.\n");
|
266
|
-
return ioReturnValue;
|
267
|
-
}
|
268
|
-
|
269
|
-
if (whichLED == kHIDUsage_LED_NumLock) {
|
270
|
-
theCookie = numlock_cookie;
|
271
|
-
} else if (whichLED == kHIDUsage_LED_CapsLock) {
|
272
|
-
theCookie = capslock_cookie;
|
273
|
-
}
|
274
|
-
|
275
|
-
if (theCookie == 0) {
|
276
|
-
fprintf(stderr, "Bad or missing LED cookie.\n");
|
277
|
-
goto out;
|
278
|
-
}
|
279
|
-
|
280
|
-
ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, 0);
|
281
|
-
if (ioReturnValue != kIOReturnSuccess) {
|
282
|
-
fprintf(stderr, "Failed to open HID device interface.\n");
|
283
|
-
goto out;
|
284
|
-
}
|
285
|
-
|
286
|
-
ioReturnValue = (*hidDeviceInterface)->getElementValue(hidDeviceInterface,
|
287
|
-
theCookie, &theEvent);
|
288
|
-
if (ioReturnValue != kIOReturnSuccess) {
|
289
|
-
(void)(*hidDeviceInterface)->close(hidDeviceInterface);
|
290
|
-
goto out;
|
291
|
-
}
|
292
|
-
|
293
|
-
//fprintf(stdout, "%s\n", (theEvent.value) ? "on" : "off");
|
294
|
-
if (value != -1) {
|
295
|
-
if (theEvent.value != value) {
|
296
|
-
theEvent.value = value;
|
297
|
-
ioReturnValue = (*hidDeviceInterface)->setElementValue(
|
298
|
-
hidDeviceInterface, theCookie,
|
299
|
-
&theEvent, 0, 0, 0, 0);
|
300
|
-
//if (ioReturnValue == kIOReturnSuccess) {
|
301
|
-
// fprintf(stdout, "%s\n", (theEvent.value) ? "on" : "off");
|
302
|
-
//}
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
ioReturnValue = (*hidDeviceInterface)->close(hidDeviceInterface);
|
307
|
-
|
308
|
-
out:
|
309
|
-
(void)(*hidDeviceInterface)->Release(hidDeviceInterface);
|
310
|
-
|
311
|
-
//return ioReturnValue;
|
312
|
-
return theEvent.value;
|
313
|
-
}
|
132
|
+
// Create a device matching dictionary
|
133
|
+
CFDictionaryRef matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( TRUE,
|
134
|
+
kHIDPage_GenericDesktop,
|
135
|
+
kHIDUsage_GD_Keyboard );
|
136
|
+
require( matchingCFDictRef, Oops );
|
137
|
+
|
138
|
+
// set the HID device matching dictionary
|
139
|
+
IOHIDManagerSetDeviceMatching( tIOHIDManagerRef, matchingCFDictRef );
|
140
|
+
|
141
|
+
if ( matchingCFDictRef ) {
|
142
|
+
CFRelease( matchingCFDictRef );
|
143
|
+
}
|
144
|
+
|
145
|
+
// Now open the IO HID Manager reference
|
146
|
+
IOReturn tIOReturn = IOHIDManagerOpen( tIOHIDManagerRef, kIOHIDOptionsTypeNone );
|
147
|
+
require_noerr( tIOReturn, Oops );
|
148
|
+
|
149
|
+
// and copy out its devices
|
150
|
+
CFSetRef deviceCFSetRef = IOHIDManagerCopyDevices( tIOHIDManagerRef );
|
151
|
+
require( deviceCFSetRef, Oops );
|
152
|
+
|
153
|
+
// how many devices in the set?
|
154
|
+
CFIndex deviceIndex, deviceCount = CFSetGetCount( deviceCFSetRef );
|
155
|
+
|
156
|
+
// allocate a block of memory to extact the device ref's from the set into
|
157
|
+
tIOHIDDeviceRefs = malloc( sizeof( IOHIDDeviceRef ) * deviceCount );
|
158
|
+
if (!tIOHIDDeviceRefs) {
|
159
|
+
CFRelease(deviceCFSetRef);
|
160
|
+
deviceCFSetRef = NULL;
|
161
|
+
goto Oops;
|
162
|
+
}
|
163
|
+
|
164
|
+
// now extract the device ref's from the set
|
165
|
+
CFSetGetValues( deviceCFSetRef, (const void **) tIOHIDDeviceRefs );
|
166
|
+
CFRelease(deviceCFSetRef);
|
167
|
+
deviceCFSetRef = NULL;
|
168
|
+
|
169
|
+
// before we get into the device loop we'll setup our element matching dictionary
|
170
|
+
matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( FALSE, kHIDPage_LEDs, 0 );
|
171
|
+
require( matchingCFDictRef, Oops );
|
172
|
+
|
173
|
+
int pass; // do 256 passes
|
174
|
+
//for ( pass = 0; pass < 256; pass++ ) {
|
175
|
+
Boolean delayFlag = FALSE; // if we find an LED element we'll set this to TRUE
|
176
|
+
|
177
|
+
//printf( "pass = %d.\n", pass );
|
178
|
+
for ( deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++ ) {
|
179
|
+
|
180
|
+
// if this isn't a keyboard device...
|
181
|
+
if ( !IOHIDDeviceConformsTo( tIOHIDDeviceRefs[deviceIndex], kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard ) ) {
|
182
|
+
continue; // ...skip it
|
183
|
+
}
|
184
|
+
|
185
|
+
//printf( " device = %p.\n", tIOHIDDeviceRefs[deviceIndex] );
|
186
|
+
|
187
|
+
// copy all the elements
|
188
|
+
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRefs[deviceIndex],
|
189
|
+
matchingCFDictRef,
|
190
|
+
kIOHIDOptionsTypeNone );
|
191
|
+
require( elementCFArrayRef, next_device );
|
192
|
+
|
193
|
+
// for each device on the system these values are divided by the value ranges of all LED elements found
|
194
|
+
// for example, if the first four LED element have a range of 0-1 then the four least significant bits of
|
195
|
+
// this value will be sent to these first four LED elements, etc.
|
196
|
+
int device_value = pass;
|
197
|
+
|
198
|
+
// iterate over all the elements
|
199
|
+
CFIndex elementIndex, elementCount = CFArrayGetCount( elementCFArrayRef );
|
200
|
+
for ( elementIndex = 0; elementIndex < elementCount; elementIndex++ ) {
|
201
|
+
IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, elementIndex );
|
202
|
+
require( tIOHIDElementRef, next_element );
|
203
|
+
|
204
|
+
uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
|
205
|
+
|
206
|
+
// if this isn't an LED element...
|
207
|
+
if ( kHIDPage_LEDs != usagePage ) {
|
208
|
+
continue; // ...skip it
|
209
|
+
}
|
210
|
+
|
211
|
+
uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
|
212
|
+
IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef );
|
213
|
+
|
214
|
+
//printf( " element = %p (page: %d, usage: %d, type: %d ).\n",
|
215
|
+
// tIOHIDElementRef, usagePage, usage, tIOHIDElementType );
|
216
|
+
|
217
|
+
// get the logical mix/max for this LED element
|
218
|
+
CFIndex minCFIndex = IOHIDElementGetLogicalMin( tIOHIDElementRef );
|
219
|
+
CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef );
|
220
|
+
|
221
|
+
// calculate the range
|
222
|
+
CFIndex modCFIndex = maxCFIndex - minCFIndex + 1;
|
223
|
+
|
224
|
+
// compute the value for this LED element
|
225
|
+
//CFIndex tCFIndex = minCFIndex + ( device_value % modCFIndex );
|
226
|
+
CFIndex tCFIndex = led_value;
|
227
|
+
device_value /= modCFIndex;
|
228
|
+
|
229
|
+
//printf( " value = 0x%08lX.\n", tCFIndex );
|
230
|
+
|
231
|
+
uint64_t timestamp = 0; // create the IO HID Value to be sent to this LED element
|
232
|
+
IOHIDValueRef tIOHIDValueRef = IOHIDValueCreateWithIntegerValue( kCFAllocatorDefault, tIOHIDElementRef, timestamp, tCFIndex );
|
233
|
+
if ( tIOHIDValueRef ) {
|
234
|
+
// now set it on the device
|
235
|
+
tIOReturn = IOHIDDeviceSetValue( tIOHIDDeviceRefs[deviceIndex], tIOHIDElementRef, tIOHIDValueRef );
|
236
|
+
CFRelease( tIOHIDValueRef );
|
237
|
+
require_noerr( tIOReturn, next_element );
|
238
|
+
delayFlag = TRUE; // set this TRUE so we'll delay before changing our LED values again
|
239
|
+
}
|
240
|
+
next_element: ;
|
241
|
+
continue;
|
242
|
+
}
|
243
|
+
CFRelease( elementCFArrayRef );
|
244
|
+
next_device: ;
|
245
|
+
continue;
|
246
|
+
}
|
247
|
+
|
248
|
+
// if we found an LED we'll delay before continuing
|
249
|
+
//if ( delayFlag ) {
|
250
|
+
// usleep( 500000 ); // sleep one half second
|
251
|
+
//}
|
252
|
+
|
253
|
+
// if the mouse is down…
|
254
|
+
//if (GetCurrentButtonState()) {
|
255
|
+
// break; // abort pass loop
|
256
|
+
//}
|
257
|
+
//} // next pass
|
258
|
+
|
259
|
+
if ( matchingCFDictRef ) {
|
260
|
+
CFRelease( matchingCFDictRef );
|
261
|
+
}
|
262
|
+
Oops: ;
|
263
|
+
if ( tIOHIDDeviceRefs ) {
|
264
|
+
free(tIOHIDDeviceRefs);
|
265
|
+
}
|
266
|
+
|
267
|
+
if ( tIOHIDManagerRef ) {
|
268
|
+
CFRelease( tIOHIDManagerRef );
|
269
|
+
}
|
270
|
+
return 0;
|
271
|
+
} /* main */
|
314
272
|
|
315
273
|
VALUE MacLight = Qnil;
|
316
274
|
|
317
275
|
void Init_maclight();
|
318
276
|
|
319
|
-
VALUE method_capslock(int argc, VALUE *argv, VALUE self);
|
320
|
-
VALUE method_numlock(int argc, VALUE *argv, VALUE self);
|
277
|
+
//VALUE method_capslock(int argc, VALUE *argv, VALUE self);
|
278
|
+
//VALUE method_numlock(int argc, VALUE *argv, VALUE self);
|
279
|
+
VALUE method_all_leds(int argc, VALUE *argv, VALUE self);
|
321
280
|
|
322
281
|
void Init_maclight() {
|
323
282
|
MacLight = rb_define_module("MacLight");
|
324
|
-
rb_define_singleton_method(MacLight, "capslock", method_capslock, -1);
|
325
|
-
rb_define_singleton_method(MacLight, "numlock", method_numlock, -1);
|
283
|
+
//rb_define_singleton_method(MacLight, "capslock", method_capslock, -1);
|
284
|
+
//rb_define_singleton_method(MacLight, "numlock", method_numlock, -1);
|
285
|
+
rb_define_singleton_method(MacLight, "all_leds", method_all_leds, -1);
|
326
286
|
}
|
327
287
|
|
328
288
|
VALUE kbd_led(UInt32 whichLED, int argc, VALUE *argv, VALUE klass) {
|
@@ -342,11 +302,15 @@ VALUE kbd_led(UInt32 whichLED, int argc, VALUE *argv, VALUE klass) {
|
|
342
302
|
return manipulate_led(whichLED, set_to) ? Qtrue : Qfalse;
|
343
303
|
}
|
344
304
|
|
345
|
-
VALUE
|
346
|
-
return kbd_led(
|
305
|
+
VALUE method_all_leds(int argc, VALUE *argv, VALUE klass) {
|
306
|
+
return kbd_led(-1, argc, argv, klass);
|
347
307
|
}
|
348
308
|
|
349
|
-
VALUE
|
350
|
-
return kbd_led(
|
351
|
-
}
|
309
|
+
//VALUE method_capslock(int argc, VALUE *argv, VALUE klass) {
|
310
|
+
// return kbd_led(kHIDUsage_LED_CapsLock, argc, argv, klass);
|
311
|
+
//}
|
312
|
+
//
|
313
|
+
//VALUE method_numlock(int argc, VALUE *argv, VALUE klass) {
|
314
|
+
// return kbd_led(kHIDUsage_LED_NumLock, argc, argv, klass);
|
315
|
+
//}
|
352
316
|
|
data/lib/maclight/cli.rb
CHANGED
@@ -14,66 +14,109 @@ module MacLight
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
# Commenting out most functionality
|
18
|
+
# until we get around to restore it.
|
19
|
+
|
20
|
+
# For now MacLight can only toggle all
|
21
|
+
# LEDs at once on and off.
|
22
|
+
|
23
|
+
#desc "Toggle keyboard LEDs"
|
24
|
+
#text "Toggle keyboard LEDs (capslock, numlock)"
|
25
|
+
#opt :capslock, "Toggle capslock LED", :default => false
|
26
|
+
#opt :numlock, "Toggle numlock LED", :default => false
|
27
|
+
#opt :verbose, "Print current state of capslock, numlock"
|
28
|
+
#parent "keyboard", "Control keyboard LEDs"
|
29
|
+
#def toggle(cmd, opts, argv)
|
30
|
+
# raise Optix::HelpNeeded unless opts.values_at(:capslock, :numlock, :verbose).any?
|
31
|
+
# MacLight.capslock(!MacLight.capslock) if opts[:capslock]
|
32
|
+
# MacLight.numlock(!MacLight.numlock) if opts[:numlock]
|
33
|
+
# puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
34
|
+
#end
|
29
35
|
|
30
36
|
desc "Set keyboard LEDs state"
|
31
37
|
text "Set keyboard LEDs (capslock, numlock) state (on, off)"
|
32
|
-
opt :
|
33
|
-
opt :
|
34
|
-
opt :
|
38
|
+
opt :all, "Set all LEDs (0|1)", :type => Integer
|
39
|
+
#opt :capslock, "Set capslock LED (0|1)", :type => Integer
|
40
|
+
#opt :numlock, "Set numlock LED (0|1)", :type => Integer
|
41
|
+
#opt :verbose, "Print current state of capslock, numlock"
|
35
42
|
parent "keyboard"
|
36
43
|
def set(cmd, opts, argv)
|
37
|
-
raise Optix::HelpNeeded unless opts.values_at(:
|
38
|
-
MacLight.
|
39
|
-
MacLight.
|
40
|
-
|
44
|
+
raise Optix::HelpNeeded unless opts.values_at(:all).any?
|
45
|
+
MacLight.all_leds(1 == opts[:all])
|
46
|
+
#MacLight.capslock(1 == opts[:capslock]) unless opts[:capslock].nil?
|
47
|
+
#MacLight.numlock(1 == opts[:numlock]) unless opts[:numlock].nil?
|
48
|
+
#puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
41
49
|
end
|
42
50
|
|
43
51
|
desc "Blink keyboard LEDs"
|
44
|
-
text "Blink keyboard LEDs
|
52
|
+
text "Blink keyboard LEDs"
|
45
53
|
text ''
|
46
54
|
text "Examples:"
|
47
|
-
text " #{File.basename($0)} keyboard blink -r 3 -f
|
48
|
-
text " #{File.basename($0)} keyboard blink -r 3
|
55
|
+
text " #{File.basename($0)} keyboard blink -r 3 -f 0 1:0.3 0:0.3"
|
56
|
+
text " #{File.basename($0)} keyboard blink -r 3 1:0.3 0:0.2 0:0.1 1:0.2 0:0.07 1:0.07 0:0.07"
|
49
57
|
text ''
|
50
58
|
text 'Parameters:'
|
51
|
-
text ' <sequence> - Space-delimited sequence;
|
52
|
-
text '
|
59
|
+
text ' <sequence> - Space-delimited sequence; V:T V:T ..'
|
60
|
+
text ' V = led value, T = time in seconds'
|
53
61
|
opt :repeat, "Repetitions", :default => 0
|
54
62
|
opt :fin, "Set this state after sequence has finished (CN)", :type => String
|
55
|
-
opt :verbose, "Print state of capslock, numlock"
|
56
63
|
params "<sequence>"
|
57
64
|
parent "keyboard"
|
58
65
|
def blink(cmd, opts, argv)
|
59
66
|
raise Optix::HelpNeeded if argv.empty?
|
60
|
-
|
61
|
-
seq = argv.map {|e| ['1'==e[0],'1'==e[1],e[3..-1].to_f] }
|
67
|
+
seq = argv.map {|e| ['1'==e[0],e[2..-1].to_f] }
|
62
68
|
(0..opts[:repeat]).each do |i|
|
63
69
|
seq.each_with_index do |mode, step|
|
64
|
-
MacLight.
|
65
|
-
|
66
|
-
puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
67
|
-
sleep mode[2]
|
70
|
+
MacLight.all_leds(mode[0])
|
71
|
+
sleep mode[1]
|
68
72
|
end
|
69
73
|
end
|
70
74
|
if opts[:fin]
|
71
|
-
MacLight.
|
72
|
-
MacLight.numlock('1'==opts[:fin][1])
|
73
|
-
puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
75
|
+
MacLight.all_leds('1'==opts[:fin][0])
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
desc "Play a short test sequence"
|
80
|
+
text "Play a short test sequence"
|
81
|
+
parent "keyboard"
|
82
|
+
def test(cmd, opts, argv)
|
83
|
+
blink(nil, { :repeat => 3 }, %w(1:0.3 0:0.2 0:0.1 1:0.2 0:0.07 1:0.07 0:0.07))
|
84
|
+
end
|
85
|
+
|
86
|
+
#desc "Blink keyboard LEDs"
|
87
|
+
#text "Blink keyboard LEDs (capslock, numlock)"
|
88
|
+
#text ''
|
89
|
+
#text "Examples:"
|
90
|
+
#text " #{File.basename($0)} keyboard blink -r 3 -f 00 10:0.3 01:0.3"
|
91
|
+
#text " #{File.basename($0)} keyboard blink -r 3 10:0.3 01:0.2 00:0.1 11:0.2 00:0.07 11:0.07 00:0.07"
|
92
|
+
#text ''
|
93
|
+
#text 'Parameters:'
|
94
|
+
#text ' <sequence> - Space-delimited sequence; CN:T CN:T ..'
|
95
|
+
#text ' C = capslock value, N = numlock value, T = time in seconds'
|
96
|
+
#opt :repeat, "Repetitions", :default => 0
|
97
|
+
#opt :fin, "Set this state after sequence has finished (CN)", :type => String
|
98
|
+
#opt :verbose, "Print state of capslock, numlock"
|
99
|
+
#params "<sequence>"
|
100
|
+
#parent "keyboard"
|
101
|
+
#def blink(cmd, opts, argv)
|
102
|
+
# raise Optix::HelpNeeded if argv.empty?
|
103
|
+
# puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
104
|
+
# seq = argv.map {|e| ['1'==e[0],'1'==e[1],e[3..-1].to_f] }
|
105
|
+
# (0..opts[:repeat]).each do |i|
|
106
|
+
# seq.each_with_index do |mode, step|
|
107
|
+
# MacLight.capslock(mode[0])
|
108
|
+
# MacLight.numlock(mode[1])
|
109
|
+
# puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
110
|
+
# sleep mode[2]
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
# if opts[:fin]
|
114
|
+
# MacLight.capslock('1'==opts[:fin][0])
|
115
|
+
# MacLight.numlock('1'==opts[:fin][1])
|
116
|
+
# puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
|
117
|
+
# end
|
118
|
+
#end
|
119
|
+
|
77
120
|
def self.start
|
78
121
|
Optix.invoke!
|
79
122
|
end
|
data/lib/maclight/version.rb
CHANGED
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maclight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: optix
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.2.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 10.1.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 10.1.0
|
41
41
|
description: Control your Mac keyboard LEDs (capslock, numlock)
|
@@ -47,7 +47,7 @@ extensions:
|
|
47
47
|
- ext/maclight/extconf.rb
|
48
48
|
extra_rdoc_files: []
|
49
49
|
files:
|
50
|
-
- .gitignore
|
50
|
+
- ".gitignore"
|
51
51
|
- Gemfile
|
52
52
|
- LICENSE.txt
|
53
53
|
- README.md
|
@@ -69,17 +69,17 @@ require_paths:
|
|
69
69
|
- lib
|
70
70
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- -
|
72
|
+
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- -
|
77
|
+
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: '0'
|
80
80
|
requirements: []
|
81
81
|
rubyforge_project:
|
82
|
-
rubygems_version: 2.
|
82
|
+
rubygems_version: 2.5.1
|
83
83
|
signing_key:
|
84
84
|
specification_version: 4
|
85
85
|
summary: Control your Mac keyboard LEDs (capslock, numlock)
|