mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 22:40:17 +00:00
Refactor input core
This commit is contained in:
parent
9d742604a1
commit
9362146672
@ -45,17 +45,21 @@ static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
|
||||
SDL_SCANCODE_L,
|
||||
|
||||
// indirectly mapped keys
|
||||
SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT
|
||||
};
|
||||
SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT};
|
||||
|
||||
void Config::ReadValues() {
|
||||
// Controls
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
|
||||
Settings::InputDeviceMapping(sdl2_config->Get("Controls", Settings::NativeInput::Mapping[i], std::to_string(defaults[i])));
|
||||
Settings::InputDeviceMapping(sdl2_config->Get(
|
||||
"Controls", Settings::NativeInput::Mapping[i], std::to_string(defaults[i])));
|
||||
}
|
||||
Settings::values.pad_circle_modifier = Settings::InputDeviceMapping(sdl2_config->Get("Controls", "pad_circle_modifier", ""));
|
||||
Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.4);
|
||||
Settings::values.pad_circle_modifier =
|
||||
Settings::InputDeviceMapping(sdl2_config->Get("Controls", "pad_circle_modifier", ""));
|
||||
Settings::values.pad_circle_modifier_scale =
|
||||
(float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.4);
|
||||
Settings::values.pad_circle_deadzone =
|
||||
(float)sdl2_config->GetReal("Controls", "pad_circle_deadzone", 0.4);
|
||||
|
||||
// Core
|
||||
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
||||
|
@ -23,17 +23,22 @@ const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> Config::defaults =
|
||||
Qt::Key_K, Qt::Key_J, Qt::Key_L,
|
||||
|
||||
// indirectly mapped keys
|
||||
Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right
|
||||
};
|
||||
Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right};
|
||||
|
||||
void Config::ReadValues() {
|
||||
qt_config->beginGroup("Controls");
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
|
||||
Settings::InputDeviceMapping(qt_config->value(Settings::NativeInput::Mapping[i], defaults[i]).toString().toStdString());
|
||||
Settings::InputDeviceMapping(
|
||||
qt_config->value(Settings::NativeInput::Mapping[i], defaults[i])
|
||||
.toString()
|
||||
.toStdString());
|
||||
}
|
||||
Settings::values.pad_circle_modifier = Settings::InputDeviceMapping(qt_config->value("pad_circle_modifier", 0).toString().toStdString());
|
||||
Settings::values.pad_circle_modifier_scale = qt_config->value("pad_circle_modifier_scale", 0.4).toFloat();
|
||||
Settings::values.pad_circle_modifier = Settings::InputDeviceMapping(
|
||||
qt_config->value("pad_circle_modifier", 0).toString().toStdString());
|
||||
Settings::values.pad_circle_modifier_scale =
|
||||
qt_config->value("pad_circle_modifier_scale", 0.4).toFloat();
|
||||
Settings::values.pad_circle_deadzone = qt_config->value("pad_circle_deadzone", 0.3f).toFloat();
|
||||
qt_config->endGroup();
|
||||
|
||||
qt_config->beginGroup("Core");
|
||||
@ -136,11 +141,16 @@ void Config::ReadValues() {
|
||||
void Config::SaveValues() {
|
||||
qt_config->beginGroup("Controls");
|
||||
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
|
||||
qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]),
|
||||
QString::fromStdString(Settings::values.input_mappings[Settings::NativeInput::All[i]].ToString()));
|
||||
qt_config->setValue(
|
||||
QString::fromStdString(Settings::NativeInput::Mapping[i]),
|
||||
QString::fromStdString(
|
||||
Settings::values.input_mappings[Settings::NativeInput::All[i]].ToString()));
|
||||
}
|
||||
qt_config->setValue("pad_circle_modifier", QString::fromStdString(Settings::values.pad_circle_modifier.ToString()));
|
||||
qt_config->setValue("pad_circle_modifier_scale", (double)Settings::values.pad_circle_modifier_scale);
|
||||
qt_config->setValue("pad_circle_modifier",
|
||||
QString::fromStdString(Settings::values.pad_circle_modifier.ToString()));
|
||||
qt_config->setValue("pad_circle_modifier_scale",
|
||||
(double)Settings::values.pad_circle_modifier_scale);
|
||||
qt_config->setValue("pad_circle_deadzone", (double)Settings::values.pad_circle_deadzone);
|
||||
qt_config->endGroup();
|
||||
|
||||
qt_config->beginGroup("Core");
|
||||
|
@ -46,37 +46,29 @@ enum Values {
|
||||
CRIGHT,
|
||||
|
||||
// indirectly mapped keys
|
||||
CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
|
||||
CIRCLE_UP,
|
||||
CIRCLE_DOWN,
|
||||
CIRCLE_LEFT,
|
||||
CIRCLE_RIGHT,
|
||||
|
||||
NUM_INPUTS
|
||||
};
|
||||
static const std::array<const char*, NUM_INPUTS> Mapping = { {
|
||||
// directly mapped keys
|
||||
"pad_a", "pad_b", "pad_x", "pad_y",
|
||||
"pad_l", "pad_r", "pad_zl", "pad_zr",
|
||||
"pad_start", "pad_select", "pad_home",
|
||||
"pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
|
||||
"pad_cup", "pad_cdown", "pad_cleft", "pad_cright",
|
||||
static const std::array<const char*, NUM_INPUTS> Mapping = {
|
||||
{// directly mapped keys
|
||||
"pad_a", "pad_b", "pad_x", "pad_y", "pad_l", "pad_r", "pad_zl", "pad_zr", "pad_start",
|
||||
"pad_select", "pad_home", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_cup",
|
||||
"pad_cdown", "pad_cleft", "pad_cright",
|
||||
|
||||
// indirectly mapped keys
|
||||
"pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right"
|
||||
} };
|
||||
static const std::array<Values, NUM_INPUTS> All = { {
|
||||
A, B, X, Y,
|
||||
L, R, ZL, ZR,
|
||||
START, SELECT, HOME,
|
||||
DUP, DDOWN, DLEFT, DRIGHT,
|
||||
CUP, CDOWN, CLEFT, CRIGHT,
|
||||
CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT
|
||||
} };
|
||||
// indirectly mapped keys
|
||||
"pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right"}};
|
||||
static const std::array<Values, NUM_INPUTS> All = {
|
||||
{A, B, X, Y, L, R, ZL, ZR,
|
||||
START, SELECT, HOME, DUP, DDOWN, DLEFT, DRIGHT, CUP,
|
||||
CDOWN, CLEFT, CRIGHT, CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT}};
|
||||
}
|
||||
|
||||
enum class DeviceFramework {
|
||||
SDL
|
||||
};
|
||||
enum class Device {
|
||||
Keyboard, Gamepad
|
||||
};
|
||||
enum class DeviceFramework { SDL };
|
||||
enum class Device { Keyboard, Gamepad };
|
||||
struct InputDeviceMapping {
|
||||
DeviceFramework framework = DeviceFramework::SDL;
|
||||
int number = 0;
|
||||
@ -105,7 +97,8 @@ struct InputDeviceMapping {
|
||||
}
|
||||
|
||||
bool operator==(const InputDeviceMapping& rhs) const {
|
||||
return std::tie(device, framework, number) == std::tie(rhs.device, rhs.framework, rhs.number);
|
||||
return std::tie(device, framework, number) ==
|
||||
std::tie(rhs.device, rhs.framework, rhs.number);
|
||||
}
|
||||
bool operator==(const std::string& rhs) const {
|
||||
return ToString() == rhs;
|
||||
@ -114,9 +107,7 @@ struct InputDeviceMapping {
|
||||
return ToString() < rhs.ToString();
|
||||
}
|
||||
|
||||
void InitKey() {
|
||||
|
||||
}
|
||||
void InitKey() {}
|
||||
|
||||
std::string ToString() const {
|
||||
std::string result;
|
||||
@ -133,7 +124,7 @@ struct InputDeviceMapping {
|
||||
result += "Gamepad";
|
||||
|
||||
result += "/";
|
||||
result += key;
|
||||
result += std::to_string(key);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@ -146,8 +137,7 @@ struct Values {
|
||||
std::array<InputDeviceMapping, NativeInput::NUM_INPUTS> input_mappings;
|
||||
InputDeviceMapping pad_circle_modifier;
|
||||
float pad_circle_modifier_scale;
|
||||
float circle_pad_deadzone = 30;
|
||||
float c_stick_deadzone = 30;
|
||||
float pad_circle_deadzone;
|
||||
|
||||
// Core
|
||||
bool use_cpu_jit;
|
||||
|
@ -20,13 +20,12 @@ public:
|
||||
* @param keymap: vector of PadStates for device to listen for
|
||||
* @return true if successful
|
||||
*/
|
||||
virtual bool InitDevice(
|
||||
int number, Settings::InputDeviceMapping device_mapping) = 0;
|
||||
virtual bool InitDevice(int number, Settings::InputDeviceMapping device_mapping) = 0;
|
||||
|
||||
/**
|
||||
* Process inputs that were pressed since last frame
|
||||
*/
|
||||
virtual std::map<Settings::InputDeviceMapping,float> ProcessInput() = 0;
|
||||
virtual std::map<Settings::InputDeviceMapping, float> ProcessInput() = 0;
|
||||
|
||||
/**
|
||||
* Close connection to device
|
||||
@ -44,6 +43,7 @@ public:
|
||||
* Clears info from last frame.
|
||||
*/
|
||||
virtual void Clear() = 0;
|
||||
|
||||
protected:
|
||||
Settings::InputDeviceMapping input_device_mapping;
|
||||
};
|
||||
|
@ -11,8 +11,7 @@ Keyboard::Keyboard() {}
|
||||
|
||||
Keyboard::~Keyboard() {}
|
||||
|
||||
bool Keyboard::InitDevice(
|
||||
int number, Settings::InputDeviceMapping device_mapping) {
|
||||
bool Keyboard::InitDevice(int number, Settings::InputDeviceMapping device_mapping) {
|
||||
|
||||
// Check if keyboard is mapped for circle up or left. if so, set modifier to -1
|
||||
/*for (const auto& entry : key_mapping) {
|
||||
@ -48,32 +47,6 @@ std::map<Settings::InputDeviceMapping, float> Keyboard::ProcessInput() {
|
||||
input_device_mapping.key = key.first.key;
|
||||
button_status.emplace(input_device_mapping, key.second ? 1.0 : 0.0);
|
||||
}
|
||||
//for (const auto& entry : key_mapping) {
|
||||
// if (entry.first == "")
|
||||
// continue;
|
||||
// int keycode = std::stoi(entry.first);
|
||||
// KeyboardKey proxy = KeyboardKey(keycode, "");
|
||||
|
||||
// // if key is pressed when prev state is unpressed, or if key pressed and is a circle pad
|
||||
// // direction
|
||||
// if ((keysPressedCopy[proxy] == true && keys_pressed_last[keycode] == false) ||
|
||||
// (keysPressedCopy[proxy] == true && circle_pad_directions.count(keycode))) {
|
||||
// for (const auto& key : entry.second) {
|
||||
// if (circle_pad_directions.count(keycode)) { // If is analog key press
|
||||
// float modifier =
|
||||
// (circlePadModPressed) ? Settings::values.pad_circle_modifier_scale : 1;
|
||||
// KeyMap::PressKey(key, circle_pad_directions[keycode] * modifier);
|
||||
// } else // Is digital key press
|
||||
// KeyMap::PressKey(key, 1.0);
|
||||
// }
|
||||
// keys_pressed_last[keycode] = true;
|
||||
// } else if (keysPressedCopy[proxy] == false && keys_pressed_last[keycode] == true) {
|
||||
// for (const auto& key : entry.second) {
|
||||
// KeyMap::ReleaseKey(key);
|
||||
// }
|
||||
// keys_pressed_last[keycode] = false;
|
||||
// }
|
||||
//}
|
||||
return button_status;
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,7 @@ class Keyboard : public IDevice {
|
||||
public:
|
||||
Keyboard();
|
||||
~Keyboard();
|
||||
bool InitDevice(
|
||||
int number, Settings::InputDeviceMapping device_mapping) override;
|
||||
bool InitDevice(int number, Settings::InputDeviceMapping device_mapping) override;
|
||||
std::map<Settings::InputDeviceMapping, float> ProcessInput() override;
|
||||
bool CloseDevice() override;
|
||||
void KeyPressed(KeyboardKey key);
|
||||
@ -45,6 +44,6 @@ private:
|
||||
std::map<int, bool> keys_pressed_last;
|
||||
std::mutex m; ///< Keys pressed from frontend is on a separate thread.
|
||||
std::map<int, float> circle_pad_directions; ///< Inverts the strength of key press if it is a
|
||||
///circle pad direction that needs it.
|
||||
/// circle pad direction that needs it.
|
||||
KeyboardKey circle_pad_modifier;
|
||||
};
|
||||
|
@ -23,8 +23,7 @@ SDLGamepad::~SDLGamepad() {
|
||||
CloseDevice();
|
||||
}
|
||||
|
||||
bool SDLGamepad::InitDevice(
|
||||
int number, Settings::InputDeviceMapping device_mapping) {
|
||||
bool SDLGamepad::InitDevice(int number, Settings::InputDeviceMapping device_mapping) {
|
||||
if (!SDLGamepad::SDLInitialized && SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_GAMECONTROLLER) failed");
|
||||
return false;
|
||||
@ -56,26 +55,24 @@ std::map<Settings::InputDeviceMapping, float> SDLGamepad::ProcessInput() {
|
||||
for (int i = 0; i < SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MAX; i++) {
|
||||
SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(i);
|
||||
Uint8 pressed = SDL_GameControllerGetButton(gamepad, button);
|
||||
input_device_mapping.key = static_cast<int>(gamepadinput_to_sdlname_mapping2[SDL_GameControllerGetStringForButton(button)]);
|
||||
input_device_mapping.key = static_cast<int>(
|
||||
gamepadinput_to_sdlname_mapping2[SDL_GameControllerGetStringForButton(button)]);
|
||||
button_status.emplace(input_device_mapping, pressed);
|
||||
}
|
||||
for (int i = 0; i < SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_MAX; i++) {
|
||||
SDL_GameControllerAxis axis = static_cast<SDL_GameControllerAxis>(i);
|
||||
float strength = fmaxf(-1, (float)SDL_GameControllerGetAxis(gamepad, axis) / 32767.0);
|
||||
input_device_mapping.key = static_cast<int>(gamepadinput_to_sdlname_mapping2[SDL_GameControllerGetStringForAxis(axis)]);
|
||||
if (strength < 0)
|
||||
input_device_mapping.key += 1; //minus axis value is always one greater
|
||||
|
||||
button_status.emplace(input_device_mapping, strength);
|
||||
//for (const auto& padstate : entry.second) {
|
||||
//// TODO: calculate deadzone by radial field rather than axial field. (sqrt(x^2 +
|
||||
//// y^2) > deadzone)
|
||||
//// dont process if in deadzone. Replace later with settings for deadzone.
|
||||
//if (abs(value) < 0.2 * 32767.0)
|
||||
//KeyMap::ReleaseKey(padstate);
|
||||
//else
|
||||
//KeyMap::PressKey(padstate, (float)value / 32767.0);
|
||||
//}
|
||||
input_device_mapping.key = static_cast<int>(
|
||||
gamepadinput_to_sdlname_mapping2[SDL_GameControllerGetStringForAxis(axis)]);
|
||||
if (strength < 0) {
|
||||
button_status.emplace(input_device_mapping, 0);
|
||||
input_device_mapping.key += 1; // minus axis value is always one greater
|
||||
button_status.emplace(input_device_mapping, abs(strength));
|
||||
} else {
|
||||
button_status.emplace(input_device_mapping, abs(strength));
|
||||
input_device_mapping.key += 1; // minus axis value is always one greater
|
||||
button_status.emplace(input_device_mapping, 0);
|
||||
}
|
||||
}
|
||||
return button_status;
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ public:
|
||||
SDLGamepad(int number_, _SDL_GameController* gamepad_);
|
||||
~SDLGamepad();
|
||||
|
||||
bool InitDevice(
|
||||
int number, Settings::InputDeviceMapping device_mapping) override;
|
||||
bool InitDevice(int number, Settings::InputDeviceMapping device_mapping) override;
|
||||
std::map<Settings::InputDeviceMapping, float> ProcessInput() override;
|
||||
bool CloseDevice() override;
|
||||
Settings::InputDeviceMapping GetInput() override;
|
||||
@ -30,7 +29,6 @@ public:
|
||||
LeftShoulder,
|
||||
RightShoulder,
|
||||
Start,
|
||||
Guide,
|
||||
Back,
|
||||
DPadUp,
|
||||
DpadDown,
|
||||
@ -81,31 +79,30 @@ private:
|
||||
{GamepadInputs::RightXMinus, "rightx"},
|
||||
};
|
||||
std::map<std::string, GamepadInputs> gamepadinput_to_sdlname_mapping2 = {
|
||||
{ "a", GamepadInputs::ButtonA },
|
||||
{ "b", GamepadInputs::ButtonB },
|
||||
{ "x", GamepadInputs::ButtonX },
|
||||
{ "y", GamepadInputs::ButtonY },
|
||||
{ "leftshoulder", GamepadInputs::LeftShoulder },
|
||||
{ "rightshoulder", GamepadInputs::RightShoulder },
|
||||
{ "start", GamepadInputs::Start },
|
||||
{ "back", GamepadInputs::Back },
|
||||
{ "dpup", GamepadInputs::DPadUp },
|
||||
{ "dpdown", GamepadInputs::DpadDown },
|
||||
{ "dpleft", GamepadInputs::DpadLeft },
|
||||
{ "dpright", GamepadInputs::DpadRight },
|
||||
{ "leftstick", GamepadInputs::L3 },
|
||||
{ "rightstick", GamepadInputs::R3 },
|
||||
{ "lefttrigger", GamepadInputs::LeftTrigger },
|
||||
{ "righttrigger", GamepadInputs::RightTrigger },
|
||||
{ "lefty", GamepadInputs::LeftYPlus },
|
||||
{ "lefty2", GamepadInputs::LeftYMinus },
|
||||
{ "leftx", GamepadInputs::LeftXPlus },
|
||||
{ "leftx2", GamepadInputs::LeftXMinus },
|
||||
{ "righty", GamepadInputs::RightYPlus },
|
||||
{ "righty2", GamepadInputs::RightYMinus },
|
||||
{ "rightx", GamepadInputs::RightXPlus },
|
||||
{ "rightx2", GamepadInputs::RightXMinus }
|
||||
};
|
||||
{"a", GamepadInputs::ButtonA},
|
||||
{"b", GamepadInputs::ButtonB},
|
||||
{"x", GamepadInputs::ButtonX},
|
||||
{"y", GamepadInputs::ButtonY},
|
||||
{"leftshoulder", GamepadInputs::LeftShoulder},
|
||||
{"rightshoulder", GamepadInputs::RightShoulder},
|
||||
{"start", GamepadInputs::Start},
|
||||
{"back", GamepadInputs::Back},
|
||||
{"dpup", GamepadInputs::DPadUp},
|
||||
{"dpdown", GamepadInputs::DpadDown},
|
||||
{"dpleft", GamepadInputs::DpadLeft},
|
||||
{"dpright", GamepadInputs::DpadRight},
|
||||
{"leftstick", GamepadInputs::L3},
|
||||
{"rightstick", GamepadInputs::R3},
|
||||
{"lefttrigger", GamepadInputs::LeftTrigger},
|
||||
{"righttrigger", GamepadInputs::RightTrigger},
|
||||
{"lefty", GamepadInputs::LeftYPlus},
|
||||
{"lefty2", GamepadInputs::LeftYMinus},
|
||||
{"leftx", GamepadInputs::LeftXPlus},
|
||||
{"leftx2", GamepadInputs::LeftXMinus},
|
||||
{"righty", GamepadInputs::RightYPlus},
|
||||
{"righty2", GamepadInputs::RightYMinus},
|
||||
{"rightx", GamepadInputs::RightXPlus},
|
||||
{"rightx2", GamepadInputs::RightXMinus}};
|
||||
static bool SDLInitialized;
|
||||
std::map<std::string, bool>
|
||||
keys_pressed; ///< Map of keys that were pressed on previous iteration
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/core_timing.h"
|
||||
|
||||
@ -13,106 +12,152 @@
|
||||
#include "input_core/devices/sdl_gamepad.h"
|
||||
#include "input_core/input_core.h"
|
||||
|
||||
namespace InputCore {
|
||||
constexpr u64 frame_ticks = 268123480ull / 60;
|
||||
static int tick_event;
|
||||
static Service::HID::PadState pad_state;
|
||||
static std::tuple<s16, s16> circle_pad = {0, 0};
|
||||
static std::shared_ptr<Keyboard> main_keyboard; ///< Keyboard is always active for Citra
|
||||
static std::vector<std::shared_ptr<IDevice>>
|
||||
devices; ///< Devices that are handling input for the game
|
||||
static std::map<Settings::InputDeviceMapping, std::vector<Service::HID::PadState>> key_mappings;
|
||||
std::map<Service::HID::PadState, bool> keys_pressed; ///< keys that were pressed on previous frame.
|
||||
static std::mutex pad_state_mutex;
|
||||
static std::mutex touch_mutex;
|
||||
static u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
static u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
static bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
int InputCore::tick_event;
|
||||
Service::HID::PadState InputCore::pad_state;
|
||||
std::tuple<s16, s16> InputCore::circle_pad;
|
||||
std::shared_ptr<Keyboard> InputCore::main_keyboard; ///< Keyboard is always active for Citra
|
||||
std::vector<std::shared_ptr<IDevice>>
|
||||
InputCore::devices; ///< Devices that are handling input for the game
|
||||
std::map<Settings::InputDeviceMapping, std::vector<Service::HID::PadState>> InputCore::key_mappings;
|
||||
std::map<Service::HID::PadState, bool>
|
||||
InputCore::keys_pressed; ///< keys that were pressed on previous frame.
|
||||
std::mutex InputCore::pad_state_mutex;
|
||||
std::mutex InputCore::touch_mutex;
|
||||
u16 InputCore::touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
u16 InputCore::touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
bool InputCore::touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
const float default_deadzone = 0.5;
|
||||
|
||||
static void UpdateEmulatorInputs(std::map<Settings::InputDeviceMapping, float> inputs) {
|
||||
for (auto& inputMapping : inputs) { //Loop through all buttons from input device
|
||||
float strength = inputMapping.second;
|
||||
auto emulator_inputs = key_mappings[inputMapping.first];
|
||||
for (auto& emulator_input : emulator_inputs) {
|
||||
if (std::find(std::begin(KeyMap::analog_inputs), std::end(KeyMap::analog_inputs), emulator_input) ==
|
||||
std::end(KeyMap::analog_inputs)) { // digital button
|
||||
if (strength < 0.5 && keys_pressed[emulator_input] == true) {
|
||||
pad_state.hex &= ~emulator_input.hex;
|
||||
keys_pressed[emulator_input] = false;
|
||||
}
|
||||
else if (strength >= 0.5 && keys_pressed[emulator_input] == false) {
|
||||
pad_state.hex |= emulator_input.hex;
|
||||
keys_pressed[emulator_input] = true;
|
||||
}
|
||||
}
|
||||
else { // analog stick
|
||||
if (emulator_input == Service::HID::PAD_CIRCLE_UP || emulator_input == Service::HID::PAD_CIRCLE_DOWN) {
|
||||
std::get<1>(circle_pad) = KeyMap::MAX_CIRCLEPAD_POS * strength * -1;
|
||||
}
|
||||
else if (emulator_input == Service::HID::PAD_CIRCLE_LEFT ||
|
||||
emulator_input == Service::HID::PAD_CIRCLE_RIGHT) {
|
||||
std::get<0>(circle_pad) = KeyMap::MAX_CIRCLEPAD_POS * strength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void InputCore::Init() {
|
||||
ParseSettings();
|
||||
tick_event = CoreTiming::RegisterEvent("InputCore::tick_event", InputTickCallback);
|
||||
CoreTiming::ScheduleEvent(frame_ticks, tick_event);
|
||||
}
|
||||
|
||||
static void InputTickCallback(u64, int cycles_late) {
|
||||
void InputCore::Shutdown() {
|
||||
CoreTiming::UnscheduleEvent(tick_event, 0);
|
||||
devices.clear();
|
||||
}
|
||||
void InputCore::InputTickCallback(u64, int cycles_late) {
|
||||
std::vector<std::map<Settings::InputDeviceMapping, float>> inputs;
|
||||
for (auto& device : devices) {
|
||||
auto inputs = device->ProcessInput();
|
||||
UpdateEmulatorInputs(inputs);
|
||||
inputs.push_back(device->ProcessInput());
|
||||
}
|
||||
UpdateEmulatorInputs(inputs);
|
||||
|
||||
Service::HID::Update();
|
||||
|
||||
// Reschedule recurrent event
|
||||
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, tick_event);
|
||||
}
|
||||
void InputCore::UpdateEmulatorInputs(
|
||||
std::vector<std::map<Settings::InputDeviceMapping, float>> inputs) {
|
||||
std::lock_guard<std::mutex> lock(pad_state_mutex);
|
||||
// Apply deadzone
|
||||
float leftx = 0, lefty = 0;
|
||||
float circle_pad_modifier = 1.0;
|
||||
auto circle_pad_modifier_mapping = Settings::values.pad_circle_modifier;
|
||||
for (auto& input_device : inputs) {
|
||||
for (auto& button_states : input_device) { // Loop through all buttons from input device
|
||||
float strength = button_states.second;
|
||||
auto emulator_inputs = key_mappings[button_states.first];
|
||||
for (auto& emulator_input : emulator_inputs) {
|
||||
if (emulator_input == Service::HID::PAD_CIRCLE_UP && abs(strength) > 0) {
|
||||
lefty = -strength;
|
||||
} else if (emulator_input == Service::HID::PAD_CIRCLE_DOWN && abs(strength) > 0) {
|
||||
lefty = strength;
|
||||
} else if (emulator_input == Service::HID::PAD_CIRCLE_LEFT && abs(strength) > 0) {
|
||||
leftx = -strength;
|
||||
} else if (emulator_input == Service::HID::PAD_CIRCLE_RIGHT && abs(strength) > 0) {
|
||||
leftx = strength;
|
||||
}
|
||||
}
|
||||
if (button_states.first == circle_pad_modifier_mapping)
|
||||
circle_pad_modifier = (button_states.second > default_deadzone)
|
||||
? Settings::values.pad_circle_modifier_scale
|
||||
: 1.0;
|
||||
}
|
||||
}
|
||||
float deadzone = Settings::values.pad_circle_deadzone;
|
||||
std::tuple<float, float> left_stick = ApplyDeadzone(leftx, lefty, deadzone);
|
||||
|
||||
Service::HID::PadState GetPadState() {
|
||||
for (auto& input_device : inputs) {
|
||||
for (auto& button_states : input_device) { // Loop through all buttons from input device
|
||||
float strength = button_states.second;
|
||||
auto emulator_inputs = key_mappings[button_states.first];
|
||||
for (auto& emulator_input : emulator_inputs) {
|
||||
if (std::find(std::begin(KeyMap::analog_inputs), std::end(KeyMap::analog_inputs),
|
||||
emulator_input) ==
|
||||
std::end(KeyMap::analog_inputs)) { // digital button
|
||||
if (abs(strength) < default_deadzone && keys_pressed[emulator_input] == true) {
|
||||
pad_state.hex &= ~emulator_input.hex;
|
||||
keys_pressed[emulator_input] = false;
|
||||
} else if (abs(strength) >= default_deadzone &&
|
||||
keys_pressed[emulator_input] == false) {
|
||||
pad_state.hex |= emulator_input.hex;
|
||||
keys_pressed[emulator_input] = true;
|
||||
}
|
||||
} else { // analog stick
|
||||
if (emulator_input == Service::HID::PAD_CIRCLE_UP ||
|
||||
emulator_input == Service::HID::PAD_CIRCLE_DOWN) {
|
||||
std::get<1>(circle_pad) = std::get<1>(left_stick) *
|
||||
KeyMap::MAX_CIRCLEPAD_POS * -1 *
|
||||
circle_pad_modifier;
|
||||
} else if (emulator_input == Service::HID::PAD_CIRCLE_LEFT ||
|
||||
emulator_input == Service::HID::PAD_CIRCLE_RIGHT) {
|
||||
std::get<0>(circle_pad) = std::get<0>(left_stick) *
|
||||
KeyMap::MAX_CIRCLEPAD_POS * circle_pad_modifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Service::HID::PadState InputCore::GetPadState() {
|
||||
std::lock_guard<std::mutex> lock(pad_state_mutex);
|
||||
return pad_state;
|
||||
}
|
||||
|
||||
void SetPadState(const Service::HID::PadState& state) {
|
||||
void InputCore::SetPadState(const Service::HID::PadState& state) {
|
||||
std::lock_guard<std::mutex> lock(pad_state_mutex);
|
||||
pad_state.hex = state.hex;
|
||||
}
|
||||
|
||||
std::tuple<s16, s16> GetCirclePad() {
|
||||
std::tuple<s16, s16> InputCore::GetCirclePad() {
|
||||
return circle_pad;
|
||||
}
|
||||
|
||||
void SetCirclePad(std::tuple<s16, s16> pad) {
|
||||
void InputCore::SetCirclePad(std::tuple<s16, s16> pad) {
|
||||
circle_pad = pad;
|
||||
}
|
||||
|
||||
std::shared_ptr<Keyboard> GetKeyboard() {
|
||||
std::shared_ptr<Keyboard> InputCore::GetKeyboard() {
|
||||
if (main_keyboard == nullptr)
|
||||
main_keyboard = std::make_shared<Keyboard>();
|
||||
return main_keyboard;
|
||||
}
|
||||
|
||||
std::tuple<u16, u16, bool> GetTouchState() {
|
||||
std::tuple<u16, u16, bool> InputCore::GetTouchState() {
|
||||
std::lock_guard<std::mutex> lock(touch_mutex);
|
||||
return std::make_tuple(touch_x, touch_y, touch_pressed);
|
||||
}
|
||||
|
||||
void SetTouchState(std::tuple<u16, u16, bool> value) {
|
||||
void InputCore::SetTouchState(std::tuple<u16, u16, bool> value) {
|
||||
std::lock_guard<std::mutex> lock(touch_mutex);
|
||||
std::tie(touch_x, touch_y, touch_pressed) = value;
|
||||
}
|
||||
|
||||
/// Helper method to check if device was already initialized
|
||||
bool CheckIfMappingExists(const std::vector<Settings::InputDeviceMapping>& uniqueMapping,
|
||||
Settings::InputDeviceMapping mappingToCheck) {
|
||||
bool InputCore::CheckIfMappingExists(const std::vector<Settings::InputDeviceMapping>& uniqueMapping,
|
||||
Settings::InputDeviceMapping mappingToCheck) {
|
||||
return std::any_of(uniqueMapping.begin(), uniqueMapping.end(),
|
||||
[mappingToCheck](const auto& mapping) { return mapping == mappingToCheck; });
|
||||
}
|
||||
|
||||
/// Get Unique input mappings from settings
|
||||
static std::vector<Settings::InputDeviceMapping> GatherUniqueMappings() {
|
||||
std::vector<Settings::InputDeviceMapping> InputCore::GatherUniqueMappings() {
|
||||
std::vector<Settings::InputDeviceMapping> uniqueMappings;
|
||||
|
||||
for (const auto& mapping : Settings::values.input_mappings) {
|
||||
@ -120,11 +165,14 @@ static std::vector<Settings::InputDeviceMapping> GatherUniqueMappings() {
|
||||
uniqueMappings.push_back(mapping);
|
||||
}
|
||||
}
|
||||
if (!CheckIfMappingExists(uniqueMappings, Settings::values.pad_circle_modifier)) {
|
||||
uniqueMappings.push_back(Settings::values.pad_circle_modifier);
|
||||
}
|
||||
return uniqueMappings;
|
||||
}
|
||||
|
||||
/// Builds map of input keys to 3ds buttons for unique device
|
||||
static void BuildKeyMapping() {
|
||||
void InputCore::BuildKeyMapping() {
|
||||
key_mappings.clear();
|
||||
for (size_t i = 0; i < Settings::values.input_mappings.size(); i++) {
|
||||
auto val = KeyMap::mapping_targets[i];
|
||||
@ -135,7 +183,7 @@ static void BuildKeyMapping() {
|
||||
}
|
||||
|
||||
/// Generate a device for each unique mapping
|
||||
static void GenerateUniqueDevices() {
|
||||
void InputCore::GenerateUniqueDevices() {
|
||||
auto uniqueMappings = GatherUniqueMappings();
|
||||
devices.clear();
|
||||
std::shared_ptr<IDevice> input;
|
||||
@ -159,29 +207,49 @@ static void GenerateUniqueDevices() {
|
||||
|
||||
input->InitDevice(mapping.number, mapping);
|
||||
}
|
||||
if (main_keyboard == nullptr) {
|
||||
main_keyboard = std::make_shared<Keyboard>();
|
||||
devices.push_back(main_keyboard);
|
||||
}
|
||||
}
|
||||
|
||||
/// Read settings to initialize devices
|
||||
void ParseSettings() {
|
||||
void InputCore::ParseSettings() {
|
||||
GenerateUniqueDevices();
|
||||
}
|
||||
|
||||
void ReloadSettings() {
|
||||
std::tuple<float, float> InputCore::ApplyDeadzone(float x, float y, float dead_zone) {
|
||||
float magnitude = sqrt((x * x) + (y * y));
|
||||
if (magnitude < dead_zone) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
} else {
|
||||
float normalized_x = x / magnitude;
|
||||
float normalized_y = y / magnitude;
|
||||
x = normalized_x * ((magnitude - dead_zone) / (1 - dead_zone));
|
||||
y = normalized_y * ((magnitude - dead_zone) / (1 - dead_zone));
|
||||
}
|
||||
return std::tuple<float, float>(x, y);
|
||||
}
|
||||
|
||||
void InputCore::ReloadSettings() {
|
||||
if (devices.empty())
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(pad_state_mutex);
|
||||
devices.clear();
|
||||
ParseSettings();
|
||||
}
|
||||
|
||||
/// Returns all available input devices. Used for key binding in GUI
|
||||
std::vector<std::shared_ptr<IDevice>> GetAllDevices() {
|
||||
std::vector<std::shared_ptr<IDevice>> InputCore::GetAllDevices() {
|
||||
auto all_devices = SDLGamepad::GetAllDevices();
|
||||
all_devices.push_back(InputCore::GetKeyboard());
|
||||
|
||||
return all_devices;
|
||||
}
|
||||
|
||||
Settings::InputDeviceMapping DetectInput(int max_time, std::function<void(void)> update_GUI) {
|
||||
Settings::InputDeviceMapping InputCore::DetectInput(int max_time,
|
||||
std::function<void(void)> update_GUI) {
|
||||
auto devices = GetAllDevices();
|
||||
for (auto& device : devices) {
|
||||
device->Clear();
|
||||
@ -204,15 +272,3 @@ Settings::InputDeviceMapping DetectInput(int max_time, std::function<void(void)>
|
||||
};
|
||||
return input_device;
|
||||
}
|
||||
|
||||
void Init() {
|
||||
ParseSettings();
|
||||
tick_event = CoreTiming::RegisterEvent("InputCore::tick_event", InputTickCallback);
|
||||
CoreTiming::ScheduleEvent(frame_ticks, tick_event);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
CoreTiming::UnscheduleEvent(tick_event, 0);
|
||||
devices.clear();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
@ -14,66 +15,101 @@
|
||||
|
||||
class Keyboard;
|
||||
|
||||
namespace InputCore {
|
||||
static class InputCore {
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
/**
|
||||
* Threadsafe getter to the current PadState
|
||||
* @return Service::HID::PadState instance
|
||||
*/
|
||||
static Service::HID::PadState GetPadState();
|
||||
|
||||
/**
|
||||
* Threadsafe getter to the current PadState
|
||||
* @return Service::HID::PadState instance
|
||||
*/
|
||||
Service::HID::PadState GetPadState();
|
||||
/**
|
||||
* Threadsafe setter for the current PadState
|
||||
* @param state New PadState to overwrite current PadState.
|
||||
*/
|
||||
static void SetPadState(const Service::HID::PadState& state);
|
||||
|
||||
/**
|
||||
* Threadsafe setter for the current PadState
|
||||
* @param state New PadState to overwrite current PadState.
|
||||
*/
|
||||
void SetPadState(const Service::HID::PadState& state);
|
||||
/**
|
||||
* Getter for current CirclePad
|
||||
* @return std::tuple<s16, s16> CirclePad state
|
||||
*/
|
||||
static std::tuple<s16, s16> GetCirclePad();
|
||||
|
||||
/**
|
||||
* Getter for current CirclePad
|
||||
* @return std::tuple<s16, s16> CirclePad state
|
||||
*/
|
||||
std::tuple<s16, s16> GetCirclePad();
|
||||
/**
|
||||
* Setter for current CirclePad
|
||||
* @param circle New CirclePad state
|
||||
*/
|
||||
static void SetCirclePad(std::tuple<s16, s16> circle);
|
||||
|
||||
/**
|
||||
* Setter for current CirclePad
|
||||
* @param circle New CirclePad state
|
||||
*/
|
||||
void SetCirclePad(std::tuple<s16, s16> circle);
|
||||
/**
|
||||
* Getter for Citra's main keyboard input handler
|
||||
* @return std::shared_ptr<Keyboard> Device Keyboard instance
|
||||
*/
|
||||
static std::shared_ptr<Keyboard> GetKeyboard();
|
||||
|
||||
/**
|
||||
* Getter for Citra's main keyboard input handler
|
||||
* @return std::shared_ptr<Keyboard> Device Keyboard instance
|
||||
*/
|
||||
std::shared_ptr<Keyboard> GetKeyboard();
|
||||
/**
|
||||
* Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
|
||||
* Threadsafe.
|
||||
* @note This should be called by the core emu thread to get a state set by the window thread.
|
||||
* @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and
|
||||
* `pressed` is true if the touch screen is currently being pressed
|
||||
*/
|
||||
static std::tuple<u16, u16, bool> GetTouchState();
|
||||
|
||||
/**
|
||||
* Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
|
||||
* Threadsafe.
|
||||
* @note This should be called by the core emu thread to get a state set by the window thread.
|
||||
* @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and
|
||||
* `pressed` is true if the touch screen is currently being pressed
|
||||
*/
|
||||
std::tuple<u16, u16, bool> GetTouchState();
|
||||
/**
|
||||
* Threadsafe setter for the current touch screen state.
|
||||
* @param value New Touch State
|
||||
*/
|
||||
static void SetTouchState(std::tuple<u16, u16, bool> value);
|
||||
|
||||
/**
|
||||
* Threadsafe setter for the current touch screen state.
|
||||
* @param value New Touch State
|
||||
*/
|
||||
void SetTouchState(std::tuple<u16, u16, bool> value);
|
||||
/**
|
||||
* Reload input key mapping settings during game-play
|
||||
*/
|
||||
static void ReloadSettings();
|
||||
|
||||
/**
|
||||
* Reload input key mapping settings during game-play
|
||||
*/
|
||||
void ReloadSettings();
|
||||
static std::vector<std::shared_ptr<IDevice>> GetAllDevices();
|
||||
|
||||
/**
|
||||
* Loops through all devices and detects the first device that produces an input
|
||||
* @param max_time: maximum amount of time to wait until input detected, in milliseconds.
|
||||
* @param update_GUI: function to run in while loop to process any gui events.
|
||||
* @return Settings::InputDeviceMapping of input device
|
||||
*/
|
||||
Settings::InputDeviceMapping DetectInput(int max_time, std::function<void(void)> update_GUI);
|
||||
}
|
||||
/**
|
||||
* Loops through all devices and detects the first device that produces an input
|
||||
* @param max_time: maximum amount of time to wait until input detected, in milliseconds.
|
||||
* @param update_GUI: function to run in while loop to process any gui events.
|
||||
* @return Settings::InputDeviceMapping of input device
|
||||
*/
|
||||
static Settings::InputDeviceMapping DetectInput(int max_time,
|
||||
std::function<void(void)> update_GUI);
|
||||
|
||||
private:
|
||||
static int tick_event;
|
||||
static Service::HID::PadState pad_state;
|
||||
static std::tuple<s16, s16> circle_pad;
|
||||
static std::shared_ptr<Keyboard> main_keyboard; ///< Keyboard is always active for Citra
|
||||
static std::vector<std::shared_ptr<IDevice>>
|
||||
devices; ///< Devices that are handling input for the game
|
||||
static std::map<Settings::InputDeviceMapping, std::vector<Service::HID::PadState>> key_mappings;
|
||||
static std::map<Service::HID::PadState, bool>
|
||||
keys_pressed; ///< keys that were pressed on previous frame.
|
||||
static std::mutex pad_state_mutex;
|
||||
static std::mutex touch_mutex;
|
||||
static u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
static u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
static bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
|
||||
static void UpdateEmulatorInputs(
|
||||
std::vector<std::map<Settings::InputDeviceMapping, float>> inputs);
|
||||
static void InputTickCallback(u64, int cycles_late);
|
||||
|
||||
static bool CheckIfMappingExists(const std::vector<Settings::InputDeviceMapping>& uniqueMapping,
|
||||
Settings::InputDeviceMapping mappingToCheck);
|
||||
|
||||
static std::vector<Settings::InputDeviceMapping> GatherUniqueMappings();
|
||||
|
||||
static void BuildKeyMapping();
|
||||
|
||||
static void GenerateUniqueDevices();
|
||||
|
||||
static void ParseSettings();
|
||||
static std::tuple<float, float> ApplyDeadzone(float x, float y, float dead_zone);
|
||||
};
|
||||
|
@ -31,42 +31,4 @@ const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> mapp
|
||||
const std::array<Service::HID::PadState, 4> analog_inputs = {
|
||||
Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT,
|
||||
Service::HID::PAD_CIRCLE_RIGHT};
|
||||
|
||||
void PressKey(const Service::HID::PadState target, const float strength) {
|
||||
auto pad_state = InputCore::GetPadState();
|
||||
// If is digital keytarget
|
||||
if (std::find(std::begin(analog_inputs), std::end(analog_inputs), target) ==
|
||||
std::end(analog_inputs)) {
|
||||
pad_state.hex |= target.hex;
|
||||
InputCore::SetPadState(pad_state);
|
||||
} else { // it is analog input
|
||||
auto circle_pad = InputCore::GetCirclePad();
|
||||
if (target == Service::HID::PAD_CIRCLE_UP || target == Service::HID::PAD_CIRCLE_DOWN) {
|
||||
std::get<1>(circle_pad) = MAX_CIRCLEPAD_POS * strength * -1;
|
||||
} else if (target == Service::HID::PAD_CIRCLE_LEFT ||
|
||||
target == Service::HID::PAD_CIRCLE_RIGHT) {
|
||||
std::get<0>(circle_pad) = MAX_CIRCLEPAD_POS * strength;
|
||||
}
|
||||
InputCore::SetCirclePad(circle_pad);
|
||||
}
|
||||
}
|
||||
|
||||
void ReleaseKey(const Service::HID::PadState target) {
|
||||
auto pad_state = InputCore::GetPadState();
|
||||
// If is digital keytarget
|
||||
if (std::find(std::begin(analog_inputs), std::end(analog_inputs), target) ==
|
||||
std::end(analog_inputs)) {
|
||||
pad_state.hex &= ~target.hex;
|
||||
InputCore::SetPadState(pad_state);
|
||||
} else { // it is analog input
|
||||
auto circle_pad = InputCore::GetCirclePad();
|
||||
if (target == Service::HID::PAD_CIRCLE_UP || target == Service::HID::PAD_CIRCLE_DOWN) {
|
||||
std::get<1>(circle_pad) = 0;
|
||||
} else if (target == Service::HID::PAD_CIRCLE_LEFT ||
|
||||
target == Service::HID::PAD_CIRCLE_RIGHT) {
|
||||
std::get<0>(circle_pad) = 0;
|
||||
}
|
||||
InputCore::SetCirclePad(circle_pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,4 @@ namespace KeyMap {
|
||||
extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> mapping_targets;
|
||||
extern const std::array<Service::HID::PadState, 4> analog_inputs;
|
||||
constexpr int MAX_CIRCLEPAD_POS = 0x9C; /// Max value for a circle pad position
|
||||
|
||||
/// Handles the pressing of a key and modifies InputCore state
|
||||
void PressKey(Service::HID::PadState target, float strength);
|
||||
|
||||
/// Handles the releasing of a key and modifies InputCore state
|
||||
void ReleaseKey(Service::HID::PadState target);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user