Skip to content

Commit

Permalink
WiimoteEmu: Add option to use system battery level
Browse files Browse the repository at this point in the history
Only supports Windows and Mac right now.
  • Loading branch information
blåhaj committed Aug 24, 2019
1 parent 3848f6d commit de783b2
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Source/Core/Core/CMakeLists.txt
Expand Up @@ -291,6 +291,8 @@ add_library(core
HW/WiimoteEmu/MotionPlus.h
HW/WiimoteEmu/Speaker.cpp
HW/WiimoteEmu/Speaker.h
HW/WiimoteEmu/SystemBattery.cpp
HW/WiimoteEmu/SystemBattery.h
HW/WiimoteEmu/WiimoteEmu.cpp
HW/WiimoteEmu/WiimoteEmu.h
HW/WiimoteEmu/Extension/Classic.cpp
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/Core.vcxproj
Expand Up @@ -190,6 +190,7 @@
<ClCompile Include="HW\WiimoteEmu\I2CBus.cpp" />
<ClCompile Include="HW\WiimoteEmu\MotionPlus.cpp" />
<ClCompile Include="HW\WiimoteEmu\Speaker.cpp" />
<ClCompile Include="HW\WiimoteEmu\SystemBattery.cpp" />
<ClCompile Include="HW\WiimoteEmu\WiimoteEmu.cpp" />
<ClCompile Include="HW\WiimoteReal\IOWin.cpp" />
<ClCompile Include="HW\WiimoteReal\WiimoteReal.cpp" />
Expand Down Expand Up @@ -465,6 +466,7 @@
<ClInclude Include="HW\WiimoteEmu\I2CBus.h" />
<ClInclude Include="HW\WiimoteEmu\MotionPlus.h" />
<ClInclude Include="HW\WiimoteEmu\Speaker.h" />
<ClInclude Include="HW\WiimoteEmu\SystemBattery.h" />
<ClInclude Include="HW\WiimoteEmu\WiimoteEmu.h" />
<ClInclude Include="HW\WiimoteReal\WiimoteReal.h" />
<ClInclude Include="HW\WiimoteReal\WiimoteRealBase.h" />
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Core/Core.vcxproj.filters
Expand Up @@ -526,6 +526,9 @@
<ClCompile Include="HW\WiimoteEmu\Encryption.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClCompile>
<ClCompile Include="HW\WiimoteEmu\SystemBattery.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClCompile>
<ClCompile Include="HW\WiimoteEmu\WiimoteEmu.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClCompile>
Expand Down Expand Up @@ -1238,6 +1241,9 @@
<ClInclude Include="HW\WiimoteEmu\Encryption.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClInclude>
<ClInclude Include="HW\WiimoteEmu\SystemBattery.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClInclude>
<ClInclude Include="HW\WiimoteEmu\WiimoteEmu.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClInclude>
Expand Down
27 changes: 25 additions & 2 deletions Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp
Expand Up @@ -16,6 +16,7 @@
#include "Core/Analytics.h"
#include "Core/Core.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
#include "Core/HW/WiimoteEmu/SystemBattery.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
Expand Down Expand Up @@ -240,13 +241,35 @@ void Wiimote::HandleRequestStatus(const OutputReportRequestStatus&)
// Max battery level seems to be 0xc8 (decimal 200)
constexpr u8 MAX_BATTERY_LEVEL = 0xc8;

m_status.battery = u8(std::lround(m_battery_setting.GetValue() / 100 * MAX_BATTERY_LEVEL));

std::optional<float> battery;
if (Core::WantsDeterminism())
{
// One less thing to break determinism:
m_status.battery = MAX_BATTERY_LEVEL;
}
else if (m_system_battery_setting.GetValue() && (battery = GetSystemBatteryLevel()))
{
// The HOME Menu and Metroid Prime 3 battery bars work like:
// 84+ => 4/4, 67+ => 3/4, 51+ => 2/4, 3+ 1/4, 2 or less => 0/4
// Something that fits those values is more useful than just multiplying
// by MAX_BATTERY_LEVEL (otherwise e.g. 50% battery status shows up as 4/4)
// The following math is not based on real battery behaviour, it just makes
// good-looking numbers..
constexpr float LOW = 0.3f;
if (*battery > LOW)
{
*battery = std::exp(*battery)/M_E;
}
else
{
*battery *= std::exp(LOW)/M_E / LOW;
}
m_status.battery = u8(std::lround(*battery * 100));
}
else
{
m_status.battery = u8(std::lround(m_battery_setting.GetValue() / 100 * MAX_BATTERY_LEVEL));
}

// Less than 0x20 triggers the low-battery flag:
m_status.battery_low = m_status.battery < 0x20;
Expand Down
109 changes: 109 additions & 0 deletions Source/Core/Core/HW/WiimoteEmu/SystemBattery.cpp
@@ -0,0 +1,109 @@
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "Core/HW/WiimoteEmu/SystemBattery.h"

#include "Common/ScopeGuard.h"

#if defined(_WIN32)
#include <Windows.h>
#elif defined(__APPLE__)
#include <CoreFoundation/CFDictionary.h>
#include <IOKit/ps/IOPSKeys.h>
#include <IOKit/ps/IOPowerSources.h>
#endif

namespace WiimoteEmu
{

#if defined(_WIN32)

std::optional<float> GetSystemBatteryLevel()
{
SYSTEM_POWER_STATUS power_status;
if (!GetSystemPowerStatus(&power_status))
{
return std::nullopt;
}

// Not on battery power, treat as 100%
if (power_status.ACLineStatus == 1)
{
return 1.0;
}

if (power_status.BatteryLifePercent != 255)
{
return power_status.BatteryLifePercent / 100.0f;
}

return std::nullopt;
}

#elif defined(__APPLE__)

std::optional<float> GetSystemBatteryLevel()
{
CFTypeRef power_blob = IOPSCopyPowerSourcesInfo();
if (!power_blob)
{
return std::nullopt;
}
Common::ScopeGuard power_blob_guard([power_blob] { CFRelease(power_blob); });

CFArrayRef power_sources = IOPSCopyPowerSourcesList(power_blob);
if (!power_sources)
{
return std::nullopt;
}
Common::ScopeGuard power_sources_guard([power_sources] { CFRelease(power_sources); });

CFStringRef current_power = IOPSGetProvidingPowerSourceType(power_blob);
// Not on battery power, treat as 100%
if (kCFCompareEqualTo != CFStringCompare(current_power, CFSTR(kIOPMBatteryPowerKey), 0))
{
return 1.0;
}

for (CFIndex i = 0; i < CFArrayGetCount(power_sources); i++)
{
CFTypeRef power_source = CFArrayGetValueAtIndex(power_sources, i);
CFDictionaryRef power_source_desc = IOPSGetPowerSourceDescription(power_blob, power_source);
if (!power_source_desc)
{
continue;
}

CFNumberRef capacity_current, capacity_max;
if (!CFDictionaryGetValueIfPresent(power_source_desc, CFSTR(kIOPSCurrentCapacityKey),
(const void**)&capacity_current) ||
!CFDictionaryGetValueIfPresent(power_source_desc, CFSTR(kIOPSMaxCapacityKey),
(const void**)&capacity_max))
{
continue;
}

float cur, max;
if (!CFNumberGetValue(capacity_current, kCFNumberFloat32Type, &cur) ||
!CFNumberGetValue(capacity_max, kCFNumberFloat32Type, &max))
{
continue;
}

return cur / max;
}

return std::nullopt;
}

#else

std::optional<float> GetSystemBatteryLevel()
{
return std::nullopt;
}

#endif

};
14 changes: 14 additions & 0 deletions Source/Core/Core/HW/WiimoteEmu/SystemBattery.h
@@ -0,0 +1,14 @@
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <optional>

namespace WiimoteEmu
{

std::optional<float> GetSystemBatteryLevel(void);

};
3 changes: 3 additions & 0 deletions Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp
Expand Up @@ -196,6 +196,9 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index)
_trans("%")},
95, 0, 100);

m_options->AddSetting(&m_system_battery_setting,
{_trans("Use system battery status if possible")}, true);

// Note: "Upright" and "Sideways" options can be enabled at the same time which produces an
// orientation where the wiimote points towards the left with the buttons towards you.
m_options->AddSetting(&m_upright_setting,
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h
Expand Up @@ -245,6 +245,7 @@ class Wiimote : public ControllerEmu::EmulatedController
ControllerEmu::SettingValue<bool> m_sideways_setting;
ControllerEmu::SettingValue<bool> m_upright_setting;
ControllerEmu::SettingValue<double> m_battery_setting;
ControllerEmu::SettingValue<bool> m_system_battery_setting;
ControllerEmu::SettingValue<double> m_speaker_pan_setting;
ControllerEmu::SettingValue<bool> m_motion_plus_setting;

Expand Down

0 comments on commit de783b2

Please sign in to comment.