Receive notification for power cord on/off in OSX Cocoa for the laptop

[亡魂溺海] 提交于 2021-01-24 09:55:18

问题


ALL,

Does OSX sends any notification when the power cord is plugged/unplugged in the Mac laptop? Or plugging/unplugging the laptop from the docking station?

It does send something on shutdown/reboot/wake-up/etc, but I didn't find anything for that specific event.

Am I missing something? Or this is not available?

TIA!


回答1:


There are no high-level notifications, but the IOPowerSources framework can post a message to your run loop whenever the power state changes.

My project has multiple PowerCondition objects that monitor various aspects of the current power (A/C vs. Battery, how much battery is left, and so on).

Here's a fragment of the PowerCondition class that shows how to observe power source change events via the run loop and turn that into a notification that multiple objects can observe (this is fairly old Obj-C):

#define kPowerConditionChangedNotification  @"PowerConditionChanged"

static NSUInteger PowerChangeListenerCount = 0;
static CFRunLoopSourceRef PowerChangeSource = NULL;
static void PowerChangeCallback(void *context)
{
    // Called by CFRunLoopSourceRef when something changes
    // Post a notification so that all PowerCondition observers can reevaluate
    [[NSNotificationCenter defaultCenter] postNotificationName:kPowerConditionChangedNotification object:nil];
}

@interface PowerCondition
{
    BOOL listening;
    //...
}

- (void)powerStateDidChangeNotification:(NSNotification*)notification;

@end

// ...

@implementation PowerCondition

- (void)startMonitoringCondition
{
    if (!listening)
        {
        // Observe the power condition change notification
        DebugLogger(@"condition '%@'",[self description]);
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(powerStateDidChangeNotification:)
                                                     name:kPowerConditionChangedNotification
                                                   object:nil];
        if (PowerChangeListenerCount++==0)
            {
            // This is the first observer: create and install the run loop source that will fire the notification
            BetaAssert(PowerChangeSource==NULL,@"zero PowerChangeListenerCount, but PowerChangeSource!=NULL");
            PowerChangeSource = IOPSNotificationCreateRunLoopSource(PowerChangeCallback,NULL);
            CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop],PowerChangeSource,kCFRunLoopCommonModes);
            DebugLoggerMessage(@"installed PowerChangeSource(PowerChangeCallback) in run loop");
            }

        listening = YES;
        previousTestState = -1;         // neither YES nor NO
        }
}

- (void)stopMonitoringCondition
{
    if (listening)
        {
        // Stop observing power condition change notifications
        PowerLogger(@"condition '%@'",[self description]);
        [[NSNotificationCenter defaultCenter] removeObserver:self];

        BetaAssert(PowerChangeListenerCount!=0,@"PowerChangeListenerCount==0");
        if (--PowerChangeListenerCount==0)
            {
            // This was the last power change observer: remove the run loop source the fires the notifications
            BetaAssertNotNil(PowerChangeSource);
            CFRunLoopRemoveSource([[NSRunLoop mainRunLoop] getCFRunLoop],PowerChangeSource,kCFRunLoopCommonModes);
            CFRelease(PowerChangeSource);
            PowerChangeSource = NULL;
            DebugLoggerMessage(@"removed PowerChangeSource(PowerChangeCallback) from run loop");
            }

        listening = NO;
        }

}

- (void)powerStateDidChangeNotification:(NSNotification*)notification
{
    // Evaluate power state here

    BOOL battery = NO;                                  // assume unlimited/external power
    double capacityRemaining = 1.0;                     // assume 100%

    // First, determine if the system's active power source is AC or battery
    CFTypeRef powerBlob = IOPSCopyPowerSourcesInfo();
    CFArrayRef powerSourcesRef = IOPSCopyPowerSourcesList(powerBlob);
    CFIndex count = CFArrayGetCount(powerSourcesRef);
    if (count!=0)
        {
        // There's precious little explination what the meaning of the different power sources
        //  are or why there would be more than one. As far as I can tell, everything can be
        //  determined by obtaining the first (and probably only) power source description.
        NSDictionary* powerInfo = (__bridge id)IOPSGetPowerSourceDescription(powerBlob,CFArrayGetValueAtIndex(powerSourcesRef,0));
        if (![powerInfo[@kIOPSPowerSourceStateKey] isEqualToString:@kIOPSACPowerValue])
            {
            // Power source is not AC (must be battery or UPS)
            battery = YES;
            // Calculate the remaining capacity, as a fraction
            NSNumber* capacityValue = powerInfo[@kIOPSCurrentCapacityKey];
            NSNumber* maxValue = powerInfo[@kIOPSMaxCapacityKey];
            if (capacityValue!=nil && maxValue!=nil)
                capacityRemaining = [capacityValue doubleValue]/[maxValue doubleValue];
            DebugLogger(@"power source is '%@', battery=%d, capacity=%@, max=%@, remaining=%f%%",
                        powerInfo[@kIOPSPowerSourceStateKey],
                        (int)battery,
                        capacityValue,maxValue,capacityRemaining*100);
            }
        }

    // ...
}

Note that the callback is installed on the main run loop, so the notification will always be posted on the main thread.



来源:https://stackoverflow.com/questions/57788386/receive-notification-for-power-cord-on-off-in-osx-cocoa-for-the-laptop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!