diff --git a/app/src/main/cpp/emu_jni.cpp b/app/src/main/cpp/emu_jni.cpp index 7fa83958..9272c4c2 100644 --- a/app/src/main/cpp/emu_jni.cpp +++ b/app/src/main/cpp/emu_jni.cpp @@ -89,19 +89,22 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv * JniMtx.unlock(); } -extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject ) { +extern "C" JNIEXPORT jint Java_emu_skyline_EmulationActivity_getFps(JNIEnv *, jobject) { return fps; } -extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *, jobject ) { +extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIEnv *, jobject) { return static_cast(frametime) / 100; } extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jlong id, jint state) { - skyline::input::npad::NpadButton button{.raw = static_cast(id)}; - input->npad[0]->SetButtonState(button, static_cast(state)); + if (input) { + skyline::input::npad::NpadButton button{.raw = static_cast(id)}; + input->npad[0]->SetButtonState(button, static_cast(state)); + } } extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint id, jint value) { - input->npad[0]->SetAxisValue(static_cast(id), value); + if (input) + input->npad[0]->SetAxisValue(static_cast(id), value); } diff --git a/app/src/main/cpp/skyline/input/npad.h b/app/src/main/cpp/skyline/input/npad.h index d98f01e7..2cc49f3e 100644 --- a/app/src/main/cpp/skyline/input/npad.h +++ b/app/src/main/cpp/skyline/input/npad.h @@ -42,7 +42,6 @@ namespace skyline { bool leftSr : 1; //!< Left Joy-Con SR button bool rightSl : 1; //!< Right Joy-Con SL button bool rightSr : 1; //!< Right Joy-Con SR button - bool touch : 1; //!< The touch button }; u64 raw; }; diff --git a/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp b/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp index a6310edf..15ec3f86 100644 --- a/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp +++ b/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include "IAppletResource.h" namespace skyline::service::hid { @@ -9,8 +10,7 @@ namespace skyline::service::hid { }) {} void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - hidSharedMemory = std::make_shared(state, NULL, constant::HidSharedMemSize, memory::Permission{true, false, false}); - auto handle = state.process->InsertItem(hidSharedMemory); + auto handle = state.process->InsertItem(state.input->hidKMem); state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); diff --git a/app/src/main/cpp/skyline/services/hid/IAppletResource.h b/app/src/main/cpp/skyline/services/hid/IAppletResource.h index cf71b0df..b4156444 100644 --- a/app/src/main/cpp/skyline/services/hid/IAppletResource.h +++ b/app/src/main/cpp/skyline/services/hid/IAppletResource.h @@ -7,25 +7,17 @@ #include #include -namespace skyline { - namespace constant { - constexpr auto HidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory) - } +namespace skyline::service::hid { + /** + * @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource) + */ + class IAppletResource : public BaseService { + public: + IAppletResource(const DeviceState &state, ServiceManager &manager); - namespace service::hid { /** - * @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource) + * @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle) */ - class IAppletResource : public BaseService { - public: - std::shared_ptr hidSharedMemory; //!< A pointer to HID shared memory - - IAppletResource(const DeviceState &state, ServiceManager &manager); - - /** - * @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle) - */ - void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - }; - } + void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; } diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index bfb133a0..c4a3a82e 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -15,9 +15,13 @@ import android.util.Log import android.view.* import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager +import emu.skyline.input.ButtonState +import emu.skyline.input.NpadAxis +import emu.skyline.input.NpadButton import emu.skyline.loader.getRomFormat import kotlinx.android.synthetic.main.emu_activity.* import java.io.File +import kotlin.math.abs class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback { init { @@ -84,8 +88,14 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback { */ private external fun getFrametime() : Float + /** + * This sets the state of a specific button + */ private external fun setButtonState(id : Long, state : Int) + /** + * This sets the value of a specific axis + */ private external fun setAxisValue(id : Int, value : Int) /** @@ -210,4 +220,113 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback { surface = null setSurface(surface) } + + /** + * This handles passing on any key events to libskyline + */ + override fun dispatchKeyEvent(event : KeyEvent) : Boolean { + val action : ButtonState = when (event.action) { + KeyEvent.ACTION_DOWN -> ButtonState.Pressed + KeyEvent.ACTION_UP -> ButtonState.Released + else -> return false + } + + val buttonMap : Map = mapOf( + KeyEvent.KEYCODE_BUTTON_A to NpadButton.A, + KeyEvent.KEYCODE_BUTTON_B to NpadButton.B, + KeyEvent.KEYCODE_BUTTON_X to NpadButton.X, + KeyEvent.KEYCODE_BUTTON_Y to NpadButton.Y, + KeyEvent.KEYCODE_BUTTON_THUMBL to NpadButton.L3, + KeyEvent.KEYCODE_BUTTON_THUMBR to NpadButton.R3, + KeyEvent.KEYCODE_BUTTON_L1 to NpadButton.L, + KeyEvent.KEYCODE_BUTTON_R1 to NpadButton.R, + KeyEvent.KEYCODE_BUTTON_L2 to NpadButton.ZL, + KeyEvent.KEYCODE_BUTTON_R2 to NpadButton.ZR, + KeyEvent.KEYCODE_BUTTON_START to NpadButton.Plus, + KeyEvent.KEYCODE_BUTTON_SELECT to NpadButton.Minus, + KeyEvent.KEYCODE_DPAD_DOWN to NpadButton.DpadDown, + KeyEvent.KEYCODE_DPAD_UP to NpadButton.DpadUp, + KeyEvent.KEYCODE_DPAD_LEFT to NpadButton.DpadLeft, + KeyEvent.KEYCODE_DPAD_RIGHT to NpadButton.DpadRight) + + return try { + setButtonState(buttonMap.getValue(event.keyCode).value(), action.ordinal); + true + } catch (ignored : NoSuchElementException) { + super.dispatchKeyEvent(event) + } + } + + /** + * This is the controller HAT X value + */ + private var controllerHatX : Float = 0.0f + + /** + * This is the controller HAT Y value + */ + private var controllerHatY : Float = 0.0f + + /** + * This handles passing on any motion events to libskyline + */ + override fun dispatchGenericMotionEvent(event : MotionEvent) : Boolean { + if ((event.source and InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || + (event.source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK) { + val hatXMap : Map = mapOf( + -1.0f to NpadButton.DpadLeft, + +1.0f to NpadButton.DpadRight) + + val hatYMap : Map = mapOf( + -1.0f to NpadButton.DpadUp, + +1.0f to NpadButton.DpadDown) + + if (controllerHatX != event.getAxisValue(MotionEvent.AXIS_HAT_X)) { + if (event.getAxisValue(MotionEvent.AXIS_HAT_X) == 0.0f) + setButtonState(hatXMap.getValue(controllerHatX).value(), ButtonState.Released.ordinal) + else + setButtonState(hatXMap.getValue(event.getAxisValue(MotionEvent.AXIS_HAT_X)).value(), ButtonState.Pressed.ordinal) + + controllerHatX = event.getAxisValue(MotionEvent.AXIS_HAT_X) + + return true + } + + if (controllerHatY != event.getAxisValue(MotionEvent.AXIS_HAT_Y)) { + if (event.getAxisValue(MotionEvent.AXIS_HAT_Y) == 0.0f) + setButtonState(hatYMap.getValue(controllerHatY).value(), ButtonState.Released.ordinal) + else + setButtonState(hatYMap.getValue(event.getAxisValue(MotionEvent.AXIS_HAT_Y)).value(), ButtonState.Pressed.ordinal) + + controllerHatY = event.getAxisValue(MotionEvent.AXIS_HAT_Y) + + return true + } + } + + if ((event.source and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.action == MotionEvent.ACTION_MOVE) { + val axisMap : Map = mapOf( + MotionEvent.AXIS_X to NpadAxis.LX, + MotionEvent.AXIS_Y to NpadAxis.LY, + MotionEvent.AXIS_Z to NpadAxis.RX, + MotionEvent.AXIS_RZ to NpadAxis.RY) + + //TODO: Digital inputs based off of analog sticks + event.device.motionRanges.forEach { + if (axisMap.containsKey(it.axis)) { + var axisValue : Float = event.getAxisValue(it.axis) + if (abs(axisValue) <= it.flat) + axisValue = 0.0f + + val ratio : Float = axisValue / (it.max - it.min) + val rangedAxisValue : Int = (ratio * (Short.MAX_VALUE - Short.MIN_VALUE)).toInt() + + setAxisValue(axisMap.getValue(it.axis).ordinal, rangedAxisValue) + } + } + return true + } + + return super.dispatchGenericMotionEvent(event) + } } diff --git a/app/src/main/java/emu/skyline/input/Button.kt b/app/src/main/java/emu/skyline/input/Button.kt new file mode 100644 index 00000000..18b3626e --- /dev/null +++ b/app/src/main/java/emu/skyline/input/Button.kt @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + */ + +package emu.skyline.input + +/** + * This is a generic interface for all Button classes to implement + */ +interface ButtonId { + /** + * This should return the value of the Button according to what libskyline expects + */ + fun value() : Long +} + +enum class ButtonState(val state : Boolean) { + Released(false), + Pressed(true), +} diff --git a/app/src/main/java/emu/skyline/input/Npad.kt b/app/src/main/java/emu/skyline/input/Npad.kt new file mode 100644 index 00000000..4028126b --- /dev/null +++ b/app/src/main/java/emu/skyline/input/Npad.kt @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + */ + +package emu.skyline.input + +/** + * This enumerates all buttons on an NPad controller + */ +enum class NpadButton : ButtonId { + A, + B, + X, + Y, + L3, + R3, + L, + R, + ZL, + ZR, + Plus, + Minus, + DpadLeft, + DpadUp, + DpadRight, + DpadDown, + LeftStickLeft, + LeftStickUp, + LeftStickRight, + LeftStickDown, + RightStickLeft, + RightStickUp, + RightStickRight, + RightStickDown, + LeftSL, + LeftSR, + RightSL, + RightSR; + + /** + * This just returns the value as setting the [ordinal]-th bit in a [Long] + */ + override fun value() : Long { + return (1.toLong()) shl ordinal + } +} + +/** + * This enumerates all the axis on an NPad controller + */ +enum class NpadAxis { + RX, + RY, + LX, + LY, +}