From a44ffd12b725fe82cd42746427c6636e2d9b3998 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 11 May 2016 01:04:59 +0300 Subject: [PATCH] reimplement circle pad --- src/common/emu_window.h | 36 +++++++++++++++++++++-- src/core/hle/service/hid/hid.cpp | 50 +++++++++++++++++--------------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 7c3486dea..610307944 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h @@ -100,13 +100,45 @@ public: void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); /** - * Gets the current pad state (which buttons are pressed and the circle pad direction). + * Gets the current pad state (which buttons are pressed). * @note This should be called by the core emu thread to get a state set by the window thread. + * @note The circle pad fields of the returned state are cleared. + * Circle pad should be handled from GetCirclePadState(). * @todo Fix this function to be thread-safe. * @return PadState object indicating the current pad state */ Service::HID::PadState GetPadState() const { - return pad_state; + auto cleared_pad_state = pad_state; + cleared_pad_state.circle_right.Assign(0); + cleared_pad_state.circle_left.Assign(0); + cleared_pad_state.circle_up.Assign(0); + cleared_pad_state.circle_down.Assign(0); + return cleared_pad_state; + } + + /** + * Gets the current cirle pad state. + * @note This should be called by the core emu thread to get a state set by the window thread. + * @todo Fix this function to be thread-safe. + * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates + */ + std::tuple GetCirclePadState() const { + const int MAX_CIRCLEPAD_POS = 0x9C; // Max radius for a circle pad position + const float SQRT_HALF = 0.707106781; + int x = 0, y = 0; + if (pad_state.circle_right.ToBool()) + x += MAX_CIRCLEPAD_POS; + if (pad_state.circle_left.ToBool()) + x -= MAX_CIRCLEPAD_POS; + if (pad_state.circle_up.ToBool()) + y += MAX_CIRCLEPAD_POS; + if (pad_state.circle_down.ToBool()) + y -= MAX_CIRCLEPAD_POS; + if (x != 0) + y *= SQRT_HALF; + if (y != 0) + x *= SQRT_HALF; + return std::make_tuple(x, y); } /** diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 1053d0f40..29e3a494d 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -19,8 +19,6 @@ namespace Service { namespace HID { -static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position - // Handle to shared memory region designated to HID_User service static Kernel::SharedPtr shared_mem; @@ -48,29 +46,37 @@ const std::array pad_ Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT }}; - -// TODO(peachum): -// Add a method for setting analog input from joystick device for the circle Pad. -// -// This method should: -// * Be called after both PadButton(). -// * Be called before PadUpdateComplete() -// * Set current PadEntry.circle_pad_ using analog data -// * Set PadData.raw_circle_pad_data -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 -// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 -// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 - void Update() { SharedMem* mem = reinterpret_cast(shared_mem->GetPointer()); - const PadState state = VideoCore::g_emu_window->GetPadState(); if (mem == nullptr) { LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); return; } + PadState state = VideoCore::g_emu_window->GetPadState(); + + // Get current circle pad positon and update circle pad direction + const float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions + const int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction + s16 circle_pad_x, circle_pad_y; + std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState(); + if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) { + float tan = abs((float)circle_pad_y / circle_pad_x); + if (circle_pad_x != 0 && tan < TAN60) { + if (circle_pad_x > 0) + state.circle_right.Assign(1); + else + state.circle_left.Assign(1); + } + if (circle_pad_x == 0 || tan > TAN30) { + if (circle_pad_y > 0) + state.circle_up.Assign(1); + else + state.circle_down.Assign(1); + } + } + mem->pad.current_state.hex = state.hex; mem->pad.index = next_pad_index; next_pad_index = (next_pad_index + 1) % mem->pad.entries.size(); @@ -88,13 +94,9 @@ void Update() { // Update entry properties pad_entry.current_state.hex = state.hex; pad_entry.delta_additions.hex = changed.hex & state.hex; - pad_entry.delta_removals.hex = changed.hex & old_state.hex;; - - // Set circle Pad - pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS : - state.circle_right ? MAX_CIRCLEPAD_POS : 0x0; - pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS : - state.circle_up ? MAX_CIRCLEPAD_POS : 0x0; + pad_entry.delta_removals.hex = changed.hex & old_state.hex; + pad_entry.circle_pad_x = circle_pad_x; + pad_entry.circle_pad_y = circle_pad_y; // If we just updated index 0, provide a new timestamp if (mem->pad.index == 0) {