mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-03 23:38:07 +03:00

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.
358 lines
12 KiB
C++
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
|