OSX erkennt die Scroll Lock-Taste auf meiner externen USB-Tastatur nicht

Ich versuche, meinen Monitor und meine Tastatur/Maus zwischen meinem PC (Windows 7) und Macbook Pro (1,1 - 2006, Snow Leopard) mit einem einfachen KVM-Switch (Trendnet TK207) gemeinsam zu nutzen.

Durch zweimaliges Drücken von Scroll Lock wechselt der KVM von einem Computer zum anderen. Das Problem ist, dass dies unter Windows funktioniert, aber nicht unter OS X. OS X erkennt meine Scroll Lock-Taste überhaupt nicht (selbst das Scroll Lock-Licht funktioniert nicht).

Irgendwelche Ideen, wie man dieses Problem debuggen/beheben kann?

Ihre Tastatur wird also an den KVM angeschlossen, der wiederum an Ihren PC und MBP angeschlossen ist? Wenn das der Fall ist, scheint das Problem beim KVM selbst zu liegen. Der Funktionsabschnitt zeigt an, dass es auch mit Macs kompatibel ist.
OSX erkennt die Scroll Lock-Taste nicht. KVM ist kein Problem. Es funktioniert auch mit Linux.

Antworten (2)

Ich habe ein kleines Befehlszeilenprogramm erstellt, um dies für mein Trendnet TK-204UK zu beheben. Der Trick besteht darin, den Status der Scroll Lock-LED auf der Tastatur umzuschalten, da er anscheinend vom Schalter überwacht wird. Der Mac schaltet die LED normalerweise nicht um, wenn Sie die Scroll Lock-Taste drücken. Ich habe ein Apple-Beispielprogramm (HID-LED-Testtool) gefunden, das Low-Level-Zugriff auf die Tastatur ausführt, und es so modifiziert, dass die Scroll-Lock-LED blinkt. Ich nannte es kvm, legte es in mein /usr/local/bin und bingo, keine Notwendigkeit, unter den Schreibtisch zu greifen, um das zu tun, wofür ich diesen Schalter gekauft habe. Hier ist die modifizierte main-Funktion der main.c-Datei des HID_LED_test_tool-Projekts. Beachten Sie, dass Sie wahrscheinlich eine Einstellung des Xcode-Projekts ändern müssen, um es mit dem 10.7 SDK zu kompilieren, da es für die Verwendung von 10.5 konfiguriert ist.

--- aktualisieren ---

Diese Lösung funktioniert (vielen Dank), aber Ihnen fehlt ein Teil des Codes. Sie müssen zu http://developer.apple.com/library/mac/#samplecode/HID_LED_test_tool/Listings/main_c.html gehen und die oben deklarierte Funktion abrufen.

Auch für alle, die nicht wissen, was damit zu tun ist, müssen Sie eine neue OS X-Befehlszeilenanwendung in Xcode erstellen und diese erstellen. Dann können Sie es ausführen, um Ihren KVM umzuschalten. Sie müssen dem Build auch CoreFoundation.framework und IOKit.framework hinzufügen.

--- Update beenden ---

--- Update 2 ---

Ich habe gerade festgestellt, dass Sie, anstatt eine "Befehlszeilen-OS X-Anwendung" zu erstellen, eine "Cocoa-Anwendung" erstellen und dann alles außer main.m löschen und den folgenden Code darin ausgeben, stattdessen eine "normale" Anwendung erstellen einer 'Befehlszeilen'-Anwendung, die schneller startet (ohne das Terminal zu laden) und an das Dock angedockt werden kann usw. Wenn Sie sich für die "Cocoa App" entscheiden, müssen Sie einige der Build-Einstellungen aktualisieren entsprechen den Dateien, die Sie löschen.

--- Update 2 beenden ---

//
//  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 */
Wow – das ist eine großartige Verwendung des Beispielcodes und eine nette kleine Einführung für jemanden, der sich kurz mit Xcode vertraut machen möchte. :-)
Dieser Code hat funktioniert. Ich konnte das HID-LED-Beispiel nie zum Laufen bringen. Es hat absolut nichts gebracht. Danke!

Die obige Lösung hat bei mir auf neueren Versionen von MacOS nicht funktioniert, also habe ich ein einfaches Tool geschrieben, um das Double-Scroll-Lock-Signal an meinen KVM zu senden – es kann sogar einer Tastenkombination zugewiesen werden: https://github.com/ benjaminstout/osx-kvm