GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 24 / 0 / 24
Functions: 100.0% 7 / 0 / 7
Branches: 100.0% 9 / 0 / 9

include/DetourModKit/input_codes.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_INPUT_CODES_HPP
2 #define DETOURMODKIT_INPUT_CODES_HPP
3
4 /**
5 * @file input_codes.hpp
6 * @brief Unified input code types for keyboard, mouse, and gamepad inputs.
7 * @details Provides a tagged InputCode type that identifies both the device source and button/key code, along with
8 * named key resolution for human-readable configuration strings. Gamepad codes correspond to XInput button
9 * masks.
10 */
11
12 #include <cstdint>
13 #include <functional>
14 #include <optional>
15 #include <string>
16 #include <string_view>
17
18 namespace DetourModKit
19 {
20 /**
21 * @enum InputSource
22 * @brief Identifies the device type for an input code.
23 */
24 enum class InputSource : uint8_t
25 {
26 Keyboard,
27 Mouse,
28 Gamepad,
29 MouseWheel
30 };
31
32 /**
33 * @brief Converts an InputSource enum to its string representation.
34 * @param source The InputSource enum value.
35 * @return std::string_view String representation of the source.
36 */
37 9 [[nodiscard]] constexpr std::string_view input_source_to_string(InputSource source) noexcept
38 {
39
5/5
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 3 times.
✓ Branch 2 → 5 taken 2 times.
✓ Branch 2 → 6 taken 2 times.
✓ Branch 2 → 7 taken 1 time.
9 switch (source)
40 {
41 1 case InputSource::Keyboard:
42 1 return "Keyboard";
43 3 case InputSource::Mouse:
44 3 return "Mouse";
45 2 case InputSource::Gamepad:
46 2 return "Gamepad";
47 2 case InputSource::MouseWheel:
48 2 return "MouseWheel";
49 }
50 1 return "Unknown";
51 }
52
53 /**
54 * @struct InputCode
55 * @brief A tagged input identifier combining a device source and a button/key code.
56 * @details For Keyboard and Mouse sources, the code is a Windows Virtual Key code (usable with GetAsyncKeyState).
57 * For Gamepad, the code is an XInput button bitmask or a synthetic trigger identifier (see GamepadCode).
58 * For MouseWheel, the code is a WheelCode direction identifier; the wheel is an event with no polled key
59 * state, so it is captured by the input layer's window-procedure hook and surfaced as a momentary
60 * per-direction pulse (trigger-only, never a held modifier).
61 */
62 struct InputCode
63 {
64 764 InputSource source = InputSource::Keyboard;
65 304 int code = 0;
66
67
4/4
✓ Branch 2 → 3 taken 460 times.
✓ Branch 2 → 4 taken 304 times.
✓ Branch 4 → 5 taken 95 times.
✓ Branch 4 → 6 taken 209 times.
764 constexpr bool operator==(const InputCode &) const noexcept = default;
68 };
69
70 /**
71 * @brief Hash functor for InputCode, enabling use in unordered containers.
72 */
73 struct InputCodeHash
74 {
75 4727 std::size_t operator()(const InputCode &ic) const noexcept
76 {
77 4727 return std::hash<int>{}(ic.code) ^ (std::hash<uint8_t>{}(static_cast<uint8_t>(ic.source)) << 16);
78 }
79 };
80
81 /**
82 * @brief Creates a keyboard InputCode from a Windows Virtual Key code.
83 * @param vk The VK code (e.g., 0x41 for 'A').
84 * @return InputCode Tagged as Keyboard.
85 */
86 1424 [[nodiscard]] constexpr InputCode keyboard_key(int vk) noexcept
87 {
88 1424 return {InputSource::Keyboard, vk};
89 }
90
91 /**
92 * @brief Creates a mouse InputCode from a Windows Virtual Key code.
93 * @param vk The VK code (e.g., 0x01 for VK_LBUTTON).
94 * @return InputCode Tagged as Mouse.
95 */
96 10 [[nodiscard]] constexpr InputCode mouse_button(int vk) noexcept
97 {
98 10 return {InputSource::Mouse, vk};
99 }
100
101 /**
102 * @brief Creates a gamepad InputCode from an XInput button code.
103 * @param code The XInput button mask or synthetic trigger code (see GamepadCode).
104 * @return InputCode Tagged as Gamepad.
105 */
106 29 [[nodiscard]] constexpr InputCode gamepad_button(int code) noexcept
107 {
108 29 return {InputSource::Gamepad, code};
109 }
110
111 /**
112 * @brief Creates a mouse-wheel InputCode from a wheel direction code.
113 * @param code The wheel direction identifier (see WheelCode).
114 * @return InputCode Tagged as MouseWheel.
115 */
116 11 [[nodiscard]] constexpr InputCode mouse_wheel(int code) noexcept
117 {
118 11 return {InputSource::MouseWheel, code};
119 }
120
121 /**
122 * @namespace GamepadCode
123 * @brief XInput-compatible gamepad button codes and synthetic analog identifiers.
124 * @details Digital button codes match XInput XINPUT_GAMEPAD_* bitmask values. LeftTrigger/RightTrigger and
125 * thumbstick direction codes are synthetic identifiers for analog inputs treated as digital with
126 * configurable deadzone thresholds.
127 */
128 namespace GamepadCode
129 {
130 inline constexpr int DpadUp = 0x0001;
131 inline constexpr int DpadDown = 0x0002;
132 inline constexpr int DpadLeft = 0x0004;
133 inline constexpr int DpadRight = 0x0008;
134 inline constexpr int Start = 0x0010;
135 inline constexpr int Back = 0x0020;
136 inline constexpr int LeftStick = 0x0040;
137 inline constexpr int RightStick = 0x0080;
138 inline constexpr int LeftBumper = 0x0100;
139 inline constexpr int RightBumper = 0x0200;
140 inline constexpr int A = 0x1000;
141 inline constexpr int B = 0x2000;
142 inline constexpr int X = 0x4000;
143 inline constexpr int Y = 0x8000;
144
145 /// Synthetic codes for analog triggers treated as digital inputs.
146 inline constexpr int LeftTrigger = 0x10000;
147 inline constexpr int RightTrigger = 0x10001;
148
149 /**
150 * @brief Synthetic codes for thumbstick axes treated as digital inputs.
151 * @details Each direction fires when the axis exceeds the stick deadzone threshold.
152 */
153 inline constexpr int LeftStickUp = 0x10002;
154 inline constexpr int LeftStickDown = 0x10003;
155 inline constexpr int LeftStickLeft = 0x10004;
156 inline constexpr int LeftStickRight = 0x10005;
157 inline constexpr int RightStickUp = 0x10006;
158 inline constexpr int RightStickDown = 0x10007;
159 inline constexpr int RightStickLeft = 0x10008;
160 inline constexpr int RightStickRight = 0x10009;
161
162 /// Default analog trigger threshold (0-255 range, values above are "pressed").
163 inline constexpr int TriggerThreshold = 30;
164
165 /**
166 * @brief Default thumbstick deadzone threshold (0-32767 range).
167 * @details Matches XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE (7849).
168 */
169 inline constexpr int StickThreshold = 7849;
170 } // namespace GamepadCode
171
172 /**
173 * @namespace WheelCode
174 * @brief Mouse-wheel direction identifiers used by InputSource::MouseWheel codes.
175 * @details Values are 1-based and dense so the input layer can map a code to a zero-based direction index with
176 * `code - WheelCode::Up`. Up/Down are the vertical wheel; Left/Right are the horizontal (tilt) wheel.
177 */
178 namespace WheelCode
179 {
180 inline constexpr int Up = 1;
181 inline constexpr int Down = 2;
182 inline constexpr int Left = 3;
183 inline constexpr int Right = 4;
184 } // namespace WheelCode
185
186 /**
187 * @brief Attempts to resolve a human-readable name to an InputCode.
188 * @details Performs case-insensitive matching against a built-in table of known key, mouse button, and gamepad
189 * button names.
190 *
191 * Recognized name formats:
192 * - Keyboard: "A"-"Z", "0"-"9", "F1"-"F24", "Ctrl", "Shift", "Alt",
193 * "Space", "Enter", "Escape", "Tab", "Backspace", Windows/menu keys ("LWin", "RWin", "Apps"), and OEM
194 * punctuation ("Grave"/"Backtick"/"Tilde", "Semicolon", "Comma", "Period", "Slash", etc.)
195 * - Mouse: "Mouse1" (left) through "Mouse5" (XButton2)
196 * - Mouse wheel: "WheelUp", "WheelDown", "WheelLeft", "WheelRight"
197 * - Gamepad: "Gamepad_A", "Gamepad_B", "Gamepad_LB", "Gamepad_LT", etc.
198 * - Source-tagged hex (the inverse of format_input_code's off-table form): "Mouse:0xFE",
199 * "Gamepad:0x800", "MouseWheel:0x9", "Keyboard:0xFF".
200 *
201 * @param name The input name to resolve.
202 * @return std::optional<InputCode> The resolved code, or std::nullopt if unrecognized.
203 */
204 [[nodiscard]] std::optional<InputCode> parse_input_name(std::string_view name);
205
206 /**
207 * @brief Returns a human-readable name for an InputCode, if one exists.
208 * @param code The input code to look up.
209 * @return std::string_view The canonical name, or an empty view if not in the table.
210 */
211 [[nodiscard]] std::string_view input_code_to_name(const InputCode &code);
212
213 /**
214 * @brief Formats an InputCode as a human-readable string.
215 * @details Returns the canonical name if the code is in the lookup table. Off-table codes fall back to hex: a
216 * Keyboard code emits bare hex ("0x72"), while any other source is tagged with its device name
217 * ("Mouse:0xFE", "Gamepad:0x800") so the source is not lost and parse_input_name can reconstruct the same
218 * code on a config round-trip. Untagged bare hex always parses back as Keyboard.
219 * @param code The input code to format.
220 * @return std::string Formatted string.
221 */
222 [[nodiscard]] std::string format_input_code(const InputCode &code);
223
224 } // namespace DetourModKit
225
226 #endif // DETOURMODKIT_INPUT_CODES_HPP
227