new input system
This commit is contained in:
parent
b3db40ebec
commit
ac2eb7fb0a
31 changed files with 3292 additions and 781 deletions
99
interfaces/Crafter.Graphics-Gamepad.cppm
Normal file
99
interfaces/Crafter.Graphics-Gamepad.cppm
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
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<Button> onButtonDown;
|
||||
Event<Button> onButtonUp;
|
||||
Event<Axis> onAxisChanged;
|
||||
};
|
||||
|
||||
// Process-level state — one input subsystem per app. Indices into
|
||||
// `connected` are NOT stable across hot-plug; use `Device::id` when
|
||||
// serializing bindings. The list is unsorted; iterate to find a
|
||||
// specific id.
|
||||
inline std::vector<std::unique_ptr<Device>> connected;
|
||||
inline Event<Device*> onConnected;
|
||||
inline Event<Device*> onDisconnected;
|
||||
|
||||
// Drains pending events from the OS, fires the relevant onButton* /
|
||||
// onAxisChanged / onConnected / onDisconnected events synchronously,
|
||||
// and updates the polled `buttons[]` / `axes[]` state on each Device.
|
||||
// Must be called from the main thread once per frame — Window's
|
||||
// event loop does this automatically. Safe to call when no gamepads
|
||||
// are connected (early-out path).
|
||||
void Tick();
|
||||
|
||||
// Optional rumble. `low` drives the heavy/low-frequency motor,
|
||||
// `high` drives the light/high-frequency motor (Xbox naming). Both
|
||||
// are clamped to 0..1. `duration` clamps to the backend's max; pass
|
||||
// 0ms to stop any active rumble. No-op if the device doesn't
|
||||
// advertise force-feedback.
|
||||
void Rumble(Device& dev, float low, float high,
|
||||
std::chrono::milliseconds duration);
|
||||
|
||||
// Find a connected device by its stable id. Returns nullptr if the
|
||||
// device isn't currently connected — typical use after deserializing
|
||||
// a saved binding.
|
||||
Device* FindById(std::uint32_t id);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue