/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Graphics:Gamepad; import std; import Crafter.Event; // Raw gamepad device API. Platform-split implementation: // - Linux: libudev (enumerate + hot-plug) + libevdev (read events, // calibrate axes). Open every /dev/input/event* node the kernel // classifies as a gamepad; ignore the rest. // - Windows: Windows.Gaming.Input via the C ABI (COBJMACROS pattern, // same as SDL). Added/Removed events fire on a thread pool and are // marshaled into a queue drained from Tick() on the main thread. // // Button names follow the standardized kernel BTN_SOUTH / BTN_EAST / // BTN_WEST / BTN_NORTH convention — physical position, not label. An // Xbox "A" and a PlayStation "Cross" both arrive as `South`. // // Stick axes are -1..1 (post-deadzone calibration, raw float). Trigger // axes are 0..1. The `LeftTrigger` / `RightTrigger` entries in `Button` // and `Axis` are both populated — pick whichever fits your use case // (digital threshold vs. analog reading). export namespace Crafter::Gamepad { enum class Button : std::uint8_t { South, East, West, North, // BTN_SOUTH/EAST/WEST/NORTH Select, Start, Home, LeftStickClick, RightStickClick, LeftBumper, RightBumper, DPadUp, DPadDown, DPadLeft, DPadRight, LeftTrigger, RightTrigger, // digital threshold; analog also on Axis Max }; enum class Axis : std::uint8_t { LeftStickX, LeftStickY, RightStickX, RightStickY, LeftTrigger, RightTrigger, Max }; enum class Stick : std::uint8_t { Left, Right }; struct Device { std::uint32_t id; // stable across the device's lifetime std::string name; bool buttons[(std::size_t)Button::Max] = {}; float axes[(std::size_t)Axis::Max] = {}; // sticks: -1..1, triggers: 0..1 Event