mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2025-04-07 07:40:08 +00:00

A vibration device is an input device that returns an unsigned byte as status. It represents whether the vibration device supports vibration or not. If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
168 lines
4.3 KiB
C++
168 lines
4.3 KiB
C++
// Copyright 2014 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include "common/common_types.h"
|
|
#include "common/threadsafe_queue.h"
|
|
#include "input_common/main.h"
|
|
|
|
struct libusb_context;
|
|
struct libusb_device;
|
|
struct libusb_device_handle;
|
|
|
|
namespace GCAdapter {
|
|
|
|
enum class PadButton {
|
|
Undefined = 0x0000,
|
|
ButtonLeft = 0x0001,
|
|
ButtonRight = 0x0002,
|
|
ButtonDown = 0x0004,
|
|
ButtonUp = 0x0008,
|
|
TriggerZ = 0x0010,
|
|
TriggerR = 0x0020,
|
|
TriggerL = 0x0040,
|
|
ButtonA = 0x0100,
|
|
ButtonB = 0x0200,
|
|
ButtonX = 0x0400,
|
|
ButtonY = 0x0800,
|
|
ButtonStart = 0x1000,
|
|
// Below is for compatibility with "AxisButton" type
|
|
Stick = 0x2000,
|
|
};
|
|
|
|
enum class PadAxes : u8 {
|
|
StickX,
|
|
StickY,
|
|
SubstickX,
|
|
SubstickY,
|
|
TriggerLeft,
|
|
TriggerRight,
|
|
Undefined,
|
|
};
|
|
|
|
enum class ControllerTypes {
|
|
None,
|
|
Wired,
|
|
Wireless,
|
|
};
|
|
|
|
struct GCPadStatus {
|
|
std::size_t port{};
|
|
|
|
PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
|
|
|
|
PadAxes axis{PadAxes::Undefined};
|
|
s16 axis_value{};
|
|
u8 axis_threshold{50};
|
|
};
|
|
|
|
struct GCController {
|
|
ControllerTypes type{};
|
|
bool enable_vibration{};
|
|
u8 rumble_amplitude{};
|
|
u16 buttons{};
|
|
PadButton last_button{};
|
|
std::array<s16, 6> axis_values{};
|
|
std::array<u8, 6> axis_origin{};
|
|
};
|
|
|
|
class Adapter {
|
|
public:
|
|
Adapter();
|
|
~Adapter();
|
|
|
|
/// Request a vibration for a controller
|
|
bool RumblePlay(std::size_t port, u8 amplitude);
|
|
|
|
/// Used for polling
|
|
void BeginConfiguration();
|
|
void EndConfiguration();
|
|
|
|
Common::SPSCQueue<GCPadStatus>& GetPadQueue();
|
|
const Common::SPSCQueue<GCPadStatus>& GetPadQueue() const;
|
|
|
|
GCController& GetPadState(std::size_t port);
|
|
const GCController& GetPadState(std::size_t port) const;
|
|
|
|
/// Returns true if there is a device connected to port
|
|
bool DeviceConnected(std::size_t port) const;
|
|
|
|
/// Used for automapping features
|
|
std::vector<Common::ParamPackage> GetInputDevices() const;
|
|
InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
|
|
InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
|
|
|
|
private:
|
|
using AdapterPayload = std::array<u8, 37>;
|
|
|
|
void UpdatePadType(std::size_t port, ControllerTypes pad_type);
|
|
void UpdateControllers(const AdapterPayload& adapter_payload);
|
|
void UpdateYuzuSettings(std::size_t port);
|
|
void UpdateStateButtons(std::size_t port, u8 b1, u8 b2);
|
|
void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload);
|
|
void UpdateVibrations();
|
|
|
|
void AdapterInputThread();
|
|
|
|
void AdapterScanThread();
|
|
|
|
bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size);
|
|
|
|
// Updates vibration state of all controllers
|
|
void SendVibrations();
|
|
|
|
/// For use in initialization, querying devices to find the adapter
|
|
void Setup();
|
|
|
|
/// Resets status of all GC controller devices to a disconected state
|
|
void ResetDevices();
|
|
|
|
/// Resets status of device connected to a disconected state
|
|
void ResetDevice(std::size_t port);
|
|
|
|
/// Returns true if we successfully gain access to GC Adapter
|
|
bool CheckDeviceAccess();
|
|
|
|
/// Captures GC Adapter endpoint address
|
|
/// Returns true if the endpoind was set correctly
|
|
bool GetGCEndpoint(libusb_device* device);
|
|
|
|
/// For shutting down, clear all data, join all threads, release usb
|
|
void Reset();
|
|
|
|
// Join all threads
|
|
void JoinThreads();
|
|
|
|
// Release usb handles
|
|
void ClearLibusbHandle();
|
|
|
|
libusb_device_handle* usb_adapter_handle = nullptr;
|
|
std::array<GCController, 4> pads;
|
|
Common::SPSCQueue<GCPadStatus> pad_queue;
|
|
|
|
std::thread adapter_input_thread;
|
|
std::thread adapter_scan_thread;
|
|
bool adapter_input_thread_running;
|
|
bool adapter_scan_thread_running;
|
|
bool restart_scan_thread;
|
|
|
|
libusb_context* libusb_ctx;
|
|
|
|
u8 input_endpoint{0};
|
|
u8 output_endpoint{0};
|
|
u8 input_error_counter{0};
|
|
u8 output_error_counter{0};
|
|
int vibration_counter{0};
|
|
|
|
bool configuring{false};
|
|
bool rumble_enabled{true};
|
|
bool vibration_changed{true};
|
|
};
|
|
} // namespace GCAdapter
|