InputCore Overhaul
This commit is contained in:
@@ -30,8 +30,7 @@ set(SRCS
|
||||
file_sys/path_parser.cpp
|
||||
file_sys/savedata_archive.cpp
|
||||
frontend/emu_window.cpp
|
||||
frontend/key_map.cpp
|
||||
frontend/motion_emu.cpp
|
||||
frontend/motion_emu.cpp
|
||||
gdbstub/gdbstub.cpp
|
||||
hle/config_mem.cpp
|
||||
hle/applets/applet.cpp
|
||||
@@ -204,8 +203,7 @@ set(HEADERS
|
||||
file_sys/path_parser.h
|
||||
file_sys/savedata_archive.h
|
||||
frontend/emu_window.h
|
||||
frontend/key_map.h
|
||||
frontend/motion_emu.h
|
||||
frontend/motion_emu.h
|
||||
gdbstub/gdbstub.h
|
||||
hle/config_mem.h
|
||||
hle/function_wrappers.h
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
#include "input_core/input_core.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -140,6 +141,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||
Kernel::Init(system_mode);
|
||||
Service::Init();
|
||||
AudioCore::Init();
|
||||
InputCore::Init();
|
||||
GDBStub::Init();
|
||||
|
||||
if (!VideoCore::Init(emu_window)) {
|
||||
@@ -153,6 +155,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||
|
||||
void System::Shutdown() {
|
||||
GDBStub::Shutdown();
|
||||
InputCore::Shutdown();
|
||||
AudioCore::Shutdown();
|
||||
VideoCore::Shutdown();
|
||||
Service::Shutdown();
|
||||
|
||||
@@ -7,32 +7,11 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/profiler_reporting.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/key_map.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
|
||||
pad_state.hex |= pad.hex;
|
||||
}
|
||||
|
||||
void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
|
||||
pad_state.hex &= ~pad.hex;
|
||||
}
|
||||
|
||||
void EmuWindow::CirclePadUpdated(float x, float y) {
|
||||
constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
|
||||
|
||||
// Make sure the coordinates are in the unit circle,
|
||||
// otherwise normalize it.
|
||||
float r = x * x + y * y;
|
||||
if (r > 1) {
|
||||
r = std::sqrt(r);
|
||||
x /= r;
|
||||
y /= r;
|
||||
}
|
||||
|
||||
circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS);
|
||||
circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS);
|
||||
}
|
||||
#include "emu_window.h"
|
||||
#include "input_core/input_core.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
/**
|
||||
* Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
|
||||
@@ -62,22 +41,25 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
|
||||
return;
|
||||
|
||||
touch_x = VideoCore::kScreenBottomWidth *
|
||||
(framebuffer_x - framebuffer_layout.bottom_screen.left) /
|
||||
(framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
|
||||
touch_y = VideoCore::kScreenBottomHeight *
|
||||
(framebuffer_y - framebuffer_layout.bottom_screen.top) /
|
||||
(framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
|
||||
|
||||
int touch_x = VideoCore::kScreenBottomWidth *
|
||||
(framebuffer_x - framebuffer_layout.bottom_screen.left) /
|
||||
(framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
|
||||
int touch_y = VideoCore::kScreenBottomHeight *
|
||||
(framebuffer_y - framebuffer_layout.bottom_screen.top) /
|
||||
(framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
|
||||
touch_pressed = true;
|
||||
InputCore::SetTouchState(std::make_tuple(touch_x, touch_y, true));
|
||||
auto pad_state = InputCore::GetPadState();
|
||||
pad_state.touch.Assign(1);
|
||||
InputCore::SetPadState(pad_state);
|
||||
}
|
||||
|
||||
void EmuWindow::TouchReleased() {
|
||||
touch_pressed = false;
|
||||
touch_x = 0;
|
||||
touch_y = 0;
|
||||
InputCore::SetTouchState(std::make_tuple(0, 0, false));
|
||||
auto pad_state = InputCore::GetPadState();
|
||||
pad_state.touch.Assign(0);
|
||||
InputCore::SetPadState(pad_state);
|
||||
}
|
||||
|
||||
void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
|
||||
@@ -52,30 +52,6 @@ public:
|
||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
|
||||
virtual void ReloadSetKeymaps() = 0;
|
||||
|
||||
/**
|
||||
* Signals a button press action to the HID module.
|
||||
* @param pad_state indicates which button to press
|
||||
* @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
|
||||
*/
|
||||
void ButtonPressed(Service::HID::PadState pad_state);
|
||||
|
||||
/**
|
||||
* Signals a button release action to the HID module.
|
||||
* @param pad_state indicates which button to press
|
||||
* @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
|
||||
*/
|
||||
void ButtonReleased(Service::HID::PadState pad_state);
|
||||
|
||||
/**
|
||||
* Signals a circle pad change action to the HID module.
|
||||
* @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0]
|
||||
* @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0]
|
||||
* @note the coordinates will be normalized if the radius is larger than 1
|
||||
*/
|
||||
void CirclePadUpdated(float x, float y);
|
||||
|
||||
/**
|
||||
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
|
||||
* @param framebuffer_x Framebuffer x-coordinate that was pressed
|
||||
@@ -114,38 +90,7 @@ public:
|
||||
*/
|
||||
void GyroscopeChanged(float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Gets the current pad state (which buttons are pressed).
|
||||
* @note This should be called by the core emu thread to get a state set by the window thread.
|
||||
* @note This doesn't include analog input like circle pad direction
|
||||
* @todo Fix this function to be thread-safe.
|
||||
* @return PadState object indicating the current pad state
|
||||
*/
|
||||
Service::HID::PadState GetPadState() const {
|
||||
return pad_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current circle pad state.
|
||||
* @note This should be called by the core emu thread to get a state set by the window thread.
|
||||
* @todo Fix this function to be thread-safe.
|
||||
* @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates
|
||||
*/
|
||||
std::tuple<s16, s16> GetCirclePadState() const {
|
||||
return std::make_tuple(circle_pad_x, circle_pad_y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
|
||||
* @note This should be called by the core emu thread to get a state set by the window thread.
|
||||
* @todo Fix this function to be thread-safe.
|
||||
* @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() const {
|
||||
return std::make_tuple(touch_x, touch_y, touch_pressed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current accelerometer state (acceleration along each three axis).
|
||||
* Axis explained:
|
||||
@@ -230,12 +175,7 @@ protected:
|
||||
// TODO: Find a better place to set this.
|
||||
config.min_client_area_size = std::make_pair(400u, 480u);
|
||||
active_config = config;
|
||||
pad_state.hex = 0;
|
||||
touch_x = 0;
|
||||
touch_y = 0;
|
||||
circle_pad_x = 0;
|
||||
circle_pad_y = 0;
|
||||
touch_pressed = false;
|
||||
|
||||
accel_x = 0;
|
||||
accel_y = -512;
|
||||
accel_z = 0;
|
||||
@@ -301,11 +241,7 @@ private:
|
||||
|
||||
bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
|
||||
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
|
||||
s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
|
||||
s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
|
||||
|
||||
|
||||
std::mutex accel_mutex;
|
||||
s16 accel_x; ///< Accelerometer X-axis value in native 3DS units
|
||||
@@ -321,6 +257,4 @@ private:
|
||||
* Clip the provided coordinates to be inside the touchscreen area.
|
||||
*/
|
||||
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
|
||||
|
||||
Service::HID::PadState pad_state;
|
||||
};
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cmath>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_spvr.h"
|
||||
#include "core/hle/service/hid/hid_user.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "input_core/input_core.h"
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
@@ -73,11 +80,10 @@ void Update() {
|
||||
return;
|
||||
}
|
||||
|
||||
PadState state = VideoCore::g_emu_window->GetPadState();
|
||||
|
||||
PadState state = InputCore::GetPadState();
|
||||
// Get current circle pad position and update circle pad direction
|
||||
s16 circle_pad_x, circle_pad_y;
|
||||
std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState();
|
||||
std::tie(circle_pad_x, circle_pad_y) = InputCore::GetCirclePad();
|
||||
state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
|
||||
|
||||
mem->pad.current_state.hex = state.hex;
|
||||
@@ -114,7 +120,7 @@ void Update() {
|
||||
TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];
|
||||
bool pressed = false;
|
||||
|
||||
std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState();
|
||||
std::tie(touch_entry.x, touch_entry.y, pressed) = InputCore::GetTouchState();
|
||||
touch_entry.valid.Assign(pressed ? 1 : 0);
|
||||
|
||||
// TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace HID {
|
||||
* Structure of a Pad controller state.
|
||||
*/
|
||||
struct PadState {
|
||||
PadState() = default;
|
||||
union {
|
||||
u32 hex;
|
||||
|
||||
@@ -53,6 +54,16 @@ struct PadState {
|
||||
BitField<30, 1, u32> circle_up;
|
||||
BitField<31, 1, u32> circle_down;
|
||||
};
|
||||
bool operator==(const PadState& other) const {
|
||||
return hex == other.hex;
|
||||
}
|
||||
bool operator<(const PadState& other) const {
|
||||
return hex < other.hex;
|
||||
}
|
||||
PadState& operator=(const PadState& other) {
|
||||
hex = other.hex;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
namespace GPU {
|
||||
|
||||
Regs g_regs;
|
||||
|
||||
/// 268MHz CPU clocks / 60Hz frames per second
|
||||
const u64 frame_ticks = 268123480ull / 60;
|
||||
/// Event id for CoreTiming
|
||||
static int vblank_event;
|
||||
/// Total number of frames drawn
|
||||
@@ -551,9 +548,6 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
|
||||
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0);
|
||||
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
|
||||
|
||||
// Check for user input updates
|
||||
Service::HID::Update();
|
||||
|
||||
if (!Settings::values.use_vsync && Settings::values.toggle_framelimit) {
|
||||
FrameLimiter();
|
||||
}
|
||||
|
||||
@@ -317,6 +317,9 @@ static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of regis
|
||||
|
||||
extern Regs g_regs;
|
||||
|
||||
/// 268MHz CPU clocks / 60Hz frames per second
|
||||
static constexpr u64 frame_ticks = 268123480ull / 60;
|
||||
|
||||
template <typename T>
|
||||
void Read(T& var, const u32 addr);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "audio_core/audio_core.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "settings.h"
|
||||
#include "input_core/input_core.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
@@ -29,6 +29,8 @@ void Apply() {
|
||||
|
||||
AudioCore::SelectSink(values.sink_id);
|
||||
AudioCore::EnableStretching(values.enable_audio_stretching);
|
||||
|
||||
InputCore::ReloadSettings();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
namespace Settings {
|
||||
|
||||
@@ -46,35 +50,94 @@ enum Values {
|
||||
CIRCLE_DOWN,
|
||||
CIRCLE_LEFT,
|
||||
CIRCLE_RIGHT,
|
||||
CIRCLE_MODIFIER,
|
||||
|
||||
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",
|
||||
"pad_circle_modifier",
|
||||
}};
|
||||
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, CIRCLE_MODIFIER,
|
||||
}};
|
||||
// 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 };
|
||||
struct InputDeviceMapping {
|
||||
DeviceFramework framework = DeviceFramework::SDL;
|
||||
int number = 0;
|
||||
Device device = Device::Keyboard;
|
||||
int key = -1;
|
||||
|
||||
InputDeviceMapping() = default;
|
||||
explicit InputDeviceMapping(int key_) {
|
||||
key = key_;
|
||||
}
|
||||
explicit InputDeviceMapping(const std::string& input) {
|
||||
std::vector<std::string> parts;
|
||||
Common::SplitString(input, '/', parts);
|
||||
if (parts.size() != 4)
|
||||
return;
|
||||
if (parts[0] == "SDL")
|
||||
framework = DeviceFramework::SDL;
|
||||
|
||||
number = std::stoi(parts[1]);
|
||||
|
||||
if (parts[2] == "Keyboard")
|
||||
device = Device::Keyboard;
|
||||
else if (parts[2] == "Gamepad")
|
||||
device = Device::Gamepad;
|
||||
Common::TryParse(parts[3], &key);
|
||||
}
|
||||
|
||||
bool operator==(const InputDeviceMapping& rhs) const {
|
||||
return std::tie(device, framework, number) ==
|
||||
std::tie(rhs.device, rhs.framework, rhs.number);
|
||||
}
|
||||
bool operator==(const std::string& rhs) const {
|
||||
return ToString() == rhs;
|
||||
}
|
||||
bool operator<(const InputDeviceMapping& rhs) const {
|
||||
return ToString() < rhs.ToString();
|
||||
}
|
||||
|
||||
void InitKey() {}
|
||||
|
||||
std::string ToString() const {
|
||||
std::string result;
|
||||
if (framework == DeviceFramework::SDL)
|
||||
result = "SDL";
|
||||
|
||||
result += "/";
|
||||
result += std::to_string(this->number);
|
||||
result += "/";
|
||||
|
||||
if (device == Device::Keyboard)
|
||||
result += "Keyboard";
|
||||
else if (device == Device::Gamepad)
|
||||
result += "Gamepad";
|
||||
|
||||
result += "/";
|
||||
result += std::to_string(key);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct Values {
|
||||
// CheckNew3DS
|
||||
bool is_new_3ds;
|
||||
|
||||
// Controls
|
||||
std::array<int, NativeInput::NUM_INPUTS> input_mappings;
|
||||
std::array<InputDeviceMapping, NativeInput::NUM_INPUTS> input_mappings;
|
||||
InputDeviceMapping pad_circle_modifier;
|
||||
float pad_circle_modifier_scale;
|
||||
float pad_circle_deadzone;
|
||||
|
||||
// Core
|
||||
bool use_cpu_jit;
|
||||
@@ -108,7 +171,8 @@ struct Values {
|
||||
// Debugging
|
||||
bool use_gdbstub;
|
||||
u16 gdbstub_port;
|
||||
} extern values;
|
||||
};
|
||||
extern Values values;
|
||||
|
||||
// a special value for Values::region_value indicating that citra will automatically select a region
|
||||
// value to fit the region lockout info of the game
|
||||
|
||||
Reference in New Issue
Block a user