mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-29 12:24:14 +01:00
Implement Guest Touch-Screen Support
This commit is contained in:
parent
89718804d0
commit
65019375ca
@ -48,6 +48,7 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/input.cpp
|
||||
${source_DIR}/skyline/input/npad.cpp
|
||||
${source_DIR}/skyline/input/npad_device.cpp
|
||||
${source_DIR}/skyline/input/touch.cpp
|
||||
${source_DIR}/skyline/os.cpp
|
||||
${source_DIR}/skyline/loader/loader.cpp
|
||||
${source_DIR}/skyline/loader/nro.cpp
|
||||
|
@ -131,3 +131,19 @@ extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValu
|
||||
// We don't mind if we miss axis updates while input hasn't been initialized
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setTouchState(JNIEnv *env, jobject, jintArray pointsJni) {
|
||||
try {
|
||||
using Point = skyline::input::TouchScreenPoint;
|
||||
|
||||
auto input = inputWeak.lock();
|
||||
jboolean isCopy{false};
|
||||
|
||||
std::span<Point> points(reinterpret_cast<Point *>(env->GetIntArrayElements(pointsJni, &isCopy)), env->GetArrayLength(pointsJni) / (sizeof(Point) / sizeof(jint)));
|
||||
input->touch.SetState(points);
|
||||
|
||||
env->ReleaseIntArrayElements(pointsJni, reinterpret_cast<jint *>(points.data()), JNI_ABORT);
|
||||
} catch (const std::bad_weak_ptr &) {
|
||||
// We don't mind if we miss axis updates while input hasn't been initialized
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ namespace skyline {
|
||||
*/
|
||||
union Result {
|
||||
u32 raw{};
|
||||
struct {
|
||||
struct __attribute__((packed)) {
|
||||
u16 module : 9;
|
||||
u16 id : 12;
|
||||
};
|
||||
@ -39,7 +39,7 @@ namespace skyline {
|
||||
/**
|
||||
* @note Success is 0, 0 - it is the only error that's not specific to a module
|
||||
*/
|
||||
Result() {}
|
||||
Result() = default;
|
||||
|
||||
constexpr Result(u16 module, u16 id) {
|
||||
this->module = module;
|
||||
|
@ -4,5 +4,5 @@
|
||||
#include "input.h"
|
||||
|
||||
namespace skyline::input {
|
||||
Input::Input(const DeviceState &state) : state(state), kHid(std::make_shared<kernel::type::KSharedMemory>(state, NULL, sizeof(HidSharedMemory), memory::Permission(true, false, false))), hid(reinterpret_cast<HidSharedMemory *>(kHid->kernel.address)), npad(state, hid) {}
|
||||
Input::Input(const DeviceState &state) : state(state), kHid(std::make_shared<kernel::type::KSharedMemory>(state, NULL, sizeof(HidSharedMemory), memory::Permission(true, false, false))), hid(reinterpret_cast<HidSharedMemory *>(kHid->kernel.address)), npad(state, hid), touch(state, hid) {}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "kernel/types/KSharedMemory.h"
|
||||
#include "input/shared_mem.h"
|
||||
#include "input/npad.h"
|
||||
#include "input/touch.h"
|
||||
|
||||
namespace skyline::input {
|
||||
/**
|
||||
@ -20,7 +21,8 @@ namespace skyline::input {
|
||||
std::shared_ptr<kernel::type::KSharedMemory> kHid; //!< The kernel shared memory object for HID Shared Memory
|
||||
HidSharedMemory *hid; //!< A pointer to HID Shared Memory on the host
|
||||
|
||||
NpadManager npad; //!< This manages all the NPad controllers
|
||||
NpadManager npad;
|
||||
TouchManager touch;
|
||||
|
||||
Input(const DeviceState &state);
|
||||
};
|
||||
|
@ -18,10 +18,10 @@ namespace skyline::input {
|
||||
u32 positionX; //!< The X position of this touch
|
||||
u32 positionY; //!< The Y position of this touch
|
||||
|
||||
u32 diameterX; //!< The diameter of the touch on the X-axis
|
||||
u32 diameterY; //!< The diameter of the touch on the Y-axis
|
||||
u32 minorAxis; //!< The diameter of the touch cross-section on the minor-axis in pixels
|
||||
u32 majorAxis; //!< The diameter of the touch cross-section on the major-axis in pixels
|
||||
|
||||
u32 angle; //!< The angle of the touch
|
||||
i32 angle; //!< The angle of the touch in degrees (from -89 to 90 [-90 and 90 aren't distinguishable]. On the Switch, this has limited resolution with only 90, -67, -45, 0, 45, 67, 90 being values)
|
||||
u32 _pad1_;
|
||||
};
|
||||
static_assert(sizeof(TouchScreenStateData) == 0x28);
|
||||
|
43
app/src/main/cpp/skyline/input/touch.cpp
Normal file
43
app/src/main/cpp/skyline/input/touch.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#include <input.h>
|
||||
#include "touch.h"
|
||||
|
||||
namespace skyline::input {
|
||||
TouchManager::TouchManager(const DeviceState &state, input::HidSharedMemory *hid) : state(state), section(hid->touchScreen) {
|
||||
Activate();
|
||||
}
|
||||
|
||||
void TouchManager::Activate() {
|
||||
activated = true;
|
||||
SetState({});
|
||||
}
|
||||
|
||||
void TouchManager::SetState(const std::span<TouchScreenPoint> &points) {
|
||||
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];
|
||||
entry.globalTimestamp = lastEntry.globalTimestamp + 1;
|
||||
entry.localTimestamp = lastEntry.localTimestamp + 1;
|
||||
entry.touchCount = points.size();
|
||||
|
||||
for (size_t i{}; i < points.size(); i++) {
|
||||
const auto& host = points[i];
|
||||
auto& guest = entry.data[i];
|
||||
guest.index = i;
|
||||
guest.positionX = host.x;
|
||||
guest.positionY = host.y;
|
||||
guest.minorAxis = host.minor;
|
||||
guest.majorAxis = host.major;
|
||||
guest.angle = host.angle;
|
||||
}
|
||||
|
||||
section.header.timestamp = util::GetTimeTicks();
|
||||
section.header.entryCount = std::min(static_cast<u8>(section.header.entryCount + 1), constant::HidEntryCount);
|
||||
section.header.currentEntry = entryIndex;
|
||||
}
|
||||
}
|
42
app/src/main/cpp/skyline/input/touch.h
Normal file
42
app/src/main/cpp/skyline/input/touch.h
Normal file
@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common.h>
|
||||
#include "shared_mem.h"
|
||||
|
||||
namespace skyline::input {
|
||||
/*
|
||||
* @brief A description of a point being touched on the screen
|
||||
* @note All members are jint as it is treated as a jint array in Kotlin
|
||||
* @note This structure corresponds to TouchScreenStateData, see that for details
|
||||
*/
|
||||
struct TouchScreenPoint {
|
||||
jint x;
|
||||
jint y;
|
||||
jint minor;
|
||||
jint major;
|
||||
jint angle;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class is used to manage the shared memory responsible for touch-screen data
|
||||
*/
|
||||
class TouchManager {
|
||||
private:
|
||||
const DeviceState &state;
|
||||
bool activated{};
|
||||
TouchScreenSection §ion;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param hid A pointer to HID Shared Memory on the host
|
||||
*/
|
||||
TouchManager(const DeviceState &state, input::HidSharedMemory *hid);
|
||||
|
||||
void Activate();
|
||||
|
||||
void SetState(const std::span<TouchScreenPoint> &points);
|
||||
};
|
||||
}
|
@ -20,7 +20,7 @@ import kotlinx.android.synthetic.main.emu_activity.*
|
||||
import java.io.File
|
||||
import kotlin.math.abs
|
||||
|
||||
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTouchListener {
|
||||
init {
|
||||
System.loadLibrary("skyline") // libskyline.so
|
||||
}
|
||||
@ -142,6 +142,13 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
*/
|
||||
private external fun setAxisValue(index : Int, axis : Int, value : Int)
|
||||
|
||||
/**
|
||||
* This sets the values of the points on the guest touch-screen
|
||||
*
|
||||
* @param points An array of skyline::input::TouchScreenPoint in C++ represented as integers
|
||||
*/
|
||||
private external fun setTouchState(points : IntArray)
|
||||
|
||||
/**
|
||||
* This initializes all of the controllers from [input] on the guest
|
||||
*/
|
||||
@ -235,6 +242,8 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
@Suppress("DEPRECATION") val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display!! else windowManager.defaultDisplay
|
||||
display?.supportedModes?.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||
|
||||
game_view.setOnTouchListener(this)
|
||||
|
||||
executeApplication(intent.data!!)
|
||||
}
|
||||
|
||||
@ -390,6 +399,30 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
return super.onGenericMotionEvent(event)
|
||||
}
|
||||
|
||||
@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
|
||||
var offset = 0
|
||||
for (index in 0 until count) {
|
||||
val pointer = MotionEvent.PointerCoords()
|
||||
event.getPointerCoords(index, pointer)
|
||||
|
||||
val x = 0f.coerceAtLeast(pointer.x * 1280 / view.width).toInt()
|
||||
val y = 0f.coerceAtLeast(pointer.y * 720 / view.height).toInt()
|
||||
|
||||
points[offset++] = x
|
||||
points[offset++] = y
|
||||
points[offset++] = pointer.touchMinor.toInt()
|
||||
points[offset++] = pointer.touchMajor.toInt()
|
||||
points[offset++] = (pointer.orientation * 180 / Math.PI).toInt()
|
||||
}
|
||||
|
||||
setTouchState(points)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
fun vibrateDevice(index : Int, timing : LongArray, amplitude : IntArray) {
|
||||
val vibrator = if (vibrators[index] != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user