mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-29 16:04:17 +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.cpp
|
||||||
${source_DIR}/skyline/input/npad.cpp
|
${source_DIR}/skyline/input/npad.cpp
|
||||||
${source_DIR}/skyline/input/npad_device.cpp
|
${source_DIR}/skyline/input/npad_device.cpp
|
||||||
|
${source_DIR}/skyline/input/touch.cpp
|
||||||
${source_DIR}/skyline/os.cpp
|
${source_DIR}/skyline/os.cpp
|
||||||
${source_DIR}/skyline/loader/loader.cpp
|
${source_DIR}/skyline/loader/loader.cpp
|
||||||
${source_DIR}/skyline/loader/nro.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
|
// 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 {
|
union Result {
|
||||||
u32 raw{};
|
u32 raw{};
|
||||||
struct {
|
struct __attribute__((packed)) {
|
||||||
u16 module : 9;
|
u16 module : 9;
|
||||||
u16 id : 12;
|
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
|
* @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) {
|
constexpr Result(u16 module, u16 id) {
|
||||||
this->module = module;
|
this->module = module;
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
namespace skyline::input {
|
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 "kernel/types/KSharedMemory.h"
|
||||||
#include "input/shared_mem.h"
|
#include "input/shared_mem.h"
|
||||||
#include "input/npad.h"
|
#include "input/npad.h"
|
||||||
|
#include "input/touch.h"
|
||||||
|
|
||||||
namespace skyline::input {
|
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
|
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
|
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);
|
Input(const DeviceState &state);
|
||||||
};
|
};
|
||||||
|
@ -18,10 +18,10 @@ namespace skyline::input {
|
|||||||
u32 positionX; //!< The X position of this touch
|
u32 positionX; //!< The X position of this touch
|
||||||
u32 positionY; //!< The Y position of this touch
|
u32 positionY; //!< The Y position of this touch
|
||||||
|
|
||||||
u32 diameterX; //!< The diameter of the touch on the X-axis
|
u32 minorAxis; //!< The diameter of the touch cross-section on the minor-axis in pixels
|
||||||
u32 diameterY; //!< The diameter of the touch on the Y-axis
|
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_;
|
u32 _pad1_;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(TouchScreenStateData) == 0x28);
|
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 java.io.File
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTouchListener {
|
||||||
init {
|
init {
|
||||||
System.loadLibrary("skyline") // libskyline.so
|
System.loadLibrary("skyline") // libskyline.so
|
||||||
}
|
}
|
||||||
@ -142,6 +142,13 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
*/
|
*/
|
||||||
private external fun setAxisValue(index : Int, axis : Int, value : Int)
|
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
|
* 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
|
@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 }
|
display?.supportedModes?.maxBy { it.refreshRate + (it.physicalHeight * it.physicalWidth) }?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||||
|
|
||||||
|
game_view.setOnTouchListener(this)
|
||||||
|
|
||||||
executeApplication(intent.data!!)
|
executeApplication(intent.data!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,6 +399,30 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
return super.onGenericMotionEvent(event)
|
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")
|
@SuppressLint("WrongConstant")
|
||||||
fun vibrateDevice(index : Int, timing : LongArray, amplitude : IntArray) {
|
fun vibrateDevice(index : Int, timing : LongArray, amplitude : IntArray) {
|
||||||
val vibrator = if (vibrators[index] != null) {
|
val vibrator = if (vibrators[index] != null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user