// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #pragma once #include "controller.h" #include class ForceFeedbackDevice; class JogCon final : public Controller { public: enum class Button : u8 { Select = 0, L3 = 1, R3 = 2, Start = 3, Up = 4, Right = 5, Down = 6, Left = 7, L2 = 8, R2 = 9, L1 = 10, R1 = 11, Triangle = 12, Circle = 13, Cross = 14, Square = 15, Mode = 16, MaxCount }; enum class HalfAxis : u8 { SteeringLeft, SteeringRight, MaxCount, }; static const Controller::ControllerInfo INFO; JogCon(u32 index); ~JogCon() override; static std::unique_ptr Create(u32 index); ControllerType GetType() const override; void Reset() override; bool DoState(StateWrapper& sw, bool apply_input_state) override; float GetBindState(u32 index) const override; float GetVibrationMotorState(u32 index) const override; void SetBindState(u32 index, float value) override; u32 GetButtonStateBits() const override; u32 GetInputOverlayIconColor() const override; void ResetTransferState() override; bool Transfer(const u8 data_in, u8* data_out) override; void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override; private: enum class Command : u8 { Idle, Ready, ReadPad, SetMode, GetAnalogMode, SetAnalogMode, GetSetRumble, Command46, Command47, Command4C, }; enum : u8 { LargeMotor = 0, SmallMotor = 1 }; enum : u8 { MOTOR_COMMAND_STOP = 0x0, MOTOR_COMMAND_RIGHT = 0x1, MOTOR_COMMAND_LEFT = 0x2, MOTOR_COMMAND_HOLD = 0x3, MOTOR_COMMAND_DROP_REVOLUTIONS = 0x8, MOTOR_COMMAND_DROP_REVOLUTIONS_AND_HOLD = 0xB, MOTOR_COMMAND_NEW_HOLD = 0xC, }; static constexpr float DEFAULT_STEERING_HOLD_DEADZONE = 0.03f; u8 GetIDByte() const; u8 GetModeID() const; // Get number of response halfwords (excluding the initial controller info halfword) u8 GetResponseNumHalfwords() const; void Poll(); void UpdateSteeringHold(); void SetMotorState(u8 value); void SetMotorDirection(u8 direction_command, u8 strength); void ResetMotorConfig(); void SetJogConMode(bool enabled, bool show_message); // buttons are active low u16 m_button_state = UINT16_C(0xFFFF); s8 m_steering_state = 0; // both directions of axis state, merged to m_steering_state std::array(HalfAxis::MaxCount)> m_half_axis_state{}; Command m_command = Command::Idle; u8 m_command_step = 0; u8 m_response_length = 0; u8 m_status_byte = 0x5A; s8 m_last_steering_state = 0; u8 m_last_motor_command = 0; s8 m_steering_hold_position = 0; u8 m_steering_hold_strength = 0; bool m_configuration_mode = false; bool m_jogcon_mode = false; bool m_mode_toggle_queued = false; std::array m_rumble_config{}; // Transmit and receive buffers, not including the first Hi-Z/ack response byte static constexpr u32 MAX_RESPONSE_LENGTH = 8; std::array m_rx_buffer; std::array m_tx_buffer; s8 m_steering_hold_deadzone = 0; float m_analog_deadzone = 0.0f; float m_analog_sensitivity = 1.33f; float m_button_deadzone = 0.0f; float m_last_strength = 0.0f; std::unique_ptr m_force_feedback_device; std::string m_force_feedback_device_name; };