mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 15:25:28 +03:00
Initial Kotlin Input Implementation
This commit contains the Kotlin side of the initial Input implementation, this is based on the work done in the `hid` branch in `bylaws/skyline`. Co-authored-by: ◱ PixelyIon <pixelyion@protonmail.com>
This commit is contained in:
parent
0219eda2db
commit
b167abcdb7
@ -98,10 +98,13 @@ extern "C" JNIEXPORT jfloat Java_emu_skyline_EmulationActivity_getFrametime(JNIE
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jlong id, jint state) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setButtonState(JNIEnv *, jobject, jlong id, jint state) {
|
||||||
|
if (input) {
|
||||||
skyline::input::npad::NpadButton button{.raw = static_cast<skyline::u64>(id)};
|
skyline::input::npad::NpadButton button{.raw = static_cast<skyline::u64>(id)};
|
||||||
input->npad[0]->SetButtonState(button, static_cast<skyline::input::npad::NpadButtonState>(state));
|
input->npad[0]->SetButtonState(button, static_cast<skyline::input::npad::NpadButtonState>(state));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint id, jint value) {
|
extern "C" JNIEXPORT void JNICALL Java_emu_skyline_EmulationActivity_setAxisValue(JNIEnv *, jobject, jint id, jint value) {
|
||||||
|
if (input)
|
||||||
input->npad[0]->SetAxisValue(static_cast<skyline::input::npad::NpadAxisId>(id), value);
|
input->npad[0]->SetAxisValue(static_cast<skyline::input::npad::NpadAxisId>(id), value);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ namespace skyline {
|
|||||||
bool leftSr : 1; //!< Left Joy-Con SR button
|
bool leftSr : 1; //!< Left Joy-Con SR button
|
||||||
bool rightSl : 1; //!< Right Joy-Con SL button
|
bool rightSl : 1; //!< Right Joy-Con SL button
|
||||||
bool rightSr : 1; //!< Right Joy-Con SR button
|
bool rightSr : 1; //!< Right Joy-Con SR button
|
||||||
bool touch : 1; //!< The touch button
|
|
||||||
};
|
};
|
||||||
u64 raw;
|
u64 raw;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include <input.h>
|
||||||
#include "IAppletResource.h"
|
#include "IAppletResource.h"
|
||||||
|
|
||||||
namespace skyline::service::hid {
|
namespace skyline::service::hid {
|
||||||
@ -9,8 +10,7 @@ namespace skyline::service::hid {
|
|||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
hidSharedMemory = std::make_shared<kernel::type::KSharedMemory>(state, NULL, constant::HidSharedMemSize, memory::Permission{true, false, false});
|
auto handle = state.process->InsertItem<type::KSharedMemory>(state.input->hidKMem);
|
||||||
auto handle = state.process->InsertItem<type::KSharedMemory>(hidSharedMemory);
|
|
||||||
state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle);
|
state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle);
|
||||||
|
|
||||||
response.copyHandles.push_back(handle);
|
response.copyHandles.push_back(handle);
|
||||||
|
@ -7,19 +7,12 @@
|
|||||||
#include <services/base_service.h>
|
#include <services/base_service.h>
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline::service::hid {
|
||||||
namespace constant {
|
|
||||||
constexpr auto HidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace service::hid {
|
|
||||||
/**
|
/**
|
||||||
* @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource)
|
* @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource)
|
||||||
*/
|
*/
|
||||||
class IAppletResource : public BaseService {
|
class IAppletResource : public BaseService {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<type::KSharedMemory> hidSharedMemory; //!< A pointer to HID shared memory
|
|
||||||
|
|
||||||
IAppletResource(const DeviceState &state, ServiceManager &manager);
|
IAppletResource(const DeviceState &state, ServiceManager &manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,4 +21,3 @@ namespace skyline {
|
|||||||
void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -15,9 +15,13 @@ import android.util.Log
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.preference.PreferenceManager
|
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 emu.skyline.loader.getRomFormat
|
||||||
import kotlinx.android.synthetic.main.emu_activity.*
|
import kotlinx.android.synthetic.main.emu_activity.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||||
init {
|
init {
|
||||||
@ -84,8 +88,14 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
*/
|
*/
|
||||||
private external fun getFrametime() : Float
|
private external fun getFrametime() : Float
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the state of a specific button
|
||||||
|
*/
|
||||||
private external fun setButtonState(id : Long, state : Int)
|
private external fun setButtonState(id : Long, state : Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the value of a specific axis
|
||||||
|
*/
|
||||||
private external fun setAxisValue(id : Int, value : Int)
|
private external fun setAxisValue(id : Int, value : Int)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,4 +220,113 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
|||||||
surface = null
|
surface = null
|
||||||
setSurface(surface)
|
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<Int, NpadButton> = 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<Float, NpadButton> = mapOf(
|
||||||
|
-1.0f to NpadButton.DpadLeft,
|
||||||
|
+1.0f to NpadButton.DpadRight)
|
||||||
|
|
||||||
|
val hatYMap : Map<Float, NpadButton> = 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<Int, NpadAxis> = 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
21
app/src/main/java/emu/skyline/input/Button.kt
Normal file
21
app/src/main/java/emu/skyline/input/Button.kt
Normal file
@ -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),
|
||||||
|
}
|
57
app/src/main/java/emu/skyline/input/Npad.kt
Normal file
57
app/src/main/java/emu/skyline/input/Npad.kt
Normal file
@ -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,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user