diff --git a/Assets/Bindings.SHConfig b/Assets/Bindings.SHConfig index 573541ac..bdc254b5 100644 --- a/Assets/Bindings.SHConfig +++ b/Assets/Bindings.SHConfig @@ -1 +1,96 @@ +7 +Controller Look Horizontal 0 +0 +5 +0.2 +5 +0 +0 +0 +1 +18 +0 +Controller Look Vertical +0 +0 +5 +0.2 +5 +0 +0 +0 +1 +19 +0 +Horizontal +0 +0 +5 +0.2 +5 +1 +2 +39 +68 +2 +37 +65 +2 +3 +16 +1 +2 +Jump +0 +0 +1000 +0.2 +1000 +0 +1 +32 +0 +1 +10 +0 +Mouse Look Horizontal +1 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Mouse Look Vertical +2 +0 +1 +0.2 +1 +0 +0 +0 +0 +0 +Vertical +0 +0 +5 +0.2 +5 +1 +2 +38 +87 +2 +40 +83 +2 +0 +17 +1 +1 diff --git a/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp new file mode 100644 index 00000000..d3fa33fa --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.cpp @@ -0,0 +1,546 @@ +#include "SHpch.h" +#include "SHInputBindingsPanel.h" +#include "Input/SHInputManager.h" +#include "Editor/SHEditorWidgets.hpp" + +namespace SHADE +{ + //Vectors containing data for elements for different bindings + static std::vector bindingRenames; + + //Flags to prevent unwanted editing of bindings + static size_t positiveKeyListeningFor; + static bool positiveKeyListening; + + static size_t negativeKeyListeningFor; + static bool negativeKeyListening; + + static size_t positiveControllerListeningFor; + static bool positiveControllerListening; + + static size_t negativeControllerListeningFor; + static bool negativeControllerListening; + + //Internal Helper function + void resizeVectors(size_t newSize) + { + bindingRenames.resize(newSize); + for (auto& s : bindingRenames) + s.clear(); + } + + //Internal Helper function + std::string labelConcat(char const* label, size_t entryNumber) + { + std::string concat = label; + concat += std::to_string(entryNumber); + return concat; + } + + void SHInputBindingsPanel::Init() + { + SHEditorWindow::Init(); + } + + void SHInputBindingsPanel::Update() + { + if (SHEditorWindow::Begin()) + { + //ImGui::ShowDemoWindow(); + + //Binding count + ImGui::Text("Binding Count: %d", SHInputManager::CountBindings()); + + //Binding file name + static std::string bindingFileName; + ImGui::InputText("Binding File Path", &bindingFileName); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text(".SHConfig will be appeneded to file name"); + ImGui::Text("If no name is provided, saves to or loads from \"Assets/Bindings.SHConfig\""); + ImGui::EndTooltip(); + } + + //Save bindings to... + if (ImGui::Button("Save Bindings")) + { + if (bindingFileName.empty()) + { + SHInputManager::SaveBindings(); + } + else + { + std::string filePath = std::string(ASSET_ROOT); + filePath += "/"; + filePath += bindingFileName; + filePath += ".SHConfig"; + SHInputManager::SaveBindings(filePath); + } + } + + //Load bindings from... + if (ImGui::Button("Load Bindings")) + { + if (bindingFileName.empty()) + { + SHInputManager::LoadBindings(); + } + else + { + std::string filePath = std::string(ASSET_ROOT); + filePath += "/"; + filePath += bindingFileName; + filePath += ".SHConfig"; + SHInputManager::LoadBindings(filePath); + } + resizeVectors(SHInputManager::CountBindings()); + } + + //Button to add new binding + if (ImGui::Button("Add New Binding")) + { + std::string newBindingName = "Binding" + std::to_string(SHInputManager::CountBindings()); + SHInputManager::AddBinding(newBindingName); + resizeVectors(SHInputManager::CountBindings()); + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Add a new binding to the list"); + ImGui::EndTooltip(); + } + + //Ensure unique label for entries + size_t entryNumber = 0; + + //Listing for each binding + for (auto& binding : SHInputManager::GetBindings()) + { + if (ImGui::CollapsingHeader(binding.first.c_str())) + { + //Modifiable binding name + ImGui::Text("Binding Name: %s", binding.first.c_str()); + ImGui::InputText(labelConcat("##bindingModifyName", entryNumber).c_str(), &bindingRenames[entryNumber]); + ImGui::SameLine(); + if (ImGui::Button(labelConcat("Rename##bindingRename", entryNumber).c_str())) + { + SHInputManager::RenameBinding(binding.first, bindingRenames[entryNumber]); + bindingRenames[entryNumber].clear(); + } + + if (ImGui::Button(labelConcat("Delete Binding##", entryNumber).c_str())) + { + SHInputManager::RemoveBinding(binding.first); + resizeVectors(SHInputManager::CountBindings()); + ImGui::End(); + return; + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Delete this binding from the list"); + ImGui::EndTooltip(); + } + + //Binding value test + ImGui::BeginDisabled(); + float val = SHInputManager::GetBindingAxis(binding.first); + ImGui::SliderFloat(labelConcat("Value##", entryNumber).c_str(), &val, -1.0f, 1.0f); + ImGui::EndDisabled(); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Test the current value of the binding"); + ImGui::Text("For mouse movement/wheel inputs, will be multiplied by Sensitivity, with 0 being neutral (no input detected)"); + ImGui::Text("Between -1 and 1 for other inputs, with 0 still being neutral (no input detected)"); + ImGui::EndTooltip(); + } + ImGui::BeginDisabled(); + float rawVal = SHInputManager::GetBindingAxisRaw(binding.first); + ImGui::SliderFloat(labelConcat("Raw Value##", entryNumber).c_str(), &rawVal, -1.0f, 1.0f); + ImGui::EndDisabled(); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Test the current value of the binding"); + ImGui::Text("Raw value means it will be fixed among -1, 0 and 1 for non-mouse movement/wheel inputs"); + ImGui::Text("No difference between this and Value for mouse movement/wheel inputs"); + ImGui::Text("But for other inputs, does not consider smoothing options such as gravity and sensitivity"); + ImGui::Text("If both positive and negative input is detected, returns neutral 0"); + ImGui::EndTooltip(); + } + + //Binding Type Combo Box + int bindingType = static_cast(SHInputManager::GetBindingType(binding.first)); + if (ImGui::Combo(labelConcat("Input Type##", entryNumber).c_str(), &bindingType, "Keyboard / Mouse Buttons / Controller\0Mouse Horizontal\0Mouse Vertical\0Mouse Scroll Wheel")) + SHInputManager::SetBindingType(binding.first, static_cast(bindingType)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Which of the four types the binding uses"); + ImGui::Text("Keyboard / Mouse Buttons / Controller = Keys, mouse buttons and ALL controller inputs"); + ImGui::Text("Mouse Horizontal = Horizontal movement of the mouse"); + ImGui::Text("Mouse Vertical = Vertical movement of the mouse"); + ImGui::Text("Mouse Scroll Wheel = The scroll wheel found at the middle of most mouses"); + ImGui::EndTooltip(); + } + + //Inversion + bool bindingInvert = SHInputManager::GetBindingInverted(binding.first); + if (ImGui::Checkbox(labelConcat("Inverted##", entryNumber).c_str(), &bindingInvert)) + SHInputManager::SetBindingInverted(binding.first, bindingInvert); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("If inverted:"); + ImGui::Text("Positive inputs mean negative value of the binding"); + ImGui::Text("Negative inputs mean positive value of the binding"); + ImGui::Text("Mouse moving up / right means negative value of the binding"); + ImGui::Text("Scrolling the mouse wheel up means negative value of the binding"); + ImGui::EndTooltip(); + } + + //Sensitivity + double bindingSensitivity = SHInputManager::GetBindingSensitivity(binding.first); + if (ImGui::InputDouble(labelConcat("Sensitivity##", entryNumber).c_str(), &bindingSensitivity)) + SHInputManager::SetBindingSensitivity(binding.first, bindingSensitivity); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Value multiplier for mouse movement and scrolling"); + ImGui::Text("For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative"); + //ImGui::Text("For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1"); + ImGui::Text("Irrelevant for other analog inputs"); + ImGui::EndTooltip(); + } + + //Below this section is only for KB/M type bindings + //Not relevant for mouse movement and scrolling + if (SHInputManager::GetBindingType(binding.first) == SHInputManager::SH_BINDINGTYPE::KB_MB_CONTROLLER) + { + //Dead + float bindingDead = static_cast(SHInputManager::GetBindingDead(binding.first)); + if (ImGui::SliderFloat(labelConcat("Deadzone##", entryNumber).c_str(), &bindingDead, 0.0f, 1.0f)) + SHInputManager::SetBindingDead(binding.first, static_cast(bindingDead)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("Any positive or negative analog input with magnitude less than this will be registered as neutral"); + ImGui::EndTooltip(); + } + + //Gravity + double bindingGravity = SHInputManager::GetBindingGravity(binding.first); + if (ImGui::InputDouble(labelConcat("Gravity##", entryNumber).c_str(), &bindingGravity)) + SHInputManager::SetBindingGravity(binding.first, static_cast(bindingGravity)); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("The rate at which the value moves to neutral if no input in the direction is read"); + ImGui::TextColored(ImVec4{ 1.0f, 0.5f, 0.5f, 1.0f }, "Should be non-negative"); + ImGui::EndTooltip(); + } + + //Snap + bool bindingSnap = SHInputManager::GetBindingSnap(binding.first); + if (ImGui::Checkbox(labelConcat("Snap##", entryNumber).c_str(), &bindingSnap)) + SHInputManager::SetBindingSnap(binding.first, bindingSnap); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("If no other input on the axis is present and a input is made in the opposite direction of the current value,"); + ImGui::Text("the binding's value will jump to neutral 0 before resuming in the input direction"); + ImGui::EndTooltip(); + } + + size_t keycodeIndex = 0; + //Positive key codes + ImGui::Separator(); + ImGui::Text("Positive Key Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this keyboard or mouse button is held, causes the value to go positive, or negative when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!positiveKeyListening) + { + if (ImGui::Button(labelConcat("New##positiveKeyCode", entryNumber).c_str())) + { + positiveKeyListening = true; + positiveKeyListeningFor = entryNumber; + } + } + else + { + if (positiveKeyListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##positiveKeyCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_KEYCODE k; + if (SHInputManager::AnyKey(&k)) + { + positiveKeyListening = false; + SHInputManager::AddBindingPositiveKeyCode(binding.first, k); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##positiveKeyCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& k : binding.second.positiveKeyCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetKeyCodeName(k).c_str()); + ImGui::SameLine(); + std::string labelString = "X##KeyPositive"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingPositiveKeyCode(binding.first, k); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + + //Negative key codes + ImGui::Separator(); + ImGui::Text("Negative Key Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this keyboard or mouse button is held, causes the value to go negative, or positive when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!negativeKeyListening) + { + if (ImGui::Button(labelConcat("New##negativeKeyCode", entryNumber).c_str())) + { + negativeKeyListening = true; + negativeKeyListeningFor = entryNumber; + } + } + else + { + if (negativeKeyListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##negativeKeyCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_KEYCODE k; + if (SHInputManager::AnyKey(&k)) + { + negativeKeyListening = false; + SHInputManager::AddBindingNegativeKeyCode(binding.first, k); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##negativeKeyCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& k : binding.second.negativeKeyCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetKeyCodeName(k).c_str()); + ImGui::SameLine(); + std::string labelString = "X##KeyNegative"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingNegativeKeyCode(binding.first, k); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + //Positive controller codes + ImGui::Separator(); + ImGui::Text("Positive Controller Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this controller button is held, causes the value to go positive, or negative when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!positiveControllerListening) + { + if (ImGui::Button(labelConcat("New##positiveControllerCode", entryNumber).c_str())) + { + positiveControllerListening = true; + positiveControllerListeningFor = entryNumber; + } + } + else + { + if (positiveControllerListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##positiveControllerCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_CONTROLLERCODE c; + if (SHInputManager::AnyControllerInput(&c)) + { + positiveControllerListening = false; + SHInputManager::AddBindingPositiveControllerCode(binding.first, c); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##positiveControllerCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& c : binding.second.positiveControllerCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetControllerCodeName(c).c_str()); + ImGui::SameLine(); + std::string labelString = "X##ControllerPositive"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingPositiveControllerCode(binding.first, c); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + + //Negative controller codes + ImGui::Separator(); + ImGui::Text("Negative Controller Codes:"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("When this controller button is pressed, causes the value to go negative, or positive when inverted"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + //Button to ask for inputs + if (!negativeControllerListening) + { + if (ImGui::Button(labelConcat("New##negativeControllerCode", entryNumber).c_str())) + { + negativeControllerListening = true; + negativeControllerListeningFor = entryNumber; + } + } + else + { + if (negativeControllerListeningFor == entryNumber) + { + //Listening for inputs + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::Button(labelConcat("PRESS##negativeControllerCode", entryNumber).c_str()); + ImGui::PopStyleColor(4); + + SHInputManager::SH_CONTROLLERCODE c; + if (SHInputManager::AnyControllerInput(&c)) + { + negativeControllerListening = false; + SHInputManager::AddBindingNegativeControllerCode(binding.first, c); + } + } + else + { + //Not listening + ImGui::BeginDisabled(); + ImGui::Button(labelConcat("New##negativeControllerCode", entryNumber).c_str()); + ImGui::EndDisabled(); + } + } + + //List and remove bindings + ImGui::Indent(); + keycodeIndex = 0; + for (auto& c : binding.second.negativeControllerCodes) + { + //ImGui::Text("%d", static_cast(k)); + ImGui::Text(SHInputManager::GetControllerCodeName(c).c_str()); + ImGui::SameLine(); + std::string labelString = "X##ControllerNegative"; + labelString += binding.first; + + //Delete button + if (ImGui::SmallButton(labelConcat(labelString.c_str(), keycodeIndex).c_str())) + { + SHInputManager::RemoveBindingNegativeControllerCode(binding.first, c); + break; + } + ++keycodeIndex; + } + ImGui::Unindent(); + } + } + ++entryNumber; //Next entry + } + } + ImGui::End(); + } + + void SHInputBindingsPanel::Exit() + { + SHEditorWindow::Exit(); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h new file mode 100644 index 00000000..db2ec0c8 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/InputBindings/SHInputBindingsPanel.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Editor/EditorWindow/SHEditorWindow.h" +#include + +namespace SHADE +{ + class SH_API SHInputBindingsPanel final : public SHEditorWindow + { + public: + SHInputBindingsPanel() : SHEditorWindow("Input Bindings Panel", ImGuiWindowFlags_MenuBar) {} + + void Init() override; + void Update() override; + void Exit() override; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h index 9aad6ede..290ed622 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h +++ b/SHADE_Engine/src/Editor/EditorWindow/SHEditorWindowIncludes.h @@ -6,4 +6,5 @@ #include "ViewportWindow/SHEditorViewport.h" //Editor Viewport #include "AssetBrowser/SHAssetBrowser.h" //Asset Browser #include "MaterialInspector/SHMaterialInspector.h" //Material Inspector -#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel \ No newline at end of file +#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel +#include "InputBindings/SHInputBindingsPanel.h" //Input Bindings \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 06e2da56..2276164f 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -107,6 +107,7 @@ namespace SHADE SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); + SHEditorWindowManager::CreateEditorWindow(); SHEditorWindowManager::CreateEditorWindow(); diff --git a/SHADE_Engine/src/Input/SHInputManager.cpp b/SHADE_Engine/src/Input/SHInputManager.cpp index b8f329b9..2f0ab6d6 100644 --- a/SHADE_Engine/src/Input/SHInputManager.cpp +++ b/SHADE_Engine/src/Input/SHInputManager.cpp @@ -100,6 +100,475 @@ namespace SHADE } } + std::string SHInputManager::GetKeyCodeName(SH_KEYCODE k) noexcept + { + int kInt = static_cast(k); + //Numbers + if (kInt >= static_cast(SH_KEYCODE::NUMBER_0) && kInt <= static_cast(SH_KEYCODE::NUMBER_9)) + { + return std::to_string(kInt - 48); + } + //Letters + if (kInt >= static_cast(SH_KEYCODE::A) && kInt <= static_cast(SH_KEYCODE::Z)) + { + return std::string(1, static_cast(kInt)); + } + //Numpads + if (kInt >= static_cast(SH_KEYCODE::NUMPAD_0) && kInt <= static_cast(SH_KEYCODE::NUMPAD_9)) + { + return "Numpad " + std::to_string(kInt - 96); + } + //Function keys + if (kInt >= static_cast(SH_KEYCODE::F1) && kInt <= static_cast(SH_KEYCODE::F24)) + { + return "F" + std::to_string(kInt - 111); + } + + //Other keys + switch (k) + { + case SH_KEYCODE::LMB: + return "Left Mouse Button"; + break; + case SH_KEYCODE::RMB: + return "Right Mouse Button"; + break; + case SH_KEYCODE::CANCEL: + return "Cancel"; + break; + case SH_KEYCODE::MMB: + return "Middle Mouse Button"; + break; + case SH_KEYCODE::XMB1: + return "X1 Mouse Button"; + break; + case SH_KEYCODE::XMB2: + return "X2 Mouse Button"; + break; + case SH_KEYCODE::BACKSPACE: + return "Backspace"; + break; + case SH_KEYCODE::TAB: + return "Tab"; + break; + case SH_KEYCODE::CLEAR: + return "Clear"; + break; + case SH_KEYCODE::ENTER: + return "Enter"; + break; + case SH_KEYCODE::SHIFT: + return "Shift"; + break; + case SH_KEYCODE::CTRL: + return "Ctrl"; + break; + case SH_KEYCODE::ALT: + return "Alt"; + break; + case SH_KEYCODE::PAUSE: + return "Pause"; + break; + case SH_KEYCODE::CAPS_LOCK: + return "Caps Lock"; + break; + case SH_KEYCODE::IME_KANA: + return "IME Kana / Hangul Mode"; + break; + case SH_KEYCODE::IME_ON: + return "IME On"; + break; + case SH_KEYCODE::IME_JUNJA: + return "IME Junja Mode"; + break; + case SH_KEYCODE::IME_FINAL: + return "IME Final Mode"; + break; + case SH_KEYCODE::IME_HANJA: + return "IME Kanji / Hanja Mode"; + break; + case SH_KEYCODE::IME_OFF: + return "IME Off"; + break; + case SH_KEYCODE::ESCAPE: + return "Esc"; + break; + case SH_KEYCODE::IME_CONVERT: + return "IME Convert"; + break; + case SH_KEYCODE::IME_NONCONVERT: + return "IME Nonconvert"; + break; + case SH_KEYCODE::IME_ACCEPT: + return "IME Accept"; + break; + case SH_KEYCODE::IME_MODECHANGE: + return "IME Mode Change Request"; + break; + case SH_KEYCODE::SPACE: + return "Spacebar"; + break; + case SH_KEYCODE::PAGE_UP: + return "Page Up"; + break; + case SH_KEYCODE::PAGE_DOWN: + return "Page Down"; + break; + case SH_KEYCODE::END: + return "End"; + break; + case SH_KEYCODE::HOME: + return "Home"; + break; + case SH_KEYCODE::LEFT_ARROW: + return "Left Arrow"; + break; + case SH_KEYCODE::UP_ARROW: + return "Up Arrow"; + break; + case SH_KEYCODE::RIGHT_ARROW: + return "Right Arrow"; + break; + case SH_KEYCODE::DOWN_ARROW: + return "Down Arrow"; + break; + case SH_KEYCODE::SELECT: + return "Select"; + break; + case SH_KEYCODE::PRINT: + return "Print"; + break; + case SH_KEYCODE::EXECUTE: + return "Execute"; + break; + case SH_KEYCODE::PRINT_SCREEN: + return "Print Screen"; + break; + case SH_KEYCODE::INSERT: + return "Insert"; + break; + case SH_KEYCODE::DEL: + return "Delete"; + break; + case SH_KEYCODE::HELP: + return "Help"; + break; + case SH_KEYCODE::LEFT_WINDOWS: + return "Left Windows"; + break; + case SH_KEYCODE::RIGHT_WINDOWS: + return "Right Windows"; + break; + case SH_KEYCODE::APPS: + return "Applications"; + break; + case SH_KEYCODE::SLEEP: + return "Sleep"; + break; + case SH_KEYCODE::MULTIPLY: + return "Numpad *"; + break; + case SH_KEYCODE::ADD: + return "Numpad +"; + break; + case SH_KEYCODE::SEPARATOR: + return "Separator"; + break; + case SH_KEYCODE::SUBTRACT: + return "Numpad -"; + break; + case SH_KEYCODE::DECIMAL: + return "Numpad ."; + break; + case SH_KEYCODE::DIVIDE: + return "Numpad /"; + break; + case SH_KEYCODE::NUM_LOCK: + return "Num Lock"; + break; + case SH_KEYCODE::SCROLL_LOCK: + return "Scroll Lock"; + break; + case SH_KEYCODE::OEM_PC98_NUMPAD_EQUAL: + return "OEM PC98 Numpad Equal / Fujitsu Dictionary"; + break; + case SH_KEYCODE::OEM_FUJITSU_UNREGISTER: + return "OEM Fujitsu Unregister"; + break; + case SH_KEYCODE::OEM_FUJITSU_REGISTER: + return "OEM Fujitsu Register"; + break; + case SH_KEYCODE::OEM_FUJITSU_LEFT_THUMB: + return "OEM Fujitsu Left Thumb"; + break; + case SH_KEYCODE::OEM_FUJITSU_RIGHT_THUMB: + return "OEM Fujitsu Right Thumb"; + break; + case SH_KEYCODE::LEFT_SHIFT: + return "Left Shift"; + break; + case SH_KEYCODE::RIGHT_SHIFT: + return "Right Shift"; + break; + case SH_KEYCODE::LEFT_CTRL: + return "Left Ctrl"; + break; + case SH_KEYCODE::RIGHT_CTRL: + return "Right Ctrl"; + break; + case SH_KEYCODE::LEFT_ALT: + return "Left Alt"; + break; + case SH_KEYCODE::RIGHT_ALT: + return "Right Alt"; + break; + case SH_KEYCODE::BROWSER_BACK: + return "Browser Back"; + break; + case SH_KEYCODE::BROWSER_FORWARD: + return "Browser Forward"; + break; + case SH_KEYCODE::BROWSER_REFRESH: + return "Browser Refresh"; + break; + case SH_KEYCODE::BROWSER_STOP: + return "Browser Stop"; + break; + case SH_KEYCODE::BROWSER_SEARCH: + return "Browser Search"; + break; + case SH_KEYCODE::BROWSER_FAVOURITES: + return "Browser Favourites"; + break; + case SH_KEYCODE::BROWSER_HOME: + return "Browser Start and Home"; + break; + case SH_KEYCODE::VOLUME_MUTE: + return "Volume Mute"; + break; + case SH_KEYCODE::VOLUME_DOWN: + return "Volume Down"; + break; + case SH_KEYCODE::VOLUME_UP: + return "Volume Up"; + break; + case SH_KEYCODE::MEDIA_NEXT_TRACK: + return "Media Next Track"; + break; + case SH_KEYCODE::MEDIA_PREVIOUS_TRACK: + return "Media Previous Track"; + break; + case SH_KEYCODE::MEDIA_STOP: + return "Media Stop"; + break; + case SH_KEYCODE::MEDIA_PLAY_PAUSE: + return "Media Play/Pause"; + break; + case SH_KEYCODE::LAUNCH_MAIL: + return "Launch Mail"; + break; + case SH_KEYCODE::LAUNCH_MEDIA_SELECT: + return "Select Media"; + break; + case SH_KEYCODE::LAUNCH_APP_1: + return "Launch App 1"; + break; + case SH_KEYCODE::LAUNCH_APP_2: + return "Launch App 2"; + break; + case SH_KEYCODE::OEM_1: + return "; or :"; + break; + case SH_KEYCODE::OEM_PLUS: + return "= or +"; + break; + case SH_KEYCODE::OEM_COMMA: + return ", or <"; + break; + case SH_KEYCODE::OEM_MINUS: + return "- or _"; + break; + case SH_KEYCODE::OEM_PERIOD: + return ". or >"; + break; + case SH_KEYCODE::OEM_2: + return "/ or ?"; + break; + case SH_KEYCODE::OEM_3: + return "` or ~"; + break; + case SH_KEYCODE::OEM_4: + return "[ or {"; + break; + case SH_KEYCODE::OEM_5: + return "\\ or |"; + break; + case SH_KEYCODE::OEM_6: + return "] or }"; + break; + case SH_KEYCODE::OEM_7: + return "\' or \""; + break; + case SH_KEYCODE::OEM_8: + return "OEM 8"; + break; + case SH_KEYCODE::OEM_AX: + return "OEM AX"; + break; + case SH_KEYCODE::OEM_102: + return "< or > or \\ or |"; + break; + case SH_KEYCODE::OEM_ICO_HELP: + return "ICO Help"; + break; + case SH_KEYCODE::OEM_ICO_00: + return "ICO 00"; + break; + case SH_KEYCODE::IME_PROCESS: + return "IME Process"; + break; + case SH_KEYCODE::OEM_ICO_CLEAR: + return "ICO Clear"; + break; + case SH_KEYCODE::PACKET: + return "Packet"; + break; + case SH_KEYCODE::OEM_RESET: + return "OEM Reset"; + break; + case SH_KEYCODE::OEM_JUMP: + return "OEM Jump"; + break; + case SH_KEYCODE::OEM_PA1: + return "OEM PA1"; + break; + case SH_KEYCODE::OEM_PA2: + return "OEM PA2"; + break; + case SH_KEYCODE::OEM_PA3: + return "OEM PA3"; + break; + case SH_KEYCODE::OEM_WSCTRL: + return "OEM WSCTRL"; + break; + case SH_KEYCODE::OEM_CUSEL: + return "OEM CuSel"; + break; + case SH_KEYCODE::OEM_ATTN: + return "OEM Attn"; + break; + case SH_KEYCODE::OEM_FINISH: + return "OEM Finish"; + break; + case SH_KEYCODE::OEM_COPY: + return "OEM Copy"; + break; + case SH_KEYCODE::OEM_AUTO: + return "OEM Auto"; + break; + case SH_KEYCODE::OEM_ENLW: + return "OEM ENLW"; + break; + case SH_KEYCODE::OEM_BACKTAB: + return "OEM Backtab"; + break; + case SH_KEYCODE::ATTN: + return "Attn"; + break; + case SH_KEYCODE::CRSEL: + return "CrSel"; + break; + case SH_KEYCODE::EXSEL: + return "ExSel"; + break; + case SH_KEYCODE::EREOF: + return "Erase EOF"; + break; + case SH_KEYCODE::PLAY: + return "Play"; + break; + case SH_KEYCODE::ZOOM: + return "Zoom"; + break; + case SH_KEYCODE::NONAME: + return "No Name Key"; + break; + case SH_KEYCODE::PA_1: + return "PA1"; + break; + case SH_KEYCODE::OEM_CLEAR: + return "OEM Clear"; + break; + } + } + + std::string SHInputManager::GetControllerCodeName(SH_CONTROLLERCODE c) noexcept + { + switch (c) + { + case SH_CONTROLLERCODE::DPAD_UP: + return "D-Pad Up"; + break; + case SH_CONTROLLERCODE::DPAD_DOWN: + return "D-Pad Down"; + break; + case SH_CONTROLLERCODE::DPAD_LEFT: + return "D-Pad Left"; + break; + case SH_CONTROLLERCODE::DPAD_RIGHT: + return "D-Pad Right"; + break; + case SH_CONTROLLERCODE::START: + return "Start Button"; + break; + case SH_CONTROLLERCODE::BACK: + return "Back Button"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK: + return "Left Thumbstick Button"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK: + return "Right Thumbstick Button"; + break; + case SH_CONTROLLERCODE::LEFT_SHOULDER: + return "Left Shoulder Button"; + break; + case SH_CONTROLLERCODE::RIGHT_SHOULDER: + return "Right Shoulder Button"; + break; + case SH_CONTROLLERCODE::A: + return "A Button"; + break; + case SH_CONTROLLERCODE::B: + return "B Button"; + break; + case SH_CONTROLLERCODE::X: + return "X Button"; + break; + case SH_CONTROLLERCODE::Y: + return "Y Button"; + break; + case SH_CONTROLLERCODE::LEFT_TRIGGER: + return "Left Trigger"; + break; + case SH_CONTROLLERCODE::RIGHT_TRIGGER: + return "Right Trigger"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK_X: + return "Left Thumbstick Horizontal"; + break; + case SH_CONTROLLERCODE::LEFT_THUMBSTICK_Y: + return "Left Thumbstick Vertical"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK_X: + return "Right Thumbstick Horizontal"; + break; + case SH_CONTROLLERCODE::RIGHT_THUMBSTICK_Y: + return "Right Thumbstick Vertical"; + break; + } + } + //The Binding File format presently goes as such: /* * Binding count @@ -680,7 +1149,7 @@ namespace SHADE digitalInput = true; } if (std::abs(newValue) > std::abs(largestMagnitude)) - largestMagnitude = newValue * data.sensitivity * (data.inverted ? -1.0 : 1.0); + largestMagnitude = newValue * (data.inverted ? -1.0 : 1.0); } } @@ -696,7 +1165,7 @@ namespace SHADE digitalInput = true; } if (std::abs(newValue) > std::abs(largestMagnitude)) - largestMagnitude = -newValue * data.sensitivity * (data.inverted ? -1.0 : 1.0); + largestMagnitude = -newValue * (data.inverted ? -1.0 : 1.0); } } @@ -740,21 +1209,23 @@ namespace SHADE if (data.value > 1.0) data.value = 1.0; else if (data.value < -1.0) data.value = -1.0; } - //If analog input was in, - //sensitivity is instead used as a multiplier + //If analog input was in, raw value taken else { - data.value = largestMagnitude * data.sensitivity; + data.value = largestMagnitude; if (data.value > 1.0) data.value = 1.0; else if (data.value < -1.0) data.value = -1.0; } if (data.snap) //Snapping { - if (data.value > 0.0 && data.negativeInputHeld) - data.value = 0.0; - if (data.value < 0.0 && data.positiveInputHeld) - data.value = 0.0; + if (digitalInput) //Only for digital inputs + { + if (data.value > 0.0 && data.negativeInputHeld) + data.value = 0.0; + if (data.value < 0.0 && data.positiveInputHeld) + data.value = 0.0; + } } } } @@ -936,11 +1407,11 @@ namespace SHADE { return 0.0; } - else if (bindings[bindingName].positiveInputHeld) + else if (GetBindingAxis(bindingName, cNum) > 0.0) { return 1.0; } - else if (bindings[bindingName].negativeInputHeld) + else if (GetBindingAxis(bindingName, cNum) < 0.0) { return -1.0; } diff --git a/SHADE_Engine/src/Input/SHInputManager.h b/SHADE_Engine/src/Input/SHInputManager.h index 680035c3..1bcafa7d 100644 --- a/SHADE_Engine/src/Input/SHInputManager.h +++ b/SHADE_Engine/src/Input/SHInputManager.h @@ -363,6 +363,7 @@ namespace SHADE //Speed in units per second that the axis will move toward target value for digital //For mouse movement / scrolling, serves as multiplier + //Irrelevant for other analog inputs double sensitivity = 1.0; //If enabled, axis value will reset to zero when pressing a button @@ -415,6 +416,12 @@ namespace SHADE return controllerInUse; } + //Get the name of key code + static std::string GetKeyCodeName(SH_KEYCODE const keyCode) noexcept; + + //Get the name of controller code + static std::string GetControllerCodeName(SH_CONTROLLERCODE const controllerCode) noexcept; + //For testing purposes //static void PrintCurrentState() noexcept; @@ -738,6 +745,16 @@ namespace SHADE return bindings.erase(bindingName); } + //Rename a binding + static inline void RenameBinding(std::string const& oldBindingName, std::string const& newBindingName) noexcept + { + //https://stackoverflow.com/a/44883472 + //https://en.cppreference.com/w/cpp/container/map/extract + auto nodeHandler = bindings.extract(oldBindingName); + nodeHandler.key() = newBindingName; + bindings.insert(std::move(nodeHandler)); + } + //Clears all bindings from the list static inline void ClearBindings() noexcept { @@ -809,7 +826,7 @@ namespace SHADE //Get the sensitivity of the binding //Serves as a multiplier for mouse movement/scrolling //For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative - //For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1 + //Irrelevant for other analog inputs static inline double GetBindingSensitivity(std::string const& bindingName) { return bindings[bindingName].sensitivity; @@ -818,7 +835,7 @@ namespace SHADE //Set the sensitivity of the binding //Serves as a multiplier for mouse movement/scrolling //For other digital inputs, serves as a rate of how fast axis value goes to maximum positive/negative - //For other analog inputs, serves as a multiplier, but axis value magnitude will still be capped at 1 + //Irrelevant for other analog inputs static inline void SetBindingSensitivity(std::string const& bindingName, double const newValue) { bindings[bindingName].sensitivity = newValue; @@ -984,8 +1001,6 @@ namespace SHADE //Get the axis value of binding, between -1 and 1 for non-mouse movement/wheel //For mouse movement/wheel, it won't be between -1 and 1. It will also be multiplied by sensitivity - //To avoid interference between mouse movement/wheel and keyboard/mouse/controller input, - //Set mouseXBound, mouseYBound and mouseScrollBound to false //controllerNumber is not used static double GetBindingAxis(std::string const& bindingName, size_t controllerNumber = 0) noexcept;