diff --git a/app/src/main/cpp/skyline/input/sections/TouchScreen.h b/app/src/main/cpp/skyline/input/sections/TouchScreen.h index c3c8ee6a..c3ee3755 100644 --- a/app/src/main/cpp/skyline/input/sections/TouchScreen.h +++ b/app/src/main/cpp/skyline/input/sections/TouchScreen.h @@ -6,13 +6,27 @@ #include "common.h" namespace skyline::input { + /** + * @brief Indicates if touch point has started or ended + * @url https://switchbrew.org/wiki/HID_services#TouchAttribute + */ + union TouchAttribute { + u32 raw{}; + struct { + bool start : 1; + bool end : 1; + }; + }; + static_assert(sizeof(TouchAttribute) == 0x4); + /** * @brief A descriptor for a single point on the touch screen * @url https://switchbrew.org/wiki/HID_Shared_Memory#TouchScreenStateData */ struct TouchScreenStateData { u64 timestamp; //!< The timestamp in samples - u32 _pad0_; + + TouchAttribute attribute; u32 index; //!< The index of this touch diff --git a/app/src/main/cpp/skyline/input/touch.cpp b/app/src/main/cpp/skyline/input/touch.cpp index 6eb5faf5..674d733b 100644 --- a/app/src/main/cpp/skyline/input/touch.cpp +++ b/app/src/main/cpp/skyline/input/touch.cpp @@ -15,21 +15,23 @@ namespace skyline::input { } } - void TouchManager::SetState(const span &points) { + void TouchManager::SetState(span touchPoints) { if (!activated) return; const auto &lastEntry{section.entries[section.header.currentEntry]}; auto entryIndex{(section.header.currentEntry != constant::HidEntryCount - 1) ? section.header.currentEntry + 1 : 0}; auto &entry{section.entries[entryIndex]}; + touchPoints = touchPoints.first(std::min(touchPoints.size(), entry.data.size())); entry.globalTimestamp = lastEntry.globalTimestamp + 1; entry.localTimestamp = lastEntry.localTimestamp + 1; - entry.touchCount = points.size(); + entry.touchCount = touchPoints.size(); - for (size_t i{}; i < points.size(); i++) { - const auto &host{points[i]}; + for (size_t i{}; i < touchPoints.size(); i++) { + const auto &host{touchPoints[i]}; auto &guest{entry.data[i]}; - guest.index = static_cast(i); + guest.attribute.raw = static_cast(host.attribute); + guest.index = static_cast(host.id); guest.positionX = static_cast(host.x); guest.positionY = static_cast(host.y); guest.minorAxis = static_cast(host.minor); @@ -37,6 +39,10 @@ namespace skyline::input { guest.angle = host.angle; } + // Clear unused touch points + for (size_t i{touchPoints.size()}; i < entry.data.size(); i++) + entry.data[i] = {}; + section.header.timestamp = util::GetTimeTicks(); section.header.entryCount = std::min(static_cast(section.header.entryCount + 1), constant::HidEntryCount); section.header.maxEntry = section.header.entryCount; diff --git a/app/src/main/cpp/skyline/input/touch.h b/app/src/main/cpp/skyline/input/touch.h index a3c51065..5aaeb0fd 100644 --- a/app/src/main/cpp/skyline/input/touch.h +++ b/app/src/main/cpp/skyline/input/touch.h @@ -13,6 +13,8 @@ namespace skyline::input { * @note This structure corresponds to TouchScreenStateData, see that for details */ struct TouchScreenPoint { + jint attribute; + jint id; jint x; jint y; jint minor; @@ -37,6 +39,6 @@ namespace skyline::input { void Activate(); - void SetState(const span &points); + void SetState(span touchPoints); }; } diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index 19e1e9a7..192afaf5 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -467,8 +467,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo @SuppressLint("ClickableViewAccessibility") override fun onTouch(view : View, event : MotionEvent) : Boolean { - val count = if (event.action != MotionEvent.ACTION_UP && event.action != MotionEvent.ACTION_CANCEL) event.pointerCount else 0 - val points = IntArray(count * 5) // This is an array of skyline::input::TouchScreenPoint in C++ as that allows for efficient transfer of values to it + val count = event.pointerCount + val points = IntArray(count * 7) // This is an array of skyline::input::TouchScreenPoint in C++ as that allows for efficient transfer of values to it var offset = 0 for (index in 0 until count) { val pointer = MotionEvent.PointerCoords() @@ -477,6 +477,14 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo val x = 0f.coerceAtLeast(pointer.x * 1280 / view.width).toInt() val y = 0f.coerceAtLeast(pointer.y * 720 / view.height).toInt() + val attribute = when (event.action) { + MotionEvent.ACTION_DOWN -> 1 + MotionEvent.ACTION_UP -> 2 + else -> 0 + } + + points[offset++] = attribute + points[offset++] = event.getPointerId(index) points[offset++] = x points[offset++] = y points[offset++] = pointer.touchMinor.toInt()