2 votos

OSX no reconoce la tecla de bloqueo de desplazamiento en mi teclado USB externo

Estoy intentando compartir mi monitor y teclado/ratón entre mi PC (Windows 7) y el Macbook Pro (1,1 - 2006, Snow Leopard) utilizando un conmutador KVM básico (Trendnet TK207).

Al pulsar dos veces el bloqueo de desplazamiento, el KVM cambia de un ordenador a otro. El problema es que esto funciona en Windows pero no en OS X. OS X no reconoce mi tecla de Bloqueo de Desplazamiento en absoluto (incluso la luz de Bloqueo de Desplazamiento no funciona).

¿Alguna idea sobre cómo depurar/arreglar este problema?

1 votos

¿Así que su teclado se conecta al KVM, que está conectado a su PC y MBP? Si ese es el caso, el problema parece estar en el propio KVM. El sección de características indica que también es compatible con los Mac.

0 votos

OSX no reconoce la tecla de bloqueo de desplazamiento. No hay ningún problema con el KVM. También funciona con Linux.

5voto

Adam Lerman Puntos 107

Hice una pequeña utilidad de línea de comandos para arreglar esto para mi Trendnet TK-204UK. El truco consiste en alternar el estado del LED de bloqueo de desplazamiento en el teclado, ya que parece ser monitoreado por el interruptor. Normalmente, el Mac no conmuta el LED cuando se pulsa la tecla de bloqueo de desplazamiento. Encontré un programa de ejemplo de Apple (HID LED test tool) que hace un acceso de bajo nivel al teclado y lo modifiqué para que parpadeara el LED de Scroll Lock. Lo llamé kvm, lo puse en mi /usr/local/bin y bingo, no hay necesidad de buscar bajo el escritorio para hacer lo que compré este interruptor para hacer. Aquí está la función principal modificada del archivo main.c del proyecto HID_LED_test_tool. Tenga en cuenta que probablemente tendrá que cambiar una configuración del proyecto de Xcode para compilarlo con el SDK 10.7 porque está configurado para usar 10.5.

--- actualizar ---

Esta solución funciona (muchas gracias) pero te falta parte del código. Usted necesita ir a http://developer.apple.com/library/mac/#samplecode/HID_LED_test_tool/Listings/main_c.html y tomar la función declarada en la parte superior.

Además, para quien no sepa qué hacer con esto, hay que crear una nueva aplicación OS X de línea de comandos en Xcode y construir esto. Entonces puedes ejecutarla para cambiar tu KVM. También tendrá que añadir CoreFoundation.framework y IOKit.framework a la construcción.

--- fin de la actualización ---

--- actualización 2 ---

Acabo de darme cuenta de que si en lugar de construir una "aplicación OS X de línea de comandos", creas una "Aplicación Cocoa" y luego borras todo excepto main.m y vuelcas el código de abajo en eso, crearás una aplicación 'normal' en lugar de una aplicación de 'línea de comandos' y eso se lanzará más rápido (sin cargar el terminal) y puede ser anclado en el dock, etc. Si vas con la "Cocoa App" tendrás que actualizar algunas de las configuraciones de compilación para que se correspondan con los archivos que elimines.

--- fin de la actualización 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 */

0 votos

Wow - que es un gran uso del código de muestra y una pequeña introducción agradable para alguien para tratar una mano corta en Xcode. :-)

0 votos

Ese trozo de código funcionó. Nunca pude conseguir que la muestra del LED HID funcionara. No hizo absolutamente nada. Gracias.

0voto

citysurrounded Puntos 99

La solución anterior no me funcionó en las nuevas versiones de MacOS, así que escribí una sencilla herramienta para enviar la señal de bloqueo de desplazamiento doble a mi KVM - incluso se puede asignar a una combinación de teclas: https://github.com/benjaminstout/osx-kvm

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X