keyboard.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <atomic>
  5. #include <list>
  6. #include <mutex>
  7. #include <utility>
  8. #include "input_common/keyboard.h"
  9. namespace InputCommon {
  10. class KeyButton final : public Input::ButtonDevice {
  11. public:
  12. explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_)
  13. : key_button_list(std::move(key_button_list_)), toggle(toggle_) {}
  14. ~KeyButton() override;
  15. bool GetStatus() const override {
  16. if (toggle) {
  17. return toggled_status.load(std::memory_order_relaxed);
  18. }
  19. return status.load();
  20. }
  21. void ToggleButton() {
  22. if (lock) {
  23. return;
  24. }
  25. lock = true;
  26. const bool old_toggle_status = toggled_status.load();
  27. toggled_status.store(!old_toggle_status);
  28. }
  29. void UnlockButton() {
  30. lock = false;
  31. }
  32. friend class KeyButtonList;
  33. private:
  34. std::shared_ptr<KeyButtonList> key_button_list;
  35. std::atomic<bool> status{false};
  36. std::atomic<bool> toggled_status{false};
  37. bool lock{false};
  38. const bool toggle;
  39. };
  40. struct KeyButtonPair {
  41. int key_code;
  42. KeyButton* key_button;
  43. };
  44. class KeyButtonList {
  45. public:
  46. void AddKeyButton(int key_code, KeyButton* key_button) {
  47. std::lock_guard guard{mutex};
  48. list.push_back(KeyButtonPair{key_code, key_button});
  49. }
  50. void RemoveKeyButton(const KeyButton* key_button) {
  51. std::lock_guard guard{mutex};
  52. list.remove_if(
  53. [key_button](const KeyButtonPair& pair) { return pair.key_button == key_button; });
  54. }
  55. void ChangeKeyStatus(int key_code, bool pressed) {
  56. std::lock_guard guard{mutex};
  57. for (const KeyButtonPair& pair : list) {
  58. if (pair.key_code == key_code) {
  59. pair.key_button->status.store(pressed);
  60. if (pressed) {
  61. pair.key_button->ToggleButton();
  62. } else {
  63. pair.key_button->UnlockButton();
  64. }
  65. pair.key_button->TriggerOnChange();
  66. }
  67. }
  68. }
  69. void ChangeAllKeyStatus(bool pressed) {
  70. std::lock_guard guard{mutex};
  71. for (const KeyButtonPair& pair : list) {
  72. pair.key_button->status.store(pressed);
  73. }
  74. }
  75. private:
  76. std::mutex mutex;
  77. std::list<KeyButtonPair> list;
  78. };
  79. Keyboard::Keyboard() : key_button_list{std::make_shared<KeyButtonList>()} {}
  80. KeyButton::~KeyButton() {
  81. key_button_list->RemoveKeyButton(this);
  82. }
  83. std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) {
  84. const int key_code = params.Get("code", 0);
  85. const bool toggle = params.Get("toggle", false);
  86. std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle);
  87. key_button_list->AddKeyButton(key_code, button.get());
  88. return button;
  89. }
  90. void Keyboard::PressKey(int key_code) {
  91. key_button_list->ChangeKeyStatus(key_code, true);
  92. }
  93. void Keyboard::ReleaseKey(int key_code) {
  94. key_button_list->ChangeKeyStatus(key_code, false);
  95. }
  96. void Keyboard::ReleaseAllKeys() {
  97. key_button_list->ChangeAllKeyStatus(false);
  98. }
  99. } // namespace InputCommon