Using OS X Mavericks, the CM Storm Devastator keyboard backlight does not light up. The light is usually activated by scroll lock being enabled, but in OS X, there is no such thing as scroll lock.
OS X: CM Storm Devastator keyboard doesn’t light up
keyboard
Related Solutions
I made a small command line utility to fix this for my Trendnet TK-204UK. The trick is to toggle the Scroll Lock LED state on the keyboard because it seems to be monitored by the switch. Mac does not normally toggle the LED when you press the Scroll Lock key. I found an Apple sample program (HID LED test tool) that does low level access to the keyboard and modified it to flash the Scroll Lock LED. I called it kvm, put it in my /usr/local/bin and bingo no need to reach under the desk to do what I bought this switch to do. Here is the modified main function of the main.c file of the HID_LED_test_tool project. Note that you will probably have to change a setting of the Xcode project to compile it with the 10.7 SDK because it is configured to use 10.5.
--- update ---
This solution works (thank you so much) but you are missing some of the code. You need to go to http://developer.apple.com/library/mac/#samplecode/HID_LED_test_tool/Listings/main_c.html and grab the function declared at the top.
Also for anyone who doesn't know what to do with this, you need to create a new command line OS X application in Xcode and build this. Then you can run it to switch your KVM. You'll also need to add CoreFoundation.framework and IOKit.framework to the build.
--- end update ---
--- update 2 ---
Just realized that if instead of building a "Command line OS X application", you create a "Cocoa Application" and then delete everything except for main.m and dump the code below in that, you'll create a 'regular' application instead of a 'command line' application and that will launch quicker (without loading up terminal) and can be docked on the dock, etc. If you do go with the "Cocoa App" you'll have to update some of the build settings to correspond to the files you delete.
--- end update 2 ---
//
// main.m
//
// ****************************************************
#pragma mark -
#pragma mark * complation directives *
// ----------------------------------------------------
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif
// ****************************************************
#pragma mark -
#pragma mark * includes & imports *
// ----------------------------------------------------
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h>
#include <IOKit/hid/IOHIDLib.h>
// ****************************************************
#pragma mark -
#pragma mark * typedef's, struct's, enums, defines, etc. *
// ----------------------------------------------------
// function to create a matching dictionary for usage page & usage
static CFMutableDictionaryRef hu_CreateMatchingDictionaryUsagePageUsage(Boolean isDeviceNotElement,
UInt32 inUsagePage,
UInt32 inUsage )
{
// create a dictionary to add usage page / usages to
CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
if ( result ) {
if ( inUsagePage ) {
// Add key for device type to refine the matching dictionary.
CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsagePage );
if ( pageCFNumberRef ) {
if ( isDeviceNotElement ) {
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ), pageCFNumberRef );
} else {
CFDictionarySetValue( result, CFSTR( kIOHIDElementUsagePageKey ), pageCFNumberRef );
}
CFRelease( pageCFNumberRef );
// note: the usage is only valid if the usage page is also defined
if ( inUsage ) {
CFNumberRef usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsage );
if ( usageCFNumberRef ) {
if ( isDeviceNotElement ) {
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ), usageCFNumberRef );
} else {
CFDictionarySetValue( result, CFSTR( kIOHIDElementUsageKey ), usageCFNumberRef );
}
CFRelease( usageCFNumberRef );
} else {
fprintf( stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__ );
}
}
} else {
fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__ );
}
}
} else {
fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__ );
}
return result;
} // hu_CreateMatchingDictionaryUsagePageUsage
int main( int argc, const char * argv[] )
{
#pragma unused ( argc, argv )
// create a IO HID Manager reference
IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );
require( tIOHIDManagerRef, Oops );
// Create a device matching dictionary
CFDictionaryRef matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( TRUE,
kHIDPage_GenericDesktop,
kHIDUsage_GD_Keyboard );
require( matchingCFDictRef, Oops );
// set the HID device matching dictionary
IOHIDManagerSetDeviceMatching( tIOHIDManagerRef, matchingCFDictRef );
if ( matchingCFDictRef ) {
CFRelease( matchingCFDictRef );
}
// Now open the IO HID Manager reference
IOReturn tIOReturn = IOHIDManagerOpen( tIOHIDManagerRef, kIOHIDOptionsTypeNone );
require_noerr( tIOReturn, Oops );
// and copy out its devices
CFSetRef deviceCFSetRef = IOHIDManagerCopyDevices( tIOHIDManagerRef );
require( deviceCFSetRef, Oops );
// how many devices in the set?
CFIndex deviceIndex, deviceCount = CFSetGetCount( deviceCFSetRef );
// allocate a block of memory to extact the device ref's from the set into
IOHIDDeviceRef * tIOHIDDeviceRefs = malloc( sizeof( IOHIDDeviceRef ) * deviceCount );
require( tIOHIDDeviceRefs, Oops );
// now extract the device ref's from the set
CFSetGetValues( deviceCFSetRef, (const void **) tIOHIDDeviceRefs );
// before we get into the device loop we'll setup our element matching dictionary
matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( FALSE, kHIDPage_LEDs, 0 );
require( matchingCFDictRef, Oops );
int pass; // do 3 passes
for ( pass = 0; pass < 3; pass++ ) {
Boolean delayFlag = FALSE; // if we find an LED element we'll set this to TRUE
//printf( "pass = %d.\n", pass );
for ( deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++ ) {
// if this isn't a keyboard device...
if ( !IOHIDDeviceConformsTo( tIOHIDDeviceRefs[deviceIndex], kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard ) ) {
continue; // ...skip it
}
//printf( " device = %p.\n", tIOHIDDeviceRefs[deviceIndex] );
// copy all the elements
CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRefs[deviceIndex],
matchingCFDictRef,
kIOHIDOptionsTypeNone );
require( elementCFArrayRef, next_device );
// for each device on the system these values are divided by the value ranges of all LED elements found
// for example, if the first four LED element have a range of 0-1 then the four least significant bits of
// this value will be sent to these first four LED elements, etc.
int device_value = pass;
// iterate over all the elements
CFIndex elementIndex, elementCount = CFArrayGetCount( elementCFArrayRef );
for ( elementIndex = 0; elementIndex < elementCount; elementIndex++ ) {
IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, elementIndex );
require( tIOHIDElementRef, next_element );
uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
// if this isn't an LED element or the Scroll Lock key...
if ( kHIDPage_LEDs != usagePage || 3 != usage ) {
continue; // ...skip it
}
//IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef );
//printf( " element = %p (page: %d, usage: %d, type: %d ).\n", tIOHIDElementRef, usagePage, usage, tIOHIDElementType );
// get the logical mix/max for this LED element
CFIndex minCFIndex = IOHIDElementGetLogicalMin( tIOHIDElementRef );
CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef );
// calculate the range
CFIndex modCFIndex = maxCFIndex - minCFIndex + 1;
// compute the value for this LED element
CFIndex tCFIndex = minCFIndex + ( device_value % modCFIndex );
device_value /= modCFIndex;
//printf( " value = 0x%08lX.\n", tCFIndex );
uint64_t timestamp = 0; // create the IO HID Value to be sent to this LED element
IOHIDValueRef tIOHIDValueRef = IOHIDValueCreateWithIntegerValue( kCFAllocatorDefault, tIOHIDElementRef, timestamp, tCFIndex );
if ( tIOHIDValueRef ) {
// now set it on the device
tIOReturn = IOHIDDeviceSetValue( tIOHIDDeviceRefs[deviceIndex], tIOHIDElementRef, tIOHIDValueRef );
CFRelease( tIOHIDValueRef );
require_noerr( tIOReturn, next_element );
delayFlag = TRUE; // set this TRUE so we'll delay before changing our LED values again
}
next_element: ;
continue;
}
next_device: ;
CFRelease( elementCFArrayRef );
continue;
}
// if we found an LED we'll delay before continuing
if ( delayFlag ) {
usleep( 250000 ); // sleep 0.25 second
}
} // next pass
if ( tIOHIDManagerRef ) {
CFRelease( tIOHIDManagerRef );
}
if ( matchingCFDictRef ) {
CFRelease( matchingCFDictRef );
}
Oops: ;
return 0;
} /* main */
gentmatt’s answer seems useful!
Alternatively, you could try going to System Preferences → Keyboard, and unchecking the “Automatically illuminate keyboard in low light” setting. That should prevent the “disabled” icon from your screenshot altogether.
Related Question
- MacOS – How to permanently disable the Mac keyboard backlight
- MacBook – No keyboard backlight until password entered
- Assigning a key to light up CM Storm Devastator keyboard problem
- Way to configure the wireless keyboard to control the keyboard light
- MacOS – Apple Extended Keyboard 2 – Caps lock key doesn’t work in macOS High Sierra
- Mac – Keyboard does not work or light up
Best Answer
I have created a fork of the apple LED test script specifically to turn on and off the LED Backlight on cmstorm keyboards. This should also work for anyone who needs to turn on scroll lock on their external keyboards (which is the backlight key for most keyboards).
To use it:
Download the binary and install it in your Applications folder
Then you can either
run it on the terminal like so
OR use an automator script as described in the following answer. Replace the automator script in step 11 with the following.
to create a script to turn it off create another automator script with the following
/Applications/led-backlight-osx off
The details for the automator script are in the edit below.
EDIT: to add this as a keyboard shortcut you must use Automator as in @AlexanderTaylor's answer, in summary:
Launch "Automator" from either Launchpad or Finder/Applications
Choose "Service" type (For Catalina, first choose "Quick Actions" on "New")
(On the left) "Library" -> "Utilities", drag "Run Shell Script" to the workflow pane.
At the top of the workflow pan, choose "no input" in "any application"
For "pass input" choose "as arguments"
For "shell" choose "/bin/sh"
Paste in this script:
Click "File" -> "Save", save it as "CMStormLedOn"
Go to System Preferences -> Keyboard -> Shortcuts -> Services -> CMStormLedOn and click on the shortcut ⌘+ScrLk. (it will show up as ⌘+F14)
Done. Now typing ⌘+ScrLk should turn those LEDs on.