maclight 1.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.
@@ -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: []