Merge pull request #6222 from iwubcode/emulated_input_improvements

Emulated wii input improvements
This commit is contained in:
spycrab 2018-07-12 20:36:53 +02:00 committed by GitHub
commit cc6526f553
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 871 additions and 33 deletions

View File

@ -0,0 +1,26 @@
# RBKJ13, RBKK69, RBKP69, RBKE69 - Boom Blox
[Core]
# Values set here will override the main Dolphin settings.
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# Add any video settings here
[Wiimote.Shake]
Soft = 3.0
Medium = 4.0
Hard = 4.8
[Wiimote.Swing]
Slow = 3.5
Medium = 4.8
Fast = 6

View File

@ -0,0 +1,26 @@
# RYBP69, RYBE69 - Boom Blox Bash Party
[Core]
# Values set here will override the main Dolphin settings.
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Settings]
# Add any video settings here
[Wiimote.Shake]
Soft = 3.0
Medium = 4.0
Hard = 4.8
[Wiimote.Swing]
Slow = 3.5
Medium = 4.8
Fast = 6

View File

@ -30,6 +30,7 @@ add_library(core
Config/NetplaySettings.cpp
Config/SYSCONFSettings.cpp
Config/UISettings.cpp
Config/WiimoteInputSettings.cpp
ConfigLoaders/BaseConfigLoader.cpp
ConfigLoaders/GameConfigLoader.cpp
ConfigLoaders/IsSettingSaveable.cpp

View File

@ -0,0 +1,53 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/Config/WiimoteInputSettings.h"
namespace Config
{
// Configuration Information
// WiimoteInput.Settings
const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_FAST{{System::WiiPad, "Swing", "Fast"}, 4.5};
const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM{{System::WiiPad, "Swing", "Medium"},
2.5};
const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_SLOW{{System::WiiPad, "Swing", "Slow"}, 1.5};
const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_HARD{{System::WiiPad, "Shake", "Hard"}, 5.0};
const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM{{System::WiiPad, "Shake", "Medium"},
3.0};
const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT{{System::WiiPad, "Shake", "Soft"}, 2.0};
// Dynamic settings
const ConfigInfo<int> WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_FAST{
{System::WiiPad, "Dynamic_Swing", "FramesHeldFast"}, 100};
const ConfigInfo<int> WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_SLOW{
{System::WiiPad, "Dynamic_Swing", "FramesHeldSlow"}, 30};
const ConfigInfo<int> WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_LENGTH{
{System::WiiPad, "Dynamic_Swing", "FrameCount"}, 30};
const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD{
{System::WiiPad, "Dynamic_Shake", "FramesHeldHard"}, 45};
const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT{
{System::WiiPad, "Dynamic_Shake", "FramesHeldSoft"}, 15};
const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH{
{System::WiiPad, "Dynamic_Shake", "FrameCount"}, 30};
// NunchuckInput.Settings
const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_FAST{
{System::WiiPad, "Nunchuk_Swing", "Fast"}, 4.5};
const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_MEDIUM{
{System::WiiPad, "Nunchuk_Swing", "Medium"}, 2.5};
const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_SLOW{
{System::WiiPad, "Nunchuk_Swing", "Slow"}, 1.5};
const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_HARD{
{System::WiiPad, "Nunchuk_Shake", "Hard"}, 5.0};
const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM{
{System::WiiPad, "Nunchuk_Shake", "Medium"}, 3.0};
const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT{
{System::WiiPad, "Nunchuk_Shake", "Soft"}, 2.0};
}

View File

@ -0,0 +1,49 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/Config/Config.h"
namespace Config
{
// Configuration Information
// WiimoteInput.Settings
extern const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_FAST;
extern const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM;
extern const ConfigInfo<double> WIIMOTE_INPUT_SWING_INTENSITY_SLOW;
extern const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_HARD;
extern const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM;
extern const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT;
// Below settings are for dynamic input only (based on how long the user holds a button)
extern const ConfigInfo<int>
WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_FAST; // How long button held constitutes a fast swing
extern const ConfigInfo<int>
WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_SLOW; // How long button held constitutes a slow swing
extern const ConfigInfo<int>
WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_LENGTH; // How long to execute the swing
extern const ConfigInfo<int>
WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD; // How long button held constitutes a hard shake
extern const ConfigInfo<int>
WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT; // How long button held constitutes a soft shake
extern const ConfigInfo<int>
WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH; // How long to execute a shake
// NunchuckInput.Settings
extern const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_FAST;
extern const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_MEDIUM;
extern const ConfigInfo<double> NUNCHUK_INPUT_SWING_INTENSITY_SLOW;
extern const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_HARD;
extern const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM;
extern const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT;
} // namespace Config

View File

@ -56,6 +56,7 @@
<ClCompile Include="ConfigLoaders\MovieConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\NetPlayConfigLoader.cpp" />
<ClCompile Include="ConfigManager.cpp" />
<ClCompile Include="Config\WiimoteInputSettings.cpp" />
<ClCompile Include="Core.cpp" />
<ClCompile Include="CoreTiming.cpp" />
<ClCompile Include="Debugger\Debugger_SymbolMap.cpp" />
@ -321,6 +322,7 @@
<ClInclude Include="ConfigLoaders\NetPlayConfigLoader.h" />
<ClInclude Include="ConfigManager.h" />
<ClInclude Include="Config\UISettings.h" />
<ClInclude Include="Config\WiimoteInputSettings.h" />
<ClInclude Include="Core.h" />
<ClInclude Include="CoreTiming.h" />
<ClInclude Include="Debugger\Debugger_SymbolMap.h" />
@ -600,4 +602,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -910,6 +910,9 @@
<ClCompile Include="Config\UISettings.cpp">
<Filter>Config</Filter>
</ClCompile>
<ClCompile Include="Config\WiimoteInputSettings.cpp">
<Filter>Config</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BootManager.h" />
@ -1604,6 +1607,9 @@
<ClInclude Include="Config\UISettings.h">
<Filter>Config</Filter>
</ClInclude>
<ClInclude Include="Config\WiimoteInputSettings.h">
<Filter>Config</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View File

@ -11,6 +11,7 @@
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "Core/Config/WiimoteInputSettings.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "InputCommon/ControllerEmu/Control/Input.h"
@ -42,6 +43,8 @@ Nunchuk::Nunchuk(ExtensionReg& reg) : Attachment(_trans("Nunchuk"), reg)
// swing
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
groups.emplace_back(m_swing_slow = new ControllerEmu::Force("SwingSlow"));
groups.emplace_back(m_swing_fast = new ControllerEmu::Force("SwingFast"));
// tilt
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
@ -55,6 +58,16 @@ Nunchuk::Nunchuk(ExtensionReg& reg) : Attachment(_trans("Nunchuk"), reg)
// i18n: Refers to a 3D axis (used when mapping motion controls)
m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Z")));
groups.emplace_back(m_shake_soft = new ControllerEmu::Buttons("ShakeSoft"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
groups.emplace_back(m_shake_hard = new ControllerEmu::Buttons("ShakeHard"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
m_id = nunchuk_id;
}
@ -91,9 +104,18 @@ void Nunchuk::GetState(u8* const data)
EmulateTilt(&accel, m_tilt);
// swing
EmulateSwing(&accel, m_swing);
EmulateSwing(&accel, m_swing, Config::Get(Config::NUNCHUK_INPUT_SWING_INTENSITY_MEDIUM));
EmulateSwing(&accel, m_swing_slow, Config::Get(Config::NUNCHUK_INPUT_SWING_INTENSITY_SLOW));
EmulateSwing(&accel, m_swing_fast, Config::Get(Config::NUNCHUK_INPUT_SWING_INTENSITY_FAST));
// shake
EmulateShake(&accel, m_shake, m_shake_step.data());
EmulateShake(&accel, m_shake, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM),
m_shake_step.data());
EmulateShake(&accel, m_shake_soft, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT),
m_shake_soft_step.data());
EmulateShake(&accel, m_shake_hard, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_HARD),
m_shake_hard_step.data());
// buttons
m_buttons->GetState(&nc_data.bt.hex, nunchuk_button_bitmasks.data());

View File

@ -55,12 +55,18 @@ public:
private:
ControllerEmu::Tilt* m_tilt;
ControllerEmu::Force* m_swing;
ControllerEmu::Force* m_swing_slow;
ControllerEmu::Force* m_swing_fast;
ControllerEmu::Buttons* m_shake;
ControllerEmu::Buttons* m_shake_soft;
ControllerEmu::Buttons* m_shake_hard;
ControllerEmu::Buttons* m_buttons;
ControllerEmu::AnalogStick* m_stick;
std::array<u8, 3> m_shake_step{};
std::array<u8, 3> m_shake_soft_step{};
std::array<u8, 3> m_shake_hard_step{};
};
}

View File

@ -17,6 +17,7 @@
#include "Common/MsgHandler.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/Config/WiimoteInputSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Wiimote.h"
@ -99,15 +100,12 @@ static const ReportFeatures reporting_mode_features[] = {
};
void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group,
u8* const shake_step)
const double intensity, u8* const shake_step)
{
// frame count of one up/down shake
// < 9 no shake detection in "Wario Land: Shake It"
auto const shake_step_max = 15;
// peak G-force
auto const shake_intensity = 3.0;
// shake is a bitfield of X,Y,Z shake button states
static const unsigned int btns[] = {0x01, 0x02, 0x04};
unsigned int shake = 0;
@ -117,7 +115,7 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_
{
if (shake & (1 << i))
{
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity;
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * intensity;
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
}
else
@ -125,6 +123,55 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_
}
}
void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data,
ControllerEmu::Buttons* const buttons_group,
const DynamicConfiguration& config, u8* const shake_step)
{
// frame count of one up/down shake
// < 9 no shake detection in "Wario Land: Shake It"
auto const shake_step_max = 15;
// shake is a bitfield of X,Y,Z shake button states
static const unsigned int btns[] = {0x01, 0x02, 0x04};
unsigned int shake = 0;
buttons_group->GetState(&shake, btns);
for (int i = 0; i != 3; ++i)
{
if ((shake & (1 << i)) && dynamic_data.executing_frames_left[i] == 0)
{
dynamic_data.timing[i]++;
}
else if (dynamic_data.executing_frames_left[i] > 0)
{
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * dynamic_data.intensity[i];
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
dynamic_data.executing_frames_left[i]--;
}
else if (shake == 0 && dynamic_data.timing[i] > 0)
{
if (dynamic_data.timing[i] > config.frames_needed_for_high_intensity)
{
dynamic_data.intensity[i] = config.high_intensity;
}
else if (dynamic_data.timing[i] < config.frames_needed_for_low_intensity)
{
dynamic_data.intensity[i] = config.low_intensity;
}
else
{
dynamic_data.intensity[i] = config.med_intensity;
}
dynamic_data.timing[i] = 0;
dynamic_data.executing_frames_left[i] = config.frames_to_execute;
}
else
{
shake_step[i] = 0;
}
}
}
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group, const bool sideways,
const bool upright)
{
@ -160,10 +207,8 @@ void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group,
(&accel->x)[fb] = sin(pitch) * sgn[fb];
}
#define SWING_INTENSITY 2.5 //-uncalibrated(aprox) 0x40-calibrated
void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const swing_group,
const bool sideways, const bool upright)
const double intensity, const bool sideways, const bool upright)
{
ControlState swing[3];
swing_group->GetState(swing);
@ -184,7 +229,61 @@ void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const swing_grou
g_dir[axis_map[0]] *= -1;
for (unsigned int i = 0; i < 3; ++i)
(&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * SWING_INTENSITY;
(&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * intensity;
}
void EmulateDynamicSwing(AccelData* const accel, DynamicData& dynamic_data,
ControllerEmu::Force* const swing_group,
const DynamicConfiguration& config, const bool sideways,
const bool upright)
{
ControlState swing[3];
swing_group->GetState(swing);
s8 g_dir[3] = {-1, -1, -1};
u8 axis_map[3];
// determine which axis is which direction
axis_map[0] = upright ? (sideways ? 0 : 1) : 2; // up/down
axis_map[1] = sideways; // left|right
axis_map[2] = upright ? 2 : (sideways ? 0 : 1); // forward/backward
// some orientations have up as positive, some as negative
// same with forward
if (sideways && !upright)
g_dir[axis_map[2]] *= -1;
if (!sideways && upright)
g_dir[axis_map[0]] *= -1;
for (unsigned int i = 0; i < 3; ++i)
{
if (swing[i] > 0 && dynamic_data.executing_frames_left[i] == 0)
{
dynamic_data.timing[i]++;
}
else if (dynamic_data.executing_frames_left[i] > 0)
{
(&accel->x)[axis_map[i]] += g_dir[i] * dynamic_data.intensity[i];
dynamic_data.executing_frames_left[i]--;
}
else if (swing[i] == 0 && dynamic_data.timing[i] > 0)
{
if (dynamic_data.timing[i] > config.frames_needed_for_high_intensity)
{
dynamic_data.intensity[i] = config.high_intensity;
}
else if (dynamic_data.timing[i] < config.frames_needed_for_low_intensity)
{
dynamic_data.intensity[i] = config.low_intensity;
}
else
{
dynamic_data.intensity[i] = config.med_intensity;
}
dynamic_data.timing[i] = 0;
dynamic_data.executing_frames_left[i] = config.frames_to_execute;
}
}
}
static const u16 button_bitmasks[] = {
@ -238,7 +337,11 @@ void Wiimote::Reset()
// 0x55 - 0xff: level 4
m_status.battery = (u8)(m_battery_setting->GetValue() * 100);
memset(m_shake_step, 0, sizeof(m_shake_step));
m_shake_step = {};
m_shake_soft_step = {};
m_shake_hard_step = {};
m_swing_dynamic_data = {};
m_shake_dynamic_data = {};
// clear read request queue
while (!m_read_requests.empty())
@ -271,6 +374,9 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1
// swing
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
groups.emplace_back(m_swing_slow = new ControllerEmu::Force("SwingSlow"));
groups.emplace_back(m_swing_fast = new ControllerEmu::Force("SwingFast"));
groups.emplace_back(m_swing_dynamic = new ControllerEmu::Force("Swing Dynamic"));
// tilt
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
@ -284,6 +390,24 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1
// i18n: Refers to a 3D axis (used when mapping motion controls)
m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Z")));
groups.emplace_back(m_shake_soft = new ControllerEmu::Buttons("ShakeSoft"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
groups.emplace_back(m_shake_hard = new ControllerEmu::Buttons("ShakeHard"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
groups.emplace_back(m_shake_dynamic = new ControllerEmu::Buttons("Shake Dynamic"));
m_shake_dynamic->controls.emplace_back(
new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X"));
m_shake_dynamic->controls.emplace_back(
new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y"));
m_shake_dynamic->controls.emplace_back(
new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z"));
// extension
groups.emplace_back(m_extension = new ControllerEmu::Extension(_trans("Extension")));
m_extension->attachments.emplace_back(new WiimoteEmu::None(m_reg_ext));
@ -484,8 +608,44 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf)
m_upright_setting->GetValue() ^ upright_modifier_toggle ^ upright_modifier_switch;
EmulateTilt(&m_accel, m_tilt, is_sideways, is_upright);
EmulateSwing(&m_accel, m_swing, is_sideways, is_upright);
EmulateShake(&m_accel, m_shake, m_shake_step);
DynamicConfiguration swing_config;
swing_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW);
swing_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM);
swing_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST);
swing_config.frames_needed_for_high_intensity =
Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_FAST);
swing_config.frames_needed_for_low_intensity =
Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_HELD_SLOW);
swing_config.frames_to_execute = Config::Get(Config::WIIMOTE_INPUT_SWING_DYNAMIC_FRAMES_LENGTH);
EmulateSwing(&m_accel, m_swing, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_MEDIUM),
is_sideways, is_upright);
EmulateSwing(&m_accel, m_swing_slow, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_SLOW),
is_sideways, is_upright);
EmulateSwing(&m_accel, m_swing_fast, Config::Get(Config::WIIMOTE_INPUT_SWING_INTENSITY_FAST),
is_sideways, is_upright);
EmulateDynamicSwing(&m_accel, m_swing_dynamic_data, m_swing_dynamic, swing_config, is_sideways,
is_upright);
DynamicConfiguration shake_config;
shake_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT);
shake_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM);
shake_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD);
shake_config.frames_needed_for_high_intensity =
Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD);
shake_config.frames_needed_for_low_intensity =
Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT);
shake_config.frames_to_execute = Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH);
EmulateShake(&m_accel, m_shake, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM),
m_shake_step.data());
EmulateShake(&m_accel, m_shake_soft, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT),
m_shake_soft_step.data());
EmulateShake(&m_accel, m_shake_hard, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD),
m_shake_hard_step.data());
EmulateDynamicShake(&m_accel, m_shake_dynamic_data, m_shake_dynamic, shake_config,
m_shake_dynamic_step.data());
wm_accel& accel = *reinterpret_cast<wm_accel*>(data + rptf.accel);
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core);
@ -562,8 +722,8 @@ void Wiimote::GetIRData(u8* const data, bool use_accel)
static const int camHeight = 768;
static const double bndup = -0.315447;
static const double bnddown = 0.85;
static const double bndleft = 0.443364;
static const double bndright = -0.443364;
static const double bndleft = 0.78820266;
static const double bndright = -0.78820266;
static const double dist1 = 100.0 / camWidth; // this seems the optimal distance for zelda
static const double dist2 = 1.2 * dist1;

View File

@ -4,6 +4,7 @@
#pragma once
#include <array>
#include <queue>
#include <string>
@ -123,6 +124,33 @@ struct AccelData
double x, y, z;
};
// Used for a dynamic swing or
// shake
struct DynamicData
{
std::array<int, 3> timing; // Hold length in frames for each axis
std::array<double, 3> intensity; // Swing or shake intensity
std::array<int, 3> executing_frames_left; // Number of frames to execute the intensity operation
};
// Used for a dynamic swing or
// shake. This is used to pass
// in data that defines the dynamic
// action
struct DynamicConfiguration
{
double low_intensity;
int frames_needed_for_low_intensity;
double med_intensity;
// Frames needed for med intensity can be calculated between high & low
double high_intensity;
int frames_needed_for_high_intensity;
int frames_to_execute; // How many frames should we execute the action for?
};
struct ADPCMState
{
s32 predictor, step;
@ -154,13 +182,22 @@ struct ExtensionReg
#pragma pack(pop)
void EmulateShake(AccelData* const accel_data, ControllerEmu::Buttons* const buttons_group,
u8* const shake_step);
const double intensity, u8* const shake_step);
void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data,
ControllerEmu::Buttons* const buttons_group,
const DynamicConfiguration& config, u8* const shake_step);
void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group,
const bool sideways = false, const bool upright = false);
void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const tilt_group,
const bool sideways = false, const bool upright = false);
const double intensity, const bool sideways = false, const bool upright = false);
void EmulateDynamicSwing(AccelData* const accel, DynamicData& dynamic_data,
ControllerEmu::Force* const swing_group,
const DynamicConfiguration& config, const bool sideways = false,
const bool upright = false);
enum
{
@ -247,9 +284,15 @@ private:
ControllerEmu::Buttons* m_buttons;
ControllerEmu::Buttons* m_dpad;
ControllerEmu::Buttons* m_shake;
ControllerEmu::Buttons* m_shake_soft;
ControllerEmu::Buttons* m_shake_hard;
ControllerEmu::Buttons* m_shake_dynamic;
ControllerEmu::Cursor* m_ir;
ControllerEmu::Tilt* m_tilt;
ControllerEmu::Force* m_swing;
ControllerEmu::Force* m_swing_slow;
ControllerEmu::Force* m_swing_fast;
ControllerEmu::Force* m_swing_dynamic;
ControllerEmu::ControlGroup* m_rumble;
ControllerEmu::Output* m_motor;
ControllerEmu::Extension* m_extension;
@ -259,6 +302,9 @@ private:
ControllerEmu::NumericSetting* m_battery_setting;
ControllerEmu::ModifySettingsButton* m_hotkeys;
DynamicData m_swing_dynamic_data;
DynamicData m_shake_dynamic_data;
// Wiimote accel data
AccelData m_accel;
@ -274,7 +320,10 @@ private:
u8 m_reporting_mode;
u16 m_reporting_channel;
u8 m_shake_step[3];
std::array<u8, 3> m_shake_step{};
std::array<u8, 3> m_shake_soft_step{};
std::array<u8, 3> m_shake_hard_step{};
std::array<u8, 3> m_shake_dynamic_step{};
bool m_sensor_bar_on_top;

View File

@ -20,7 +20,7 @@
#include "InputCommon/GCPadStatus.h"
// clang-format off
constexpr std::array<const char*, 114> s_hotkey_labels{{
constexpr std::array<const char*, 130> s_hotkey_labels{{
_trans("Open"),
_trans("Change Disc"),
_trans("Eject Disc"),
@ -69,6 +69,23 @@ constexpr std::array<const char*, 114> s_hotkey_labels{{
_trans("Connect Wii Remote 4"),
_trans("Connect Balance Board"),
_trans("Next Profile for Wii Remote 1"),
_trans("Previous Profile for Wii Remote 1"),
_trans("Next Game Profile for Wii Remote 1"),
_trans("Previous Game Profile for Wii Remote 1"),
_trans("Next Profile for Wii Remote 2"),
_trans("Previous Profile for Wii Remote 2"),
_trans("Next Game Profile for Wii Remote 2"),
_trans("Previous Game Profile for Wii Remote 2"),
_trans("Next Profile for Wii Remote 3"),
_trans("Previous Profile for Wii Remote 3"),
_trans("Next Game Profile for Wii Remote 3"),
_trans("Previous Game Profile for Wii Remote 3"),
_trans("Next Profile for Wii Remote 4"),
_trans("Previous Profile for Wii Remote 4"),
_trans("Next Game Profile for Wii Remote 4"),
_trans("Previous Game Profile for Wii Remote 4"),
_trans("Toggle Crop"),
_trans("Toggle Aspect Ratio"),
_trans("Toggle EFB Copies"),
@ -255,6 +272,7 @@ constexpr std::array<HotkeyGroupInfo, NUM_HOTKEY_GROUPS> s_groups_info = {
{_trans("Program Counter"), HK_SHOW_PC, HK_SET_PC},
{_trans("Breakpoint"), HK_BP_TOGGLE, HK_MBP_ADD},
{_trans("Wii"), HK_TRIGGER_SYNC_BUTTON, HK_BALANCEBOARD_CONNECT},
{_trans("Controller Profile"), HK_NEXT_WIIMOTE_PROFILE_1, HK_PREV_GAME_WIIMOTE_PROFILE_4},
{_trans("Graphics Toggles"), HK_TOGGLE_CROP, HK_TOGGLE_TEXTURES},
{_trans("Internal Resolution"), HK_INCREASE_IR, HK_DECREASE_IR},
{_trans("Freelook"), HK_FREELOOK_DECREASE_SPEED, HK_FREELOOK_RESET},

View File

@ -67,6 +67,23 @@ enum Hotkey
HK_WIIMOTE4_CONNECT,
HK_BALANCEBOARD_CONNECT,
HK_NEXT_WIIMOTE_PROFILE_1,
HK_PREV_WIIMOTE_PROFILE_1,
HK_NEXT_GAME_WIIMOTE_PROFILE_1,
HK_PREV_GAME_WIIMOTE_PROFILE_1,
HK_NEXT_WIIMOTE_PROFILE_2,
HK_PREV_WIIMOTE_PROFILE_2,
HK_NEXT_GAME_WIIMOTE_PROFILE_2,
HK_PREV_GAME_WIIMOTE_PROFILE_2,
HK_NEXT_WIIMOTE_PROFILE_3,
HK_PREV_WIIMOTE_PROFILE_3,
HK_NEXT_GAME_WIIMOTE_PROFILE_3,
HK_PREV_GAME_WIIMOTE_PROFILE_3,
HK_NEXT_WIIMOTE_PROFILE_4,
HK_PREV_WIIMOTE_PROFILE_4,
HK_NEXT_GAME_WIIMOTE_PROFILE_4,
HK_PREV_GAME_WIIMOTE_PROFILE_4,
HK_TOGGLE_CROP,
HK_TOGGLE_AR,
HK_TOGGLE_EFBCOPIES,
@ -166,6 +183,7 @@ enum HotkeyGroup : int
HKGP_PC,
HKGP_BREAKPOINT,
HKGP_WII,
HKGP_CONTROLLER_PROFILE,
HKGP_GRAPHICS_TOGGLES,
HKGP_IR,
HKGP_FREELOOK,

View File

@ -50,6 +50,7 @@ add_executable(dolphin-emu
Config/Mapping/GCPadEmu.cpp
Config/Mapping/GCPadWiiUConfigDialog.cpp
Config/Mapping/Hotkey3D.cpp
Config/Mapping/HotkeyControllerProfile.cpp
Config/Mapping/HotkeyDebugging.cpp
Config/Mapping/HotkeyGeneral.cpp
Config/Mapping/HotkeyGraphics.cpp

View File

@ -0,0 +1,40 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt/Config/Mapping/HotkeyControllerProfile.h"
#include <QGroupBox>
#include <QHBoxLayout>
#include "Core/HotkeyManager.h"
HotkeyControllerProfile::HotkeyControllerProfile(MappingWindow* window) : MappingWidget(window)
{
CreateMainLayout();
}
void HotkeyControllerProfile::CreateMainLayout()
{
m_main_layout = new QHBoxLayout();
m_main_layout->addWidget(CreateGroupBox(
tr("Controller Profile"), HotkeyManagerEmu::GetHotkeyGroup(HKGP_CONTROLLER_PROFILE)));
setLayout(m_main_layout);
}
InputConfig* HotkeyControllerProfile::GetConfig()
{
return HotkeyManagerEmu::GetConfig();
}
void HotkeyControllerProfile::LoadSettings()
{
HotkeyManagerEmu::LoadConfig();
}
void HotkeyControllerProfile::SaveSettings()
{
HotkeyManagerEmu::GetConfig()->SaveConfig();
}

View File

@ -0,0 +1,26 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "DolphinQt/Config/Mapping/MappingWidget.h"
class QHBoxLayout;
class HotkeyControllerProfile final : public MappingWidget
{
Q_OBJECT
public:
explicit HotkeyControllerProfile(MappingWindow* window);
InputConfig* GetConfig() override;
private:
void LoadSettings() override;
void SaveSettings() override;
void CreateMainLayout();
// Main
QHBoxLayout* m_main_layout;
};

View File

@ -25,6 +25,7 @@
#include "DolphinQt/Config/Mapping/GCMicrophone.h"
#include "DolphinQt/Config/Mapping/GCPadEmu.h"
#include "DolphinQt/Config/Mapping/Hotkey3D.h"
#include "DolphinQt/Config/Mapping/HotkeyControllerProfile.h"
#include "DolphinQt/Config/Mapping/HotkeyDebugging.h"
#include "DolphinQt/Config/Mapping/HotkeyGeneral.h"
#include "DolphinQt/Config/Mapping/HotkeyGraphics.h"
@ -316,6 +317,7 @@ void MappingWindow::SetMappingType(MappingWindow::Type type)
AddWidget(tr("Debugging"), new HotkeyDebugging(this));
AddWidget(tr("Wii and Wii Remote"), new HotkeyWii(this));
AddWidget(tr("Controller Profile"), new HotkeyControllerProfile(this));
AddWidget(tr("Graphics"), new HotkeyGraphics(this));
AddWidget(tr("3D"), new Hotkey3D(this));
AddWidget(tr("Save and Load State"), new HotkeyStates(this));

View File

@ -70,6 +70,7 @@
<QtMoc Include="Config\Mapping\GCPadEmu.h" />
<QtMoc Include="Config\Mapping\GCPadWiiUConfigDialog.h" />
<QtMoc Include="Config\Mapping\Hotkey3D.h" />
<QtMoc Include="Config\Mapping\HotkeyControllerProfile.h" />
<QtMoc Include="Config\Mapping\HotkeyDebugging.h" />
<QtMoc Include="Config\Mapping\HotkeyGeneral.h" />
<QtMoc Include="Config\Mapping\HotkeyGraphics.h" />
@ -204,6 +205,7 @@
<ClCompile Include="$(QtMocOutPrefix)HacksWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)Host.cpp" />
<ClCompile Include="$(QtMocOutPrefix)Hotkey3D.cpp" />
<ClCompile Include="$(QtMocOutPrefix)HotkeyControllerProfile.cpp" />
<ClCompile Include="$(QtMocOutPrefix)HotkeyDebugging.cpp" />
<ClCompile Include="$(QtMocOutPrefix)HotkeyGeneral.cpp" />
<ClCompile Include="$(QtMocOutPrefix)HotkeyGraphics.cpp" />
@ -285,6 +287,7 @@
<ClCompile Include="Config\Mapping\GCPadEmu.cpp" />
<ClCompile Include="Config\Mapping\GCPadWiiUConfigDialog.cpp" />
<ClCompile Include="Config\Mapping\Hotkey3D.cpp" />
<ClCompile Include="Config\Mapping\HotkeyControllerProfile.cpp" />
<ClCompile Include="Config\Mapping\HotkeyDebugging.cpp" />
<ClCompile Include="Config\Mapping\HotkeyGeneral.cpp" />
<ClCompile Include="Config\Mapping\HotkeyGraphics.cpp" />

View File

@ -240,6 +240,46 @@ void HotkeyScheduler::Run()
emit ConnectWiiRemote(wiimote_id);
}
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_1))
m_profile_cycler.PreviousWiimoteProfile(0);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_1))
m_profile_cycler.NextWiimoteProfile(0);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_2))
m_profile_cycler.PreviousWiimoteProfile(1);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_2))
m_profile_cycler.NextWiimoteProfile(1);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_3))
m_profile_cycler.PreviousWiimoteProfile(2);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_3))
m_profile_cycler.NextWiimoteProfile(2);
if (IsHotkey(HK_PREV_WIIMOTE_PROFILE_4))
m_profile_cycler.PreviousWiimoteProfile(3);
else if (IsHotkey(HK_NEXT_WIIMOTE_PROFILE_4))
m_profile_cycler.NextWiimoteProfile(3);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_1))
m_profile_cycler.PreviousWiimoteProfileForGame(0);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_1))
m_profile_cycler.NextWiimoteProfileForGame(0);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_2))
m_profile_cycler.PreviousWiimoteProfileForGame(1);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_2))
m_profile_cycler.NextWiimoteProfileForGame(1);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_3))
m_profile_cycler.PreviousWiimoteProfileForGame(2);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_3))
m_profile_cycler.NextWiimoteProfileForGame(2);
if (IsHotkey(HK_PREV_GAME_WIIMOTE_PROFILE_4))
m_profile_cycler.PreviousWiimoteProfileForGame(3);
else if (IsHotkey(HK_NEXT_GAME_WIIMOTE_PROFILE_4))
m_profile_cycler.NextWiimoteProfileForGame(3);
const auto show_msg = [](OSDMessage message) {
if (g_renderer)
g_renderer->ShowOSDMessage(message);

View File

@ -9,6 +9,7 @@
#include <QObject>
#include "Common/Flag.h"
#include "InputCommon/InputProfile.h"
class HotkeyScheduler : public QObject
{
@ -64,4 +65,6 @@ private:
Common::Flag m_stop_requested;
std::thread m_thread;
InputProfile::ProfileCycler m_profile_cycler;
};

View File

@ -1,5 +1,6 @@
add_library(inputcommon
InputConfig.cpp
InputProfile.cpp
ControllerEmu/ControllerEmu.cpp
ControllerEmu/Control/Control.cpp
ControllerEmu/Control/Input.cpp

View File

@ -40,10 +40,7 @@ void Force::GetState(ControlState* axis)
controls[i + 1]->control_ref->State() - controls[i]->control_ref->State();
if (fabs(state) > deadzone)
tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone));
ControlState& ax = m_swing[i >> 1];
*axis++ = (tmpf - ax);
ax = tmpf;
*axis++ = tmpf;
}
}
} // namespace ControllerEmu

View File

@ -71,6 +71,7 @@
<DisableSpecificWarnings>4200;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ClCompile Include="InputConfig.cpp" />
<ClCompile Include="InputProfile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ControllerEmu\ControllerEmu.h" />
@ -105,6 +106,7 @@
<ClInclude Include="GCAdapter.h" />
<ClInclude Include="GCPadStatus.h" />
<ClInclude Include="InputConfig.h" />
<ClInclude Include="InputProfile.h" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View File

@ -110,6 +110,7 @@
<ClCompile Include="ControlReference\ControlReference.cpp">
<Filter>ControllerInterface</Filter>
</ClCompile>
<ClCompile Include="InputProfile.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="GCAdapter.h" />
@ -202,6 +203,7 @@
<ClInclude Include="ControlReference\ControlReference.h">
<Filter>ControllerInterface</Filter>
</ClInclude>
<ClInclude Include="InputProfile.h" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View File

@ -7,12 +7,15 @@
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Wiimote.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/InputConfig.h"
#include "InputCommon/InputProfile.h"
InputConfig::InputConfig(const std::string& ini_name, const std::string& gui_name,
const std::string& profile_name)
@ -51,17 +54,24 @@ bool InputConfig::LoadConfig(bool isGC)
{
if (control_section->Exists(type + "Profile" + num[i]))
{
if (control_section->Get(type + "Profile" + num[i], &profile[i]))
std::string profile_setting;
if (control_section->Get(type + "Profile" + num[i], &profile_setting))
{
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile[i] + ".ini"))
{
useProfile[i] = true;
}
else
auto profiles = InputProfile::GetProfilesFromSetting(
profile_setting, File::GetUserPath(D_CONFIG_IDX) + path);
if (profiles.empty())
{
const std::string error =
"No profiles found for game setting '" + profile_setting + "'";
// TODO: PanicAlert shouldn't be used for this.
PanicAlertT("Selected controller profile does not exist");
PanicAlertT("%s", error.c_str());
continue;
}
// Use the first profile by default
profile[i] = profiles[0];
useProfile[i] = true;
}
}
}
@ -75,8 +85,14 @@ bool InputConfig::LoadConfig(bool isGC)
// Load settings from ini
if (useProfile[n])
{
std::string base;
SplitPath(profile[n], nullptr, &base, nullptr);
Core::DisplayMessage("Loading game specific input profile '" + base + "' for device '" +
controller->GetName() + "'",
6000);
IniFile profile_ini;
profile_ini.Load(File::GetUserPath(D_CONFIG_IDX) + path + profile[n] + ".ini");
profile_ini.Load(profile[n]);
controller->LoadConfig(profile_ini.GetOrCreateSection("Profile"));
}
else
@ -128,6 +144,11 @@ bool InputConfig::ControllersNeedToBeCreated() const
return m_controllers.empty();
}
std::size_t InputConfig::GetControllerCount() const
{
return m_controllers.size();
}
bool InputConfig::IsControllerControlledByGamepadDevice(int index) const
{
if (static_cast<size_t>(index) >= m_controllers.size())

View File

@ -38,6 +38,7 @@ public:
std::string GetGUIName() const { return m_gui_name; }
std::string GetProfileName() const { return m_profile_name; }
std::size_t GetControllerCount() const;
private:
std::vector<std::unique_ptr<ControllerEmu::EmulatedController>> m_controllers;

View File

@ -0,0 +1,210 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Common/FileSearch.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Wiimote.h"
#include "Core/HotkeyManager.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/InputConfig.h"
#include "InputCommon/InputProfile.h"
#include <algorithm>
#include <iterator>
namespace InputProfile
{
namespace
{
constexpr int display_message_ms = 3000;
}
std::vector<std::string> GetProfilesFromSetting(const std::string& setting, const std::string& root)
{
const auto& setting_choices = SplitString(setting, ',');
std::vector<std::string> result;
for (const std::string& setting_choice : setting_choices)
{
const std::string path = root + StripSpaces(setting_choice);
if (File::IsDirectory(path))
{
const auto files_under_directory = Common::DoFileSearch({path}, {".ini"}, true);
result.insert(result.end(), files_under_directory.begin(), files_under_directory.end());
}
else
{
const std::string file_path = path + ".ini";
if (File::Exists(file_path))
{
result.push_back(file_path);
}
}
}
return result;
}
std::vector<std::string> ProfileCycler::GetProfilesForDevice(InputConfig* device_configuration)
{
const std::string device_profile_root_location(File::GetUserPath(D_CONFIG_IDX) + "Profiles/" +
device_configuration->GetProfileName());
return Common::DoFileSearch({device_profile_root_location}, {".ini"}, true);
}
std::string ProfileCycler::GetProfile(CycleDirection cycle_direction, int& profile_index,
const std::vector<std::string>& profiles)
{
// update the index and bind it to the number of available strings
auto positive_modulo = [](int& i, int n) { i = (i % n + n) % n; };
profile_index += static_cast<int>(cycle_direction);
positive_modulo(profile_index, static_cast<int>(profiles.size()));
return profiles[profile_index];
}
void ProfileCycler::UpdateToProfile(const std::string& profile_filename,
ControllerEmu::EmulatedController* controller)
{
std::string base;
SplitPath(profile_filename, nullptr, &base, nullptr);
IniFile ini_file;
if (ini_file.Load(profile_filename))
{
Core::DisplayMessage("Loading input profile '" + base + "' for device '" +
controller->GetName() + "'",
display_message_ms);
controller->LoadConfig(ini_file.GetOrCreateSection("Profile"));
controller->UpdateReferences(g_controller_interface);
}
else
{
Core::DisplayMessage("Unable to load input profile '" + base + "' for device '" +
controller->GetName() + "'",
display_message_ms);
}
}
std::vector<std::string>
ProfileCycler::GetMatchingProfilesFromSetting(const std::string& setting,
const std::vector<std::string>& profiles,
InputConfig* device_configuration)
{
const std::string device_profile_root_location(File::GetUserPath(D_CONFIG_IDX) + "Profiles/" +
device_configuration->GetProfileName() + "/");
const auto& profiles_from_setting = GetProfilesFromSetting(setting, device_profile_root_location);
if (profiles_from_setting.empty())
{
return {};
}
std::vector<std::string> result;
std::set_intersection(profiles.begin(), profiles.end(), profiles_from_setting.begin(),
profiles_from_setting.end(), std::back_inserter(result));
return result;
}
void ProfileCycler::CycleProfile(CycleDirection cycle_direction, InputConfig* device_configuration,
int& profile_index, int controller_index)
{
const auto& profiles = GetProfilesForDevice(device_configuration);
if (profiles.empty())
{
Core::DisplayMessage("No input profiles found", display_message_ms);
return;
}
const std::string profile = GetProfile(cycle_direction, profile_index, profiles);
auto* controller = device_configuration->GetController(controller_index);
if (controller)
{
UpdateToProfile(profile, controller);
}
else
{
Core::DisplayMessage("No controller found for index: " + std::to_string(controller_index),
display_message_ms);
}
}
void ProfileCycler::CycleProfileForGame(CycleDirection cycle_direction,
InputConfig* device_configuration, int& profile_index,
const std::string& setting, int controller_index)
{
const auto& profiles = GetProfilesForDevice(device_configuration);
if (profiles.empty())
{
Core::DisplayMessage("No input profiles found", display_message_ms);
return;
}
if (setting.empty())
{
Core::DisplayMessage("No setting found for game", display_message_ms);
return;
}
const auto& profiles_for_game =
GetMatchingProfilesFromSetting(setting, profiles, device_configuration);
if (profiles_for_game.empty())
{
Core::DisplayMessage("No input profiles found for game", display_message_ms);
return;
}
const std::string profile = GetProfile(cycle_direction, profile_index, profiles_for_game);
auto* controller = device_configuration->GetController(controller_index);
if (controller)
{
UpdateToProfile(profile, controller);
}
else
{
Core::DisplayMessage("No controller found for index: " + std::to_string(controller_index),
display_message_ms);
}
}
std::string ProfileCycler::GetWiimoteInputProfilesForGame(int controller_index)
{
IniFile game_ini = SConfig::GetInstance().LoadGameIni();
const IniFile::Section* const control_section = game_ini.GetOrCreateSection("Controls");
std::string result;
control_section->Get(StringFromFormat("WiimoteProfile%d", controller_index + 1), &result);
return result;
}
void ProfileCycler::NextWiimoteProfile(int controller_index)
{
CycleProfile(CycleDirection::Forward, Wiimote::GetConfig(), m_wiimote_profile_index,
controller_index);
}
void ProfileCycler::PreviousWiimoteProfile(int controller_index)
{
CycleProfile(CycleDirection::Backward, Wiimote::GetConfig(), m_wiimote_profile_index,
controller_index);
}
void ProfileCycler::NextWiimoteProfileForGame(int controller_index)
{
CycleProfileForGame(CycleDirection::Forward, Wiimote::GetConfig(), m_wiimote_profile_index,
GetWiimoteInputProfilesForGame(controller_index), controller_index);
}
void ProfileCycler::PreviousWiimoteProfileForGame(int controller_index)
{
CycleProfileForGame(CycleDirection::Backward, Wiimote::GetConfig(), m_wiimote_profile_index,
GetWiimoteInputProfilesForGame(controller_index), controller_index);
}
}

View File

@ -0,0 +1,53 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
class InputConfig;
namespace ControllerEmu
{
class EmulatedController;
}
#include <string>
#include <vector>
namespace InputProfile
{
std::vector<std::string> GetProfilesFromSetting(const std::string& setting,
const std::string& root);
enum class CycleDirection : int
{
Forward = 1,
Backward = -1
};
class ProfileCycler
{
public:
void NextWiimoteProfile(int controller_index);
void PreviousWiimoteProfile(int controller_index);
void NextWiimoteProfileForGame(int controller_index);
void PreviousWiimoteProfileForGame(int controller_index);
private:
void CycleProfile(CycleDirection cycle_direction, InputConfig* device_configuration,
int& profile_index, int controller_index);
void CycleProfileForGame(CycleDirection cycle_direction, InputConfig* device_configuration,
int& profile_index, const std::string& setting, int controller_index);
std::vector<std::string> GetProfilesForDevice(InputConfig* device_configuration);
std::string GetProfile(CycleDirection cycle_direction, int& profile_index,
const std::vector<std::string>& profiles);
std::vector<std::string> GetMatchingProfilesFromSetting(const std::string& setting,
const std::vector<std::string>& profiles,
InputConfig* device_configuration);
void UpdateToProfile(const std::string& profile_filename,
ControllerEmu::EmulatedController* controller);
std::string GetWiimoteInputProfilesForGame(int controller_index);
int m_wiimote_profile_index = 0;
};
}