Merge pull request #6040 from german77/toggleKeyboard
Enable toggle buttons for keyboard and mouse
This commit is contained in:
		| @@ -12,20 +12,39 @@ namespace InputCommon { | ||||
|  | ||||
| class KeyButton final : public Input::ButtonDevice { | ||||
| public: | ||||
|     explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) | ||||
|         : key_button_list(std::move(key_button_list_)) {} | ||||
|     explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_) | ||||
|         : key_button_list(std::move(key_button_list_)), toggle(toggle_) {} | ||||
|  | ||||
|     ~KeyButton() override; | ||||
|  | ||||
|     bool GetStatus() const override { | ||||
|         if (toggle) { | ||||
|             return toggled_status.load(std::memory_order_relaxed); | ||||
|         } | ||||
|         return status.load(); | ||||
|     } | ||||
|  | ||||
|     void ToggleButton() { | ||||
|         if (lock) { | ||||
|             return; | ||||
|         } | ||||
|         lock = true; | ||||
|         const bool old_toggle_status = toggled_status.load(); | ||||
|         toggled_status.store(!old_toggle_status); | ||||
|     } | ||||
|  | ||||
|     void UnlockButton() { | ||||
|         lock = false; | ||||
|     } | ||||
|  | ||||
|     friend class KeyButtonList; | ||||
|  | ||||
| private: | ||||
|     std::shared_ptr<KeyButtonList> key_button_list; | ||||
|     std::atomic<bool> status{false}; | ||||
|     std::atomic<bool> toggled_status{false}; | ||||
|     bool lock{false}; | ||||
|     const bool toggle; | ||||
| }; | ||||
|  | ||||
| struct KeyButtonPair { | ||||
| @@ -51,6 +70,11 @@ public: | ||||
|         for (const KeyButtonPair& pair : list) { | ||||
|             if (pair.key_code == key_code) { | ||||
|                 pair.key_button->status.store(pressed); | ||||
|                 if (pressed) { | ||||
|                     pair.key_button->ToggleButton(); | ||||
|                 } else { | ||||
|                     pair.key_button->UnlockButton(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -75,7 +99,8 @@ KeyButton::~KeyButton() { | ||||
|  | ||||
| std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { | ||||
|     const int key_code = params.Get("code", 0); | ||||
|     std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); | ||||
|     const bool toggle = params.Get("toggle", false); | ||||
|     std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle); | ||||
|     key_button_list->AddKeyButton(key_code, button.get()); | ||||
|     return button; | ||||
| } | ||||
|   | ||||
| @@ -162,6 +162,42 @@ void Mouse::EndConfiguration() { | ||||
|     configuring = false; | ||||
| } | ||||
|  | ||||
| bool Mouse::ToggleButton(std::size_t button_) { | ||||
|     if (button_ >= mouse_info.size()) { | ||||
|         return false; | ||||
|     } | ||||
|     const auto button = 1U << button_; | ||||
|     const bool button_state = (toggle_buttons & button) != 0; | ||||
|     const bool button_lock = (lock_buttons & button) != 0; | ||||
|  | ||||
|     if (button_lock) { | ||||
|         return button_state; | ||||
|     } | ||||
|  | ||||
|     lock_buttons |= static_cast<u16>(button); | ||||
|  | ||||
|     if (button_state) { | ||||
|         toggle_buttons &= static_cast<u16>(0xFF - button); | ||||
|     } else { | ||||
|         toggle_buttons |= static_cast<u16>(button); | ||||
|     } | ||||
|  | ||||
|     return !button_state; | ||||
| } | ||||
|  | ||||
| bool Mouse::UnlockButton(std::size_t button_) { | ||||
|     if (button_ >= mouse_info.size()) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     const auto button = 1U << button_; | ||||
|     const bool button_state = (toggle_buttons & button) != 0; | ||||
|  | ||||
|     lock_buttons &= static_cast<u16>(0xFF - button); | ||||
|  | ||||
|     return button_state; | ||||
| } | ||||
|  | ||||
| Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { | ||||
|     return mouse_queue; | ||||
| } | ||||
|   | ||||
| @@ -69,6 +69,9 @@ public: | ||||
|      */ | ||||
|     void ReleaseButton(MouseButton button_); | ||||
|  | ||||
|     [[nodiscard]] bool ToggleButton(std::size_t button_); | ||||
|     [[nodiscard]] bool UnlockButton(std::size_t button_); | ||||
|  | ||||
|     [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); | ||||
|     [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; | ||||
|  | ||||
| @@ -94,6 +97,8 @@ private: | ||||
|     }; | ||||
|  | ||||
|     u16 buttons{}; | ||||
|     u16 toggle_buttons{}; | ||||
|     u16 lock_buttons{}; | ||||
|     std::thread update_thread; | ||||
|     MouseButton last_button{MouseButton::Undefined}; | ||||
|     std::array<MouseInfo, 7> mouse_info; | ||||
|   | ||||
| @@ -14,16 +14,25 @@ namespace InputCommon { | ||||
|  | ||||
| class MouseButton final : public Input::ButtonDevice { | ||||
| public: | ||||
|     explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_) | ||||
|         : button(button_), mouse_input(mouse_input_) {} | ||||
|     explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_) | ||||
|         : button(button_), toggle(toggle_), mouse_input(mouse_input_) {} | ||||
|  | ||||
|     bool GetStatus() const override { | ||||
|         return mouse_input->GetMouseState(button).pressed; | ||||
|         const bool button_state = mouse_input->GetMouseState(button).pressed; | ||||
|         if (!toggle) { | ||||
|             return button_state; | ||||
|         } | ||||
|  | ||||
|         if (button_state) { | ||||
|             return mouse_input->ToggleButton(button); | ||||
|         } | ||||
|         return mouse_input->UnlockButton(button); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const u32 button; | ||||
|     const MouseInput::Mouse* mouse_input; | ||||
|     const bool toggle; | ||||
|     MouseInput::Mouse* mouse_input; | ||||
| }; | ||||
|  | ||||
| MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) | ||||
| @@ -32,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_ | ||||
| std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( | ||||
|     const Common::ParamPackage& params) { | ||||
|     const auto button_id = params.Get("button", 0); | ||||
|     const auto toggle = params.Get("toggle", false); | ||||
|  | ||||
|     return std::make_unique<MouseButton>(button_id, mouse_input.get()); | ||||
|     return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get()); | ||||
| } | ||||
|  | ||||
| Common::ParamPackage MouseButtonFactory::GetNextInput() const { | ||||
|   | ||||
| @@ -376,11 +376,15 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { | ||||
| } | ||||
|  | ||||
| void GRenderWindow::keyPressEvent(QKeyEvent* event) { | ||||
|     input_subsystem->GetKeyboard()->PressKey(event->key()); | ||||
|     if (!event->isAutoRepeat()) { | ||||
|         input_subsystem->GetKeyboard()->PressKey(event->key()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { | ||||
|     input_subsystem->GetKeyboard()->ReleaseKey(event->key()); | ||||
|     if (!event->isAutoRepeat()) { | ||||
|         input_subsystem->GetKeyboard()->ReleaseKey(event->key()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { | ||||
|   | ||||
| @@ -105,7 +105,9 @@ QString ButtonToText(const Common::ParamPackage& param) { | ||||
|     } | ||||
|  | ||||
|     if (param.Get("engine", "") == "keyboard") { | ||||
|         return GetKeyName(param.Get("code", 0)); | ||||
|         const QString button_str = GetKeyName(param.Get("code", 0)); | ||||
|         const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); | ||||
|         return QObject::tr("%1%2").arg(toggle, button_str); | ||||
|     } | ||||
|  | ||||
|     if (param.Get("engine", "") == "gcpad") { | ||||
| @@ -157,7 +159,8 @@ QString ButtonToText(const Common::ParamPackage& param) { | ||||
|     if (param.Get("engine", "") == "mouse") { | ||||
|         if (param.Has("button")) { | ||||
|             const QString button_str = QString::number(int(param.Get("button", 0))); | ||||
|             return QObject::tr("Click %1").arg(button_str); | ||||
|             const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); | ||||
|             return QObject::tr("%1Click %2").arg(toggle, button_str); | ||||
|         } | ||||
|         return GetKeyName(param.Get("code", 0)); | ||||
|     } | ||||
| @@ -301,6 +304,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                         buttons_param[button_id].Clear(); | ||||
|                         button_map[button_id]->setText(tr("[not set]")); | ||||
|                     }); | ||||
|                     context_menu.addAction(tr("Toggle button"), [&] { | ||||
|                         const bool toggle_value = !buttons_param[button_id].Get("toggle", false); | ||||
|                         buttons_param[button_id].Set("toggle", toggle_value); | ||||
|                         button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | ||||
|                     }); | ||||
|                     context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); | ||||
|                     ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); | ||||
|                 }); | ||||
| @@ -413,6 +421,15 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                         analogs_param[analog_id].Set("modifier", ""); | ||||
|                         analog_map_modifier_button[analog_id]->setText(tr("[not set]")); | ||||
|                     }); | ||||
|                     context_menu.addAction(tr("Toggle button"), [&] { | ||||
|                         Common::ParamPackage modifier_param = | ||||
|                             Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")}; | ||||
|                         const bool toggle_value = !modifier_param.Get("toggle", false); | ||||
|                         modifier_param.Set("toggle", toggle_value); | ||||
|                         analogs_param[analog_id].Set("modifier", modifier_param.Serialize()); | ||||
|                         analog_map_modifier_button[analog_id]->setText( | ||||
|                             ButtonToText(modifier_param)); | ||||
|                     }); | ||||
|                     context_menu.exec( | ||||
|                         analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); | ||||
|                 }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user