dolphin/Source/Core/Core/FreeLookManager.cpp
JosJuice e0562abb7d ControllerEmu: Add default mappings for Android
Unlike PCs, Android doesn't really have any input method (not counting
touch) that can reasonably be expected to exist on most devices.
Because of this, I don't think shipping with a default mapping for the
buttons and sticks of GameCube controllers and Wii Remotes makes sense.
I would however like to ship default mappings for a few things:

1. Mapping the Wii Remote's accelerometer and gyroscope to the device's
   accelerometer and gyroscope. This functionality is useful mainly
   for people who use the touchscreen, but can also be useful when
   using a clip-on controller. The disadvantage of having this mapped
   by default is that games disable pointer input if the accelerometer
   reports that the Wii Remote is pointed at the ceiling.

2. Mapping GC keyboards for use with a physical keyboard, like on PC.
   After all, there's no other way of mapping them that makes sense.

3. Mapping rumble to the device's vibrator.

Aside from the GC keyboards, this approach is effectively the same as
what we were doing before the input overhaul.
2023-03-03 22:28:23 +01:00

358 lines
12 KiB
C++

// Copyright 2020 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/FreeLookManager.h"
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/ScopeGuard.h"
#include "Core/Config/FreeLookSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/FreeLookConfig.h"
#include "InputCommon/ControlReference/ControlReference.h"
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
#include "InputCommon/InputConfig.h"
#include "VideoCommon/FreeLookCamera.h"
#include "VideoCommon/OnScreenDisplay.h"
namespace
{
namespace MoveButtons
{
enum MoveButtons
{
Up,
Down,
Left,
Right,
Forward,
Backward,
};
}
namespace SpeedButtons
{
enum SpeedButtons
{
Decrease,
Increase,
Reset,
};
}
namespace OtherButtons
{
enum OtherButtons
{
ResetView,
};
}
namespace FieldOfViewButtons
{
enum FieldOfViewButtons
{
IncreaseX,
DecreaseX,
IncreaseY,
DecreaseY,
};
}
namespace GyroButtons
{
enum GyroButtons
{
PitchUp,
PitchDown,
RollLeft,
RollRight,
YawLeft,
YawRight,
};
}
} // namespace
FreeLookController::FreeLookController(const unsigned int index) : m_index(index)
{
groups.emplace_back(m_move_buttons = new ControllerEmu::Buttons(_trans("Move")));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Up"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Down"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Left"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Right"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Forward"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Backward"));
groups.emplace_back(m_speed_buttons = new ControllerEmu::Buttons(_trans("Speed")));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease"));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Increase"));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Reset"));
groups.emplace_back(m_other_buttons = new ControllerEmu::Buttons(_trans("Other")));
m_other_buttons->AddInput(ControllerEmu::Translate, _trans("Reset View"));
groups.emplace_back(m_fov_buttons = new ControllerEmu::Buttons(_trans("Field of View")));
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Increase X"));
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease X"));
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Increase Y"));
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease Y"));
groups.emplace_back(m_rotation_gyro = new ControllerEmu::IMUGyroscope(
_trans("Incremental Rotation"), _trans("Incremental Rotation")));
}
std::string FreeLookController::GetName() const
{
return std::string("FreeLook") + char('1' + m_index);
}
void FreeLookController::LoadDefaults(const ControllerInterface& ciface)
{
EmulatedController::LoadDefaults(ciface);
#ifndef ANDROID
auto hotkey_string = [](std::vector<std::string> inputs) {
return "@(" + JoinStrings(inputs, "+") + ')';
};
m_move_buttons->SetControlExpression(MoveButtons::Up, hotkey_string({"Shift", "E"}));
m_move_buttons->SetControlExpression(MoveButtons::Down, hotkey_string({"Shift", "Q"}));
m_move_buttons->SetControlExpression(MoveButtons::Left, hotkey_string({"Shift", "A"}));
m_move_buttons->SetControlExpression(MoveButtons::Right, hotkey_string({"Shift", "D"}));
m_move_buttons->SetControlExpression(MoveButtons::Forward, hotkey_string({"Shift", "W"}));
m_move_buttons->SetControlExpression(MoveButtons::Backward, hotkey_string({"Shift", "S"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Decrease, hotkey_string({"Shift", "`1`"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Increase, hotkey_string({"Shift", "`2`"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Reset, hotkey_string({"Shift", "F"}));
m_other_buttons->SetControlExpression(OtherButtons::ResetView, hotkey_string({"Shift", "R"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::IncreaseX,
hotkey_string({"Shift", "`Axis Z+`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseX,
hotkey_string({"Shift", "`Axis Z-`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::IncreaseY,
hotkey_string({"Shift", "`Axis Z+`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseY,
hotkey_string({"Shift", "`Axis Z-`"}));
// Left Click
#if defined HAVE_X11 && HAVE_X11
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
"if(`Click 3`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
"if(`Click 3`,`RelativeMouse Y+` * 0.10, 0)");
#elif __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
"if(`Left Click`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
"if(`Left Click`,`RelativeMouse Y+` * 0.10, 0)");
#else
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
"if(`Click 1`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
"if(`Click 1`,`RelativeMouse Y+` * 0.10, 0)");
#endif
// Middle Click
#ifdef __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::RollLeft,
"if(`Middle Click`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::RollRight,
"if(`Middle Click`,`RelativeMouse X+` * 0.10, 0)");
#else
m_rotation_gyro->SetControlExpression(GyroButtons::RollLeft,
"if(`Click 2`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::RollRight,
"if(`Click 2`,`RelativeMouse X+` * 0.10, 0)");
#endif
// Right Click
#if defined HAVE_X11 && HAVE_X11
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
"if(`Click 3`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
"if(`Click 3`,`RelativeMouse X+` * 0.10, 0)");
#elif __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
"if(`Right Click`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
"if(`Right Click`,`RelativeMouse X+` * 0.10, 0)");
#else
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
"if(`Click 1`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
"if(`Click 1`,`RelativeMouse X+` * 0.10, 0)");
#endif
#endif
}
ControllerEmu::ControlGroup* FreeLookController::GetGroup(FreeLookGroup group) const
{
switch (group)
{
case FreeLookGroup::Move:
return m_move_buttons;
case FreeLookGroup::Speed:
return m_speed_buttons;
case FreeLookGroup::FieldOfView:
return m_fov_buttons;
case FreeLookGroup::Other:
return m_other_buttons;
case FreeLookGroup::Rotation:
return m_rotation_gyro;
default:
return nullptr;
}
}
void FreeLookController::Update()
{
if (!g_freelook_camera.IsActive())
return;
auto* camera_controller = g_freelook_camera.GetController();
if (camera_controller->SupportsInput())
{
UpdateInput(static_cast<CameraControllerInput*>(camera_controller));
}
}
void FreeLookController::UpdateInput(CameraControllerInput* camera_controller)
{
const auto lock = GetStateLock();
// Preserve the old controller gate state
const auto old_gate = ControlReference::GetInputGate();
Common::ScopeGuard gate_guard{[old_gate] { ControlReference::SetInputGate(old_gate); }};
// Switch to the free look focus gate
Core::UpdateInputGate(!Config::Get(Config::FREE_LOOK_BACKGROUND_INPUT));
float dt = 1.0;
if (m_last_free_look_rotate_time)
{
using seconds = std::chrono::duration<float, std::ratio<1>>;
dt = std::chrono::duration_cast<seconds>(std::chrono::steady_clock::now() -
*m_last_free_look_rotate_time)
.count();
}
m_last_free_look_rotate_time = std::chrono::steady_clock::now();
const auto gyro_motion_rad_velocity =
m_rotation_gyro->GetState() ? *m_rotation_gyro->GetState() : Common::Vec3{};
// Due to gyroscope implementation we need to swap the yaw and roll values
// and because of the different axis used for Wii and the PS3 motion directions,
// we need to invert the yaw and roll as well
const Common::Vec3 gyro_motion_rad_velocity_converted{
gyro_motion_rad_velocity.x, gyro_motion_rad_velocity.z * -1, gyro_motion_rad_velocity.y * -1};
const auto gyro_motion_quat =
Common::Quaternion::RotateXYZ(gyro_motion_rad_velocity_converted * dt);
camera_controller->Rotate(gyro_motion_quat);
if (m_move_buttons->controls[MoveButtons::Up]->GetState<bool>())
camera_controller->MoveVertical(-camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Down]->GetState<bool>())
camera_controller->MoveVertical(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Left]->GetState<bool>())
camera_controller->MoveHorizontal(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Right]->GetState<bool>())
camera_controller->MoveHorizontal(-camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Forward]->GetState<bool>())
camera_controller->MoveForward(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Backward]->GetState<bool>())
camera_controller->MoveForward(-camera_controller->GetSpeed() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseX]->GetState<bool>())
camera_controller->IncreaseFovX(camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseX]->GetState<bool>())
camera_controller->IncreaseFovX(-1.0f * camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseY]->GetState<bool>())
camera_controller->IncreaseFovY(camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseY]->GetState<bool>())
camera_controller->IncreaseFovY(-1.0f * camera_controller->GetFovStepSize() * dt);
if (m_speed_buttons->controls[SpeedButtons::Decrease]->GetState<bool>())
camera_controller->ModifySpeed(camera_controller->GetSpeed() * -0.9 * dt);
if (m_speed_buttons->controls[SpeedButtons::Increase]->GetState<bool>())
camera_controller->ModifySpeed(camera_controller->GetSpeed() * 1.1 * dt);
if (m_speed_buttons->controls[SpeedButtons::Reset]->GetState<bool>())
camera_controller->ResetSpeed();
if (m_other_buttons->controls[OtherButtons::ResetView]->GetState<bool>())
camera_controller->Reset();
}
namespace FreeLook
{
static InputConfig s_config("FreeLookController", _trans("FreeLook"), "FreeLookController");
InputConfig* GetInputConfig()
{
return &s_config;
}
void Shutdown()
{
s_config.UnregisterHotplugCallback();
s_config.ClearControllers();
}
void Initialize()
{
if (s_config.ControllersNeedToBeCreated())
{
s_config.CreateController<FreeLookController>(0);
}
s_config.RegisterHotplugCallback();
FreeLook::GetConfig().Refresh();
s_config.LoadConfig(InputConfig::InputClass::GC);
}
void LoadInputConfig()
{
s_config.LoadConfig(InputConfig::InputClass::GC);
}
bool IsInitialized()
{
return !s_config.ControllersNeedToBeCreated();
}
ControllerEmu::ControlGroup* GetInputGroup(int pad_num, FreeLookGroup group)
{
return static_cast<FreeLookController*>(s_config.GetController(pad_num))->GetGroup(group);
}
void UpdateInput()
{
for (int i = 0; i < s_config.GetControllerCount(); i++)
{
static_cast<FreeLookController*>(s_config.GetController(i))->Update();
}
}
} // namespace FreeLook