/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "InputManagementFramework_precompiled.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "InputConfigurationComponent.h" namespace Input { class InputManagementFrameworkSystemComponent : public AZ::Component , public AZ::InputRequestBus::Handler { public: AZ_COMPONENT(InputManagementFrameworkSystemComponent, "{B52457FC-2DEA-4F0E-B0D0-F17786B40F02}"); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("InputManagementFrameworkService")); } static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC("InputManagementFrameworkService")); } static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("AssetDatabaseService")); required.push_back(AZ_CRC("AssetCatalogService")); } static void Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { serializeContext->Class() ->Version(1) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { editContext->Class( "Input management framework", "Manages input bindings and events") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Editor") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) ; } } Input::InputEventBindings::Reflect(context); Input::InputEventGroup::Reflect(context); Input::InputEventBindingsAsset::Reflect(context); } void Activate() override { // Register asset handlers. Requires "AssetDatabaseService" AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!"); m_inputEventBindingsAssetHandler = aznew AzFramework::GenericAssetHandler("Input Bindings", "Other", "inputbindings", AZ::AzTypeInfo::Uuid()); m_inputEventBindingsAssetHandler->Register(); AZ::InputRequestBus::Handler::BusConnect(); AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextActivated); } void Deactivate() override { AZ::InputRequestBus::Handler::BusDisconnect(); delete m_inputEventBindingsAssetHandler; m_inputEventBindingsAssetHandler = nullptr; } protected: void PushContext(const AZStd::string& context) override { AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextDeactivated); m_contexts.push_back(context); AZ::InputContextNotificationBus::Event(AZ::Crc32(context.c_str()), &AZ::InputContextNotifications::OnInputContextActivated); } void PopContext() override { if (m_contexts.size()) { AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextDeactivated); m_contexts.pop_back(); AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextActivated); } } void PopAllContexts() override { if (m_contexts.size()) { AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextDeactivated); m_contexts.clear(); AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextActivated); } } bool InsertContext(const AZStd::string& context, const AZStd::string& existingContextToInsertPriorTo) override { const auto it = AZStd::find(m_contexts.begin(), m_contexts.end(), existingContextToInsertPriorTo); if (it == m_contexts.end()) { return false; } m_contexts.insert(it, context); return true; } bool ReplaceContext(const AZStd::string& context, const AZStd::string& existingContextToReplace) override { const auto it = AZStd::find(m_contexts.begin(), m_contexts.end(), existingContextToReplace); if (it == m_contexts.end()) { return false; } const bool isReplacingCurrentContext = (AZStd::next(it) == m_contexts.end()); if (isReplacingCurrentContext) { AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextDeactivated); } *it = context; if (isReplacingCurrentContext) { AZ::InputContextNotificationBus::Event(AZ::Crc32(GetCurrentContext().c_str()), &AZ::InputContextNotifications::OnInputContextActivated); } return true; } bool RemoveContext(const AZStd::string& existingContextToRemove) override { const auto it = AZStd::find(m_contexts.begin(), m_contexts.end(), existingContextToRemove); if (it == m_contexts.end()) { return false; } const bool isRemovingCurrentContext = (AZStd::next(it) == m_contexts.end()); if (isRemovingCurrentContext) { PopContext(); return true; } m_contexts.erase(it); return true; } AZStd::string GetCurrentContext() override { if (m_contexts.size()) { return m_contexts.back(); } return AZStd::string(""); } AZStd::vector GetContextStack() override { return m_contexts; } private: AzFramework::GenericAssetHandler* m_inputEventBindingsAssetHandler = nullptr; AZStd::vector m_contexts; }; class InputManagementFrameworkModule : public CryHooksModule { public: AZ_RTTI(InputManagementFrameworkModule, "{F42A5E0C-2EA5-46C1-BA0F-D4A665653B0B}", AZ::Module); InputManagementFrameworkModule() : CryHooksModule() { m_descriptors.insert(m_descriptors.end(), { InputConfigurationComponent::CreateDescriptor(), InputManagementFrameworkSystemComponent::CreateDescriptor() }); // This is an internal Amazon gem, so register it's components for metrics tracking, otherwise the name of the component won't get sent back. // IF YOU ARE A THIRDPARTY WRITING A GEM, DO NOT REGISTER YOUR COMPONENTS WITH EditorMetricsComponentRegistrationBus AZStd::vector typeIds; typeIds.reserve(m_descriptors.size()); for (AZ::ComponentDescriptor* descriptor : m_descriptors) { typeIds.emplace_back(descriptor->GetUuid()); } EBUS_EVENT(AzFramework::MetricsPlainTextNameRegistrationBus, RegisterForNameSending, typeIds); } AZ::ComponentTypeList GetRequiredSystemComponents() const override { return{ azrtti_typeid() }; } void OnSystemEvent(ESystemEvent event, UINT_PTR, UINT_PTR) override { switch (event) { case ESYSTEM_EVENT_LEVEL_LOAD_START: case ESYSTEM_EVENT_GAME_MODE_SWITCH_START: { AZ::InputRequestBus::Broadcast(&AZ::InputRequests::PopAllContexts); } break; default: break; } } }; } // DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM // The first parameter should be GemName_GemIdLower // The second should be the fully qualified name of the class above AZ_DECLARE_MODULE_CLASS(InputManagementFramework_59b1b2acc1974aae9f18faddcaddac5b, Input::InputManagementFrameworkModule)