mirror of
https://github.com/CTCaer/dolphin.git
synced 2024-11-27 04:00:50 +00:00
WiimoteReal: Add a hidapi IO implementation
Based on ca0c2efe7ab19c85449d52dd1bf4beec8603bbfe. Credits go to flacs. However, unlike the original commit, hidapi does not completely replace the current implementations, so we can still connect Wiimotes with 1+2 (without pairing). Also, it is only used on Linux and OS X for now. This removes the advantage of having only one implementation but there is no other choice: using hidapi on Windows is currently impossible because hid_write() is implemented in a way that won't work with Wiimotes. Additionally: * We now check for the device name in addition to the PID/VID so we can support the Balance Board and maybe third-party Wiimotes too. This doesn't achieve anything with the DolphinBar but it does with hidraw. * Added a check to not connect to the same device more than once.
This commit is contained in:
parent
84467d2ff1
commit
843b030eda
@ -835,6 +835,33 @@ else()
|
||||
endif()
|
||||
list(APPEND LIBS ${ICONV_LIBRARIES})
|
||||
|
||||
if(NOT ANDROID)
|
||||
include(FindHIDAPI OPTIONAL)
|
||||
find_package(HIDAPI)
|
||||
if(HIDAPI_FOUND)
|
||||
message("Using shared ${HIDAPI_LIBRARIES} ${HIDAPI_VERSION}")
|
||||
include_directories(${HIDAPI_INCLUDE_DIRS})
|
||||
list(APPEND LIBS ${HIDAPI_LIBRARIES})
|
||||
else()
|
||||
include_directories(Externals/hidapi/hidapi)
|
||||
if(APPLE)
|
||||
message("Using static hidapi from Externals")
|
||||
add_subdirectory(Externals/hidapi/mac)
|
||||
list(APPEND LIBS hidapi)
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
message("Using static hidapi-hidraw from Externals")
|
||||
add_subdirectory(Externals/hidapi/linux)
|
||||
list(APPEND LIBS hidapi-hidraw udev)
|
||||
else()
|
||||
message("Using static hidapi-libusb from Externals")
|
||||
add_subdirectory(Externals/hidapi/libusb)
|
||||
list(APPEND LIBS hidapi-libusb)
|
||||
endif()
|
||||
endif()
|
||||
set(HIDAPI_FOUND 1)
|
||||
add_definitions(-DHAVE_HIDAPI=1)
|
||||
endif()
|
||||
|
||||
find_library(OPENSLES_LIBRARIES NAMES OpenSLES)
|
||||
find_path(OPENSLES_INCLUDE_DIR NAMES SLES/OpenSLES.h)
|
||||
|
||||
|
9
CMakeTests/FindHIDAPI.cmake
Normal file
9
CMakeTests/FindHIDAPI.cmake
Normal file
@ -0,0 +1,9 @@
|
||||
find_path(HIDAPI_INCLUDE_DIR NAMES hidapi.h PATH_SUFFIXES hidapi)
|
||||
find_library(HIDAPI_LIBRARY NAMES hidapi hidapi-hidraw hidapi-libusb)
|
||||
set(HIDAPI_LIBRARIES ${HIDAPI_LIBRARY})
|
||||
set(HIDAPI_INCLUDE_DIRS ${HIDAPI_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(HIDAPI DEFAULT_MSG HIDAPI_LIBRARY HIDAPI_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)
|
@ -1,5 +1,6 @@
|
||||
#GameCube Controller Adapter
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0337", TAG+="uaccess"
|
||||
|
||||
#Mayflash DolphinBar
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0306", TAG+="uaccess"
|
||||
#Wiimotes or DolphinBar
|
||||
SUBSYSTEM=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0306", TAG+="uaccess"
|
||||
SUBSYSTEM=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="0330", TAG+="uaccess"
|
||||
|
1
Externals/hidapi/libusb/CMakeLists.txt
vendored
Normal file
1
Externals/hidapi/libusb/CMakeLists.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
add_library(hidapi-libusb hid.c)
|
1
Externals/hidapi/linux/CMakeLists.txt
vendored
Normal file
1
Externals/hidapi/linux/CMakeLists.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
add_library(hidapi-hidraw hid.c)
|
1
Externals/hidapi/mac/CMakeLists.txt
vendored
Normal file
1
Externals/hidapi/mac/CMakeLists.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
add_library(hidapi hid.c)
|
@ -263,6 +263,9 @@ elseif(UNIX)
|
||||
set(SRCS ${SRCS} HW/WiimoteReal/IOAndroid.cpp)
|
||||
endif()
|
||||
endif()
|
||||
if(HIDAPI_FOUND)
|
||||
set(SRCS ${SRCS} HW/WiimoteReal/IOhidapi.cpp)
|
||||
endif(HIDAPI_FOUND)
|
||||
|
||||
if(PORTAUDIO_FOUND)
|
||||
set(LIBS ${LIBS} portaudio)
|
||||
|
@ -90,7 +90,7 @@ void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wi
|
||||
}
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "device name %s", name);
|
||||
if (!IsValidBluetoothName(name))
|
||||
if (!IsValidDeviceName(name))
|
||||
continue;
|
||||
|
||||
char bdaddr_str[18] = {};
|
||||
|
@ -983,7 +983,7 @@ void ProcessWiimotes(bool new_scan, T& callback)
|
||||
DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ", btdi.fAuthenticated,
|
||||
btdi.fConnected, btdi.fRemembered);
|
||||
|
||||
if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName)))
|
||||
if (IsValidDeviceName(UTF16ToUTF8(btdi.szName)))
|
||||
{
|
||||
callback(hRadio, radioInfo, btdi);
|
||||
}
|
||||
|
@ -18,16 +18,6 @@ public:
|
||||
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
|
||||
void Update() override{}; // not needed
|
||||
};
|
||||
|
||||
class WiimoteScannerDarwinHID final : public WiimoteScannerBackend
|
||||
{
|
||||
public:
|
||||
WiimoteScannerDarwinHID() = default;
|
||||
~WiimoteScannerDarwinHID() override = default;
|
||||
bool IsReady() const override;
|
||||
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
|
||||
void Update() override{}; // not needed
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
@ -35,6 +25,5 @@ public:
|
||||
namespace WiimoteReal
|
||||
{
|
||||
using WiimoteScannerDarwin = WiimoteScannerDummy;
|
||||
using WiimoteScannerDarwinHID = WiimoteScannerDummy;
|
||||
}
|
||||
#endif
|
||||
|
@ -66,7 +66,7 @@ void WiimoteScannerDarwin::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
|
||||
for (int i = 0; i < found_devices; i++)
|
||||
{
|
||||
IOBluetoothDevice* dev = [en nextObject];
|
||||
if (!IsValidBluetoothName([[dev name] UTF8String]))
|
||||
if (!IsValidDeviceName([[dev name] UTF8String]))
|
||||
continue;
|
||||
|
||||
Wiimote* wm = new WiimoteDarwin([dev retain]);
|
||||
@ -92,55 +92,6 @@ bool WiimoteScannerDarwin::IsReady() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void WiimoteScannerDarwinHID::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
|
||||
Wiimote*& found_board)
|
||||
{
|
||||
found_board = nullptr;
|
||||
|
||||
IOHIDManagerRef hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone);
|
||||
bool hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID();
|
||||
if (hidFailed)
|
||||
{
|
||||
CFRelease(hid);
|
||||
WARN_LOG(WIIMOTE, "No HID manager");
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray* criteria = @[
|
||||
@{ @kIOHIDVendorIDKey : @0x057e,
|
||||
@kIOHIDProductIDKey : @0x0306 },
|
||||
@{ @kIOHIDVendorIDKey : @0x057e,
|
||||
@kIOHIDProductIDKey : @0x0330 },
|
||||
];
|
||||
IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria);
|
||||
if (IOHIDManagerOpen(hid, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
|
||||
WARN_LOG(WIIMOTE, "Failed to open HID Manager");
|
||||
CFSetRef devices = IOHIDManagerCopyDevices(hid);
|
||||
if (devices)
|
||||
{
|
||||
int found_devices = CFSetGetCount(devices);
|
||||
if (found_devices)
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices);
|
||||
|
||||
IOHIDDeviceRef values[found_devices];
|
||||
CFSetGetValues(devices, reinterpret_cast<const void**>(&values));
|
||||
for (int i = 0; i < found_devices; i++)
|
||||
{
|
||||
Wiimote* wm = new WiimoteDarwinHid(values[i]);
|
||||
found_wiimotes.push_back(wm);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(hid);
|
||||
}
|
||||
|
||||
bool WiimoteScannerDarwinHID::IsReady() const
|
||||
{
|
||||
// TODO: only return true when !hidFailed
|
||||
return true;
|
||||
}
|
||||
|
||||
WiimoteDarwin::WiimoteDarwin(IOBluetoothDevice* device) : m_btd(device)
|
||||
{
|
||||
m_inputlen = 0;
|
||||
@ -296,117 +247,6 @@ void WiimoteDarwin::DisablePowerAssertionInternal()
|
||||
ERROR_LOG(WIIMOTE, "Could not release power management assertion: %08x", ret);
|
||||
}
|
||||
}
|
||||
|
||||
WiimoteDarwinHid::WiimoteDarwinHid(IOHIDDeviceRef device) : m_device(device)
|
||||
{
|
||||
CFRetain(m_device);
|
||||
m_connected = false;
|
||||
m_report_buffer = Report(MAX_PAYLOAD);
|
||||
}
|
||||
|
||||
WiimoteDarwinHid::~WiimoteDarwinHid()
|
||||
{
|
||||
Shutdown();
|
||||
CFRelease(m_device);
|
||||
}
|
||||
|
||||
bool WiimoteDarwinHid::ConnectInternal()
|
||||
{
|
||||
IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone);
|
||||
m_connected = ret == kIOReturnSuccess;
|
||||
if (m_connected)
|
||||
{
|
||||
IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDDeviceRegisterInputReportCallback(m_device, m_report_buffer.data() + 1, MAX_PAYLOAD - 1,
|
||||
&WiimoteDarwinHid::ReportCallback, this);
|
||||
IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this);
|
||||
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret);
|
||||
}
|
||||
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void WiimoteDarwinHid::DisconnectInternal()
|
||||
{
|
||||
IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOWakeup();
|
||||
IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone);
|
||||
if (ret != kIOReturnSuccess)
|
||||
ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret);
|
||||
|
||||
if (!IsConnected())
|
||||
return;
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1);
|
||||
|
||||
m_buffered_reports.Clear();
|
||||
|
||||
m_connected = false;
|
||||
}
|
||||
|
||||
bool WiimoteDarwinHid::IsConnected() const
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
void WiimoteDarwinHid::IOWakeup()
|
||||
{
|
||||
m_interrupted.store(true);
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
}
|
||||
|
||||
int WiimoteDarwinHid::IORead(u8* buf)
|
||||
{
|
||||
Report rpt;
|
||||
m_interrupted.store(false);
|
||||
while (m_buffered_reports.Empty() && !m_interrupted.load())
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
|
||||
|
||||
if (m_buffered_reports.Pop(rpt))
|
||||
{
|
||||
memcpy(buf, rpt.data(), rpt.size());
|
||||
return rpt.size();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WiimoteDarwinHid::IOWrite(u8 const* buf, size_t len)
|
||||
{
|
||||
IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1);
|
||||
if (ret != kIOReturnSuccess)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret);
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void WiimoteDarwinHid::QueueBufferReport(int length)
|
||||
{
|
||||
Report rpt(m_report_buffer);
|
||||
rpt[0] = 0xa1;
|
||||
rpt.resize(length + 1);
|
||||
m_buffered_reports.Push(std::move(rpt));
|
||||
}
|
||||
|
||||
void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type,
|
||||
u32 report_id, u8* report, CFIndex report_length)
|
||||
{
|
||||
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
|
||||
report[0] = report_id;
|
||||
wm->QueueBufferReport(report_length);
|
||||
}
|
||||
|
||||
void WiimoteDarwinHid::RemoveCallback(void* context, IOReturn result, void*)
|
||||
{
|
||||
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
|
||||
wm->DisconnectInternal();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@implementation SearchBT
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
|
||||
// Work around an Apple bug: for some reason, IOBluetooth.h errors on
|
||||
// inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed
|
||||
// this as <rdar://15312520>; in the meantime...
|
||||
@ -13,10 +11,11 @@
|
||||
#undef NS_ENUM_AVAILABLE
|
||||
#define NS_ENUM_AVAILABLE(...)
|
||||
// end hack
|
||||
#include <IOBluetooth/IOBluetooth.h>
|
||||
#include <IOKit/hid/IOHIDManager.h>
|
||||
#import <IOBluetooth/IOBluetooth.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
class WiimoteDarwin final : public Wiimote
|
||||
@ -47,31 +46,4 @@ private:
|
||||
CFRunLoopRef m_wiimote_thread_run_loop;
|
||||
IOPMAssertionID m_pm_assertion;
|
||||
};
|
||||
|
||||
class WiimoteDarwinHid final : public Wiimote
|
||||
{
|
||||
public:
|
||||
WiimoteDarwinHid(IOHIDDeviceRef device);
|
||||
~WiimoteDarwinHid() override;
|
||||
|
||||
protected:
|
||||
bool ConnectInternal() override;
|
||||
void DisconnectInternal() override;
|
||||
bool IsConnected() const override;
|
||||
void IOWakeup() override;
|
||||
int IORead(u8* buf) override;
|
||||
int IOWrite(u8 const* buf, size_t len) override;
|
||||
|
||||
private:
|
||||
static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type,
|
||||
u32 reportID, u8* report, CFIndex reportLength);
|
||||
static void RemoveCallback(void* context, IOReturn result, void* sender);
|
||||
void QueueBufferReport(int length);
|
||||
IOHIDDeviceRef m_device;
|
||||
bool m_connected;
|
||||
std::atomic<bool> m_interrupted;
|
||||
Report m_report_buffer;
|
||||
Common::FifoQueue<Report> m_buffered_reports;
|
||||
};
|
||||
|
||||
} // namespace WiimoteReal
|
||||
|
152
Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
Normal file
152
Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteHid.h"
|
||||
#include "Core/HW/WiimoteReal/IOhidapi.h"
|
||||
|
||||
// This is used to store connected Wiimotes' paths, so we don't connect
|
||||
// more than once to the same device.
|
||||
static std::unordered_set<std::string> s_known_paths;
|
||||
|
||||
static bool IsDeviceUsable(const std::string& device_path)
|
||||
{
|
||||
hid_device* handle = hid_open_path(device_path.c_str());
|
||||
if (handle == nullptr)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Could not connect to Wiimote at \"%s\". "
|
||||
"Do you have permission to access the device?",
|
||||
device_path.c_str());
|
||||
return false;
|
||||
}
|
||||
// Some third-party adapters (DolphinBar) always expose all four Wiimotes as HIDs
|
||||
// even when they are not connected, which causes an endless error loop when we try to use them.
|
||||
// Try to write a report to the device to see if this Wiimote is really usable.
|
||||
static const u8 report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
|
||||
const int result = hid_write(handle, report, sizeof(report));
|
||||
// The DolphinBar uses EPIPE to signal the absence of a Wiimote connected to this HID.
|
||||
if (result == -1 && errno != EPIPE)
|
||||
ERROR_LOG(WIIMOTE, "Couldn't write to Wiimote at \"%s\".", device_path.c_str());
|
||||
|
||||
hid_close(handle);
|
||||
return result != -1;
|
||||
}
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
WiimoteScannerHidapi::WiimoteScannerHidapi()
|
||||
{
|
||||
s_known_paths.clear();
|
||||
int ret = hid_init();
|
||||
_assert_msg_(WIIMOTE, ret == 0, "Couldn't initialise hidapi.");
|
||||
}
|
||||
|
||||
WiimoteScannerHidapi::~WiimoteScannerHidapi()
|
||||
{
|
||||
if (hid_exit() == -1)
|
||||
ERROR_LOG(WIIMOTE, "Failed to clean up hidapi.");
|
||||
}
|
||||
|
||||
bool WiimoteScannerHidapi::IsReady() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote*& board)
|
||||
{
|
||||
hid_device_info* list = hid_enumerate(0x0, 0x0);
|
||||
for (hid_device_info* device = list; device; device = device->next)
|
||||
{
|
||||
const std::string name = device->product_string ? UTF16ToUTF8(device->product_string) : "";
|
||||
const bool is_wiimote =
|
||||
IsValidDeviceName(name) || (device->vendor_id == 0x057e &&
|
||||
(device->product_id == 0x0306 || device->product_id == 0x0330));
|
||||
if (!is_wiimote || s_known_paths.count(device->path) != 0 || !IsDeviceUsable(device->path))
|
||||
continue;
|
||||
|
||||
const bool is_balance_board = IsBalanceBoardName(name);
|
||||
NOTICE_LOG(WIIMOTE, "Found %s at %s: %ls %ls (%04hx:%04hx)",
|
||||
is_balance_board ? "balance board" : "Wiimote", device->path,
|
||||
device->manufacturer_string, device->product_string, device->vendor_id,
|
||||
device->product_id);
|
||||
|
||||
Wiimote* wiimote = new WiimoteHidapi(device->path);
|
||||
if (is_balance_board)
|
||||
board = wiimote;
|
||||
else
|
||||
wiimotes.push_back(wiimote);
|
||||
}
|
||||
hid_free_enumeration(list);
|
||||
}
|
||||
|
||||
WiimoteHidapi::WiimoteHidapi(const std::string& device_path) : m_device_path(device_path)
|
||||
{
|
||||
s_known_paths.insert(m_device_path);
|
||||
}
|
||||
|
||||
WiimoteHidapi::~WiimoteHidapi()
|
||||
{
|
||||
Shutdown();
|
||||
s_known_paths.erase(m_device_path);
|
||||
}
|
||||
|
||||
bool WiimoteHidapi::ConnectInternal()
|
||||
{
|
||||
m_handle = hid_open_path(m_device_path.c_str());
|
||||
if (m_handle == nullptr)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Could not connect to Wiimote at \"%s\". "
|
||||
"Do you have permission to access the device?",
|
||||
m_device_path.c_str());
|
||||
s_known_paths.erase(m_device_path);
|
||||
}
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
void WiimoteHidapi::DisconnectInternal()
|
||||
{
|
||||
hid_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
|
||||
bool WiimoteHidapi::IsConnected() const
|
||||
{
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
int WiimoteHidapi::IORead(u8* buf)
|
||||
{
|
||||
int timeout = 200; // ms
|
||||
int result = hid_read_timeout(m_handle, buf + 1, MAX_PAYLOAD - 1, timeout);
|
||||
// TODO: If and once we use hidapi across plaforms, change our internal API to clean up this mess.
|
||||
if (result == -1)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Failed to read from %s.", m_device_path.c_str());
|
||||
return 0; // error
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
return -1; // didn't read packet
|
||||
}
|
||||
buf[0] = WM_SET_REPORT | WM_BT_INPUT;
|
||||
return result + 1; // number of bytes read
|
||||
}
|
||||
|
||||
int WiimoteHidapi::IOWrite(const u8* buf, size_t len)
|
||||
{
|
||||
_dbg_assert_(WIIMOTE, buf[0] == (WM_SET_REPORT | WM_BT_OUTPUT));
|
||||
int result = hid_write(m_handle, buf + 1, len - 1);
|
||||
if (result == -1)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Failed to write to %s.", m_device_path.c_str());
|
||||
return 0;
|
||||
}
|
||||
return (result == 0) ? 1 : result;
|
||||
}
|
||||
}; // WiimoteReal
|
50
Source/Core/Core/HW/WiimoteReal/IOhidapi.h
Normal file
50
Source/Core/Core/HW/WiimoteReal/IOhidapi.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_HIDAPI
|
||||
#include <hidapi.h>
|
||||
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
class WiimoteHidapi final : public Wiimote
|
||||
{
|
||||
public:
|
||||
explicit WiimoteHidapi(const std::string& device_path);
|
||||
~WiimoteHidapi() override;
|
||||
|
||||
protected:
|
||||
bool ConnectInternal() override;
|
||||
void DisconnectInternal() override;
|
||||
bool IsConnected() const override;
|
||||
void IOWakeup() override {}
|
||||
int IORead(u8* buf) override;
|
||||
int IOWrite(const u8* buf, size_t len) override;
|
||||
|
||||
private:
|
||||
std::string m_device_path;
|
||||
hid_device* m_handle = nullptr;
|
||||
};
|
||||
|
||||
class WiimoteScannerHidapi final : public WiimoteScannerBackend
|
||||
{
|
||||
public:
|
||||
WiimoteScannerHidapi();
|
||||
~WiimoteScannerHidapi();
|
||||
bool IsReady() const override;
|
||||
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
|
||||
void Update() override{}; // not needed for hidapi
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
#include "Core/HW/WiimoteReal/IODummy.h"
|
||||
namespace WiimoteReal
|
||||
{
|
||||
using WiimoteScannerHidapi = WiimoteScannerDummy;
|
||||
}
|
||||
#endif
|
@ -21,6 +21,7 @@
|
||||
#include "Core/HW/WiimoteReal/IOLinux.h"
|
||||
#include "Core/HW/WiimoteReal/IOWin.h"
|
||||
#include "Core/HW/WiimoteReal/IOdarwin.h"
|
||||
#include "Core/HW/WiimoteReal/IOhidapi.h"
|
||||
#include "Core/Host.h"
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
@ -616,7 +617,7 @@ void Initialize(::Wiimote::InitializeMode init_mode)
|
||||
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerAndroid>());
|
||||
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerWindows>());
|
||||
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerDarwin>());
|
||||
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerDarwinHID>());
|
||||
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerHidapi>());
|
||||
g_wiimote_scanner.StartThread();
|
||||
}
|
||||
|
||||
@ -810,7 +811,7 @@ void StateChange(EMUSTATE_CHANGE newState)
|
||||
// TODO: disable/enable auto reporting, maybe
|
||||
}
|
||||
|
||||
bool IsValidBluetoothName(const std::string& name)
|
||||
bool IsValidDeviceName(const std::string& name)
|
||||
{
|
||||
return "Nintendo RVL-CNT-01" == name || "Nintendo RVL-CNT-01-TR" == name ||
|
||||
IsBalanceBoardName(name);
|
||||
|
@ -160,7 +160,7 @@ void ConnectOnInput(int _WiimoteNumber);
|
||||
void StateChange(EMUSTATE_CHANGE newState);
|
||||
void ChangeWiimoteSource(unsigned int index, int source);
|
||||
|
||||
bool IsValidBluetoothName(const std::string& name);
|
||||
bool IsValidDeviceName(const std::string& name);
|
||||
bool IsBalanceBoardName(const std::string& name);
|
||||
|
||||
#ifdef ANDROID
|
||||
|
Loading…
Reference in New Issue
Block a user