Add HID touch attribute and index reporting

Adds missing parameter TouchAttribute and emulates correctly the touch point index. Both changes are necessary on Voez to keep track of each finger.
This commit is contained in:
Narr the Reg 2022-05-29 04:28:51 -05:00 committed by GitHub
parent 80c8fb8791
commit 7aa6a5c4ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 9 deletions

View File

@ -6,13 +6,27 @@
#include "common.h" #include "common.h"
namespace skyline::input { 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 * @brief A descriptor for a single point on the touch screen
* @url https://switchbrew.org/wiki/HID_Shared_Memory#TouchScreenStateData * @url https://switchbrew.org/wiki/HID_Shared_Memory#TouchScreenStateData
*/ */
struct TouchScreenStateData { struct TouchScreenStateData {
u64 timestamp; //!< The timestamp in samples u64 timestamp; //!< The timestamp in samples
u32 _pad0_;
TouchAttribute attribute;
u32 index; //!< The index of this touch u32 index; //!< The index of this touch

View File

@ -15,21 +15,23 @@ namespace skyline::input {
} }
} }
void TouchManager::SetState(const span<TouchScreenPoint> &points) { void TouchManager::SetState(span<TouchScreenPoint> touchPoints) {
if (!activated) if (!activated)
return; return;
const auto &lastEntry{section.entries[section.header.currentEntry]}; const auto &lastEntry{section.entries[section.header.currentEntry]};
auto entryIndex{(section.header.currentEntry != constant::HidEntryCount - 1) ? section.header.currentEntry + 1 : 0}; auto entryIndex{(section.header.currentEntry != constant::HidEntryCount - 1) ? section.header.currentEntry + 1 : 0};
auto &entry{section.entries[entryIndex]}; auto &entry{section.entries[entryIndex]};
touchPoints = touchPoints.first(std::min(touchPoints.size(), entry.data.size()));
entry.globalTimestamp = lastEntry.globalTimestamp + 1; entry.globalTimestamp = lastEntry.globalTimestamp + 1;
entry.localTimestamp = lastEntry.localTimestamp + 1; entry.localTimestamp = lastEntry.localTimestamp + 1;
entry.touchCount = points.size(); entry.touchCount = touchPoints.size();
for (size_t i{}; i < points.size(); i++) { for (size_t i{}; i < touchPoints.size(); i++) {
const auto &host{points[i]}; const auto &host{touchPoints[i]};
auto &guest{entry.data[i]}; auto &guest{entry.data[i]};
guest.index = static_cast<u32>(i); guest.attribute.raw = static_cast<u32>(host.attribute);
guest.index = static_cast<u32>(host.id);
guest.positionX = static_cast<u32>(host.x); guest.positionX = static_cast<u32>(host.x);
guest.positionY = static_cast<u32>(host.y); guest.positionY = static_cast<u32>(host.y);
guest.minorAxis = static_cast<u32>(host.minor); guest.minorAxis = static_cast<u32>(host.minor);
@ -37,6 +39,10 @@ namespace skyline::input {
guest.angle = host.angle; 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.timestamp = util::GetTimeTicks();
section.header.entryCount = std::min(static_cast<u8>(section.header.entryCount + 1), constant::HidEntryCount); section.header.entryCount = std::min(static_cast<u8>(section.header.entryCount + 1), constant::HidEntryCount);
section.header.maxEntry = section.header.entryCount; section.header.maxEntry = section.header.entryCount;

View File

@ -13,6 +13,8 @@ namespace skyline::input {
* @note This structure corresponds to TouchScreenStateData, see that for details * @note This structure corresponds to TouchScreenStateData, see that for details
*/ */
struct TouchScreenPoint { struct TouchScreenPoint {
jint attribute;
jint id;
jint x; jint x;
jint y; jint y;
jint minor; jint minor;
@ -37,6 +39,6 @@ namespace skyline::input {
void Activate(); void Activate();
void SetState(const span<TouchScreenPoint> &points); void SetState(span<TouchScreenPoint> touchPoints);
}; };
} }

View File

@ -467,8 +467,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onTouch(view : View, event : MotionEvent) : Boolean { 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 count = event.pointerCount
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 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 var offset = 0
for (index in 0 until count) { for (index in 0 until count) {
val pointer = MotionEvent.PointerCoords() 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 x = 0f.coerceAtLeast(pointer.x * 1280 / view.width).toInt()
val y = 0f.coerceAtLeast(pointer.y * 720 / view.height).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++] = x
points[offset++] = y points[offset++] = y
points[offset++] = pointer.touchMinor.toInt() points[offset++] = pointer.touchMinor.toInt()