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..df8c7a18 --- /dev/null +++ b/core/src/Input/HID.cpp @@ -0,0 +1,277 @@ +#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[], int32_t 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[1]; + data[0] = 0x01; + SendSubcommand(prop.Handler, 0x48, data, 1); + + // send player light + data[0] = 0b1111; + 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[1]; + + // set light + data[0] = 0b1111; + this->SendSubcommand(prop.Handler, 0x30, data, 1); + + // vibration + data[0] = 0x01; + this->SendSubcommand(prop.Handler, 0x48, data, 1); + } + } + + hid_close(prop.Handler); + } + } +} + +void HID::Refresh(int32_t 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::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[1]; + // 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; + } + + 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 (int32_t 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..75c6f0ab --- /dev/null +++ b/core/src/Input/HID.h @@ -0,0 +1,46 @@ +#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(int32_t connectedJoystickCount); + + 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 740b93b2..a98bb7f0 100644 --- a/core/src/Input/Joystick.cpp +++ b/core/src/Input/Joystick.cpp @@ -1,12 +1,15 @@ #include "Joystick.h" +#include + #include #include #include "../Logger/Log.h" namespace Altseed2 { + 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)); @@ -39,12 +42,24 @@ Joystick::Joystick() : connectedJoystickCount_(0) { bool Joystick::Initialize() { instance_ = MakeAsdShared(); + + // 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(); + // } + instance_ = nullptr; } @@ -74,6 +89,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); @@ -85,6 +103,7 @@ void Joystick::RefreshInputState() { // Joystickの接続が外れたフレーム if (joystickInfo_[jind] != nullptr) { connectedJoystickCount_--; + isConnectionUpdated = true; joystickInfo_[jind] = nullptr; } @@ -129,9 +148,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; } // 特定のジョイスティックに対する補正 @@ -141,6 +158,11 @@ void Joystick::RefreshInputState() { currentHit_[jind][15] = currentAxis_[jind][5] > 0.8; } } + + // HID + // if (hid_ != nullptr && isConnectionUpdated) { + // hid_->Refresh(connectedJoystickCount_); + // } }; bool Joystick::IsPresent(int32_t joystickIndex) const { @@ -238,8 +260,426 @@ 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::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 at {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); +// return false; +// } + +// const auto info = joystickInfo_[joystickIndex]; + +// 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); // } } // 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..ac983720 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 { @@ -95,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_; @@ -106,6 +105,8 @@ class Joystick : public BaseObject { std::array, MAX_JOYSTICKS_NUM> gamepadPreHit_; std::array, MAX_JOYSTICKS_NUM> gamepadCurrentAxis_; + // std::unique_ptr hid_; + std::u16string ToU16(const std::wstring& wstr) const; public: @@ -129,7 +130,8 @@ 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 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 6463a243..7c18c0bd 100644 --- a/core/test/Joystick.cpp +++ b/core/test/Joystick.cpp @@ -20,61 +20,63 @@ 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; -// } +// TEST(Joystick, SetLight) { +// auto config = Altseed2TestConfig(Altseed2::CoreModules::Joystick); +// EXPECT_TRUE(config != nullptr); -// 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; +// 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; // } +// } + +// Altseed2::Core::Terminate(); +// } + +// 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; -// if (vibrated && std::chrono::duration_cast(end - start).count() >= vibrate_time) { -// Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, 100.0f, 0); -// vibrated = false; +// while (Altseed2::Core::GetInstance()->DoEvent()) { +// int joystickIndex = 0; +// float frequency = 150.0f; +// float amplitude = 0.8f; + +// float t = 0.5f * std::sin(time) + 0.5f; + +// if (time < 5.0f) { +// amplitude *= t; +// } else { +// frequency *= t; // } -// end = std::chrono::system_clock::now(); -// count++; +// Altseed2::Joystick::GetInstance()->Vibrate(joystickIndex, frequency, amplitude); + +// time += Altseed2::Core::GetInstance()->GetDeltaSecond(); + +// if (time > 10.0f) { +// break; +// } // } + +// Altseed2::Core::Terminate(); // } void printJoystickInformation() { 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