#pragma once #define DIRECTINPUT_VERSION 0x0800 #include "common/windows_headers.h" #include "controller_interface.h" #include "core/types.h" #include #include #include #include #include #include class DInputControllerInterface final : public ControllerInterface { public: DInputControllerInterface(); ~DInputControllerInterface() override; Backend GetBackend() const override; bool Initialize(CommonHostInterface* host_interface) override; void Shutdown() override; // Removes all bindings. Call before setting new bindings. void ClearBindings() override; // Binding to events. If a binding for this axis/button already exists, returns false. bool BindControllerAxis(int controller_index, int axis_number, AxisSide axis_side, AxisCallback callback) override; bool BindControllerButton(int controller_index, int button_number, ButtonCallback callback) override; bool BindControllerAxisToButton(int controller_index, int axis_number, bool direction, ButtonCallback callback) override; bool BindControllerHatToButton(int controller_index, int hat_number, std::string_view hat_position, ButtonCallback callback) override; bool BindControllerButtonToAxis(int controller_index, int button_number, AxisCallback callback) override; // Changing rumble strength. u32 GetControllerRumbleMotorCount(int controller_index) override; void SetControllerRumbleStrength(int controller_index, const float* strengths, u32 num_motors) override; // Set deadzone that will be applied on axis-to-button mappings bool SetControllerDeadzone(int controller_index, float size = 0.25f) override; void PollEvents() override; private: template using ComPtr = Microsoft::WRL::ComPtr; enum : u32 { NUM_AXISES = 8, NUM_BUTTONS = 16, NUM_HATS = 1, TOTAL_NUM_BUTTONS = NUM_BUTTONS + (NUM_HATS * NUM_HAT_DIRECTIONS), }; struct ControllerData { ComPtr device; DIJOYSTATE last_state = {}; u32 num_buttons = 0; u32 num_axes = 0; float deadzone = 0.25f; std::array axis_offsets; std::array, NUM_AXISES> axis_mapping; std::array button_mapping; std::array, NUM_AXISES> axis_button_mapping; std::array button_axis_mapping; bool has_hat = false; bool needs_poll = true; }; using ControllerDataArray = std::vector; void AddDevices(); bool AddDevice(ControllerData& cd, const char* name); static std::array GetHatButtons(DWORD hat); void CheckForStateChanges(u32 index, const DIJOYSTATE& new_state); bool HandleAxisEvent(u32 index, u32 axis, s32 value); bool HandleButtonEvent(u32 index, u32 button, bool pressed); ControllerDataArray m_controllers; HMODULE m_dinput_module{}; LPCDIDATAFORMAT m_joystick_data_format{}; ComPtr m_dinput; std::mutex m_event_intercept_mutex; Hook::Callback m_event_intercept_callback; };