Pregunta

Hice una pequeña aplicación para permitir cambiar rápidamente las resoluciones de pantalla en varios monitores.Quiero mostrar el nombre del producto como título del monitor y es muy sencillo de encontrarlo usando este código:

NSDictionary *deviceInfo = (__bridge NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dispID), kIODisplayOnlyPreferredName);

NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];

if([localizedNames count] > 0) {
    _title = [localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]];
} else {
    _title = @"Unknown display";
}

Pero CGDisplayIOServicePort está en desuso en OS X >= 10.9 y la documentación de Apple dice que no hay reemplazo.¿Cómo encontrar el puerto de servicio o el nombre del producto sin utilizar este método?

Intenté iterar a través del registro IO e intenté usar IOServiceGetMatchingServices método para encontrar servicios de visualización, pero no estoy muy familiarizado con el registro IO, por lo que no pude encontrar una solución.

¡Gracias por la ayuda!

¿Fue útil?

Solución

Parece que la publicación de @ Eun se perdió una pieza de información para cerrar esta discusión. Con una pequeña búsqueda, encontré que iOservicePortFromCgdisplayid no es una API que proporciona Apple. Más bien, es un código de código abierto que se encuentra aquí: https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src /cocoa_monitor.m

Copiado iOSERVICEPORTFROMCGDISPLAYID y también 'GetDisplayName' de él. Necesitaba dos ajustes para que funcione en OS X 10.10.

  1. Elimine el código para manejar el número de serie en iOSERVICEPORTFROMCGDISPLAYID. (CFDicticionaryGetValue para kdisplayserialnumber devuelve nulo para mí.)
  2. eliminar el proyecto específico Código de manejo de errores en GetDisplayName.
  3. Si necesita más información

    • Rastreador de emisión del problema: github.com/glfw/glfw/issues/165
    • cometer Para la solución: github.com/glfw/glfw/commit/e0a6772e5e4c672179fc69a90bcda3369792ed1f

    Agradecería a Matthew Henry, quien envió el código allí.

Otros consejos

Aquí está mi opinión sobre el tema.También comencé con el código de GLFW 3.1, archivo cacaa_monitor.m.
Pero tuve que modificarlo de diferentes maneras que Hiroshi dijo, así que aquí va:

// Get the name of the specified display
- (NSString*) screenNameForDisplay: (NSNumber*) screen_id
{
    CGDirectDisplayID displayID = [screen_id unsignedIntValue];

    io_service_t serv = [self IOServicePortFromCGDisplayID: displayID];
    if (serv == 0)
        return @"unknown";

    CFDictionaryRef info = IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
    IOObjectRelease(serv);

    CFStringRef display_name;
    CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));

    if ( !names ||
         !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), (const void**) & display_name)  )
    {
        // This may happen if a desktop Mac is running headless
        CFRelease( info );
        return @"unknown";
    }

    NSString * displayname = [NSString stringWithString: (__bridge NSString *) display_name];
    CFRelease(info);
    return displayname;
}


// Returns the io_service_t (an int) corresponding to a CG display ID, or 0 on failure.
// The io_service_t should be released with IOObjectRelease when not needed.

- (io_service_t) IOServicePortFromCGDisplayID: (CGDirectDisplayID) displayID
{
    io_iterator_t iter;
    io_service_t serv, servicePort = 0;

    CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect");

    // releases matching for us
    kern_return_t err = IOServiceGetMatchingServices( kIOMasterPortDefault, matching, & iter );
    if ( err )
        return 0;

    while ( (serv = IOIteratorNext(iter)) != 0 )
    {
        CFDictionaryRef displayInfo;
        CFNumberRef vendorIDRef;
        CFNumberRef productIDRef;
        CFNumberRef serialNumberRef;

        displayInfo = IODisplayCreateInfoDictionary( serv, kIODisplayOnlyPreferredName );

        Boolean success;
        success =  CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayVendorID),  (const void**) & vendorIDRef );
        success &= CFDictionaryGetValueIfPresent( displayInfo, CFSTR(kDisplayProductID), (const void**) & productIDRef );

        if ( !success )
        {
            CFRelease(displayInfo);
            continue;
        }

        SInt32 vendorID;
        CFNumberGetValue( vendorIDRef, kCFNumberSInt32Type, &vendorID );
        SInt32 productID;
        CFNumberGetValue( productIDRef, kCFNumberSInt32Type, &productID );

        // If a serial number is found, use it.
        // Otherwise serial number will be nil (= 0) which will match with the output of 'CGDisplaySerialNumber'
        SInt32 serialNumber = 0;
        if ( CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplaySerialNumber), (const void**) & serialNumberRef) )
        {
            CFNumberGetValue( serialNumberRef, kCFNumberSInt32Type, &serialNumber );
        }

        // If the vendor and product id along with the serial don't match
        // then we are not looking at the correct monitor.
        // NOTE: The serial number is important in cases where two monitors
        //       are the exact same.
        if( CGDisplayVendorNumber(displayID) != vendorID ||
            CGDisplayModelNumber(displayID)  != productID ||
            CGDisplaySerialNumber(displayID) != serialNumber )
        {
            CFRelease(displayInfo);
            continue;
        }

        servicePort = serv;
        CFRelease(displayInfo);
        break;
    }

    IOObjectRelease(iter);
    return servicePort;
}

Esto funciona bien para mí en un protector de pantalla que escribí bajo MacOS 10.11 (El Capitan). Lo probé con la visualización incorporada de mi MacBookPro y una pantalla de Apple conectada a través de Thunderbolt.

NSString* screenNameForDisplay(CGDirectDisplayID displayID)
{
    NSString *screenName = nil;
    io_service_t service = IOServicePortFromCGDisplayID(displayID);
    if (service)
    {
        NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(service, kIODisplayOnlyPreferredName);
        NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];

        if ([localizedNames count] > 0) {
            screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
        }

        [deviceInfo release];
    }
    return [screenName autorelease];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top