// Copyright 2021 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include "InputCommon/ControllerInterface/Touch/InputOverrider.h" #include #include #include #include #include #include #include "Common/Assert.h" #include "Core/HW/GCPad.h" #include "Core/HW/GCPadEmu.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/Extension/Classic.h" #include "Core/HW/WiimoteEmu/Extension/Nunchuk.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/StickGate.h" #include "InputCommon/ControllerInterface/CoreDevice.h" #include "InputCommon/InputConfig.h" namespace ciface::Touch { namespace { struct InputState { ControlState normal_state = 0; ControlState override_state = 0; bool overriding = false; }; using ControlsMap = std::map, ControlID>; using StateArray = std::array; std::array s_state_arrays; const ControlsMap s_gcpad_controls_map = {{ {{GCPad::BUTTONS_GROUP, GCPad::A_BUTTON}, ControlID::GCPAD_A_BUTTON}, {{GCPad::BUTTONS_GROUP, GCPad::B_BUTTON}, ControlID::GCPAD_B_BUTTON}, {{GCPad::BUTTONS_GROUP, GCPad::X_BUTTON}, ControlID::GCPAD_X_BUTTON}, {{GCPad::BUTTONS_GROUP, GCPad::Y_BUTTON}, ControlID::GCPAD_Y_BUTTON}, {{GCPad::BUTTONS_GROUP, GCPad::Z_BUTTON}, ControlID::GCPAD_Z_BUTTON}, {{GCPad::BUTTONS_GROUP, GCPad::START_BUTTON}, ControlID::GCPAD_START_BUTTON}, {{GCPad::DPAD_GROUP, DIRECTION_UP}, ControlID::GCPAD_DPAD_UP}, {{GCPad::DPAD_GROUP, DIRECTION_DOWN}, ControlID::GCPAD_DPAD_DOWN}, {{GCPad::DPAD_GROUP, DIRECTION_LEFT}, ControlID::GCPAD_DPAD_LEFT}, {{GCPad::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::GCPAD_DPAD_RIGHT}, {{GCPad::TRIGGERS_GROUP, GCPad::L_DIGITAL}, ControlID::GCPAD_L_DIGITAL}, {{GCPad::TRIGGERS_GROUP, GCPad::R_DIGITAL}, ControlID::GCPAD_R_DIGITAL}, {{GCPad::TRIGGERS_GROUP, GCPad::L_ANALOG}, ControlID::GCPAD_L_ANALOG}, {{GCPad::TRIGGERS_GROUP, GCPad::R_ANALOG}, ControlID::GCPAD_R_ANALOG}, {{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::GCPAD_MAIN_STICK_X}, {{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::GCPAD_MAIN_STICK_Y}, {{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::GCPAD_C_STICK_X}, {{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::GCPAD_C_STICK_Y}, }}; const ControlsMap s_wiimote_controls_map = {{ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::A_BUTTON}, ControlID::WIIMOTE_A_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::B_BUTTON}, ControlID::WIIMOTE_B_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::ONE_BUTTON}, ControlID::WIIMOTE_ONE_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::TWO_BUTTON}, ControlID::WIIMOTE_TWO_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::PLUS_BUTTON}, ControlID::WIIMOTE_PLUS_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::MINUS_BUTTON}, ControlID::WIIMOTE_MINUS_BUTTON}, {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::HOME_BUTTON}, ControlID::WIIMOTE_HOME_BUTTON}, {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_UP}, ControlID::WIIMOTE_DPAD_UP}, {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_DOWN}, ControlID::WIIMOTE_DPAD_DOWN}, {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_LEFT}, ControlID::WIIMOTE_DPAD_LEFT}, {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::WIIMOTE_DPAD_RIGHT}, {{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::WIIMOTE_IR_X}, {{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::WIIMOTE_IR_Y}, }}; const ControlsMap s_nunchuk_controls_map = {{ {{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::C_BUTTON}, ControlID::NUNCHUK_C_BUTTON}, {{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::Z_BUTTON}, ControlID::NUNCHUK_Z_BUTTON}, {{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::NUNCHUK_STICK_X}, {{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::NUNCHUK_STICK_Y}, }}; const ControlsMap s_classic_controls_map = {{ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::A_BUTTON}, ControlID::CLASSIC_A_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::B_BUTTON}, ControlID::CLASSIC_B_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::X_BUTTON}, ControlID::CLASSIC_X_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::Y_BUTTON}, ControlID::CLASSIC_Y_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZL_BUTTON}, ControlID::CLASSIC_ZL_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZR_BUTTON}, ControlID::CLASSIC_ZR_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::PLUS_BUTTON}, ControlID::CLASSIC_PLUS_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::MINUS_BUTTON}, ControlID::CLASSIC_MINUS_BUTTON}, {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::HOME_BUTTON}, ControlID::CLASSIC_HOME_BUTTON}, {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_UP}, ControlID::CLASSIC_DPAD_UP}, {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_DOWN}, ControlID::CLASSIC_DPAD_DOWN}, {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_LEFT}, ControlID::CLASSIC_DPAD_LEFT}, {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::CLASSIC_DPAD_RIGHT}, {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_DIGITAL}, ControlID::CLASSIC_L_DIGITAL}, {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_DIGITAL}, ControlID::CLASSIC_R_DIGITAL}, {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_ANALOG}, ControlID::CLASSIC_L_ANALOG}, {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_ANALOG}, ControlID::CLASSIC_R_ANALOG}, {{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::CLASSIC_LEFT_STICK_X}, {{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::CLASSIC_LEFT_STICK_Y}, {{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE}, ControlID::CLASSIC_RIGHT_STICK_X}, {{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE}, ControlID::CLASSIC_RIGHT_STICK_Y}, }}; ControllerEmu::InputOverrideFunction GetInputOverrideFunction(const ControlsMap& controls_map, size_t i) { StateArray& state_array = s_state_arrays[i]; return [&](std::string_view group_name, std::string_view control_name, ControlState controller_state) -> std::optional { const auto it = controls_map.find(std::make_pair(group_name, control_name)); if (it == controls_map.end()) return std::nullopt; const ControlID control = it->second; InputState& input_state = state_array[control]; if (input_state.normal_state != controller_state) { input_state.normal_state = controller_state; input_state.overriding = false; } return input_state.overriding ? std::make_optional(input_state.override_state) : std::nullopt; }; } } // namespace void RegisterGameCubeInputOverrider(int controller_index) { Pad::GetConfig() ->GetController(controller_index) ->SetInputOverrideFunction(GetInputOverrideFunction(s_gcpad_controls_map, controller_index)); } void RegisterWiiInputOverrider(int controller_index) { auto* wiimote = static_cast(Wiimote::GetConfig()->GetController(controller_index)); wiimote->SetInputOverrideFunction( GetInputOverrideFunction(s_wiimote_controls_map, controller_index)); auto& attachments = static_cast( wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments)) ->GetAttachmentList(); attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->SetInputOverrideFunction( GetInputOverrideFunction(s_nunchuk_controls_map, controller_index)); attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->SetInputOverrideFunction( GetInputOverrideFunction(s_classic_controls_map, controller_index)); } void UnregisterGameCubeInputOverrider(int controller_index) { Pad::GetConfig()->GetController(controller_index)->ClearInputOverrideFunction(); for (size_t i = ControlID::FIRST_GC_CONTROL; i <= ControlID::LAST_GC_CONTROL; ++i) s_state_arrays[controller_index][i].overriding = false; } void UnregisterWiiInputOverrider(int controller_index) { auto* wiimote = static_cast(Wiimote::GetConfig()->GetController(controller_index)); wiimote->ClearInputOverrideFunction(); auto& attachments = static_cast( wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments)) ->GetAttachmentList(); attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->ClearInputOverrideFunction(); attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->ClearInputOverrideFunction(); for (size_t i = ControlID::FIRST_WII_CONTROL; i <= ControlID::LAST_WII_CONTROL; ++i) s_state_arrays[controller_index][i].overriding = false; } void SetControlState(int controller_index, ControlID control, double state) { InputState& input_state = s_state_arrays[controller_index][control]; input_state.override_state = state; input_state.overriding = true; } void ClearControlState(int controller_index, ControlID control) { InputState& input_state = s_state_arrays[controller_index][control]; input_state.overriding = false; } double GetGateRadiusAtAngle(int controller_index, ControlID stick, double angle) { ControllerEmu::ControlGroup* group; switch (stick) { case ControlID::GCPAD_MAIN_STICK_X: case ControlID::GCPAD_MAIN_STICK_Y: group = Pad::GetGroup(controller_index, PadGroup::MainStick); break; case ControlID::GCPAD_C_STICK_X: case ControlID::GCPAD_C_STICK_Y: group = Pad::GetGroup(controller_index, PadGroup::CStick); break; case ControlID::NUNCHUK_STICK_X: case ControlID::NUNCHUK_STICK_Y: group = Wiimote::GetNunchukGroup(controller_index, WiimoteEmu::NunchukGroup::Stick); break; case ControlID::CLASSIC_LEFT_STICK_X: case ControlID::CLASSIC_LEFT_STICK_Y: group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::LeftStick); break; case ControlID::CLASSIC_RIGHT_STICK_X: case ControlID::CLASSIC_RIGHT_STICK_Y: group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::RightStick); break; default: ASSERT(false); return 0; } return static_cast(group)->GetGateRadiusAtAngle(angle); } } // namespace ciface::Touch