-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
190 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
from typing import Mapping | ||
|
||
from rpcclient.darwin.consts import MACH_PORT_NULL, kCFAllocatorDefault, kIOServicePlane | ||
from rpcclient.darwin.structs import mach_port_t, io_name_t, io_object_t | ||
from rpcclient.exceptions import RpcClientException, BadReturnValueError | ||
from rpcclient.allocated import Allocated | ||
|
||
|
||
class IOServiceIter(Allocated): | ||
def __init__(self, client, service): | ||
super().__init__() | ||
self._client = client | ||
self._service = service | ||
|
||
def __iter__(self): | ||
with self._client.safe_malloc(io_object_t.sizeof()) as p_child_iter: | ||
if self._client.symbols.IORegistryEntryGetChildIterator(self._service, kIOServicePlane, p_child_iter): | ||
raise BadReturnValueError('IORegistryEntryGetChildIterator failed') | ||
child_iter = p_child_iter[0] | ||
|
||
while True: | ||
child = self._client.symbols.IOIteratorNext(child_iter) | ||
if not child: | ||
break | ||
s = IOService(self._client, child) | ||
yield s | ||
|
||
self.deallocate() | ||
|
||
def _deallocate(self): | ||
self._client.symbols.IOObjectRelease(self._service) | ||
|
||
|
||
class IOService(Allocated): | ||
""" representation of a remote IOService """ | ||
|
||
def __init__(self, client, service): | ||
super().__init__() | ||
self._client = client | ||
self._service = service | ||
|
||
@property | ||
def name(self) -> str: | ||
with self._client.safe_malloc(io_name_t.sizeof()) as name: | ||
if self._client.symbols.IORegistryEntryGetName(self._service, name): | ||
raise BadReturnValueError('IORegistryEntryGetName failed') | ||
return name.peek_str() | ||
|
||
@property | ||
def properties(self) -> Mapping: | ||
with self._client.safe_malloc(8) as p_properties: | ||
if self._client.symbols.IORegistryEntryCreateCFProperties(self._service, p_properties, | ||
kCFAllocatorDefault, 0): | ||
raise BadReturnValueError('IORegistryEntryCreateCFProperties failed') | ||
return p_properties[0].py | ||
|
||
def iter(self) -> IOServiceIter: | ||
return IOServiceIter(self._client, self._service) | ||
|
||
def set(self, properties: Mapping): | ||
self._client.symbols.IORegistryEntrySetCFProperties(self._service, self._client.cf(properties)) | ||
|
||
def get(self, key: str): | ||
return self._client.symbols.IORegistryEntryCreateCFProperty(self._service, self._client.cf(key), 0, 0).py | ||
|
||
def _deallocate(self): | ||
self._client.symbols.IOObjectRelease(self._service) | ||
|
||
def __repr__(self): | ||
return f'<IOService NAME:{self.name}>' | ||
|
||
|
||
class BacklightControlService(IOService): | ||
@property | ||
def display_parameters(self) -> Mapping: | ||
return self.get('IODisplayParameters') | ||
|
||
@property | ||
def brightness(self) -> int: | ||
return self.display_parameters['brightness']['value'] | ||
|
||
@brightness.setter | ||
def brightness(self, value: int): | ||
self.set({'EnableBacklight': bool(value)}) | ||
self.set({'brightness': value}) | ||
|
||
|
||
class PowerSourceService(IOService): | ||
@property | ||
def battery_voltage(self) -> int: | ||
return self.get('AppleRawBatteryVoltage') | ||
|
||
@property | ||
def charging(self) -> bool: | ||
return self.get('IsCharging') | ||
|
||
@charging.setter | ||
def charging(self, value: bool): | ||
self.set({'IsCharging': value, 'ExternalConnected': value}) | ||
|
||
@property | ||
def external_connected(self) -> bool: | ||
return self.get('ExternalConnected') | ||
|
||
@external_connected.setter | ||
def external_connected(self, value: bool): | ||
self.set({'ExternalConnected': value}) | ||
|
||
@property | ||
def current_capacity(self) -> int: | ||
return self.get('CurrentCapacity') | ||
|
||
@current_capacity.setter | ||
def current_capacity(self, value: int): | ||
self.set({'CurrentCapacity': value}) | ||
|
||
@property | ||
def at_warn_level(self) -> bool: | ||
return self.get('AtWarnLevel') | ||
|
||
@at_warn_level.setter | ||
def at_warn_level(self, value: bool): | ||
self.set({'AtWarnLevel': value}) | ||
|
||
@property | ||
def time_remaining(self) -> int: | ||
return self.get('TimeRemaining') | ||
|
||
@property | ||
def temperature(self) -> int: | ||
return self.get('Temperature') | ||
|
||
@temperature.setter | ||
def temperature(self, value: int): | ||
self.set({'Temperature': value}) | ||
|
||
|
||
class IORegistry: | ||
""" | ||
IORegistry utils | ||
For more information please read: | ||
https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/TheRegistry/TheRegistry.html | ||
""" | ||
|
||
def __init__(self, client): | ||
""" | ||
:param rpcclient.darwin.client.DarwinClient client: | ||
""" | ||
self._client = client | ||
|
||
@property | ||
def backlight_control(self) -> BacklightControlService: | ||
service = self._client.symbols.IOServiceGetMatchingService( | ||
0, self._client.cf({'IOPropertyMatch': {'backlight-control': True}})) | ||
if not service: | ||
raise RpcClientException('IOServiceGetMatchingService failed') | ||
return BacklightControlService(self._client, service) | ||
|
||
@property | ||
def power_source(self) -> PowerSourceService: | ||
service = self._client.symbols.IOServiceGetMatchingService( | ||
0, self._client.symbols.IOServiceMatching('IOPMPowerSource')) | ||
if not service: | ||
raise RpcClientException('IOServiceGetMatchingService failed') | ||
return PowerSourceService(self._client, service) | ||
|
||
@property | ||
def root(self) -> IOService: | ||
with self._client.safe_malloc(mach_port_t.sizeof()) as p_master_port: | ||
self._client.symbols.IOMasterPort(MACH_PORT_NULL, p_master_port) | ||
return IOService(self._client, self._client.symbols.IORegistryGetRootEntry(p_master_port[0])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters