From eb4e1bcf4482f148d2a163d143dbcba75db95fe8 Mon Sep 17 00:00:00 2001 From: durswd Date: Sun, 20 Sep 2020 21:22:07 +0900 Subject: [PATCH 1/5] Implemented hid detector --- core/src/Input/Joystick.cpp | 527 +++++++++++++++++++++++++++++++++++- core/src/Input/Joystick.h | 4 + 2 files changed, 530 insertions(+), 1 deletion(-) diff --git a/core/src/Input/Joystick.cpp b/core/src/Input/Joystick.cpp index 740b93b2..99657299 100644 --- a/core/src/Input/Joystick.cpp +++ b/core/src/Input/Joystick.cpp @@ -1,12 +1,120 @@ #include "Joystick.h" +#include + #include #include #include "../Logger/Log.h" namespace Altseed2 { + +class HID { + bool initialized_ = false; + +public: + struct DeviceProperty { + bool IsValid = false; + std::string Path; + std::wstring ProductString; + std::wstring ManifactureString; + uint16_t ProductID; + uint16_t VenderID; + std::wstring SerialNumber; + }; + + bool Init() { + if (initialized_) { + return false; + } + + if (hid_init() != 0) { + return false; + } + + initialized_ = true; + return true; + } + + ~HID() { + if (initialized_) { + hid_exit(); + } + } + + std::vector Enumerate() const { + std::vector devices; + + // Get HID handler + hid_device_info* firstDevice = hid_enumerate(0, 0); + auto device = firstDevice; + + while (device) { + DeviceProperty prop; + prop.Path = device->path; + prop.ProductID = device->product_id; + prop.VenderID = device->vendor_id; + + if (device->product_string != nullptr) { + prop.ProductString = device->product_string; + } + + if (device->manufacturer_string != nullptr) { + prop.ManifactureString = device->manufacturer_string; + } + + if (device->serial_number != nullptr) { + prop.SerialNumber = device->serial_number; + } + + prop.IsValid = true; + + devices.emplace_back(std::move(prop)); + device = device->next; + } + hid_free_enumeration(firstDevice); + + return std::move(devices); + } + + std::vector GetPairDevices(std::vector properties) const { + std::vector devices; + + if (properties.size() == 0) { + return std::move(devices); + } + + auto hid = Enumerate(); + + size_t propIndex = 0; + + devices.resize(properties.size()); + + for (size_t i = 0; i < hid.size(); i++) { + if (properties[propIndex].SerialNumber != L"" && properties[propIndex].SerialNumber == hid[i].SerialNumber) { + devices[propIndex] = hid[i]; + propIndex++; + if (propIndex >= properties.size()) { + break; + } + + continue; + } else if (properties[propIndex].ProductString != L"" && properties[propIndex].ProductString == hid[i].ProductString) { + devices[propIndex] = hid[i]; + propIndex++; + if (propIndex >= properties.size()) { + break; + } + + continue; + } + } + + return std::move(devices); + } +}; + JoystickInfo::JoystickInfo(const std::u16string name, const int32_t buttonCount, const int32_t axisCount, const bool isGamepad, const std::u16string gamepadName, const char* guid) : name_(name), buttonCount_(buttonCount), axisCount_(axisCount), isGamepad_(isGamepad), gamepadName_(gamepadName) { guid_ = utf8_to_utf16(std::string(guid)); @@ -40,7 +148,6 @@ Joystick::Joystick() : connectedJoystickCount_(0) { bool Joystick::Initialize() { instance_ = MakeAsdShared(); instance_->RefreshInputState(); - return true; }; @@ -141,6 +248,34 @@ void Joystick::RefreshInputState() { currentHit_[jind][15] = currentAxis_[jind][5] > 0.8; } } + + if (hid_ == nullptr) { + hid_ = std::make_shared(); + if (!hid_->Init()) { + hid_ = nullptr; + } + } + + if (hid_ != nullptr) { + std::vector props; + props.resize(connectedJoystickCount_); + + for (int32_t i = 0; i < connectedJoystickCount_; i++) { +#if defined(_WIN32) + props[i].ProductString = glfwJoystickGetProductName(i); +#elif defined(__APPLE__) + props[i].SerialNumber = glfwJoystickGetSerialNumberStr(i); +#endif + } + + const auto pairs = hid_->GetPairDevices(props); + + for (size_t i = 0; i < pairs.size(); i++) { + if (pairs[i].IsValid) { + // TODO + } + } + } }; bool Joystick::IsPresent(int32_t joystickIndex) const { @@ -243,3 +378,393 @@ float Joystick::GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) con // } } // namespace Altseed2 + +// Oldcode +/** + +#include +#include + +#include "../Common/Miscs.h" +#include "Joystick.h" + +#define JOYCON_BUTTON_COUNT 15 + +#define JOYCON_L_PRODUCT_ID 8198 +#define JOYCON_R_PRODUCT_ID 8199 +#define DUALSHOCK4_PRODUCT_ID 0x0 +#define XBOX360_PRODUCT_ID 0x0 + +#define JOYCON_L + +namespace Altseed { + +std::shared_ptr Joystick::instance_ = nullptr; + +bool Joystick::Initialize() { + if (instance_ == nullptr) { + instance_ = MakeAsdShared(); + instance_->types_.fill(JoystickType::Other); + instance_->globalCount_ = 0; + } + + for (int32_t i = 0; i < MAX_JOYSTICKS_NUM; i++) { + instance_->currentHit_[i].fill(false); + instance_->preHit_[i].fill(false); + // currentAxis[i].fill(0); + } + return true; +}; + +void Joystick::Terminate() { + for (int jind = 0; jind < MAX_JOYSTICKS_NUM; jind++) { + if (!instance_->handler_[jind]) return; + + if (instance_->types_[jind] == JoystickType::JoyconL || instance_->types_[jind] == JoystickType::JoyconR) { + uint8_t data[0x01]; + data[0] = 0; + instance_->SendSubcommand(instance_->handler_[jind], 0x30, data, 1); + + data[0] = 0x01; + instance_->SendSubcommand(instance_->handler_[jind], 0x48, data, 1); + + hid_close(instance_->handler_[jind]); + } + } + + instance_ = nullptr; +} + +std::shared_ptr& Joystick::GetInstance() { return instance_; } + +bool Joystick::IsPresent(int32_t joystickIndex) { return (bool)handler_[joystickIndex]; } + +std::u16string Joystick::ToU16(const std::wstring& wstr) { + if (sizeof(wchar_t) == 4) { + std::u32string u32(wstr.cbegin(), wstr.cend()); + + std::array u16char; + for (size_t i = 0; i < std::min(u32.size(), u16char.size()); ++i) { + u16char[i] = (char16_t)u32[i]; + } + + if (u32.size() > 0) { + u16char[std::min(u32.size(), u16char.size()) - 1] = 0; + return std::u16string(u16char.data()); + } + + return std::u16string(); + } else { + return std::u16string(wstr.cbegin(), wstr.cend()); + } +} + +void Joystick::SendSubcommand(hid_device* dev, uint8_t command, uint8_t data[], int len) { + std::array buf; + buf.fill(0); + + buf[0] = 1; // 0x10 for rumble only + buf[1] = globalCount_; // Increment by 1 for each packet sent. It loops in 0x0 - 0xF range. + + if (globalCount_ == 0xf0) { + globalCount_ = 0x00; + } else { + globalCount_++; + } + + buf[10] = command; + memcpy(buf.data() + 11, data, len); + + hid_write(dev, buf.data(), 0x40); +} + +void Joystick::RefreshConnectedState() { + // Get HID handler + hid_device_info* firstDevice = hid_enumerate(0, 0); + auto device = firstDevice; + const char* path; + int i = 0; + + // hid_device_info* device = devices; + while (device) { + path = device->path; + + if (device->product_id == JOYCON_L_PRODUCT_ID || device->product_id == JOYCON_R_PRODUCT_ID || + device->product_id == DUALSHOCK4_PRODUCT_ID || device->product_id == XBOX360_PRODUCT_ID) { + hid_device* dev = hid_open(device->vendor_id, device->product_id, device->serial_number); + if (!dev) { + break; + } + + hid_set_nonblocking(dev, 1); + handler_[i] = dev; + + if (device->product_string != nullptr) names_[i] = ToU16(std::wstring(device->product_string)); + types_[i] = (JoystickType)device->product_id; + + if (types_[i] == JoystickType::JoyconL || types_[i] == JoystickType::JoyconR) { + // enable vibration for joycon + uint8_t data[0x01]; + data[0] = 0x01; + this->SendSubcommand(dev, 0x48, data, 1); + + // send input report mode + data[0] = 0x3F; + this->SendSubcommand(dev, 0x03, data, 1); + + // send player light + data[0] = (i + 1) % 4; + this->SendSubcommand(dev, 0x30, data, 1); + } + i++; + } + device = device->next; + } + hid_free_enumeration(firstDevice); +}; + +// NOTE: pushing in stick is handled as button +void Joystick::HandleJoyconInput(int index, unsigned char* buff, bool is_left) { + if (*buff == 0x21) { + // buttons + int target_index = 3; + if (is_left) { + target_index = 5; + } + + for (int i = 0; i <= 7; i++) { + currentHit_[index][i] = buff[target_index] & (1 << i); + currentHit_[index][i + 8] = buff[4] & (1 << i); + } + + } else if (*buff == 0x3F) { + // hundle buttons + + // convert 0x3F input report buttons status format to standard input report button status format. + int to_standard_buttons[16] = {0, 2, 3, 1, 5, 4, 14, 15, 8, 9, 11, 10, 12, 13, 6, 7}; + + for (int i = 0; i <= 7; i++) { + currentHit_[index][to_standard_buttons[i]] = buff[1] & (1 << i); + currentHit_[index][to_standard_buttons[i + 8]] = buff[2] & (1 << i); + } + + // stick + int axis_type_H = (int32_t)JoystickAxisType::RightH; + int axis_type_V = (int32_t)JoystickAxisType::RightV; + if (is_left) { + axis_type_H = (int32_t)JoystickAxisType::LeftH; + axis_type_V = (int32_t)JoystickAxisType::LeftV; + } + + switch (buff[3]) { + // Top + case 0: + currentAxis_[index][axis_type_H] = 0; + currentAxis_[index][axis_type_V] = 1; + break; + // Top-right + case 1: + currentAxis_[index][axis_type_H] = 1; + currentAxis_[index][axis_type_V] = 1; + break; + // Right + case 2: + currentAxis_[index][axis_type_H] = 1; + currentAxis_[index][axis_type_V] = 0; + break; + // Bottom-right + case 3: + currentAxis_[index][axis_type_H] = 1; + currentAxis_[index][axis_type_V] = -1; + break; + // Bottom + case 4: + currentAxis_[index][axis_type_H] = 0; + currentAxis_[index][axis_type_V] = -1; + break; + // Bottom-Left + case 5: + currentAxis_[index][axis_type_H] = -1; + currentAxis_[index][axis_type_V] = -1; + break; + // Left + case 6: + currentAxis_[index][axis_type_H] = -1; + currentAxis_[index][axis_type_V] = 0; + break; + // Top-left + case 7: + currentAxis_[index][axis_type_H] = -1; + currentAxis_[index][axis_type_V] = 1; + break; + + default: + currentAxis_[index][axis_type_H] = 0; + currentAxis_[index][axis_type_V] = 0; + break; + } + } +}; + +void Joystick::RefreshInputState() { + preHit_ = currentHit_; + + for (int jind = 0; jind < MAX_JOYSTICKS_NUM; jind++) { + if (!handler_[jind]) return; + + // read input report + uint8_t buff[0x40]; + memset(buff, 0x40, size_t(0x40)); + size_t size = 49; + + int ret = hid_read(handler_[jind], buff, size); + if (!ret) { + return; + } + + if (types_[jind] == JoystickType::JoyconL) { + HandleJoyconInput(jind, buff, true); + } else if (types_[jind] == JoystickType::JoyconR) { + HandleJoyconInput(jind, buff, false); + } + } +}; + +void Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { + if (types_[joystickIndex] == Altseed::JoystickType::JoyconL || types_[joystickIndex] == Altseed::JoystickType::JoyconR) { + uint8_t buf[0x40]; + memset(buf, 0x0, size_t(0x40)); + buf[0] = 0x10; + buf[1] = 0x01; + + float freq = std::clamp(frequency, 40.0f, 1252.0f); + float amp = std::clamp(amplitude, 0.0f, 1.0f); + + uint8_t encoded_hex_freq = (uint8_t)round(log2((double)freq / 10.0) * 32.0); + + uint16_t hf = (encoded_hex_freq - 0x60) * 4; + uint8_t lf = encoded_hex_freq - 0x40; + + uint8_t encoded_hex_amp = 0; + if (amp > 0.23f) + encoded_hex_amp = (uint8_t)round(log2f(amp * 8.7f) * 32.f); + else if (amp > 0.12f) + encoded_hex_amp = (uint8_t)round(log2f(amp * 17.f) * 16.f); + else { + encoded_hex_amp = 0; + } + uint16_t hf_amp = encoded_hex_amp * 2; + uint8_t lf_amp = encoded_hex_amp / 2 + 64; + + uint8_t byte[0x08]; + + byte[0] = hf & 0xFF; + byte[1] = hf_amp + ((hf >> 8) & 0xFF); + + byte[2] = lf + ((lf_amp >> 8) & 0xFF); + byte[3] = lf_amp & 0xFF; + + for (int i = 4; i <= 7; i++) { + byte[i] = byte[i - 4]; + } + + memcpy(buf + 2, byte, 8); + hid_write(handler_[0], buf, sizeof(buf)); + } +}; + +ButtonState Joystick::GetButtonStateByIndex(int32_t joystickIndex, int32_t buttonIndex) const { + if (buttonIndex < 0) return ButtonState::Free; + + if (currentHit_[joystickIndex][buttonIndex] && preHit_[joystickIndex][buttonIndex]) + return ButtonState::Hold; + else if (!currentHit_[joystickIndex][buttonIndex] && preHit_[joystickIndex][buttonIndex]) + return ButtonState::Release; + else if (currentHit_[joystickIndex][buttonIndex] && !preHit_[joystickIndex][buttonIndex]) + return ButtonState::Push; + else + return ButtonState::Free; +}; + +ButtonState Joystick::GetButtonStateByType(int32_t joystickIndex, JoystickButtonType type) const { + auto jtype = GetJoystickType(joystickIndex); + + if (jtype == JoystickType::Other) return ButtonState::Free; + + if (jtype == JoystickType::JoyconL) { + std::array maps; + maps.fill(-1); + + maps[(int32_t)JoystickButtonType::LeftDown] = 0; + maps[(int32_t)JoystickButtonType::LeftUp] = 1; + maps[(int32_t)JoystickButtonType::LeftRight] = 2; + maps[(int32_t)JoystickButtonType::LeftLeft] = 3; + + maps[(int32_t)JoystickButtonType::R3] = 4; + maps[(int32_t)JoystickButtonType::L3] = 5; + + maps[(int32_t)JoystickButtonType::L1] = 6; + maps[(int32_t)JoystickButtonType::L2] = 7; + + maps[(int32_t)JoystickButtonType::Select] = 8; + maps[(int32_t)JoystickButtonType::Start] = 9; + maps[(int32_t)JoystickButtonType::RightPush] = 10; + maps[(int32_t)JoystickButtonType::LeftPush] = 11; + + maps[(int32_t)JoystickButtonType::Home] = 12; + maps[(int32_t)JoystickButtonType::Capture] = 13; + + return GetButtonStateByIndex(joystickIndex, maps[(int32_t)type]); + } else if (jtype == JoystickType::JoyconR) { + std::array maps; + maps.fill(-1); + + maps[(int32_t)JoystickButtonType::RightDown] = 0; + maps[(int32_t)JoystickButtonType::RightUp] = 1; + maps[(int32_t)JoystickButtonType::RightRight] = 2; + maps[(int32_t)JoystickButtonType::RightLeft] = 3; + + maps[(int32_t)JoystickButtonType::R3] = 4; + maps[(int32_t)JoystickButtonType::L3] = 5; + + maps[(int32_t)JoystickButtonType::R1] = 6; + maps[(int32_t)JoystickButtonType::R2] = 7; + + maps[(int32_t)JoystickButtonType::Select] = 8; + maps[(int32_t)JoystickButtonType::Start] = 9; + maps[(int32_t)JoystickButtonType::RightPush] = 10; + maps[(int32_t)JoystickButtonType::LeftPush] = 11; + + maps[(int32_t)JoystickButtonType::Home] = 12; + maps[(int32_t)JoystickButtonType::Capture] = 13; + + return GetButtonStateByIndex(joystickIndex, maps[(int32_t)type]); + } + + return ButtonState::Hold; +}; + +float Joystick::GetAxisStateByIndex(int32_t joystickIndex, int32_t axisIndex) const { + if (axisIndex < 0) return 0; + + return currentAxis_[joystickIndex][axisIndex]; +}; + +float Joystick::GetAxisStateByType(int32_t joystickIndex, JoystickAxisType type) const { + auto jtype = GetJoystickType(joystickIndex); + if (jtype == JoystickType::Other) return 0; + + if (jtype == JoystickType::JoyconL || jtype == JoystickType::JoyconR) { + return GetAxisStateByIndex(joystickIndex, (int32_t)type); + } + + return 0.0f; +}; + +JoystickType Joystick::GetJoystickType(int32_t index) const { return types_[index]; }; + +const char16_t* Joystick::GetJoystickName(int32_t index) const { return names_[index].c_str(); } + +} // namespace Altseed + +*/ \ No newline at end of file diff --git a/core/src/Input/Joystick.h b/core/src/Input/Joystick.h index 8e715c94..1aa037fe 100644 --- a/core/src/Input/Joystick.h +++ b/core/src/Input/Joystick.h @@ -49,6 +49,8 @@ enum class JoystickAxis : int32_t { RightTrigger = GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, }; +class HID; + class JoystickInfo : public BaseObject { private: std::u16string name_; @@ -106,6 +108,8 @@ class Joystick : public BaseObject { std::array, MAX_JOYSTICKS_NUM> gamepadPreHit_; std::array, MAX_JOYSTICKS_NUM> gamepadCurrentAxis_; + std::shared_ptr hid_; + std::u16string ToU16(const std::wstring& wstr) const; public: From fcd3360446e5cafd7d1f5ff99926aafa605cdae5 Mon Sep 17 00:00:00 2001 From: wraikny Date: Sun, 4 Oct 2020 16:37:39 +0900 Subject: [PATCH 2/5] update glfw --- thirdparty/glfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/glfw b/thirdparty/glfw index 1574faf4..7c85a620 160000 --- a/thirdparty/glfw +++ b/thirdparty/glfw @@ -1 +1 @@ -Subproject commit 1574faf4e37c864c574c35dad12f25628a01783c +Subproject commit 7c85a620db3409713dd6ee4828be479b1aaaaa6c From c0a46f2c4118075e3453bcfdfe953cfcc345fc14 Mon Sep 17 00:00:00 2001 From: wraikny Date: Sun, 4 Oct 2020 18:16:49 +0900 Subject: [PATCH 3/5] implement hid vibration --- core/src/CMakeLists.txt | 2 + core/src/Input/HID.cpp | 248 ++++++++++++++++++++++++++++++++++++ core/src/Input/HID.h | 45 +++++++ core/src/Input/Joystick.cpp | 171 +++++-------------------- core/src/Input/Joystick.h | 8 +- core/test/Joystick.cpp | 139 ++++++++++++-------- 6 files changed, 417 insertions(+), 196 deletions(-) create mode 100644 core/src/Input/HID.cpp create mode 100644 core/src/Input/HID.h diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt index aa1cdf62..ee64b8be 100644 --- a/core/src/CMakeLists.txt +++ b/core/src/CMakeLists.txt @@ -92,6 +92,8 @@ set(core_files Input/Keyboard.cpp Input/Mouse.h Input/Mouse.cpp + Input/HID.h + Input/HID.cpp Logger/Log.h Logger/Log.cpp Math/Easing.h diff --git a/core/src/Input/HID.cpp b/core/src/Input/HID.cpp new file mode 100644 index 00000000..017188f9 --- /dev/null +++ b/core/src/Input/HID.cpp @@ -0,0 +1,248 @@ +#include "HID.h" + +#include + +#include +#include + +#include "../Logger/Log.h" + +namespace Altseed2 { + +static const uint16_t VendorNintendo = 1406; +static const uint16_t ProductJoyconL = 8198; +static const uint16_t ProductJoyconR = 8199; + +bool HID::Initialize() { + if (initialized_) { + return false; + } + + if (hid_init() != 0) { + return false; + } + + initialized_ = true; + return true; +} + +HID::~HID() { + if (initialized_) { + hid_exit(); + } +} + +void HID::SendSubcommand(hid_device* handler, uint8_t command, uint8_t data[], int len) { + RETURN_IF_NULL(handler, ); + + std::array buf; + buf.fill(0); + + buf[0] = 1; // 0x10 for rumble only + buf[1] = globalCount_; // Increment by 1 for each packet sent. It loops in 0x0 - 0xF range. + + if (globalCount_ == 0xf0) { + globalCount_ = 0x00; + } else { + globalCount_++; + } + + buf[10] = command; + memcpy(buf.data() + 11, data, len); + + hid_write(handler, buf.data(), 0x40); +} + +std::vector HID::Enumerate() { + std::vector devices; + + auto firstDevice = hid_enumerate(0, 0); + auto device = firstDevice; + + while (device) { + HID::DeviceProperty prop; + prop.Path = device->path; + prop.ProductID = device->product_id; + prop.VendorID = device->vendor_id; + + if (device->product_string != nullptr) { + prop.ProductString = device->product_string; + } + + if (device->manufacturer_string != nullptr) { + prop.ManifactureString = device->manufacturer_string; + } + + if (device->serial_number != nullptr) { + prop.SerialNumber = device->serial_number; + } + + if (prop.VendorID == VendorNintendo) { + if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { + prop.Handler = hid_open(device->vendor_id, device->product_id, device->serial_number); + + if (prop.Handler != nullptr) { + hid_set_nonblocking(prop.Handler, 1); + + // enable vibration for joycon + uint8_t data[0x01]; + data[0] = 0x01; + SendSubcommand(prop.Handler, 0x48, data, 1); + + // // send player light + // data[0] = (i + 1) % 4; + // SendSubcommand(prop.Handler, 0x30, data, 1); + } + } + } + + devices.emplace_back(std::move(prop)); + device = device->next; + } + hid_free_enumeration(firstDevice); + + return devices; +} + +std::vector HID::GetPairDevices(std::vector properties) { + std::vector devices; + + if (properties.size() == 0) { + return devices; + } + + auto hid = Enumerate(); + + size_t propIndex = 0; + + devices.resize(properties.size()); + + for (size_t i = 0; i < hid.size(); i++) { + if (properties[propIndex].SerialNumber != L"" && properties[propIndex].SerialNumber == hid[i].SerialNumber) { + devices[propIndex] = std::move(hid[i]); + propIndex++; + if (propIndex >= properties.size()) { + break; + } + + continue; + } else if (properties[propIndex].ProductString != L"" && properties[propIndex].ProductString == hid[i].ProductString) { + devices[propIndex] = std::move(hid[i]); + propIndex++; + if (propIndex >= properties.size()) { + break; + } + + continue; + } + } + + return devices; +} + +void HID::TerminateDevices() { + for (const auto& prop : pairs_) { + if (prop.Handler != nullptr) { + if (prop.VendorID == VendorNintendo) { + if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { + uint8_t data[0x01]; + // data[0] = 0; + // this->SendSubcommand(prop.Handler, 0x30, data, 1); + + data[0] = 0x01; + this->SendSubcommand(prop.Handler, 0x48, data, 1); + } + } + + hid_close(prop.Handler); + } + } +} + +void HID::Refresh(int connectedJoystickCount) { + TerminateDevices(); + + std::vector props; + props.resize(connectedJoystickCount); + + for (int32_t i = 0; i < connectedJoystickCount; i++) { +#if defined(_WIN32) + props[i].ProductString = glfwJoystickGetProductName(i); +#elif defined(__APPLE__) + props[i].SerialNumber = glfwJoystickGetSerialNumberStr(i); +#endif + } + + pairs_ = GetPairDevices(props); +} + +bool HID::Vibrate(int joystickIndex, float frequency, float amplitude) { + if (joystickIndex < 0 || pairs_.size() <= joystickIndex) { + Log::GetInstance()->Error(LogCategory::Core, u"HID::Vibarte: index is out of range"); + return false; + } + + const DeviceProperty& prop = pairs_.at(joystickIndex); + if (prop.Handler == nullptr) { + Log::GetInstance()->Error(LogCategory::Core, u"HID::Vibarte: Device is not valid"); + return false; + } + + if (prop.VendorID == VendorNintendo) { + if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { + VibrateJoycon(prop.Handler, frequency, amplitude); + return true; + } + } + + Log::GetInstance()->Error(LogCategory::Core, u"HID::Vibarte: Device type is not supported"); + return false; +} + +void HID::VibrateJoycon(hid_device* handler, float frequency, float amplitude) { + RETURN_IF_NULL(handler,); + + uint8_t buf[0x40]; + memset(buf, 0x0, size_t(0x40)); + buf[0] = 0x10; + buf[1] = 0x01; + + float freq = std::clamp(frequency, 40.0f, 1252.0f); + float amp = std::clamp(amplitude, 0.0f, 1.0f); + + uint8_t encoded_hex_freq = (uint8_t)round(log2((double)freq / 10.0) * 32.0); + + uint16_t hf = (encoded_hex_freq - 0x60) * 4; + uint8_t lf = encoded_hex_freq - 0x40; + + uint8_t encoded_hex_amp = 0; + + if (amp > 0.23f) { + encoded_hex_amp = (uint8_t)round(log2f(amp * 8.7f) * 32.f); + } else if (amp > 0.12f) { + encoded_hex_amp = (uint8_t)round(log2f(amp * 17.f) * 16.f); + } else { + encoded_hex_amp = 0; + } + + uint16_t hf_amp = encoded_hex_amp * 2; + uint8_t lf_amp = encoded_hex_amp / 2 + 64; + + uint8_t byte[0x08]; + + byte[0] = hf & 0xFF; + byte[1] = hf_amp + ((hf >> 8) & 0xFF); + + byte[2] = lf + ((lf_amp >> 8) & 0xFF); + byte[3] = lf_amp & 0xFF; + + for (int i = 4; i <= 7; i++) { + byte[i] = byte[i - 4]; + } + + memcpy(buf + 2, byte, 8); + + hid_write(handler, buf, sizeof(buf)); +} + +} // namespace Altseed2 \ No newline at end of file diff --git a/core/src/Input/HID.h b/core/src/Input/HID.h new file mode 100644 index 00000000..03986481 --- /dev/null +++ b/core/src/Input/HID.h @@ -0,0 +1,45 @@ +#pragma once +#include + +#include +#include +#include + +#include "../Window/Window.h" +#include "ButtonState.h" + +namespace Altseed2 { + +class HID { +private: + struct DeviceProperty { + std::string Path; + std::wstring ProductString; + std::wstring ManifactureString; + uint16_t ProductID; + uint16_t VendorID; + std::wstring SerialNumber; + hid_device* Handler; + }; + + uint8_t globalCount_; + + bool initialized_ = false; + std::vector pairs_; + + std::vector Enumerate(); + std::vector GetPairDevices(std::vector properties); + void SendSubcommand(hid_device* handler, uint8_t command, uint8_t data[], int len); + + void VibrateJoycon(hid_device* handler, float frequency, float amplitude); + +public: + ~HID(); + bool Initialize(); + void TerminateDevices(); + void Refresh(int connectedJoystickCount); + + bool Vibrate(int joystickIndex, float frequency, float amplitude); +}; + +} // namespace Altseed2 \ No newline at end of file diff --git a/core/src/Input/Joystick.cpp b/core/src/Input/Joystick.cpp index 99657299..d9cabb08 100644 --- a/core/src/Input/Joystick.cpp +++ b/core/src/Input/Joystick.cpp @@ -10,111 +10,6 @@ namespace Altseed2 { -class HID { - bool initialized_ = false; - -public: - struct DeviceProperty { - bool IsValid = false; - std::string Path; - std::wstring ProductString; - std::wstring ManifactureString; - uint16_t ProductID; - uint16_t VenderID; - std::wstring SerialNumber; - }; - - bool Init() { - if (initialized_) { - return false; - } - - if (hid_init() != 0) { - return false; - } - - initialized_ = true; - return true; - } - - ~HID() { - if (initialized_) { - hid_exit(); - } - } - - std::vector Enumerate() const { - std::vector devices; - - // Get HID handler - hid_device_info* firstDevice = hid_enumerate(0, 0); - auto device = firstDevice; - - while (device) { - DeviceProperty prop; - prop.Path = device->path; - prop.ProductID = device->product_id; - prop.VenderID = device->vendor_id; - - if (device->product_string != nullptr) { - prop.ProductString = device->product_string; - } - - if (device->manufacturer_string != nullptr) { - prop.ManifactureString = device->manufacturer_string; - } - - if (device->serial_number != nullptr) { - prop.SerialNumber = device->serial_number; - } - - prop.IsValid = true; - - devices.emplace_back(std::move(prop)); - device = device->next; - } - hid_free_enumeration(firstDevice); - - return std::move(devices); - } - - std::vector GetPairDevices(std::vector properties) const { - std::vector devices; - - if (properties.size() == 0) { - return std::move(devices); - } - - auto hid = Enumerate(); - - size_t propIndex = 0; - - devices.resize(properties.size()); - - for (size_t i = 0; i < hid.size(); i++) { - if (properties[propIndex].SerialNumber != L"" && properties[propIndex].SerialNumber == hid[i].SerialNumber) { - devices[propIndex] = hid[i]; - propIndex++; - if (propIndex >= properties.size()) { - break; - } - - continue; - } else if (properties[propIndex].ProductString != L"" && properties[propIndex].ProductString == hid[i].ProductString) { - devices[propIndex] = hid[i]; - propIndex++; - if (propIndex >= properties.size()) { - break; - } - - continue; - } - } - - return std::move(devices); - } -}; - JoystickInfo::JoystickInfo(const std::u16string name, const int32_t buttonCount, const int32_t axisCount, const bool isGamepad, const std::u16string gamepadName, const char* guid) : name_(name), buttonCount_(buttonCount), axisCount_(axisCount), isGamepad_(isGamepad), gamepadName_(gamepadName) { guid_ = utf8_to_utf16(std::string(guid)); @@ -147,11 +42,22 @@ Joystick::Joystick() : connectedJoystickCount_(0) { bool Joystick::Initialize() { instance_ = MakeAsdShared(); + + instance_->hid_ = std::make_unique(); + if (!instance_->hid_->Initialize()) { + Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Initialize: failed to initialize HID"); + instance_->hid_ = nullptr; + } + instance_->RefreshInputState(); return true; }; void Joystick::Terminate() { + if(instance_->hid_ != nullptr) { + instance_->hid_->TerminateDevices(); + } + instance_ = nullptr; } @@ -181,6 +87,9 @@ void Joystick::RefreshInputState() { preHit_ = currentHit_; gamepadPreHit_ = gamepadCurrentHit_; + // Joystickが接続された、または接続が外された + bool isConnectionUpdated = false; + for (int jind = 0; jind < MAX_JOYSTICKS_NUM; jind++) { const auto isPresent = (glfwJoystickPresent(jind) == GLFW_TRUE); @@ -192,6 +101,7 @@ void Joystick::RefreshInputState() { // Joystickの接続が外れたフレーム if (joystickInfo_[jind] != nullptr) { connectedJoystickCount_--; + isConnectionUpdated = true; joystickInfo_[jind] = nullptr; } @@ -236,9 +146,7 @@ void Joystick::RefreshInputState() { auto guid = glfwGetJoystickGUID(jind); joystickInfo_[jind] = MakeAsdShared(utf8_to_utf16(std::string(name)), buttonsCount, axesCount, isGamepad, gamepadName, guid); connectedJoystickCount_++; - - // VendorId, ProductIdをもとにhid_device*を取得してunique_ptrに変換する。 - // 同じJoystickが接続されている場合にそれらをどうやって区別しよう? + isConnectionUpdated = true; } // 特定のジョイスティックに対する補正 @@ -249,32 +157,9 @@ void Joystick::RefreshInputState() { } } - if (hid_ == nullptr) { - hid_ = std::make_shared(); - if (!hid_->Init()) { - hid_ = nullptr; - } - } - - if (hid_ != nullptr) { - std::vector props; - props.resize(connectedJoystickCount_); - - for (int32_t i = 0; i < connectedJoystickCount_; i++) { -#if defined(_WIN32) - props[i].ProductString = glfwJoystickGetProductName(i); -#elif defined(__APPLE__) - props[i].SerialNumber = glfwJoystickGetSerialNumberStr(i); -#endif - } - - const auto pairs = hid_->GetPairDevices(props); - - for (size_t i = 0; i < pairs.size(); i++) { - if (pairs[i].IsValid) { - // TODO - } - } + // HID + if (hid_ != nullptr && isConnectionUpdated) { + hid_->Refresh(connectedJoystickCount_); } }; @@ -373,9 +258,21 @@ float Joystick::GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) con return gamepadCurrentAxis_[joystickIndex][index]; }; -// void Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { -// Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate is not supported yet"); -// } +bool Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { + if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { + Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: index '{0}' is out of range", joystickIndex); + return false; + } + + const auto info = joystickInfo_[joystickIndex]; + + if (info == nullptr) { + Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: joystick is not connected as {0}", joystickIndex); + return false; + } + + return hid_->Vibrate(joystickIndex, frequency, amplitude); +} } // namespace Altseed2 diff --git a/core/src/Input/Joystick.h b/core/src/Input/Joystick.h index 1aa037fe..5594f1a9 100644 --- a/core/src/Input/Joystick.h +++ b/core/src/Input/Joystick.h @@ -8,6 +8,7 @@ #include "../Window/Window.h" #include "ButtonState.h" +#include "HID.h" namespace Altseed2 { @@ -49,8 +50,6 @@ enum class JoystickAxis : int32_t { RightTrigger = GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, }; -class HID; - class JoystickInfo : public BaseObject { private: std::u16string name_; @@ -108,11 +107,12 @@ class Joystick : public BaseObject { std::array, MAX_JOYSTICKS_NUM> gamepadPreHit_; std::array, MAX_JOYSTICKS_NUM> gamepadCurrentAxis_; - std::shared_ptr hid_; + std::unique_ptr hid_; std::u16string ToU16(const std::wstring& wstr) const; public: + Joystick(); static bool Initialize(); @@ -133,7 +133,7 @@ class Joystick : public BaseObject { float GetAxisStateByIndex(int32_t joystickIndex, int32_t axisIndex) const; float GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) const; - // void Vibrate(int32_t joystickIndex, float frequency, float amplitude); + bool Vibrate(int32_t joystickIndex, float frequency, float amplitude); }; } // namespace Altseed2 diff --git a/core/test/Joystick.cpp b/core/test/Joystick.cpp index 6463a243..8cbe50eb 100644 --- a/core/test/Joystick.cpp +++ b/core/test/Joystick.cpp @@ -21,61 +21,90 @@ bool IsPushedOrHolded(int joystickIndex, Altseed2::JoystickButton btn, int count } // TODO -// void CheckVibration(int joystickIndex) { -// int vibrate_time = 500; // milliseconds -// float frequency = 150.0f; -// float amplitude = 0.8f; -// int32_t count = 0; -// std::chrono::system_clock::time_point start, end; -// start = std::chrono::system_clock::now(); -// end = std::chrono::system_clock::now(); -// bool vibrated = false; - -// while (true) { -// Altseed2::Joystick::GetInstance()->RefreshInputState(); - -// if (!vibrated && Altseed2::Joystick::GetInstance()->GetButtonStateByType(joystickIndex, Altseed2::JoystickButton::RightDown) == -// Altseed2::ButtonState::Push) { -// Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); -// start = std::chrono::system_clock::now(); -// vibrated = true; -// } - -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightRight, count)) { -// frequency += 10.0f; -// std::cout << "freq: " << frequency << std::endl; -// } -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightLeft, count)) { -// frequency -= 10.0f; -// std::cout << "freq: " << frequency << std::endl; -// } -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::R3, count)) { -// amplitude += 0.05f; -// std::cout << "amp : " << amplitude << std::endl; -// } -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::L3, count)) { -// amplitude -= 0.05f; -// ; -// std::cout << "amp : " << amplitude << std::endl; -// } -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::R2, count)) { -// vibrate_time += 10.0f; -// std::cout << "time: " << vibrate_time << std::endl; -// } -// if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::R1, count)) { -// vibrate_time -= 10.0f; -// std::cout << "time: " << vibrate_time << std::endl; -// } - -// if (vibrated && std::chrono::duration_cast(end - start).count() >= vibrate_time) { -// Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, 100.0f, 0); -// vibrated = false; -// } - -// end = std::chrono::system_clock::now(); -// count++; -// } -// } +TEST(Joystick, Vibrate) { + + auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); + EXPECT_TRUE(config != nullptr); + + EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); + + float time = 0.0f; + + while (Altseed2::Core::GetInstance()->DoEvent()) { + int joystickIndex = 0; + float frequency = 150.0f; + float amplitude = 0.8f; + + if (time < 5.0f) { + frequency = 150.0f; + amplitude = 0.5f * (0.5f * std::sin(time)) * 0.8f; + } else { + frequency = 0.5f * (0.5f * std::sin(time)) * 150.0f; + amplitude = 0.8f; + } + + Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); + + time += Altseed2::Core::GetInstance()->GetDeltaSecond(); + + if (time > 10.0f) { + break; + } + } + + // while (Altseed2::Core::GetInstance()->DoEvent()) { + // if (!vibrated && Altseed2::Joystick::GetInstance()->GetButtonStateByType(joystickIndex, Altseed2::JoystickButton::RightDown) == Altseed2::ButtonState::Push) { + // Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); + // start = std::chrono::system_clock::now(); + // vibrated = true; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightRight, count)) { + // frequency += 10.0f; + // std::cout << "freq: " << frequency << std::endl; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightDown, count)) { + // frequency -= 10.0f; + // std::cout << "freq: " << frequency << std::endl; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightUp, count)) { + // amplitude += 0.05f; + // std::cout << "amp : " << amplitude << std::endl; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightLeft, count)) { + // amplitude -= 0.05f; + // std::cout << "amp : " << amplitude << std::endl; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightBumper, count)) { + // vibrate_time += 10.0f; + // std::cout << "time: " << vibrate_time << std::endl; + // } + + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::LeftBumper, count)) { + // vibrate_time -= 10.0f; + // std::cout << "time: " << vibrate_time << std::endl; + // } + + // if (vibrated && std::chrono::duration_cast(end - start).count() >= vibrate_time) { + // Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, 100.0f, 0); + // vibrated = false; + // } + + // end = std::chrono::system_clock::now(); + // count++; + + // time += Altseed2::Core::GetInstance()->GetDeltaSecond(); + // if (time > 10.0f) { + // break; + // } + // } + + Altseed2::Core::Terminate(); +} void printJoystickInformation() { for (int i = 0; i < 16; i++) { From 59854de28f4b5113e1bcbc08f12d3c73583c149d Mon Sep 17 00:00:00 2001 From: wraikny Date: Sun, 4 Oct 2020 18:27:21 +0900 Subject: [PATCH 4/5] implement hid setlight --- core/src/Input/HID.cpp | 44 +++++++++++++++++++++++++++++-------- core/src/Input/HID.h | 5 +++-- core/src/Input/Joystick.cpp | 16 ++++++++++++++ core/src/Input/Joystick.h | 1 + core/test/Joystick.cpp | 38 ++++++++++++++++++++++++++------ 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/core/src/Input/HID.cpp b/core/src/Input/HID.cpp index 017188f9..838c1c0f 100644 --- a/core/src/Input/HID.cpp +++ b/core/src/Input/HID.cpp @@ -32,7 +32,7 @@ HID::~HID() { } } -void HID::SendSubcommand(hid_device* handler, uint8_t command, uint8_t data[], int len) { +void HID::SendSubcommand(hid_device* handler, uint8_t command, uint8_t data[], int32_t len) { RETURN_IF_NULL(handler, ); std::array buf; @@ -89,9 +89,9 @@ std::vector HID::Enumerate() { data[0] = 0x01; SendSubcommand(prop.Handler, 0x48, data, 1); - // // send player light - // data[0] = (i + 1) % 4; - // SendSubcommand(prop.Handler, 0x30, data, 1); + // send player light + data[0] = 0; + SendSubcommand(prop.Handler, 0x30, data, 1); } } } @@ -146,8 +146,8 @@ void HID::TerminateDevices() { if (prop.VendorID == VendorNintendo) { if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { uint8_t data[0x01]; - // data[0] = 0; - // this->SendSubcommand(prop.Handler, 0x30, data, 1); + data[0] = 0; + this->SendSubcommand(prop.Handler, 0x30, data, 1); data[0] = 0x01; this->SendSubcommand(prop.Handler, 0x48, data, 1); @@ -159,7 +159,7 @@ void HID::TerminateDevices() { } } -void HID::Refresh(int connectedJoystickCount) { +void HID::Refresh(int32_t connectedJoystickCount) { TerminateDevices(); std::vector props; @@ -176,7 +176,33 @@ void HID::Refresh(int connectedJoystickCount) { pairs_ = GetPairDevices(props); } -bool HID::Vibrate(int joystickIndex, float frequency, float amplitude) { +bool HID::SetLight(int32_t joystickIndex, int32_t number) { + if (joystickIndex < 0 || pairs_.size() <= joystickIndex) { + Log::GetInstance()->Error(LogCategory::Core, u"HID::SetLight: index is out of range"); + return false; + } + + const DeviceProperty& prop = pairs_.at(joystickIndex); + if (prop.Handler == nullptr) { + Log::GetInstance()->Error(LogCategory::Core, u"HID::SetLight: Device is not valid"); + return false; + } + + if (prop.VendorID == VendorNintendo) { + if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { + uint8_t data[0x01]; + // send player light + data[0] = 0b1111 & number; + SendSubcommand(prop.Handler, 0x30, data, 1); + return true; + } + } + + Log::GetInstance()->Error(LogCategory::Core, u"HID::Vibarte: Device type is not supported"); + return false; +} + +bool HID::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { if (joystickIndex < 0 || pairs_.size() <= joystickIndex) { Log::GetInstance()->Error(LogCategory::Core, u"HID::Vibarte: index is out of range"); return false; @@ -236,7 +262,7 @@ void HID::VibrateJoycon(hid_device* handler, float frequency, float amplitude) { byte[2] = lf + ((lf_amp >> 8) & 0xFF); byte[3] = lf_amp & 0xFF; - for (int i = 4; i <= 7; i++) { + for (int32_t i = 4; i <= 7; i++) { byte[i] = byte[i - 4]; } diff --git a/core/src/Input/HID.h b/core/src/Input/HID.h index 03986481..75c6f0ab 100644 --- a/core/src/Input/HID.h +++ b/core/src/Input/HID.h @@ -37,9 +37,10 @@ class HID { ~HID(); bool Initialize(); void TerminateDevices(); - void Refresh(int connectedJoystickCount); + void Refresh(int32_t connectedJoystickCount); - bool Vibrate(int joystickIndex, float frequency, float amplitude); + bool SetLight(int32_t joystickIndex, int32_t number); + bool Vibrate(int32_t joystickIndex, float frequency, float amplitude); }; } // namespace Altseed2 \ No newline at end of file diff --git a/core/src/Input/Joystick.cpp b/core/src/Input/Joystick.cpp index d9cabb08..05754b1b 100644 --- a/core/src/Input/Joystick.cpp +++ b/core/src/Input/Joystick.cpp @@ -258,6 +258,22 @@ float Joystick::GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) con return gamepadCurrentAxis_[joystickIndex][index]; }; +bool Joystick::SetLight(int32_t joystickIndex, int number) { + if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { + Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: index '{0}' is out of range", joystickIndex); + return false; + } + + const auto info = joystickInfo_[joystickIndex]; + + if (info == nullptr) { + Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: joystick is not connected as {0}", joystickIndex); + return false; + } + + return hid_->SetLight(joystickIndex, number); +} + bool Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: index '{0}' is out of range", joystickIndex); diff --git a/core/src/Input/Joystick.h b/core/src/Input/Joystick.h index 5594f1a9..944e2fb2 100644 --- a/core/src/Input/Joystick.h +++ b/core/src/Input/Joystick.h @@ -133,6 +133,7 @@ class Joystick : public BaseObject { float GetAxisStateByIndex(int32_t joystickIndex, int32_t axisIndex) const; float GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) const; + bool SetLight(int32_t joystickIndex, int32_t number); bool Vibrate(int32_t joystickIndex, float frequency, float amplitude); }; diff --git a/core/test/Joystick.cpp b/core/test/Joystick.cpp index 8cbe50eb..bbfd6c6d 100644 --- a/core/test/Joystick.cpp +++ b/core/test/Joystick.cpp @@ -21,8 +21,32 @@ bool IsPushedOrHolded(int joystickIndex, Altseed2::JoystickButton btn, int count } // TODO -TEST(Joystick, Vibrate) { +TEST(Joystick, SetLight) { + auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); + EXPECT_TRUE(config != nullptr); + + EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); + + float time = 0.0f; + while (Altseed2::Core::GetInstance()->DoEvent()) { + int joystickIndex = 0; + + float t = 0.5f * std::sin(time) + 0.5f; + + int lightNumber = t * 15; + Altseed2::Joystick::GetInstance()->SetLight(joystickIndex, lightNumber); + + time += Altseed2::Core::GetInstance()->GetDeltaSecond(); + + if (time > 10.0f) { + break; + } + } +} + +// TODO +TEST(Joystick, Vibrate) { auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); EXPECT_TRUE(config != nullptr); @@ -35,16 +59,16 @@ TEST(Joystick, Vibrate) { float frequency = 150.0f; float amplitude = 0.8f; + float t = 0.5f * std::sin(time) + 0.5f; + if (time < 5.0f) { - frequency = 150.0f; - amplitude = 0.5f * (0.5f * std::sin(time)) * 0.8f; + amplitude *= t; } else { - frequency = 0.5f * (0.5f * std::sin(time)) * 150.0f; - amplitude = 0.8f; + frequency *= t; } Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); - + time += Altseed2::Core::GetInstance()->GetDeltaSecond(); if (time > 10.0f) { @@ -63,7 +87,7 @@ TEST(Joystick, Vibrate) { // frequency += 10.0f; // std::cout << "freq: " << frequency << std::endl; // } - + // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightDown, count)) { // frequency -= 10.0f; // std::cout << "freq: " << frequency << std::endl; From 8ee0d22dfc6606d8e77d52e1fabf43690f7b61c5 Mon Sep 17 00:00:00 2001 From: wraikny Date: Sun, 4 Oct 2020 18:40:13 +0900 Subject: [PATCH 5/5] HID cannot be alive with glfw --- core/src/Input/HID.cpp | 15 +++-- core/src/Input/Joystick.cpp | 72 ++++++++++---------- core/src/Input/Joystick.h | 9 +-- core/test/Joystick.cpp | 131 +++++++++++------------------------- 4 files changed, 89 insertions(+), 138 deletions(-) diff --git a/core/src/Input/HID.cpp b/core/src/Input/HID.cpp index 838c1c0f..df8c7a18 100644 --- a/core/src/Input/HID.cpp +++ b/core/src/Input/HID.cpp @@ -85,12 +85,12 @@ std::vector HID::Enumerate() { hid_set_nonblocking(prop.Handler, 1); // enable vibration for joycon - uint8_t data[0x01]; + uint8_t data[1]; data[0] = 0x01; SendSubcommand(prop.Handler, 0x48, data, 1); // send player light - data[0] = 0; + data[0] = 0b1111; SendSubcommand(prop.Handler, 0x30, data, 1); } } @@ -145,10 +145,13 @@ void HID::TerminateDevices() { if (prop.Handler != nullptr) { if (prop.VendorID == VendorNintendo) { if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { - uint8_t data[0x01]; - data[0] = 0; + uint8_t data[1]; + + // set light + data[0] = 0b1111; this->SendSubcommand(prop.Handler, 0x30, data, 1); + // vibration data[0] = 0x01; this->SendSubcommand(prop.Handler, 0x48, data, 1); } @@ -190,7 +193,7 @@ bool HID::SetLight(int32_t joystickIndex, int32_t number) { if (prop.VendorID == VendorNintendo) { if (prop.ProductID == ProductJoyconL || prop.ProductID == ProductJoyconR) { - uint8_t data[0x01]; + uint8_t data[1]; // send player light data[0] = 0b1111 & number; SendSubcommand(prop.Handler, 0x30, data, 1); @@ -226,7 +229,7 @@ bool HID::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { } void HID::VibrateJoycon(hid_device* handler, float frequency, float amplitude) { - RETURN_IF_NULL(handler,); + RETURN_IF_NULL(handler, ); uint8_t buf[0x40]; memset(buf, 0x0, size_t(0x40)); diff --git a/core/src/Input/Joystick.cpp b/core/src/Input/Joystick.cpp index 05754b1b..a98bb7f0 100644 --- a/core/src/Input/Joystick.cpp +++ b/core/src/Input/Joystick.cpp @@ -43,20 +43,22 @@ Joystick::Joystick() : connectedJoystickCount_(0) { bool Joystick::Initialize() { instance_ = MakeAsdShared(); - instance_->hid_ = std::make_unique(); - if (!instance_->hid_->Initialize()) { - Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Initialize: failed to initialize HID"); - instance_->hid_ = nullptr; - } + // TODO + // instance_->hid_ = std::make_unique(); + // if (!instance_->hid_->Initialize()) { + // Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Initialize: failed to initialize HID"); + // instance_->hid_ = nullptr; + // } instance_->RefreshInputState(); + return true; }; void Joystick::Terminate() { - if(instance_->hid_ != nullptr) { - instance_->hid_->TerminateDevices(); - } + // if (instance_->hid_ != nullptr) { + // instance_->hid_->TerminateDevices(); + // } instance_ = nullptr; } @@ -158,9 +160,9 @@ void Joystick::RefreshInputState() { } // HID - if (hid_ != nullptr && isConnectionUpdated) { - hid_->Refresh(connectedJoystickCount_); - } + // if (hid_ != nullptr && isConnectionUpdated) { + // hid_->Refresh(connectedJoystickCount_); + // } }; bool Joystick::IsPresent(int32_t joystickIndex) const { @@ -258,37 +260,37 @@ float Joystick::GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) con return gamepadCurrentAxis_[joystickIndex][index]; }; -bool Joystick::SetLight(int32_t joystickIndex, int number) { - if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { - Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: index '{0}' is out of range", joystickIndex); - return false; - } +// bool Joystick::SetLight(int32_t joystickIndex, int number) { +// if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { +// Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: index '{0}' is out of range", joystickIndex); +// return false; +// } - const auto info = joystickInfo_[joystickIndex]; +// const auto info = joystickInfo_[joystickIndex]; - if (info == nullptr) { - Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: joystick is not connected as {0}", joystickIndex); - return false; - } +// if (info == nullptr) { +// Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::SetLight: joystick is not connected at {0}", joystickIndex); +// return false; +// } - return hid_->SetLight(joystickIndex, number); -} +// return hid_->SetLight(joystickIndex, number); +// } -bool Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { - if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { - Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: index '{0}' is out of range", joystickIndex); - return false; - } +// bool Joystick::Vibrate(int32_t joystickIndex, float frequency, float amplitude) { +// if (joystickIndex < 0 || MAX_JOYSTICKS_NUM <= joystickIndex) { +// Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: index '{0}' is out of range", joystickIndex); +// return false; +// } - const auto info = joystickInfo_[joystickIndex]; +// const auto info = joystickInfo_[joystickIndex]; - if (info == nullptr) { - Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: joystick is not connected as {0}", joystickIndex); - return false; - } +// if (info == nullptr) { +// Log::GetInstance()->Warn(LogCategory::Core, u"Joystick::Vibrate: joystick is not connected at {0}", joystickIndex); +// return false; +// } - return hid_->Vibrate(joystickIndex, frequency, amplitude); -} +// return hid_->Vibrate(joystickIndex, frequency, amplitude); +// } } // namespace Altseed2 diff --git a/core/src/Input/Joystick.h b/core/src/Input/Joystick.h index 944e2fb2..ac983720 100644 --- a/core/src/Input/Joystick.h +++ b/core/src/Input/Joystick.h @@ -96,8 +96,6 @@ class Joystick : public BaseObject { int32_t connectedJoystickCount_; - // std::array, MAX_JOYSTICKS_NUM> hidapiDevices_; - std::array, MAX_JOYSTICKS_NUM> joystickInfo_; std::array, MAX_JOYSTICKS_NUM> currentHit_; std::array, MAX_JOYSTICKS_NUM> preHit_; @@ -107,12 +105,11 @@ class Joystick : public BaseObject { std::array, MAX_JOYSTICKS_NUM> gamepadPreHit_; std::array, MAX_JOYSTICKS_NUM> gamepadCurrentAxis_; - std::unique_ptr hid_; + // std::unique_ptr hid_; std::u16string ToU16(const std::wstring& wstr) const; public: - Joystick(); static bool Initialize(); @@ -133,8 +130,8 @@ class Joystick : public BaseObject { float GetAxisStateByIndex(int32_t joystickIndex, int32_t axisIndex) const; float GetAxisStateByType(int32_t joystickIndex, JoystickAxis type) const; - bool SetLight(int32_t joystickIndex, int32_t number); - bool Vibrate(int32_t joystickIndex, float frequency, float amplitude); + // bool SetLight(int32_t joystickIndex, int32_t number); + // bool Vibrate(int32_t joystickIndex, float frequency, float amplitude); }; } // namespace Altseed2 diff --git a/core/test/Joystick.cpp b/core/test/Joystick.cpp index bbfd6c6d..7c18c0bd 100644 --- a/core/test/Joystick.cpp +++ b/core/test/Joystick.cpp @@ -20,115 +20,64 @@ bool IsPushedOrHolded(int joystickIndex, Altseed2::JoystickButton btn, int count } } -// TODO -TEST(Joystick, SetLight) { - auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); - EXPECT_TRUE(config != nullptr); +// TEST(Joystick, SetLight) { +// auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); +// EXPECT_TRUE(config != nullptr); - EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); +// EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); - float time = 0.0f; +// float time = 0.0f; - while (Altseed2::Core::GetInstance()->DoEvent()) { - int joystickIndex = 0; +// while (Altseed2::Core::GetInstance()->DoEvent()) { +// int joystickIndex = 0; - float t = 0.5f * std::sin(time) + 0.5f; +// float t = 0.5f * std::sin(time) + 0.5f; - int lightNumber = t * 15; - Altseed2::Joystick::GetInstance()->SetLight(joystickIndex, lightNumber); +// int lightNumber = t * 15; +// Altseed2::Joystick::GetInstance()->SetLight(joystickIndex, lightNumber); - time += Altseed2::Core::GetInstance()->GetDeltaSecond(); +// time += Altseed2::Core::GetInstance()->GetDeltaSecond(); - if (time > 10.0f) { - break; - } - } -} +// if (time > 10.0f) { +// break; +// } +// } -// TODO -TEST(Joystick, Vibrate) { - auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); - EXPECT_TRUE(config != nullptr); +// Altseed2::Core::Terminate(); +// } - EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); +// TEST(Joystick, Vibrate) { +// auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); +// EXPECT_TRUE(config != nullptr); - float time = 0.0f; +// EXPECT_TRUE(Altseed2::Core::Initialize(u"Joystick ButtonState", 640, 480, config)); - while (Altseed2::Core::GetInstance()->DoEvent()) { - int joystickIndex = 0; - float frequency = 150.0f; - float amplitude = 0.8f; +// float time = 0.0f; - float t = 0.5f * std::sin(time) + 0.5f; +// while (Altseed2::Core::GetInstance()->DoEvent()) { +// int joystickIndex = 0; +// float frequency = 150.0f; +// float amplitude = 0.8f; - if (time < 5.0f) { - amplitude *= t; - } else { - frequency *= t; - } +// float t = 0.5f * std::sin(time) + 0.5f; - Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); +// if (time < 5.0f) { +// amplitude *= t; +// } else { +// frequency *= t; +// } - time += Altseed2::Core::GetInstance()->GetDeltaSecond(); +// Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); - if (time > 10.0f) { - break; - } - } +// time += Altseed2::Core::GetInstance()->GetDeltaSecond(); - // while (Altseed2::Core::GetInstance()->DoEvent()) { - // if (!vibrated && Altseed2::Joystick::GetInstance()->GetButtonStateByType(joystickIndex, Altseed2::JoystickButton::RightDown) == Altseed2::ButtonState::Push) { - // Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); - // start = std::chrono::system_clock::now(); - // vibrated = true; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightRight, count)) { - // frequency += 10.0f; - // std::cout << "freq: " << frequency << std::endl; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightDown, count)) { - // frequency -= 10.0f; - // std::cout << "freq: " << frequency << std::endl; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightUp, count)) { - // amplitude += 0.05f; - // std::cout << "amp : " << amplitude << std::endl; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightLeft, count)) { - // amplitude -= 0.05f; - // std::cout << "amp : " << amplitude << std::endl; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::RightBumper, count)) { - // vibrate_time += 10.0f; - // std::cout << "time: " << vibrate_time << std::endl; - // } - - // if (IsPushedOrHolded(joystickIndex, Altseed2::JoystickButton::LeftBumper, count)) { - // vibrate_time -= 10.0f; - // std::cout << "time: " << vibrate_time << std::endl; - // } - - // if (vibrated && std::chrono::duration_cast(end - start).count() >= vibrate_time) { - // Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, 100.0f, 0); - // vibrated = false; - // } - - // end = std::chrono::system_clock::now(); - // count++; - - // time += Altseed2::Core::GetInstance()->GetDeltaSecond(); - // if (time > 10.0f) { - // break; - // } - // } +// if (time > 10.0f) { +// break; +// } +// } - Altseed2::Core::Terminate(); -} +// Altseed2::Core::Terminate(); +// } void printJoystickInformation() { for (int i = 0; i < 16; i++) {