Skip to main content

GLFWInputAdapter.ixx File

GLFW-based InputAdapter implementation. More...

Included Headers

#include <GLFW/glfw3.h> #include <array> #include <memory> #include <format> #include <stdexcept> #include <utility> #include <cmath> #include <helios.ext.glfw.window.GLFWWindow> #include <helios.ext.glfw.input.GLFWGamepadLookup> #include <helios.input.gamepad.GamepadSettings> #include <helios.input.types.Key> #include <helios.ext.glfw.input.GLFWKeyLookup> #include <helios.input.types.Gamepad> #include <helios.input.InputAdapter> #include <helios.input.gamepad.DeadzoneStrategy> #include <helios.window.Window> #include <helios.input.gamepad.GamepadState>

Namespaces Index

namespacehelios
namespaceext

Platform-specific extensions and backend implementations. More...

namespaceglfw

GLFW-specific implementations. More...

namespaceinput

GLFW input handling. More...

Classes Index

classGLFWInputAdapter

InputAdapter implementation for a GLFWWindow. More...

Description

GLFW-based InputAdapter implementation.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file GLFWInputAdapter.ixx
3 * @brief GLFW-based InputAdapter implementation.
4 */
5module;
6
7#include <GLFW/glfw3.h>
8#include <array>
9#include <memory>
10#include <format>
11#include <stdexcept>
12#include <utility>
13#include <cmath>
14
15export module helios.ext.glfw.input.GLFWInputAdapter;
16
17import helios.input.gamepad.GamepadState;
18import helios.input.gamepad.DeadzoneStrategy;
19import helios.input.InputAdapter;
20import helios.input.types.Gamepad;
21import helios.window.Window;
22import helios.input.types.Key;
23import helios.input.gamepad.GamepadSettings;
24
25import helios.ext.glfw.input.GLFWKeyLookup;
26import helios.ext.glfw.input.GLFWGamepadLookup;
27import helios.ext.glfw.window.GLFWWindow;
28
29export namespace helios::ext::glfw::input {
30
31 /**
32 * @brief InputAdapter implementation for a GLFWWindow.
33 *
34 * This class translates generic input queries into GLFW-specific API calls.
35 * Input queries are always executed against a GLFWWindow instance, which is to
36 * be specified by the caller.
37 *
38 * The adapter applies the configured `DeadzoneStrategy` and `GamepadSettings`
39 * during gamepad state updates to normalize analog stick input and handle
40 * axis inversion.
41 *
42 * @see InputAdapter for the abstract interface.
43 * @see GamepadSettings for per-controller configuration.
44 * @see DeadzoneStrategy for input normalization strategies.
45 */
47
48
49
50 private:
51 /**
52 * @brief Array storing the current state of each connected gamepad.
53 *
54 * Indexed by gamepad ID, each entry holds the most recently polled
55 * button and axis states for that controller.
56 */
57 std::array<helios::input::gamepad::GamepadState, std::to_underlying(helios::input::types::Gamepad::size_)> gamepadStates_= {};
58
59 public:
60
61 /**
62 * @brief Constructs a GLFWInputAdapter with the specified deadzone strategy.
63 *
64 * @param deadzoneStrategy The strategy used for analog stick normalization.
65 * Ownership is transferred to the base InputAdapter.
66 */
67 GLFWInputAdapter(std::unique_ptr<helios::input::gamepad::DeadzoneStrategy> deadzoneStrategy) :
68 helios::input::InputAdapter(std::move(deadzoneStrategy))
69 {}
70
71 /**
72 * @brief Checks if a specific key is currently pressed for the given window.
73 * If the specified window is not of type GLFWWindow, this method always returns false.
74 *
75 * @copydoc helios::input::InputAdapter::isKeyPressed()
76 */
77 [[nodiscard]] bool isKeyPressed(helios::input::types::Key key,
78 const helios::window::Window& win) const noexcept override {
79 auto const* win_ptr = dynamic_cast<helios::ext::glfw::window::GLFWWindow const*>(&win);
80
81 if (!win_ptr) {
82 logger_.warn("GLFWInput requires GLFWWindow");
83 return false;
84 }
85
86 return isKeyPressed(key, *win_ptr);
87 }
88
89 /**
90 * @brief Checks if a specific key is currently released for the given window.
91 *
92 * If the specified window is not of type GLFWWindow, this method always returns false.
93 *
94 * @copydoc helios::input::InputAdapter::isKeyReleased()
95 */
97 const helios::window::Window& win) const noexcept override {
98 auto const* win_ptr = dynamic_cast<helios::ext::glfw::window::GLFWWindow const*>(&win);
99
100 if (!win_ptr) {
101 logger_.warn("GLFWInput requires GLFWWindow");
102 return false;
103 }
104
105 return isKeyReleased(key, *win_ptr);
106 }
107
108 /**
109 * @brief Checks if a specific key is currently pressed for the given GLFWWindow.
110 *
111 * @param key The helios key to check.
112 * @param win The `GLFWWindow` instance to query for the key-press.
113 *
114 * @return true if the key is pressed, otherwise false.
115 */
117 const helios::ext::glfw::window::GLFWWindow& win) const noexcept {
118 return glfwGetKey(
119 win.nativeHandle(),
121 ) == GLFW_PRESS;
122 }
123
124 /**
125 * @brief Checks if a specific key is currently released for the given GLFWWindow.
126 *
127 * @param key The helios key to check.
128 * @param win The `GLFWWindow` instance to query for the key-release.
129 *
130 * @return true if the key is released, otherwise false.
131 */
133 const helios::ext::glfw::window::GLFWWindow& win) const noexcept {
134 return glfwGetKey(
135 win.nativeHandle(),
137 ) == GLFW_RELEASE;
138 }
139
140 /**
141 * @copydoc helios::input::InputAdapter::gamepadState()
142 */
144 helios::input::types::Gamepad gamepadId) const noexcept override {
145 return gamepadStates_[
147 ];
148 }
149
150 /**
151 * @copydoc helios::input::InputAdapter::updateGamepadState()
152 */
153 void updateGamepadState(unsigned int gamepadMask) noexcept override {
154 int index = 0;
155 while (gamepadMask != 0) {
156
157 unsigned int id = gamepadMask & 1;
158
159 if (id) {
160 // update gamepad
161 const auto gamepadId = static_cast<helios::input::types::Gamepad>(static_cast<unsigned int>(std::pow(2, index)));
162
163 int glfwGamepadId = helios::ext::glfw::input::GLFWGamepadLookup::from(gamepadId);
164
165 auto& gamepadSettings = InputAdapter::gamepadSettings(gamepadId);
166
167
168 if (glfwJoystickIsGamepad(glfwGamepadId)) {
169 GLFWgamepadstate state;
170 glfwGetGamepadState(glfwGamepadId, &state);
171
172 const float* axes = state.axes;
173 const unsigned char* buttons = state.buttons;
174
175 // left stick
176 float leftX = (gamepadSettings.invertLeftX() ? -1.0f : 1.0f) * axes[GLFW_GAMEPAD_AXIS_LEFT_X];
177 // invert left Y, glfw uses down:1, up:-1, we need down:-1, up:1
178 float leftY = (gamepadSettings.invertLeftY() ? -1.0f : 1.0f) * -axes[GLFW_GAMEPAD_AXIS_LEFT_Y];
179 deadzoneStrategy_->normalize(gamepadSettings.leftStickDeadzone(), leftX, leftY);
180
181 // right stick
182 float rightX = (gamepadSettings.invertRightX() ? -1.0f : 1.0f) * axes[GLFW_GAMEPAD_AXIS_RIGHT_X];
183 // invert right Y, same logic as left Y
184 float rightY = (gamepadSettings.invertRightY() ? -1.0f : 1.0f) * -axes[GLFW_GAMEPAD_AXIS_RIGHT_Y];
185 deadzoneStrategy_->normalize(gamepadSettings.rightStickDeadzone(), rightX, rightY);
186
187 gamepadStates_[index].updateAxes(
188 leftX,
189 leftY,
190 rightX,
191 rightY,
192 // normalize trigger values, since glfw returns them in the range
193 // [-1, 1]
194 axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER]/2 + 0.5f ,
195 axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER]/2 + 0.5f,
196
197 // button section
198 !!buttons[GLFW_GAMEPAD_BUTTON_A],
199 !!buttons[GLFW_GAMEPAD_BUTTON_B],
200 !!buttons[GLFW_GAMEPAD_BUTTON_X],
201 !!buttons[GLFW_GAMEPAD_BUTTON_Y],
202 !!buttons[GLFW_GAMEPAD_BUTTON_START],
203 !!buttons[GLFW_GAMEPAD_BUTTON_BACK],
204 !!buttons[GLFW_GAMEPAD_BUTTON_GUIDE],
205 !!buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER],
206 !!buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER],
207 !!buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB],
208 !!buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB],
209 !!buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP],
210 !!buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT],
211 !!buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN],
212 !!buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]
213 );
214
215 } else {
216 // could also be a reset() method in GamepadState-object,
217 // but since we use it only once a manual assignment will do for now
218 gamepadStates_[index].updateAxes(
219 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
220 false, false, false, false, false,
221 false, false, false, false,
222 false, false, false, false,
223 false, false
224
225 );
226 }
227
228 } // if id
229
230 index++;
231 gamepadMask >>= 1;
232 }
233 }
234
235 /**
236 * @copydoc helios::input::InputAdapter::isConnected()
237 */
238 [[nodiscard]] bool isConnected(
239 helios::input::types::Gamepad gamepadId) const noexcept override {
240 const int glfwGamepadId = helios::ext::glfw::input::GLFWGamepadLookup::from(gamepadId);
241 return glfwJoystickPresent(glfwGamepadId) != 0;
242 }
243 };
244
245
246}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.