J'ai créé un petit utilitaire de ligne de commande pour résoudre ce problème pour mon Trendnet TK-204UK. L'astuce consiste à basculer l'état de la LED de verrouillage de défilement sur le clavier car elle semble être surveillée par le commutateur. Le Mac ne fait normalement pas basculer la LED lorsque vous appuyez sur la touche de verrouillage du défilement. J'ai trouvé un exemple de programme Apple (HID LED test tool) qui permet un accès de bas niveau au clavier et je l'ai modifié pour faire clignoter la LED de verrouillage du défilement. Je l'ai appelé kvm, je l'ai mis dans mon /usr/local/bin et bingo, plus besoin d'aller sous le bureau pour faire ce pour quoi j'ai acheté ce switch. Voici la fonction principale modifiée du fichier main.c du projet HID_LED_test_tool. Notez que vous devrez probablement changer un paramètre du projet Xcode pour le compiler avec le SDK 10.7 car il est configuré pour utiliser la 10.5.
--- mise à jour ---
Cette solution fonctionne (merci beaucoup) mais il manque une partie du code. Vous devez aller à http://developer.apple.com/library/mac/#samplecode/HID_LED_test_tool/Listings/main_c.html et saisir la fonction déclarée en haut de la page.
Pour ceux qui ne savent pas quoi faire, il faut créer une nouvelle application OS X en ligne de commande dans Xcode et la construire. Ensuite, vous pouvez l'exécuter pour basculer votre KVM. Vous devrez également ajouter CoreFoundation.framework et IOKit.framework à la compilation.
--- fin de la mise à jour ---
--- mise à jour 2 ---
Je viens de réaliser que si au lieu de créer une "application OS X en ligne de commande", vous créez une "application Cocoa" et que vous supprimez tout sauf le fichier main.m et que vous y insérez le code ci-dessous, vous créerez une application "normale" au lieu d'une application "en ligne de commande" et qui se lancera plus rapidement (sans charger le terminal) et qui pourra être ancrée dans le dock, etc. Si vous optez pour la "Cocoa App", vous devrez mettre à jour certains paramètres de construction pour qu'ils correspondent aux fichiers que vous supprimez.
--- fin de la mise à jour 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 */