This commit is contained in:
Jordan Woyak 2024-11-10 16:47:08 -06:00 committed by GitHub
commit 39ae4b2c0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 341 additions and 24 deletions

View File

@ -190,6 +190,8 @@ const Info<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING{
const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER{{System::Main, "Core", "WiimoteEnableSpeaker"}, false}; const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER{{System::Main, "Core", "WiimoteEnableSpeaker"}, false};
const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE{ const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE{
{System::Main, "Core", "WiimoteControllerInterface"}, false}; {System::Main, "Core", "WiimoteControllerInterface"}, false};
const Info<bool> MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE{
{System::Main, "Core", "GCAdapterControllerInterface"}, false};
const Info<bool> MAIN_MMU{{System::Main, "Core", "MMU"}, false}; const Info<bool> MAIN_MMU{{System::Main, "Core", "MMU"}, false};
const Info<bool> MAIN_PAUSE_ON_PANIC{{System::Main, "Core", "PauseOnPanic"}, false}; const Info<bool> MAIN_PAUSE_ON_PANIC{{System::Main, "Core", "PauseOnPanic"}, false};
const Info<int> MAIN_BB_DUMP_PORT{{System::Main, "Core", "BBDumpPort"}, -1}; const Info<int> MAIN_BB_DUMP_PORT{{System::Main, "Core", "BBDumpPort"}, -1};

View File

@ -108,6 +108,7 @@ extern const Info<bool> MAIN_WII_KEYBOARD;
extern const Info<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING; extern const Info<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING;
extern const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER; extern const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER;
extern const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE; extern const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE;
extern const Info<bool> MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE;
extern const Info<bool> MAIN_MMU; extern const Info<bool> MAIN_MMU;
extern const Info<bool> MAIN_PAUSE_ON_PANIC; extern const Info<bool> MAIN_PAUSE_ON_PANIC;
extern const Info<int> MAIN_BB_DUMP_PORT; extern const Info<int> MAIN_BB_DUMP_PORT;

View File

@ -532,6 +532,7 @@
<ClInclude Include="InputCommon\ControllerInterface\MappingCommon.h" /> <ClInclude Include="InputCommon\ControllerInterface\MappingCommon.h" />
<ClInclude Include="InputCommon\ControllerInterface\WGInput\WGInput.h" /> <ClInclude Include="InputCommon\ControllerInterface\WGInput\WGInput.h" />
<ClInclude Include="InputCommon\ControllerInterface\Wiimote\WiimoteController.h" /> <ClInclude Include="InputCommon\ControllerInterface\Wiimote\WiimoteController.h" />
<ClInclude Include="InputCommon\ControllerInterface\GCAdapter\GCAdapter.h" />
<ClInclude Include="InputCommon\ControllerInterface\Win32\Win32.h" /> <ClInclude Include="InputCommon\ControllerInterface\Win32\Win32.h" />
<ClInclude Include="InputCommon\ControllerInterface\XInput\XInput.h" /> <ClInclude Include="InputCommon\ControllerInterface\XInput\XInput.h" />
<ClInclude Include="InputCommon\ControllerInterface\SDL\SDL.h" /> <ClInclude Include="InputCommon\ControllerInterface\SDL\SDL.h" />
@ -1193,6 +1194,7 @@
<ClCompile Include="InputCommon\ControllerInterface\MappingCommon.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\MappingCommon.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\WGInput\WGInput.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\WGInput\WGInput.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\Wiimote\WiimoteController.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\Wiimote\WiimoteController.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\GCAdapter\GCAdapter.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\Win32\Win32.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\Win32\Win32.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\XInput\XInput.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\XInput\XInput.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\SDL\SDL.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\SDL\SDL.cpp" />

View File

@ -3,6 +3,7 @@
#include "DolphinQt/Config/GamecubeControllersWidget.h" #include "DolphinQt/Config/GamecubeControllersWidget.h"
#include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QGridLayout> #include <QGridLayout>
#include <QGroupBox> #include <QGroupBox>
@ -95,6 +96,10 @@ void GamecubeControllersWidget::CreateLayout()
m_gc_layout->addWidget(gc_box, controller_row, 1); m_gc_layout->addWidget(gc_box, controller_row, 1);
m_gc_layout->addWidget(gc_button, controller_row, 2); m_gc_layout->addWidget(gc_button, controller_row, 2);
} }
m_gcpad_ciface = new QCheckBox(tr("Use Wii-U Adapter for Emulated Controllers"));
m_gc_layout->addWidget(m_gcpad_ciface, m_gc_layout->rowCount(), 0, 1, -1);
m_gc_box->setLayout(m_gc_layout); m_gc_box->setLayout(m_gc_layout);
auto* layout = new QVBoxLayout; auto* layout = new QVBoxLayout;
@ -114,6 +119,8 @@ void GamecubeControllersWidget::ConnectWidgets()
}); });
connect(m_gc_buttons[i], &QPushButton::clicked, this, [this, i] { OnGCPadConfigure(i); }); connect(m_gc_buttons[i], &QPushButton::clicked, this, [this, i] { OnGCPadConfigure(i); });
} }
connect(m_gcpad_ciface, &QCheckBox::toggled, this, &GamecubeControllersWidget::SaveSettings);
} }
void GamecubeControllersWidget::OnGCTypeChanged(size_t index) void GamecubeControllersWidget::OnGCTypeChanged(size_t index)
@ -184,6 +191,9 @@ void GamecubeControllersWidget::LoadSettings(Core::State state)
OnGCTypeChanged(i); OnGCTypeChanged(i);
} }
} }
SignalBlocking(m_gcpad_ciface)
->setChecked(Config::Get(Config::MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE));
} }
void GamecubeControllersWidget::SaveSettings() void GamecubeControllersWidget::SaveSettings()
@ -203,11 +213,15 @@ void GamecubeControllersWidget::SaveSettings()
system.GetSerialInterface().ChangeDevice(si_device, static_cast<s32>(i)); system.GetSerialInterface().ChangeDevice(si_device, static_cast<s32>(i));
} }
} }
Config::SetBaseOrCurrent(Config::MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE,
m_gcpad_ciface->isChecked());
} }
SConfig::GetInstance().SaveSettings();
if (GCAdapter::UseAdapter()) if (GCAdapter::UseAdapter())
GCAdapter::StartScanThread(); GCAdapter::StartScanThread();
else else
GCAdapter::StopScanThread(); GCAdapter::StopScanThread();
SConfig::GetInstance().SaveSettings();
} }

View File

@ -7,6 +7,7 @@
#include <array> #include <array>
class QCheckBox;
class QComboBox; class QComboBox;
class QHBoxLayout; class QHBoxLayout;
class QGridLayout; class QGridLayout;
@ -40,4 +41,5 @@ private:
std::array<QComboBox*, 4> m_gc_controller_boxes; std::array<QComboBox*, 4> m_gc_controller_boxes;
std::array<QPushButton*, 4> m_gc_buttons; std::array<QPushButton*, 4> m_gc_buttons;
std::array<QHBoxLayout*, 4> m_gc_groups; std::array<QHBoxLayout*, 4> m_gc_groups;
QCheckBox* m_gcpad_ciface;
}; };

View File

@ -64,6 +64,8 @@ add_library(inputcommon
ControllerInterface/MappingCommon.h ControllerInterface/MappingCommon.h
ControllerInterface/Wiimote/WiimoteController.cpp ControllerInterface/Wiimote/WiimoteController.cpp
ControllerInterface/Wiimote/WiimoteController.h ControllerInterface/Wiimote/WiimoteController.h
ControllerInterface/GCAdapter/GCAdapter.cpp
ControllerInterface/GCAdapter/GCAdapter.h
ControlReference/ControlReference.cpp ControlReference/ControlReference.cpp
ControlReference/ControlReference.h ControlReference/ControlReference.h
ControlReference/ExpressionParser.cpp ControlReference/ExpressionParser.cpp

View File

@ -8,6 +8,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "InputCommon/ControllerInterface/GCAdapter/GCAdapter.h"
#ifdef CIFACE_USE_WIN32 #ifdef CIFACE_USE_WIN32
#include "InputCommon/ControllerInterface/Win32/Win32.h" #include "InputCommon/ControllerInterface/Win32/Win32.h"
@ -86,6 +87,9 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
m_input_backends.emplace_back(ciface::SteamDeck::CreateInputBackend(this)); m_input_backends.emplace_back(ciface::SteamDeck::CreateInputBackend(this));
#endif #endif
// TODO: obey Config::Get(Config::MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE)
m_input_backends.emplace_back(ciface::GCAdapter::CreateInputBackend(this));
// Don't allow backends to add devices before the first RefreshDevices() as they will be cleaned // Don't allow backends to add devices before the first RefreshDevices() as they will be cleaned
// there. Or they'd end up waiting on the devices mutex if populated from another thread. // there. Or they'd end up waiting on the devices mutex if populated from another thread.
m_is_init = true; m_is_init = true;

View File

@ -0,0 +1,258 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "InputCommon/ControllerInterface/GCAdapter/GCAdapter.h"
#include <array>
#include "Core/HW/SI/SI.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/GCAdapter.h"
#include "InputCommon/GCPadStatus.h"
// TODO: namespace name matching the one in InputCommon/GCAdapter.h is annoying
namespace ciface::GCAdapter
{
constexpr auto SOURCE_NAME = "GCAdapter";
class GCController;
class InputBackend final : public ciface::InputBackend
{
public:
InputBackend(ControllerInterface* controller_interface);
void PopulateDevices() override;
void UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove) override;
private:
std::array<std::weak_ptr<GCController>, SerialInterface::MAX_SI_CHANNELS> m_devices;
};
std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
{
return std::make_unique<InputBackend>(controller_interface);
}
struct DigitalInputProps
{
u16 value;
const char* name;
};
constexpr DigitalInputProps digital_inputs[] = {
{PAD_BUTTON_UP, "Up"},
{PAD_BUTTON_DOWN, "Down"},
{PAD_BUTTON_LEFT, "Left"},
{PAD_BUTTON_RIGHT, "Right"},
{PAD_BUTTON_A, "A"},
{PAD_BUTTON_B, "B"},
{PAD_BUTTON_X, "X"},
{PAD_BUTTON_Y, "Y"},
{PAD_TRIGGER_Z, "Z"},
{PAD_TRIGGER_L, "L"},
{PAD_TRIGGER_R, "R"},
// TODO: "START" or "Start"?
{PAD_BUTTON_START, "Start"},
};
struct AnalogInputProps
{
u8 GCPadStatus::*ptr;
const char* name;
};
constexpr AnalogInputProps stick_inputs[] = {
{&GCPadStatus::stickX, "Main X"},
{&GCPadStatus::stickY, "Main Y"},
{&GCPadStatus::substickX, "C X"},
{&GCPadStatus::substickY, "C Y"},
};
constexpr AnalogInputProps trigger_inputs[] = {
{&GCPadStatus::triggerLeft, "L-Analog"},
{&GCPadStatus::triggerRight, "R-Analog"},
};
class DigitalInput : public Core::Device::Input
{
public:
DigitalInput(const u16* button_state, u32 index) : m_button_state{*button_state}, m_index{index}
{
}
std::string GetName() const override { return digital_inputs[m_index].name; }
ControlState GetState() const override
{
return (digital_inputs[m_index].value & m_button_state) != 0;
}
private:
const u16& m_button_state;
const u32 m_index;
};
class AnalogInput : public Core::Device::Input
{
public:
AnalogInput(const GCPadStatus* pad_status, const AnalogInputProps& props, u8 neutral_value,
s32 range)
: m_base_name{props.name}, m_neutral_value{neutral_value}, m_range{range},
m_state{pad_status->*props.ptr}
{
}
ControlState GetState() const override
{
return ControlState(m_state - m_neutral_value) / m_range;
}
protected:
const char* const m_base_name;
const u8 m_neutral_value;
const s32 m_range;
private:
const u8& m_state;
};
class StickInput : public AnalogInput
{
public:
using AnalogInput::AnalogInput;
std::string GetName() const override
{
return std::string(m_base_name) + (m_range > 0 ? '+' : '-');
}
};
class TriggerInput : public AnalogInput
{
public:
using AnalogInput::AnalogInput;
std::string GetName() const override { return m_base_name; }
};
class Motor : public Core::Device::Output
{
public:
Motor(u32 index) : m_index{index} {}
void SetState(ControlState value) override
{
const bool new_state = std::lround(value);
if (new_state == m_last_state)
return;
m_last_state = new_state;
::GCAdapter::Output(m_index, new_state);
}
std::string GetName() const override { return "Motor"; }
private:
u32 m_index;
bool m_last_state = false;
};
class GCController : public Core::Device
{
public:
GCController(u32 index) : m_index{index}
{
// Add buttons.
for (u32 i = 0; i != std::size(digital_inputs); ++i)
AddInput(new DigitalInput{&m_pad_status.button, i});
// TODO: use origin values.
const auto origin = ::GCAdapter::GetOrigin(index);
// Add sticks.
for (auto& props : stick_inputs)
{
// Add separate -/+ inputs.
AddInput(new StickInput{&m_pad_status, props, GCPadStatus::MAIN_STICK_CENTER_X,
-GCPadStatus::MAIN_STICK_RADIUS});
AddInput(new StickInput{&m_pad_status, props, GCPadStatus::MAIN_STICK_CENTER_X,
GCPadStatus::MAIN_STICK_RADIUS});
}
// Add triggers.
for (auto& props : trigger_inputs)
AddInput(new TriggerInput{&m_pad_status, props, 0, std::numeric_limits<u8>::max()});
// Rumble.
AddOutput(new Motor{index});
}
std::optional<int> GetPreferredId() const override { return m_index; }
std::string GetName() const override
{
// TODO: name?
return "GCPad";
}
std::string GetSource() const override { return SOURCE_NAME; }
int GetSortPriority() const override { return -3; }
Core::DeviceRemoval UpdateInput() override
{
m_pad_status = ::GCAdapter::PeekInput(m_index);
return Core::DeviceRemoval::Keep;
}
private:
GCPadStatus m_pad_status;
const u32 m_index;
};
InputBackend::InputBackend(ControllerInterface* controller_interface)
: ciface::InputBackend(controller_interface)
{
::GCAdapter::Init();
}
void InputBackend::PopulateDevices()
{
for (int i = 0; i != SerialInterface::MAX_SI_CHANNELS; ++i)
{
if (::GCAdapter::DeviceConnected(i))
{
auto new_device = std::make_shared<GCController>(i);
m_devices[i] = new_device;
GetControllerInterface().AddDevice(std::move(new_device));
}
}
}
void InputBackend::UpdateInput(std::vector<std::weak_ptr<ciface::Core::Device>>& devices_to_remove)
{
// "Hotplug" is handled here.
for (int i = 0; i != SerialInterface::MAX_SI_CHANNELS; ++i)
{
const bool is_device_connected = ::GCAdapter::DeviceConnected(i);
const auto device = m_devices[i].lock();
if (is_device_connected == (device != nullptr))
continue;
if (is_device_connected)
{
auto new_device = std::make_shared<GCController>(i);
m_devices[i] = new_device;
GetControllerInterface().AddDevice(std::move(new_device));
}
else
{
devices_to_remove.emplace_back(device);
}
}
}
} // namespace ciface::GCAdapter

View File

@ -0,0 +1,14 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "InputCommon/ControllerInterface/InputBackend.h"
namespace ciface::GCAdapter
{
std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface);
} // namespace ciface::GCAdapter

View File

@ -142,15 +142,6 @@ static Common::Event s_hotplug_event;
static std::function<void(void)> s_detect_callback; static std::function<void(void)> s_detect_callback;
#if defined(__FreeBSD__) && __FreeBSD__ >= 11
static bool s_libusb_hotplug_enabled = true;
#else
static bool s_libusb_hotplug_enabled = false;
#endif
#if LIBUSB_API_HAS_HOTPLUG
static libusb_hotplug_callback_handle s_hotplug_handle;
#endif
static std::unique_ptr<LibusbUtils::Context> s_libusb_context; static std::unique_ptr<LibusbUtils::Context> s_libusb_context;
static u8 s_endpoint_in = 0; static u8 s_endpoint_in = 0;
@ -346,24 +337,32 @@ static void ScanThreadFunc()
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
#if LIBUSB_API_HAS_HOTPLUG #if LIBUSB_API_HAS_HOTPLUG
#ifndef __FreeBSD__
s_libusb_hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0; #if defined(__FreeBSD__)
#if __FreeBSD__ >= 11
bool hotplug_enabled = true;
#else
bool hotplug_enabled = false;
#endif #endif
if (s_libusb_hotplug_enabled) #else
bool hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0;
#endif
libusb_hotplug_callback_handle hotplug_handle = {};
if (hotplug_enabled)
{ {
const int error = libusb_hotplug_register_callback( const int error = libusb_hotplug_register_callback(
*s_libusb_context, *s_libusb_context,
(libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback,
nullptr, &s_hotplug_handle); nullptr, &hotplug_handle);
if (error == LIBUSB_SUCCESS) if (error == LIBUSB_SUCCESS)
{ {
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Using libUSB hotplug detection"); NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Using libUSB hotplug detection");
} }
else else
{ {
s_libusb_hotplug_enabled = false; hotplug_enabled = false;
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to add libUSB hotplug detection callback: {}", ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to add libUSB hotplug detection callback: {}",
LibusbUtils::ErrorWrap(error)); LibusbUtils::ErrorWrap(error));
} }
@ -378,11 +377,17 @@ static void ScanThreadFunc()
Setup(); Setup();
} }
if (s_libusb_hotplug_enabled) if (hotplug_enabled)
s_hotplug_event.Wait(); s_hotplug_event.Wait();
else else
Common::SleepCurrentThread(500); Common::SleepCurrentThread(500);
} }
#if LIBUSB_API_HAS_HOTPLUG
if (hotplug_enabled)
libusb_hotplug_deregister_callback(*s_libusb_context, hotplug_handle);
#endif
#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION #elif GCADAPTER_USE_ANDROID_IMPLEMENTATION
JNIEnv* const env = IDCache::GetEnvForThread(); JNIEnv* const env = IDCache::GetEnvForThread();
@ -410,12 +415,14 @@ void SetAdapterCallback(std::function<void(void)> func)
static void RefreshConfig() static void RefreshConfig()
{ {
s_is_adapter_wanted = false; s_is_adapter_wanted = Config::Get(Config::MAIN_USE_GC_ADAPTER_FOR_CONTROLLER_INTERFACE);
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{ {
s_is_adapter_wanted |= Config::Get(Config::GetInfoForSIDevice(i)) == s_is_adapter_wanted |= Config::Get(Config::GetInfoForSIDevice(i)) ==
SerialInterface::SIDevices::SIDEVICE_WIIU_ADAPTER; SerialInterface::SIDevices::SIDEVICE_WIIU_ADAPTER;
// TODO: ControllerInterface shouldn't obey this setting.
s_config_rumble_enabled[i] = Config::Get(Config::GetInfoForAdapterRumble(i)); s_config_rumble_enabled[i] = Config::Get(Config::GetInfoForAdapterRumble(i));
} }
} }
@ -676,12 +683,6 @@ static void AddGCAdapter(libusb_device* device)
void Shutdown() void Shutdown()
{ {
StopScanThread(); StopScanThread();
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
#if LIBUSB_API_HAS_HOTPLUG
if (s_libusb_context->IsValid() && s_libusb_hotplug_enabled)
libusb_hotplug_deregister_callback(*s_libusb_context, s_hotplug_handle);
#endif
#endif
Reset(); Reset();
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
@ -766,6 +767,18 @@ GCPadStatus Input(int chan)
return pad_state.status; return pad_state.status;
} }
GCPadStatus PeekInput(int chan)
{
std::lock_guard lk(s_read_mutex);
return s_port_states[chan].status;
}
GCPadStatus GetOrigin(int chan)
{
std::lock_guard lk(s_read_mutex);
return s_port_states[chan].origin;
}
// Get ControllerType from first byte in input payload. // Get ControllerType from first byte in input payload.
static ControllerType IdentifyControllerType(u8 data) static ControllerType IdentifyControllerType(u8 data)
{ {

View File

@ -22,6 +22,11 @@ void StopScanThread();
// Netplay and CSIDevice_GCAdapter make use of this. // Netplay and CSIDevice_GCAdapter make use of this.
GCPadStatus Input(int chan); GCPadStatus Input(int chan);
// Retreive the latest input without changing the new connection flag.
GCPadStatus PeekInput(int chan);
GCPadStatus GetOrigin(int chan);
void Output(int chan, u8 rumble_command); void Output(int chan, u8 rumble_command);
bool IsDetected(const char** error_message); bool IsDetected(const char** error_message);
bool DeviceConnected(int chan); bool DeviceConnected(int chan);