// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/settings.h" #include "input_common/input_engine.h" #include "input_common/input_mapping.h" namespace InputCommon { MappingFactory::MappingFactory() = default; void MappingFactory::BeginMapping(Polling::InputType type) { is_enabled = true; input_type = type; input_queue.Clear(); first_axis = -1; second_axis = -1; } Common::ParamPackage MappingFactory::GetNextInput() { Common::ParamPackage input; input_queue.Pop(input); return input; } void MappingFactory::RegisterInput(const MappingData& data) { if (!is_enabled) { return; } if (!IsDriverValid(data)) { return; } switch (input_type) { case Polling::InputType::Button: RegisterButton(data); return; case Polling::InputType::Stick: RegisterStick(data); return; case Polling::InputType::Motion: RegisterMotion(data); return; default: return; } } void MappingFactory::StopMapping() { is_enabled = false; input_type = Polling::InputType::None; input_queue.Clear(); } void MappingFactory::RegisterButton(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.RawString()); } new_input.Set("port", static_cast(data.pad.port)); new_input.Set("pad", static_cast(data.pad.pad)); switch (data.type) { case EngineInputType::Button: // Workaround for old compatibility if (data.engine == "keyboard") { new_input.Set("code", data.index); break; } new_input.Set("button", data.index); break; case EngineInputType::HatButton: new_input.Set("hat", data.index); new_input.Set("direction", data.hat_name); break; case EngineInputType::Analog: // Ignore mouse axis when mapping buttons if (data.engine == "mouse" && data.index != 4) { return; } new_input.Set("axis", data.index); new_input.Set("threshold", 0.5f); break; case EngineInputType::Motion: new_input.Set("motion", data.index); break; default: return; } input_queue.Push(new_input); } void MappingFactory::RegisterStick(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.RawString()); } new_input.Set("port", static_cast(data.pad.port)); new_input.Set("pad", static_cast(data.pad.pad)); // If engine is mouse map the mouse position as a joystick if (data.engine == "mouse") { new_input.Set("axis_x", 0); new_input.Set("axis_y", 1); new_input.Set("threshold", 0.5f); new_input.Set("range", 1.0f); new_input.Set("deadzone", 0.0f); input_queue.Push(new_input); return; } switch (data.type) { case EngineInputType::Button: case EngineInputType::HatButton: RegisterButton(data); return; case EngineInputType::Analog: if (first_axis == data.index) { return; } if (first_axis == -1) { first_axis = data.index; return; } new_input.Set("axis_x", first_axis); new_input.Set("axis_y", data.index); new_input.Set("threshold", 0.5f); new_input.Set("range", 0.95f); new_input.Set("deadzone", 0.15f); break; default: return; } input_queue.Push(new_input); } void MappingFactory::RegisterMotion(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.RawString()); } new_input.Set("port", static_cast(data.pad.port)); new_input.Set("pad", static_cast(data.pad.pad)); // If engine is mouse map it automatically to mouse motion if (data.engine == "mouse") { new_input.Set("motion", 0); new_input.Set("pad", 1); new_input.Set("threshold", 0.001f); input_queue.Push(new_input); return; } switch (data.type) { case EngineInputType::Button: case EngineInputType::HatButton: RegisterButton(data); return; case EngineInputType::Analog: if (first_axis == data.index) { return; } if (second_axis == data.index) { return; } if (first_axis == -1) { first_axis = data.index; return; } if (second_axis == -1) { second_axis = data.index; return; } new_input.Set("axis_x", first_axis); new_input.Set("axis_y", second_axis); new_input.Set("axis_z", data.index); new_input.Set("range", 1.0f); new_input.Set("deadzone", 0.20f); break; case EngineInputType::Motion: new_input.Set("motion", data.index); break; default: return; } input_queue.Push(new_input); } bool MappingFactory::IsDriverValid(const MappingData& data) const { // Only port 0 can be mapped on the keyboard if (data.engine == "keyboard" && data.pad.port != 0) { return false; } // Only port 0 can be mapped on the mouse if (data.engine == "mouse" && data.pad.port != 0) { return false; } // To prevent mapping with two devices we disable any UDP except motion if (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" && data.type != EngineInputType::Motion) { return false; } // The following drivers don't need to be mapped if (data.engine == "touch_from_button") { return false; } if (data.engine == "analog_from_button") { return false; } if (data.engine == "virtual_gamepad") { return false; } return true; } } // namespace InputCommon