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

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 Tagged input codes for keyboard, mouse, mouse-wheel, and gamepad inputs, with named-key resolution.
7 * @details Each PascalCase constant in GamepadCode and WheelCode also has an UPPER_SNAKE_CASE spelling with the same
8 * value. Both spellings are public API.
9 */
10
11 #include <cstdint>
12 #include <functional>
13 #include <optional>
14 #include <string>
15 #include <string_view>
16
17 namespace DetourModKit
18 {
19 /** @brief Identifies the device type for an input code. */
20 enum class InputSource : std::uint8_t
21 {
22 Keyboard,
23 Mouse,
24 Gamepad,
25 MouseWheel
26 };
27
28 /** @brief Returns the enumerator name of @p source, or "Unknown" for a value outside the enum. */
29 9 [[nodiscard]] constexpr std::string_view input_source_to_string(InputSource source) noexcept
30 {
31
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)
32 {
33 1 case InputSource::Keyboard:
34 1 return "Keyboard";
35 3 case InputSource::Mouse:
36 3 return "Mouse";
37 2 case InputSource::Gamepad:
38 2 return "Gamepad";
39 2 case InputSource::MouseWheel:
40 2 return "MouseWheel";
41 }
42 1 return "Unknown";
43 }
44
45 /**
46 * @brief A tagged input identifier: a device source and a button or key code.
47 * @details A Keyboard or Mouse code is a Windows virtual-key code, usable with GetAsyncKeyState. A Gamepad code is
48 * an XInput button bitmask or a synthetic GamepadCode identifier. A MouseWheel code is a WheelCode
49 * direction. It fires at most one momentary pulse per whole notch of queue-delivered wheel input and
50 * never acts as a held modifier. `input::Input::WheelBackend` documents the capture scope.
51 */
52 struct InputCode
53 {
54 1544 InputSource source = InputSource::Keyboard;
55 1024 int code = 0;
56
57
4/4
✓ Branch 2 → 3 taken 520 times.
✓ Branch 2 → 4 taken 1024 times.
✓ Branch 4 → 5 taken 163 times.
✓ Branch 4 → 6 taken 861 times.
1544 constexpr bool operator==(const InputCode &) const noexcept = default;
58 };
59
60 /** @brief Hash functor for InputCode keys in unordered containers. */
61 struct InputCodeHash
62 {
63 5830 std::size_t operator()(const InputCode &ic) const noexcept
64 {
65 5830 return std::hash<int>{}(ic.code) ^ (std::hash<std::uint8_t>{}(static_cast<std::uint8_t>(ic.source)) << 16);
66 }
67 };
68
69 /** @brief Creates a Keyboard InputCode from a Windows virtual-key code, for example 0x41 for 'A'. */
70 1851 [[nodiscard]] constexpr InputCode keyboard_key(int vk) noexcept
71 {
72 1851 return {InputSource::Keyboard, vk};
73 }
74
75 /** @brief Creates a Mouse InputCode from a Windows virtual-key code, for example 0x01 for VK_LBUTTON. */
76 10 [[nodiscard]] constexpr InputCode mouse_button(int vk) noexcept
77 {
78 10 return {InputSource::Mouse, vk};
79 }
80
81 /** @brief Creates a Gamepad InputCode from an XInput button mask or a synthetic GamepadCode identifier. */
82 268 [[nodiscard]] constexpr InputCode gamepad_button(int code) noexcept
83 {
84 268 return {InputSource::Gamepad, code};
85 }
86
87 /** @brief Creates a MouseWheel InputCode from a WheelCode direction. */
88 13 [[nodiscard]] constexpr InputCode mouse_wheel(int code) noexcept
89 {
90 13 return {InputSource::MouseWheel, code};
91 }
92
93 /** @brief Button codes equal XINPUT_GAMEPAD_* bitmasks. Trigger and stick-direction codes are synthetic. */
94 namespace GamepadCode
95 {
96 inline constexpr int DpadUp = 0x0001;
97 inline constexpr int DpadDown = 0x0002;
98 inline constexpr int DpadLeft = 0x0004;
99 inline constexpr int DpadRight = 0x0008;
100 inline constexpr int Start = 0x0010;
101 inline constexpr int Back = 0x0020;
102 inline constexpr int LeftStick = 0x0040;
103 inline constexpr int RightStick = 0x0080;
104 inline constexpr int LeftBumper = 0x0100;
105 inline constexpr int RightBumper = 0x0200;
106 inline constexpr int A = 0x1000;
107 inline constexpr int B = 0x2000;
108 inline constexpr int X = 0x4000;
109 inline constexpr int Y = 0x8000;
110
111 /// Synthetic codes for analog triggers treated as digital inputs.
112 inline constexpr int LeftTrigger = 0x10000;
113 inline constexpr int RightTrigger = 0x10001;
114
115 /** @brief Synthetic thumbstick codes. Each fires when its axis exceeds the stick deadzone threshold. */
116 inline constexpr int LeftStickUp = 0x10002;
117 inline constexpr int LeftStickDown = 0x10003;
118 inline constexpr int LeftStickLeft = 0x10004;
119 inline constexpr int LeftStickRight = 0x10005;
120 inline constexpr int RightStickUp = 0x10006;
121 inline constexpr int RightStickDown = 0x10007;
122 inline constexpr int RightStickLeft = 0x10008;
123 inline constexpr int RightStickRight = 0x10009;
124
125 /// Default of `input::Input::Settings::trigger_threshold` (0 to 255 range). A trigger fires above the setting.
126 inline constexpr int TriggerThreshold = 30;
127
128 /** @brief Default stick deadzone threshold (0 to 32767 range), equal to XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE. */
129 inline constexpr int StickThreshold = 7849;
130
131 // A, B, X, and Y are identical in both spellings.
132 inline constexpr int DPAD_UP = DpadUp;
133 inline constexpr int DPAD_DOWN = DpadDown;
134 inline constexpr int DPAD_LEFT = DpadLeft;
135 inline constexpr int DPAD_RIGHT = DpadRight;
136 inline constexpr int START = Start;
137 inline constexpr int BACK = Back;
138 inline constexpr int LEFT_STICK = LeftStick;
139 inline constexpr int RIGHT_STICK = RightStick;
140 inline constexpr int LEFT_BUMPER = LeftBumper;
141 inline constexpr int RIGHT_BUMPER = RightBumper;
142 inline constexpr int LEFT_TRIGGER = LeftTrigger;
143 inline constexpr int RIGHT_TRIGGER = RightTrigger;
144 inline constexpr int LEFT_STICK_UP = LeftStickUp;
145 inline constexpr int LEFT_STICK_DOWN = LeftStickDown;
146 inline constexpr int LEFT_STICK_LEFT = LeftStickLeft;
147 inline constexpr int LEFT_STICK_RIGHT = LeftStickRight;
148 inline constexpr int RIGHT_STICK_UP = RightStickUp;
149 inline constexpr int RIGHT_STICK_DOWN = RightStickDown;
150 inline constexpr int RIGHT_STICK_LEFT = RightStickLeft;
151 inline constexpr int RIGHT_STICK_RIGHT = RightStickRight;
152 inline constexpr int TRIGGER_THRESHOLD = TriggerThreshold;
153 inline constexpr int STICK_THRESHOLD = StickThreshold;
154 } // namespace GamepadCode
155
156 /**
157 * @brief Mouse-wheel direction identifiers for InputSource::MouseWheel codes.
158 * @details Values are 1-based and dense, so `code - WheelCode::Up` is a zero-based direction index. Up and Down
159 * are the vertical wheel. Left and Right are the horizontal (tilt) wheel.
160 */
161 namespace WheelCode
162 {
163 inline constexpr int Up = 1;
164 inline constexpr int Down = 2;
165 inline constexpr int Left = 3;
166 inline constexpr int Right = 4;
167
168 inline constexpr int UP = Up;
169 inline constexpr int DOWN = Down;
170 inline constexpr int LEFT = Left;
171 inline constexpr int RIGHT = Right;
172 } // namespace WheelCode
173
174 /**
175 * @brief Resolves a human-readable input name to an InputCode, case-insensitively.
176 * @details Recognized name formats:
177 * - Keyboard: "A" through "Z", "0" through "9", "F1" through "F24", "Ctrl", "Shift", "Alt", "Space",
178 * "Enter", "Escape", "Tab", "Backspace", "LWin", "RWin", "Apps", and others.
179 * - OEM punctuation: "Grave"/"Backtick"/"Tilde", "Semicolon", "Comma", "Period", "Slash", and others.
180 * - Mouse: "Mouse1" (left) through "Mouse5" (XButton2).
181 * - Mouse wheel: "WheelUp", "WheelDown", "WheelLeft", "WheelRight".
182 * - Gamepad: "Gamepad_A", "Gamepad_B", "Gamepad_LB", "Gamepad_LT", and others.
183 * - Source-tagged hex: "Mouse:0xFE", "Gamepad:0x800", "MouseWheel:0x9", "Keyboard:0xFF".
184 * @return The resolved code, or std::nullopt for an unrecognized name or a bare hex token such as "0xFF".
185 */
186 [[nodiscard]] std::optional<InputCode> parse_input_name(std::string_view name);
187
188 /** @brief Returns the canonical name of @p code, or an empty view if the name table has no entry for it. */
189 [[nodiscard]] std::string_view input_code_to_name(const InputCode &code);
190
191 /**
192 * @brief Formats an InputCode as a human-readable string.
193 * @details Returns the canonical name if the name table has one. An off-table Keyboard code formats as bare hex
194 * ("0xFF"). Any other off-table code formats as source-tagged hex ("Mouse:0xFE"). parse_input_name reads
195 * the tagged form back, and config::bind_combos reads bare hex back as a Keyboard code.
196 */
197 [[nodiscard]] std::string format_input_code(const InputCode &code);
198
199 } // namespace DetourModKit
200
201 #endif // DETOURMODKIT_INPUT_CODES_HPP
202