Question

J'ai créé une petite application pour permettre de modifier rapidement les résolutions d'écran sur plusieurs moniteurs.Je souhaite afficher le nom du produit comme titre du moniteur, et c'est très simple à trouver en utilisant ce code :

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";
}

Mais CGDisplayIOServicePort est obsolète dans OS X >= 10.9 et la documentation d'Apple indique qu'il n'y a pas de remplacement.Comment trouver le port de service ou le nom du produit sans utiliser cette méthode ?

J'ai essayé de parcourir le registre IO et j'ai essayé d'utiliser IOServiceGetMatchingServices méthode pour trouver des services d'affichage mais je ne suis pas très familier avec le registre IO donc je n'ai pas trouvé de solution.

Merci pour l'aide!

Était-ce utile?

La solution

Il semble que le message de @Eun ait manqué une information pour clôturer cette discussion.Avec une petite recherche, j'ai découvert que IOServicePortFromCGDisplayID n'est pas une API fournie par Apple.Il s'agit plutôt d'un morceau de code open source trouvé ici :https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src/cocoa_monitor.m

J'en ai copié IOServicePortFromCGDisplayID et également 'getDisplayName'.J'avais besoin de deux ajustements pour que cela fonctionne sous OS X 10.10.

  1. Supprimez le code pour gérer le numéro de série dans IOServicePortFromCGDisplayID.(CFDictionaryGetValue pour kDisplaySerialNumber renvoie la valeur NULL pour moi.)
  2. Supprimez le code de gestion des erreurs spécifique du projet dans getDisplayName.

Si vous avez besoin de plus d'informations

  • Suivi du problème :github.com/glfw/glfw/issues/165
  • Commettre Pour la solution :github.com/glfw/glfw/commit/e0a6772e5e4c672179fc69a90bcda3369792ed1f

Je remercie Matthew Henry qui y a soumis le code.

Autres conseils

Voici mon point de vue sur la question.J'ai également commencé avec le code de GLFW 3.1, le fichier cocoa_monitor.m.
Mais j'ai dû le modifier d'une manière différente de celle indiquée par Hiroshi, alors voici :

// 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;
}

Cela fonctionne bien pour moi dans un économiseur d'écran que j'ai écrit sous macOS 10.11 (El Capitan).Je l'ai testé avec l'écran intégré de mon MacBookPro et un Apple Display connecté via 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];
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top