💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
5.3 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_INPUT_GAMEPAD_HPP
  20. #define ANTKEEPER_INPUT_GAMEPAD_HPP
  21. #include "input/device.hpp"
  22. #include "input/input-events.hpp"
  23. #include "input/gamepad-axis.hpp"
  24. #include "input/gamepad-button.hpp"
  25. #include "event/publisher.hpp"
  26. namespace input {
  27. /// Gamepad axis activation response curves.
  28. enum class gamepad_response_curve
  29. {
  30. /// Linear response curve.
  31. linear,
  32. /// Squared response curve.
  33. square,
  34. /// Cubed response curve.
  35. cube
  36. };
  37. /**
  38. * A virtual gamepad which generates gamepad-related input events.
  39. */
  40. class gamepad: public device
  41. {
  42. public:
  43. /**
  44. * Constructs a gamepad input device.
  45. */
  46. gamepad();
  47. /// Destructs a gamepad input device.
  48. virtual ~gamepad() = default;
  49. /**
  50. * Sets the activation threshold for a gamepad axis.
  51. *
  52. * @param axis Gamepad axis.
  53. * @param min Axis minimum activation threshold.
  54. * @param max Axis maximum activation threshold.
  55. */
  56. void set_activation_threshold(gamepad_axis axis, float min, float max);
  57. /**
  58. * Sets the activation response curve of an axis.
  59. *
  60. * @param axis Gamepad axis.
  61. * @param curve Activation response curve.
  62. */
  63. void set_response_curve(gamepad_axis axis, gamepad_response_curve curve);
  64. /**
  65. * Sets the type of deadzone shape for the axes on the left stick.
  66. *
  67. * @param cross If `true`, the x and y axes are independently activated, if `false`, activation of the x and y axes are dependent on their combined magnitude.
  68. */
  69. void set_left_deadzone_cross(bool cross);
  70. /**
  71. * Sets the type of deadzone shape for the axes on the right stick.
  72. *
  73. * @param cross If `true`, the x and y axes are independently activated, if `false`, activation of the x and y axes are dependent on their combined magnitude.
  74. */
  75. void set_right_deadzone_cross(bool cross);
  76. /**
  77. * Sets the roundness of the deadzone for the axes on the left stick.
  78. *
  79. * @param roundness Roundness of the deadzone shape for non-cross deadzones. A value of `0.0` results in a square deadzone, while a value of `1.0` results in a circular deadzone. Values between `0.0` and `1.0` result in a rounded rectangle deadzone.
  80. */
  81. void set_left_deadzone_roundness(float roundness);
  82. /**
  83. * Sets the roundness of the deadzone for the axes on the right stick.
  84. *
  85. * @param roundness Roundness of the deadzone shape for non-cross deadzones. A value of `0.0` results in a square deadzone, while a value of `1.0` results in a circular deadzone. Values between `0.0` and `1.0` result in a rounded rectangle deadzone.
  86. */
  87. void set_right_deadzone_roundness(float roundness);
  88. /**
  89. * Simulates a gamepad button press.
  90. *
  91. * @param button Button to press.
  92. */
  93. void press(gamepad_button button);
  94. /**
  95. * Simulates a gamepad button release.
  96. *
  97. * @param button Button to release.
  98. */
  99. void release(gamepad_button button);
  100. /**
  101. * Simulates a gamepad axis movement.
  102. *
  103. * @param axis Gamepad axis.
  104. * @param position Position on the axis, on `[-1, 1]`.
  105. */
  106. void move(gamepad_axis axis, float position);
  107. /// Returns the channel through which gamepad button pressed events are published.
  108. [[nodiscard]] inline ::event::channel<gamepad_button_pressed_event>& get_button_pressed_channel() noexcept
  109. {
  110. return button_pressed_publisher.channel();
  111. }
  112. /// Returns the channel through which gamepad button released events are published.
  113. [[nodiscard]] inline ::event::channel<gamepad_button_released_event>& get_button_released_channel() noexcept
  114. {
  115. return button_released_publisher.channel();
  116. }
  117. /// Returns the channel through which gamepad axis moved events are published.
  118. [[nodiscard]] inline ::event::channel<gamepad_axis_moved_event>& get_axis_moved_channel() noexcept
  119. {
  120. return axis_moved_publisher.channel();
  121. }
  122. /// Returns device_type::gamepad.
  123. [[nodiscard]] inline virtual constexpr device_type get_device_type() const noexcept
  124. {
  125. return device_type::gamepad;
  126. }
  127. private:
  128. void handle_axial_motion(gamepad_axis axis);
  129. void handle_biaxial_motion(gamepad_axis axis_x, gamepad_axis axis_y);
  130. float curve_response(gamepad_axis axis, float response) const;
  131. float axis_positions[6];
  132. float axis_activation_min[6];
  133. float axis_activation_max[6];
  134. gamepad_response_curve axis_response_curves[6];
  135. bool left_deadzone_cross;
  136. bool right_deadzone_cross;
  137. float left_deadzone_roundness;
  138. float right_deadzone_roundness;
  139. ::event::publisher<gamepad_button_pressed_event> button_pressed_publisher;
  140. ::event::publisher<gamepad_button_released_event> button_released_publisher;
  141. ::event::publisher<gamepad_axis_moved_event> axis_moved_publisher;
  142. };
  143. } // namespace input
  144. #endif // ANTKEEPER_INPUT_GAMEPAD_HPP