Frage

Ich habe eine kleine App erstellt, um die Bildschirmauflösung auf mehreren Monitoren schnell ändern zu können.Ich möchte den Produktnamen als Titel des Monitors anzeigen. Mit diesem Code ist er ganz einfach zu finden:

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

Aber CGDisplayIOServicePort ist in OS X >= 10.9 veraltet und in der Dokumentation von Apple heißt es, dass es keinen Ersatz gibt.Wie finde ich den Service-Port oder den Produktnamen, ohne diese Methode zu verwenden?

Ich habe versucht, die IO-Registrierung zu durchlaufen und zu verwenden IOServiceGetMatchingServices Methode, um Anzeigedienste zu finden, aber ich bin mit der IO-Registrierung nicht sehr vertraut, daher konnte ich keine Lösung finden.

Danke für die Hilfe!

War es hilfreich?

Lösung

Es sieht so aus, als ob in @Euns Beitrag eine Information zum Abschluss dieser Diskussion fehlte.Bei einer kleinen Suche habe ich herausgefunden, dass IOServicePortFromCGDisplayID keine API ist, die Apple bereitstellt.Es handelt sich vielmehr um einen Teil des Open-Source-Codes, den Sie hier finden:https://github.com/glfw/glfw/blob/e0a6772e5e4c672179fc69a90bcda3369792ed1f/src/cocoa_monitor.m

Ich habe IOServicePortFromCGDisplayID und auch „getDisplayName“ daraus kopiert.Ich brauchte zwei Optimierungen, damit es unter OS X 10.10 funktioniert.

  1. Entfernen Sie den Code zur Verarbeitung der Seriennummer in IOServicePortFromCGDisplayID.,
  2. Entfernen Sie projektspezifische Fehlerbehandlungscode in getDisplayName.

Wenn Sie weitere Informationen benötigen

  • Issue-Tracker des Problems:github.com/glfw/glfw/issues/165
  • Sich für die Lösung verpflichten:github.com/glfw/glfw/commit/e0a6772e5e4c672179fc69a90bcda3369792ed1f

Ich möchte Matthew Henry danken, der den Code dort eingereicht hat.

Andere Tipps

Hier ist meine Sicht auf das Problem.Ich habe auch mit dem Code aus GLFW 3.1, Datei Cocoa_monitor.m, begonnen.
Aber ich musste es anders modifizieren, als Hiroshi sagte, also hier:

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

Das funktioniert bei mir in einem Bildschirmschoner, den ich unter macOS 10.11 (El Capitan) geschrieben habe, einwandfrei.Getestet habe ich es mit dem eingebauten Display meines MacBookPro und einem über Thunderbolt angeschlossenen Apple Display.

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];
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top