InputCore Overhaul

This commit is contained in:
Anon
2016-12-16 22:50:33 -06:00
parent 16a3f9e393
commit 63fc6e6c48
41 changed files with 1459 additions and 321 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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;
}
};
/**

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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