是否可以控制OS X上的CAPS LOCK LED?


8

我没有在OS X中使用CAPS LOCK功能,因此我在系统偏好设置下禁用了该键。现在,该键对我完全没有用-好的,我可以将CMD / CTRL / ALT键映射到该键,但是我已经有了该键…

因此,我要记住的是使用键上的LED(我使用最近的Apple无线键盘)来提醒我是否有邮件在等待……之类的东西。是否可以直接控制LED?可以通过Objective-C可可应用程序进行控制,我将自己编写该应用程序,但是直到现在,我都可以从Apple可可文档中找到有用的东西。


我想这大概是硬连接到键盘固件中的,所以您必须先破解它。
slhck

1
我使用Seil(以前称为PCKeyboardHack)不仅禁用Caps Lock的默认功能(这是无用的),而且还将其设置为另一个键,然后又在命令行中大量使用此键作为通用命令键(一种重载的上下文切换功能)。这真的很有用。2年后,我开始想知道如何控制这个绿色的LED灯,这个绿色的LED灯也是我遗忘的那个按键。
史蒂文·卢

Answers:


6

一个Python示例:http//www.psychicorigami.com/2009/03/01/5k-morse-code-app-using-capslock-led/

有可能的。我试图找到我几年前发现的应用程序,该应用程序可以切换旧iBook(10.4)上的num lock和caps lock LED。今天看的时候发现了。

找到了。

不过需要编译。

哦,还有HID LED测试工具 – Xcode示例:D


谢谢。注意:在当前的Mac OS X 10.6上,仅最后一个示例(Xcode)有效。
DASKAjA,2011年

好吧,最后一个示例在Apple页面上列为10.5。但是,莫尔斯电码应用程序基于该代码,无法在10.6上运行。不知道一个keyboard_leds,但我希望它能做到。
cde

HID LED测试工具可同时在El Capitan的内部和外部Apple键盘上使用。我不确定代码中是否有直接方法来设置Caps灯的状态,所以我只是将通过次数更改为3以打开灯,将通过次数更改为1通过以将其关闭。然后,如果您从脚本中运行它,它将立即关闭照明灯,但是大约需要一到两秒钟才能打开照明灯。
RusI 2015年

1
@cde keyboard_leds在OSX 10.11.1上对我有效,但仅对内部键盘有效。它无法控制USB Apple键盘上的Caps LED。
RusI 2015年

8

这是在OSX下控制键盘指示灯的另一种工具:https : //github.com/busyloop/maclight

MacLight使您可以控制Mac上的键盘LED(大写锁定,数字锁定)。


1
在OSX 10.10.5中,这似乎不再起作用。在2个用例中进行了测试:1.没有重新映射,Apple的键盘默认设置。2.在系统设置中禁用了Caps Lock,并在Karabiner中将Seil和F19设置为Hyper Key(CTRL + ALT + CMD)重新映射到F19。 $ maclight keyboard toggle --capslock $ maclight keyboard toggle -v 1 0但是Caps Lock指示灯熄灭。
RusI

现在在OSX 10.11.1上,它仅适用于内置键盘,而不适用于外部USB Apple键盘。
RusI 2015年

0

您可以使用此操作Mac键盘LED。

/*
 * keyboard_leds.c
 * Manipulate keyboard LEDs (capslock and numlock) programmatically.
 *
 * gcc -Wall -o keyboard_leds keyboard_leds.c -framework IOKit
 *     -framework CoreFoundation
 *
 * Copyright (c) 2007,2008 Amit Singh. All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *     
 *  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 *  SUCH DAMAGE.
 */

#define PROGNAME "keyboard_leds"
#define PROGVERS "0.1"

#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <sysexits.h>
#include <mach/mach_error.h>

#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDUsageTables.h>

static IOHIDElementCookie capslock_cookie = (IOHIDElementCookie)0;
static IOHIDElementCookie numlock_cookie  = (IOHIDElementCookie)0;
static int capslock_value = -1;
static int numlock_value  = -1;

void         usage(void);
inline void  print_errmsg_if_io_err(int expr, char* msg);
inline void  print_errmsg_if_err(int expr, char* msg);

io_service_t find_a_keyboard(void);
void         find_led_cookies(IOHIDDeviceInterface122** handle);
void         create_hid_interface(io_object_t hidDevice,
                                  IOHIDDeviceInterface*** hdi);
int          manipulate_led(UInt32 whichLED, UInt32 value);

void
usage(void)
{
    fprintf(stderr, "%s (version %s)\n"
      "Copyright (c) 2007,2008 Amit Singh. All Rights Reserved.\n"
      "Manipulate keyboard LEDs\n\n"
      "Usage: %s [OPTIONS...], where OPTIONS is one of the following\n\n"
      "  -c[1|0], --capslock[=1|=0] get or set (on=1, off=0) caps lock LED\n"
      "  -h,      --help            print this help message and exit\n"
      "  -n[1|0], --numlock[=1|=0]  get or set (on=1, off=0) num lock LED\n",
    PROGNAME, PROGVERS, PROGNAME);
}

inline void
print_errmsg_if_io_err(int expr, char* msg)
{
    IOReturn err = (expr);

    if (err != kIOReturnSuccess) {
        fprintf(stderr, "*** %s - %s(%x, %d).\n", msg, mach_error_string(err),
                err, err & 0xffffff);
        fflush(stderr);
        exit(EX_OSERR);
    }
}

inline void
print_errmsg_if_err(int expr, char* msg)
{
    if (expr) {
        fprintf(stderr, "*** %s.\n", msg);
        fflush(stderr);
        exit(EX_OSERR);
    }
}

io_service_t
find_a_keyboard(void)
{
    io_service_t result = (io_service_t)0;

    CFNumberRef usagePageRef = (CFNumberRef)0;
    CFNumberRef usageRef = (CFNumberRef)0;
    CFMutableDictionaryRef matchingDictRef = (CFMutableDictionaryRef)0;

    if (!(matchingDictRef = IOServiceMatching(kIOHIDDeviceKey))) {
        return result;
    }

    UInt32 usagePage = kHIDPage_GenericDesktop;
    UInt32 usage = kHIDUsage_GD_Keyboard;

    if (!(usagePageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
                                        &usagePage))) {
        goto out;
    }

    if (!(usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
                                    &usage))) {
        goto out;
    }

    CFDictionarySetValue(matchingDictRef, CFSTR(kIOHIDPrimaryUsagePageKey),
                         usagePageRef);
    CFDictionarySetValue(matchingDictRef, CFSTR(kIOHIDPrimaryUsageKey),
                         usageRef);

    result = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDictRef);

out:
    if (usageRef) {
        CFRelease(usageRef);
    }
    if (usagePageRef) {
        CFRelease(usagePageRef);
    }

    return result;
}

void
find_led_cookies(IOHIDDeviceInterface122** handle)
{
    IOHIDElementCookie cookie;
    CFTypeRef          object;
    long               number;
    long               usage;
    long               usagePage;
    CFArrayRef         elements;
    CFDictionaryRef    element;
    IOReturn           result;

    if (!handle || !(*handle)) {
        return;
    }

    result = (*handle)->copyMatchingElements(handle, NULL, &elements);

    if (result != kIOReturnSuccess) {
        fprintf(stderr, "Failed to copy cookies.\n");
        exit(1);
    }

    CFIndex i;

    for (i = 0; i < CFArrayGetCount(elements); i++) {

        element = CFArrayGetValueAtIndex(elements, i);

        object = (CFDictionaryGetValue(element, CFSTR(kIOHIDElementCookieKey)));
        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
            continue;
        }
        if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType,
                              &number)) {
            continue;
        }
        cookie = (IOHIDElementCookie)number;

        object = CFDictionaryGetValue(element, CFSTR(kIOHIDElementUsageKey));
        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
            continue;
        }
        if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType,
                              &number)) {
            continue;
        }
        usage = number;

        object = CFDictionaryGetValue(element,CFSTR(kIOHIDElementUsagePageKey));
        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) {
            continue;
        }
        if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType,
                              &number)) {
            continue;
        }
        usagePage = number;

        if (usagePage == kHIDPage_LEDs) {
            switch (usage) {

            case kHIDUsage_LED_NumLock:
                numlock_cookie = cookie;
                break;

            case kHIDUsage_LED_CapsLock:
                capslock_cookie = cookie;
                break;

            default:
                break;
            }
        }
    }

    return;
}

void
create_hid_interface(io_object_t hidDevice, IOHIDDeviceInterface*** hdi)
{
    IOCFPlugInInterface** plugInInterface = NULL;

    io_name_t className;
    HRESULT   plugInResult = S_OK;
    SInt32    score = 0;
    IOReturn  ioReturnValue = kIOReturnSuccess;

    ioReturnValue = IOObjectGetClass(hidDevice, className);

    print_errmsg_if_io_err(ioReturnValue, "Failed to get class name.");

    ioReturnValue = IOCreatePlugInInterfaceForService(
                        hidDevice, kIOHIDDeviceUserClientTypeID,
                        kIOCFPlugInInterfaceID, &plugInInterface, &score);
    if (ioReturnValue != kIOReturnSuccess) {
        return;
    }

    plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,
                     CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID)hdi);
    print_errmsg_if_err(plugInResult != S_OK,
                        "Failed to create device interface.\n");

    (*plugInInterface)->Release(plugInInterface);
}

int
manipulate_led(UInt32 whichLED, UInt32 value)
{
    io_service_t           hidService = (io_service_t)0;
    io_object_t            hidDevice = (io_object_t)0;
    IOHIDDeviceInterface **hidDeviceInterface = NULL;
    IOReturn               ioReturnValue = kIOReturnError;
    IOHIDElementCookie     theCookie = (IOHIDElementCookie)0;
    IOHIDEventStruct       theEvent;

    if (!(hidService = find_a_keyboard())) {
        fprintf(stderr, "No keyboard found.\n");
        return ioReturnValue;
    }

    hidDevice = (io_object_t)hidService;

    create_hid_interface(hidDevice, &hidDeviceInterface);

    find_led_cookies((IOHIDDeviceInterface122 **)hidDeviceInterface);

    ioReturnValue = IOObjectRelease(hidDevice);
    if (ioReturnValue != kIOReturnSuccess) {
        goto out;
    }

    ioReturnValue = kIOReturnError;

    if (hidDeviceInterface == NULL) {
        fprintf(stderr, "Failed to create HID device interface.\n");
        return ioReturnValue;
    }

    if (whichLED == kHIDUsage_LED_NumLock) {
        theCookie = numlock_cookie;
    } else if (whichLED == kHIDUsage_LED_CapsLock) {
        theCookie = capslock_cookie;
    }

    if (theCookie == 0) {
        fprintf(stderr, "Bad or missing LED cookie.\n");
        goto out;
    }

    ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, 0);
    if (ioReturnValue != kIOReturnSuccess) {
        fprintf(stderr, "Failed to open HID device interface.\n");
        goto out;
    }

    ioReturnValue = (*hidDeviceInterface)->getElementValue(hidDeviceInterface,
                                               theCookie, &theEvent);
    if (ioReturnValue != kIOReturnSuccess) {
        (void)(*hidDeviceInterface)->close(hidDeviceInterface);
        goto out;
    }

    fprintf(stdout, "%s\n", (theEvent.value) ? "on" : "off");
    if (value != -1) {
        if (theEvent.value != value) {
            theEvent.value = value;
            ioReturnValue = (*hidDeviceInterface)->setElementValue(
                                hidDeviceInterface, theCookie,
                                &theEvent, 0, 0, 0, 0);
            if (ioReturnValue == kIOReturnSuccess) {
                fprintf(stdout, "%s\n", (theEvent.value) ? "on" : "off");
            }
        }
    }

    ioReturnValue = (*hidDeviceInterface)->close(hidDeviceInterface);

out:
    (void)(*hidDeviceInterface)->Release(hidDeviceInterface);

    return ioReturnValue;
}

static const char *options = "c::hn::";
static struct option
long_options[] = {
    { "capslock", optional_argument, 0, 'c' },
    { "help",     no_argument,       0, 'h' },
    { "numlock",  optional_argument, 0, 'n' },
    { 0, 0, 0, 0 },
};

int
main (int argc, char **argv)
{
    UInt32 whichLED = (UInt32)0;
    int c, ctr = 0;
    int target_value = -1;

    while ((c = getopt_long(argc, argv, options, long_options, NULL)) != -1) {

        switch (c) {

        case 0:
            break;

        case 'c':
            ctr++;
            whichLED = kHIDUsage_LED_CapsLock;
            if (optarg) {
                capslock_value = atoi(optarg);
                target_value = (capslock_value);
            }
            break;

        case 'h':
            usage();
            exit(0);
            break;

        case 'n':
            ctr++;
            whichLED = kHIDUsage_LED_NumLock;
            if (optarg) {
                numlock_value = atoi(optarg);
                target_value = (numlock_value);
            }
            break;

        default:
            usage();
            exit(1);
            break;
        }
    }

    if (ctr != 1) {
        fprintf(stderr, "Missing options or invalid combination of options. "
                        "Try -h for help.\n");
        exit(1);
    }

    return manipulate_led(whichLED, target_value);
}

编译和使用此脚本

gcc -Wall -o keyboard_leds keyboard_leds.c \
    -framework IOKit -framework CoreFoundation
./keyboard_leds -h
./keyboard_leds -c # query caps lock LED state
./keyboard_leds -c1 # turn caps lock LED on
./keyboard_leds -c0 # turn caps lock LED off

1
我终于在OSX 10.11.1上运行了它,但是它只控制内部键盘上的Caps LED,而不控制USB Apple键盘上的Caps LED。
RusI 2015年

已添加-std=gnu89以使to声在macOS Mojave上满意,但LED不起作用。
Arnie97
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.