maclight 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ *.bundle
4
+ *.o
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in maclight.gemspec
4
+ gemspec
@@ -0,0 +1,25 @@
1
+ The file ext/maclight/maclight.c is derived from
2
+ http://osxbook.com/book/bonus/chapter10/kbdleds/download/keyboard_leds.c
3
+ which is Copyright (c) 2007,2008 Amit Singh.
4
+
5
+ All remaining files are Copyright (c) 2012 moe@busyloop.net
6
+ and provided under MIT license;
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining
9
+ a copy of this software and associated documentation files (the
10
+ "Software"), to deal in the Software without restriction, including
11
+ without limitation the rights to use, copy, modify, merge, publish,
12
+ distribute, sublicense, and/or sell copies of the Software, and to
13
+ permit persons to whom the Software is furnished to do so, subject to
14
+ the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be
17
+ included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # MacLight [![Dependency Status](https://gemnasium.com/busyloop/maclight.png)](https://gemnasium.com/busyloop/maclight)
2
+
3
+ MacLight lets you control the keyboard-LEDs (capslock, numlock) on your Mac.
4
+
5
+ ## Screenshot
6
+
7
+ ![capslock](http://github.com/busyloop/maclight/raw/master/ass/screenshot_capslock.jpg)
8
+
9
+ ## Installation
10
+
11
+ $ gem install maclight
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ $ maclight --help
17
+
18
+ Usage: maclight <subcommand>
19
+
20
+ MacLight v1.0.0 - LED control utility
21
+
22
+ Options:
23
+ --version: Print version and exit
24
+ --help, -h: Show this message
25
+
26
+ Commands:
27
+ keyboard Control keyboard LEDs
28
+ ```
29
+
30
+
31
+ ## API Usage
32
+
33
+ ```ruby
34
+ #!/usr/bin/env ruby
35
+
36
+ require 'maclight'
37
+
38
+ # Turn both LEDs on
39
+ MacLight.capslock(true)
40
+ MacLight.numlock(true)
41
+
42
+ sleep 2
43
+
44
+ # Turn both LEDs off
45
+ MacLight.capslock(false)
46
+ MacLight.numlock(false)
47
+ ```
48
+
49
+ ## Credits
50
+
51
+ MacLight is based on HID demonstration code by [Amit Singh](http://googlemac.blogspot.de/2008/04/manipulating-keyboard-leds-through.html).
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'maclight/cli'
4
+
5
+ MacLight::Cli.start
6
+
@@ -0,0 +1,198 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ #### Start of system configuration section. ####
5
+
6
+ srcdir = .
7
+ topdir = /Users/moe/.rbenv/versions/1.9.2-p290/include/ruby-1.9.1
8
+ hdrdir = /Users/moe/.rbenv/versions/1.9.2-p290/include/ruby-1.9.1
9
+ arch_hdrdir = /Users/moe/.rbenv/versions/1.9.2-p290/include/ruby-1.9.1/$(arch)
10
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
11
+ prefix = $(DESTDIR)/Users/moe/.rbenv/versions/1.9.2-p290
12
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
13
+ exec_prefix = $(prefix)
14
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
15
+ sitehdrdir = $(rubyhdrdir)/site_ruby
16
+ rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
17
+ vendordir = $(rubylibprefix)/vendor_ruby
18
+ sitedir = $(rubylibprefix)/site_ruby
19
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
20
+ mandir = $(datarootdir)/man
21
+ localedir = $(datarootdir)/locale
22
+ libdir = $(exec_prefix)/lib
23
+ psdir = $(docdir)
24
+ pdfdir = $(docdir)
25
+ dvidir = $(docdir)
26
+ htmldir = $(docdir)
27
+ infodir = $(datarootdir)/info
28
+ docdir = $(datarootdir)/doc/$(PACKAGE)
29
+ oldincludedir = $(DESTDIR)/usr/include
30
+ includedir = $(prefix)/include
31
+ localstatedir = $(prefix)/var
32
+ sharedstatedir = $(prefix)/com
33
+ sysconfdir = $(prefix)/etc
34
+ datadir = $(datarootdir)
35
+ datarootdir = $(prefix)/share
36
+ libexecdir = $(exec_prefix)/libexec
37
+ sbindir = $(exec_prefix)/sbin
38
+ bindir = $(exec_prefix)/bin
39
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
40
+ archdir = $(rubylibdir)/$(arch)
41
+ sitelibdir = $(sitedir)/$(ruby_version)
42
+ sitearchdir = $(sitelibdir)/$(sitearch)
43
+ vendorlibdir = $(vendordir)/$(ruby_version)
44
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
45
+
46
+ CC = gcc
47
+ CXX = g++
48
+ LIBRUBY = $(LIBRUBY_A)
49
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
50
+ LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
51
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
52
+ OUTFLAG = -o
53
+ COUTFLAG = -o
54
+
55
+ RUBY_EXTCONF_H =
56
+ cflags = $(optflags) $(debugflags) $(warnflags)
57
+ optflags = -O3
58
+ debugflags = -ggdb
59
+ warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long
60
+ CFLAGS = -fno-common $(cflags) -pipe
61
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
62
+ DEFS =
63
+ CPPFLAGS = -I'/Users/moe/.rbenv/versions/1.9.2-p290/include' -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
64
+ CXXFLAGS = $(CFLAGS) $(cxxflags)
65
+ ldflags = -L. -L'/Users/moe/.rbenv/versions/1.9.2-p290/lib' -L/usr/local/lib -framework IOKit -framework CoreFoundation
66
+ dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace
67
+ ARCH_FLAG =
68
+ DLDFLAGS = $(ldflags) $(dldflags)
69
+ LDSHARED = $(CC) -dynamic -bundle
70
+ LDSHAREDXX = $(CXX) -dynamic -bundle
71
+ AR = ar
72
+ EXEEXT =
73
+
74
+ RUBY_BASE_NAME = ruby
75
+ RUBY_INSTALL_NAME = ruby
76
+ RUBY_SO_NAME = ruby
77
+ arch = x86_64-darwin11.3.0
78
+ sitearch = $(arch)
79
+ ruby_version = 1.9.1
80
+ ruby = /Users/moe/.rbenv/versions/1.9.2-p290/bin/ruby
81
+ RUBY = $(ruby)
82
+ RM = rm -f
83
+ RM_RF = $(RUBY) -run -e rm -- -rf
84
+ RMDIRS = $(RUBY) -run -e rmdir -- -p
85
+ MAKEDIRS = mkdir -p
86
+ INSTALL = /usr/bin/install -c
87
+ INSTALL_PROG = $(INSTALL) -m 0755
88
+ INSTALL_DATA = $(INSTALL) -m 644
89
+ COPY = cp
90
+
91
+ #### End of system configuration section. ####
92
+
93
+ preload =
94
+
95
+ libpath = . $(libdir)
96
+ LIBPATH = -L. -L$(libdir)
97
+ DEFFILE =
98
+
99
+ CLEANFILES = mkmf.log
100
+ DISTCLEANFILES =
101
+ DISTCLEANDIRS =
102
+
103
+ extout =
104
+ extout_prefix =
105
+ target_prefix =
106
+ LOCAL_LIBS =
107
+ LIBS = -lpthread -ldl -lobjc
108
+ SRCS = maclight.c
109
+ OBJS = maclight.o
110
+ TARGET = maclight
111
+ DLLIB = $(TARGET).bundle
112
+ EXTSTATIC =
113
+ STATIC_LIB =
114
+
115
+ BINDIR = $(bindir)
116
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
117
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
118
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
119
+ HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
120
+ ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
121
+
122
+ TARGET_SO = $(DLLIB)
123
+ CLEANLIBS = $(TARGET).bundle
124
+ CLEANOBJS = *.o *.bak
125
+
126
+ all: $(DLLIB)
127
+ static: $(STATIC_LIB)
128
+ .PHONY: all install static install-so install-rb
129
+ .PHONY: clean clean-so clean-rb
130
+
131
+ clean-rb-default::
132
+ clean-rb::
133
+ clean-so::
134
+ clean: clean-so clean-rb-default clean-rb
135
+ @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
136
+
137
+ distclean-rb-default::
138
+ distclean-rb::
139
+ distclean-so::
140
+ distclean: clean distclean-so distclean-rb-default distclean-rb
141
+ @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
142
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
143
+ @-$(RMDIRS) $(DISTCLEANDIRS)
144
+
145
+ realclean: distclean
146
+ install: install-so install-rb
147
+
148
+ install-so: $(RUBYARCHDIR)
149
+ install-so: $(RUBYARCHDIR)/$(DLLIB)
150
+ $(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
151
+ @-$(MAKEDIRS) $(@D)
152
+ $(INSTALL_PROG) $(DLLIB) $(@D)
153
+ install-rb: pre-install-rb install-rb-default
154
+ install-rb-default: pre-install-rb-default
155
+ pre-install-rb: Makefile
156
+ pre-install-rb-default: Makefile
157
+ pre-install-rb-default: $(RUBYLIBDIR)
158
+ install-rb-default: $(RUBYLIBDIR)/extconf.rb
159
+ $(RUBYLIBDIR)/extconf.rb: $(srcdir)/lib/extconf.rb
160
+ @-$(MAKEDIRS) $(@D)
161
+ $(INSTALL_DATA) $(srcdir)/lib/extconf.rb $(@D)
162
+ install-rb-default: $(RUBYLIBDIR)/test.rb
163
+ $(RUBYLIBDIR)/test.rb: $(srcdir)/lib/test.rb
164
+ @-$(MAKEDIRS) $(@D)
165
+ $(INSTALL_DATA) $(srcdir)/lib/test.rb $(@D)
166
+ $(RUBYARCHDIR):
167
+ $(MAKEDIRS) $@
168
+ $(RUBYLIBDIR):
169
+ $(MAKEDIRS) $@
170
+
171
+ site-install: site-install-so site-install-rb
172
+ site-install-so: install-so
173
+ site-install-rb: install-rb
174
+
175
+ .SUFFIXES: .c .m .cc .cxx .cpp .C .o
176
+
177
+ .cc.o:
178
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
179
+
180
+ .cxx.o:
181
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
182
+
183
+ .cpp.o:
184
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
185
+
186
+ .C.o:
187
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
188
+
189
+ .c.o:
190
+ $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
191
+
192
+ $(DLLIB): $(OBJS) Makefile
193
+ @-$(RM) $(@)
194
+ $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
195
+
196
+
197
+
198
+ $(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
@@ -0,0 +1,14 @@
1
+ # Loads mkmf which is used to make makefiles for Ruby extensions
2
+ require 'mkmf'
3
+
4
+ # Give it a name
5
+ extension_name = 'maclight'
6
+
7
+ # The destination
8
+ dir_config(extension_name)
9
+
10
+ $LDFLAGS += ' -framework IOKit -framework CoreFoundation'
11
+
12
+ # Do the work
13
+ create_makefile(extension_name)
14
+
@@ -0,0 +1,352 @@
1
+ /*
2
+ * keyboard_leds.c
3
+ * Manipulate keyboard LEDs (capslock and numlock) programmatically.
4
+ *
5
+ * gcc -Wall -o keyboard_leds keyboard_leds.c -framework IOKit
6
+ * -framework CoreFoundation
7
+ *
8
+ * Copyright (c) 2007,2008 Amit Singh. All Rights Reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without
11
+ * modification, are permitted provided that the following conditions
12
+ * are met:
13
+ * 1. Redistributions of source code must retain the above copyright
14
+ * notice, this list of conditions and the following disclaimer.
15
+ * 2. Redistributions in binary form must reproduce the above copyright
16
+ * notice, this list of conditions and the following disclaimer in the
17
+ * documentation and/or other materials provided with the distribution.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
+ * SUCH DAMAGE.
30
+ */
31
+
32
+ /* rubyfied by moe@busyloop.net */
33
+
34
+ #include <stdio.h>
35
+ #include <getopt.h>
36
+ #include <stdlib.h>
37
+ #include <sysexits.h>
38
+ #include <mach/mach_error.h>
39
+
40
+ #include <IOKit/IOCFPlugIn.h>
41
+ #include <IOKit/hid/IOHIDLib.h>
42
+ #include <IOKit/hid/IOHIDUsageTables.h>
43
+
44
+ #include "ruby.h"
45
+
46
+ static IOHIDElementCookie capslock_cookie = (IOHIDElementCookie)0;
47
+ static IOHIDElementCookie numlock_cookie = (IOHIDElementCookie)0;
48
+ static int capslock_value = -1;
49
+ static int numlock_value = -1;
50
+
51
+ void usage(void);
52
+ inline void print_errmsg_if_io_err(int expr, char* msg);
53
+ inline void print_errmsg_if_err(int expr, char* msg);
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)
63
+ {
64
+ IOReturn err = (expr);
65
+
66
+ if (err != kIOReturnSuccess) {
67
+ fprintf(stderr, "*** %s - %s(%x, %d).\n", msg, mach_error_string(err),
68
+ err, err & 0xffffff);
69
+ fflush(stderr);
70
+ exit(EX_OSERR);
71
+ }
72
+ }
73
+
74
+ inline void
75
+ print_errmsg_if_err(int expr, char* msg)
76
+ {
77
+ if (expr) {
78
+ fprintf(stderr, "*** %s.\n", msg);
79
+ fflush(stderr);
80
+ exit(EX_OSERR);
81
+ }
82
+ }
83
+
84
+ io_service_t
85
+ find_a_keyboard(void)
86
+ {
87
+ io_service_t result = (io_service_t)0;
88
+
89
+ CFNumberRef usagePageRef = (CFNumberRef)0;
90
+ CFNumberRef usageRef = (CFNumberRef)0;
91
+ CFMutableDictionaryRef matchingDictRef = (CFMutableDictionaryRef)0;
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
+ }
104
+
105
+ if (!(usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
106
+ &usage))) {
107
+ goto out;
108
+ }
109
+
110
+ CFDictionarySetValue(matchingDictRef, CFSTR(kIOHIDPrimaryUsagePageKey),
111
+ usagePageRef);
112
+ CFDictionarySetValue(matchingDictRef, CFSTR(kIOHIDPrimaryUsageKey),
113
+ usageRef);
114
+
115
+ result = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDictRef);
116
+
117
+ out:
118
+ if (usageRef) {
119
+ CFRelease(usageRef);
120
+ }
121
+ if (usagePageRef) {
122
+ CFRelease(usagePageRef);
123
+ }
124
+
125
+ return result;
126
+ }
127
+
128
+ void
129
+ find_led_cookies(IOHIDDeviceInterface122** handle)
130
+ {
131
+ IOHIDElementCookie cookie;
132
+ CFTypeRef object;
133
+ long number;
134
+ long usage;
135
+ long usagePage;
136
+ CFArrayRef elements;
137
+ CFDictionaryRef element;
138
+ IOReturn result;
139
+
140
+ if (!handle || !(*handle)) {
141
+ return;
142
+ }
143
+
144
+ result = (*handle)->copyMatchingElements(handle, NULL, &elements);
145
+
146
+ if (result != kIOReturnSuccess) {
147
+ fprintf(stderr, "Failed to copy cookies.\n");
148
+ exit(1);
149
+ }
150
+
151
+ CFIndex i;
152
+
153
+ for (i = 0; i < CFArrayGetCount(elements); i++) {
154
+
155
+ element = CFArrayGetValueAtIndex(elements, i);
156
+
157
+ object = (CFDictionaryGetValue(element, CFSTR(kIOHIDElementCookieKey)));
158
+ if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
159
+ continue;
160
+ }
161
+ if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType,
162
+ &number)) {
163
+ continue;
164
+ }
165
+ cookie = (IOHIDElementCookie)number;
166
+
167
+ object = CFDictionaryGetValue(element, CFSTR(kIOHIDElementUsageKey));
168
+ if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
169
+ continue;
170
+ }
171
+ if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType,
172
+ &number)) {
173
+ continue;
174
+ }
175
+ usage = number;
176
+
177
+ object = CFDictionaryGetValue(element,CFSTR(kIOHIDElementUsagePageKey));
178
+ if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
179
+ continue;
180
+ }
181
+ if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType,
182
+ &number)) {
183
+ continue;
184
+ }
185
+ usagePage = number;
186
+
187
+ if (usagePage == kHIDPage_LEDs) {
188
+ switch (usage) {
189
+
190
+ case kHIDUsage_LED_NumLock:
191
+ numlock_cookie = cookie;
192
+ break;
193
+
194
+ case kHIDUsage_LED_CapsLock:
195
+ capslock_cookie = cookie;
196
+ break;
197
+
198
+ default:
199
+ break;
200
+ }
201
+ }
202
+ }
203
+
204
+ return;
205
+ }
206
+
207
+ void
208
+ create_hid_interface(io_object_t hidDevice, IOHIDDeviceInterface*** hdi)
209
+ {
210
+ IOCFPlugInInterface** plugInInterface = NULL;
211
+
212
+ io_name_t className;
213
+ HRESULT plugInResult = S_OK;
214
+ SInt32 score = 0;
215
+ IOReturn ioReturnValue = kIOReturnSuccess;
216
+
217
+ ioReturnValue = IOObjectGetClass(hidDevice, className);
218
+
219
+ //print_errmsg_if_io_err(ioReturnValue, "Failed to get class name.");
220
+
221
+ ioReturnValue = IOCreatePlugInInterfaceForService(
222
+ hidDevice, kIOHIDDeviceUserClientTypeID,
223
+ kIOCFPlugInInterfaceID, &plugInInterface, &score);
224
+ if (ioReturnValue != kIOReturnSuccess) {
225
+ return;
226
+ }
227
+
228
+ plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,
229
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID)hdi);
230
+ //print_errmsg_if_err(plugInResult != S_OK,
231
+ // "Failed to create device interface.\n");
232
+
233
+ (*plugInInterface)->Release(plugInInterface);
234
+ }
235
+
236
+ int
237
+ manipulate_led(UInt32 whichLED, SInt32 value)
238
+ {
239
+ io_service_t hidService = (io_service_t)0;
240
+ io_object_t hidDevice = (io_object_t)0;
241
+ IOHIDDeviceInterface **hidDeviceInterface = NULL;
242
+ IOReturn ioReturnValue = kIOReturnError;
243
+ IOHIDElementCookie theCookie = (IOHIDElementCookie)0;
244
+ IOHIDEventStruct theEvent;
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
+ }
314
+
315
+ VALUE MacLight = Qnil;
316
+
317
+ void Init_maclight();
318
+
319
+ VALUE method_capslock(int argc, VALUE *argv, VALUE self);
320
+ VALUE method_numlock(int argc, VALUE *argv, VALUE self);
321
+
322
+ void Init_maclight() {
323
+ 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);
326
+ }
327
+
328
+ VALUE kbd_led(UInt32 whichLED, int argc, VALUE *argv, VALUE klass) {
329
+ VALUE flag;
330
+ rb_scan_args(argc, argv, "01", &flag);
331
+
332
+ int set_to = -1;
333
+ switch (flag) {
334
+ case Qtrue:
335
+ set_to = 1;
336
+ break;
337
+ case Qfalse:
338
+ set_to = 0;
339
+ break;
340
+ }
341
+
342
+ return manipulate_led(whichLED, set_to) ? Qtrue : Qfalse;
343
+ }
344
+
345
+ VALUE method_capslock(int argc, VALUE *argv, VALUE klass) {
346
+ return kbd_led(kHIDUsage_LED_CapsLock, argc, argv, klass);
347
+ }
348
+
349
+ VALUE method_numlock(int argc, VALUE *argv, VALUE klass) {
350
+ return kbd_led(kHIDUsage_LED_NumLock, argc, argv, klass);
351
+ }
352
+
@@ -0,0 +1,68 @@
1
+ require 'maclight'
2
+ require 'maclight/version'
3
+ require 'optix'
4
+
5
+ module MacLight
6
+ class Cli < Optix::Cli
7
+
8
+ cli_root do
9
+ text "MacLight v#{MacLight::VERSION} - LED control utility"
10
+
11
+ opt :version, "Print version and exit", :short => :none
12
+ trigger :version do
13
+ puts "MacLight v#{MacLight::VERSION}"
14
+ end
15
+ end
16
+
17
+ desc "Toggle keyboard LEDs"
18
+ text "Toggle keyboard LEDs (capslock, numlock)"
19
+ opt :capslock, "Toggle capslock LED (0|1)", :type => Integer
20
+ opt :numlock, "Toggle numlock LED (0|1)", :type => Integer
21
+ opt :verbose, "Print current state of capslock, numlock"
22
+ parent "keyboard", "Control keyboard LEDs"
23
+ def toggle(cmd, opts, argv)
24
+ raise Optix::HelpNeeded unless opts.values_at(:capslock, :numlock, :verbose).any?
25
+ MacLight.capslock(1 == opts[:capslock]) unless opts[:capslock].nil?
26
+ MacLight.numlock(1 == opts[:numlock]) unless opts[:numlock].nil?
27
+ puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
28
+ end
29
+
30
+ desc "Blink keyboard LEDs"
31
+ text "Blink keyboard LEDs (capslock, numlock)"
32
+ text ''
33
+ text "Examples:"
34
+ text " #{File.basename($0)} keyboard blink -r 3 -f 00 10:0.3 01:0.3"
35
+ 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"
36
+ text ''
37
+ text 'Parameters:'
38
+ text ' <sequence> - Space-delimited sequence; CN:T CN:T ..'
39
+ text ' C = capslock value, N = numlock value, T = time in seconds'
40
+ opt :repeat, "Repetitions", :default => 0
41
+ opt :fin, "Set this state after sequence has finished (CN)", :type => String
42
+ opt :verbose, "Print state of capslock, numlock"
43
+ params "<sequence>"
44
+ parent "keyboard"
45
+ def blink(cmd, opts, argv)
46
+ raise Optix::HelpNeeded if argv.empty?
47
+ puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
48
+ seq = argv.map {|e| ['1'==e[0],'1'==e[1],e[3..-1].to_f] }
49
+ (0..opts[:repeat]).each do |i|
50
+ seq.each_with_index do |mode, step|
51
+ MacLight.capslock(mode[0])
52
+ MacLight.numlock(mode[1])
53
+ puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
54
+ sleep mode[2]
55
+ end
56
+ end
57
+ if opts[:fin]
58
+ MacLight.capslock('1'==opts[:fin][0])
59
+ MacLight.numlock('1'==opts[:fin][1])
60
+ puts "#{MacLight.capslock ? 1:0} #{MacLight.numlock ? 1:0}" if opts[:verbose]
61
+ end
62
+ end
63
+
64
+ def self.start
65
+ Optix.invoke!
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module MacLight
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'maclight/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "maclight"
8
+ gem.version = MacLight::VERSION
9
+ gem.authors = ["Moe"]
10
+ gem.email = ["moe@busyloop.net"]
11
+ gem.description = %q{Control your Mac keyboard LEDs (capslock, numlock)}
12
+ gem.summary = %q{Control your Mac keyboard LEDs (capslock, numlock)}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.extensions = ['ext/maclight/extconf.rb']
20
+
21
+ gem.add_dependency 'optix', '>= 1.2.2'
22
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maclight
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Moe
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: optix
16
+ requirement: &70099458189040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70099458189040
25
+ description: Control your Mac keyboard LEDs (capslock, numlock)
26
+ email:
27
+ - moe@busyloop.net
28
+ executables:
29
+ - maclight
30
+ extensions:
31
+ - ext/maclight/extconf.rb
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - ass/screenshot_capslock.jpg
40
+ - bin/maclight
41
+ - ext/maclight/Makefile
42
+ - ext/maclight/extconf.rb
43
+ - ext/maclight/maclight.c
44
+ - lib/maclight/cli.rb
45
+ - lib/maclight/version.rb
46
+ - maclight.gemspec
47
+ homepage: ''
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.10
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Control your Mac keyboard LEDs (capslock, numlock)
71
+ test_files: []