CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Battery/AppleBatteryClient.m
Views: 1401
1
//
2
// AppleBatteryClient.m
3
// PPSSPP
4
//
5
// Created by Serena on 24/01/2023.
6
//
7
8
#include "Battery.h"
9
#import <Foundation/Foundation.h>
10
11
#if PPSSPP_PLATFORM(MAC)
12
#include <IOKit/ps/IOPSKeys.h>
13
#include <IOKit/ps/IOPowerSources.h>
14
#elif PPSSPP_PLATFORM(IOS)
15
#import <UIKit/UIKit.h>
16
#endif
17
18
@interface AppleBatteryClient : NSObject
19
+(instancetype)sharedClient;
20
-(void)setNeedsToUpdateLevel;
21
@property int batteryLevel;
22
@end
23
24
void _powerSourceRunLoopCallback(void * __unused ctx) {
25
// IOKit has told us that battery information has changed, now update the batteryLevel var
26
[[AppleBatteryClient sharedClient] setNeedsToUpdateLevel];
27
}
28
29
// You may ask,
30
// "Why an entire class?
31
// Why not just call the UIDevice/IOKitPowerSource functions every time getCurrentBatteryCapacity() is called?"
32
// Well, calling the UIDevice/IOKitPowerSource functions very frequently (every second, it seems?) is expensive
33
// So, instead, I made a class with a cached batteryLevel property
34
// that only gets set when it needs to.
35
@implementation AppleBatteryClient
36
37
+ (instancetype)sharedClient {
38
static AppleBatteryClient *client;
39
static dispatch_once_t onceToken;
40
dispatch_once(&onceToken, ^{
41
client = [AppleBatteryClient new];
42
[client initialSetup];
43
[client setNeedsToUpdateLevel];
44
});
45
46
return client;
47
}
48
49
-(void)initialSetup {
50
#if TARGET_OS_IOS
51
// on iOS, this needs to be true to get the battery level
52
// and it needs to be set just once, so do it here
53
UIDevice.currentDevice.batteryMonitoringEnabled = YES;
54
// Register for when the battery % changes
55
[[NSNotificationCenter defaultCenter] addObserver:self
56
selector:@selector(setNeedsToUpdateLevel)
57
name:UIDeviceBatteryLevelDidChangeNotification object:nil];
58
59
#elif TARGET_OS_MAC
60
CFRunLoopSourceRef loop = IOPSNotificationCreateRunLoopSource(_powerSourceRunLoopCallback, nil);
61
CFRunLoopAddSource(CFRunLoopGetMain(), loop, kCFRunLoopDefaultMode);
62
#endif
63
}
64
65
- (void)setNeedsToUpdateLevel {
66
#if TARGET_OS_IOS
67
// `-[UIDevice batteryLevel]` returns the % like '0.(actual %)' (ie, 0.28 when the battery is 28%)
68
// so multiply it by 100 to get a visually appropriate version
69
self.batteryLevel = [[UIDevice currentDevice] batteryLevel] * 100;
70
#elif TARGET_OS_MAC
71
CFTypeRef snapshot = IOPSCopyPowerSourcesInfo();
72
NSArray *sourceList = (__bridge NSArray *)IOPSCopyPowerSourcesList(snapshot);
73
if (!sourceList) {
74
if (snapshot) CFRelease(snapshot);
75
return;
76
}
77
78
for (NSDictionary *source in sourceList) {
79
// kIOPSCurrentCapacityKey = battery level
80
NSNumber *currentCapacity = [source objectForKey:@(kIOPSCurrentCapacityKey)];
81
if (currentCapacity) {
82
// we found what we want
83
self.batteryLevel = currentCapacity.intValue;
84
break;
85
}
86
}
87
CFRelease(snapshot);
88
#endif
89
}
90
91
@end
92
93
94
int getCurrentBatteryCapacity() {
95
return [[AppleBatteryClient sharedClient] batteryLevel];
96
}
97
98