Merge pull request #1789 from wwylele/input-refactor

Refactor input mapping & implement circle pad modifier
This commit is contained in:
bunnei 2016-06-10 22:28:58 -04:00 committed by GitHub
commit f99961581e
12 changed files with 313 additions and 73 deletions

View file

@ -44,12 +44,16 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
} }
static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = { static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
// directly mapped keys
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X,
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2,
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B, SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B,
SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H,
SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, 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,
SDL_SCANCODE_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L SDL_SCANCODE_D,
}; };
void Config::ReadValues() { void Config::ReadValues() {
@ -58,6 +62,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[i]] = Settings::values.input_mappings[Settings::NativeInput::All[i]] =
sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]); sdl2_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]);
} }
Settings::values.pad_circle_modifier_scale = (float)sdl2_config->GetReal("Controls", "pad_circle_modifier_scale", 0.5);
// Core // Core
Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0); Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0);

View file

@ -23,14 +23,19 @@ pad_l =
pad_r = pad_r =
pad_zl = pad_zl =
pad_zr = pad_zr =
pad_sup =
pad_sdown =
pad_sleft =
pad_sright =
pad_cup = pad_cup =
pad_cdown = pad_cdown =
pad_cleft = pad_cleft =
pad_cright = pad_cright =
pad_circle_up =
pad_circle_down =
pad_circle_left =
pad_circle_right =
pad_circle_modifier =
# The applied modifier scale to circle pad.
# Must be in range of 0.0-1.0. Defaults to 0.5
pad_circle_modifier_scale =
[Core] [Core]
# The applied frameskip amount. Must be a power of two. # The applied frameskip amount. Must be a power of two.

View file

@ -40,9 +40,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) { if (state == SDL_PRESSED) {
KeyPressed({ key, keyboard_id }); KeyMap::PressKey(*this, { key, keyboard_id });
} else if (state == SDL_RELEASED) { } else if (state == SDL_RELEASED) {
KeyReleased({ key, keyboard_id }); KeyMap::ReleaseKey(*this, { key, keyboard_id });
} }
} }
@ -168,8 +168,9 @@ void EmuWindow_SDL2::DoneCurrent() {
} }
void EmuWindow_SDL2::ReloadSetKeymaps() { void EmuWindow_SDL2::ReloadSetKeymaps() {
KeyMap::ClearKeyMapping(keyboard_id);
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, Service::HID::pad_mapping[i]); KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
} }
} }

View file

@ -235,12 +235,12 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
void GRenderWindow::keyPressEvent(QKeyEvent* event) void GRenderWindow::keyPressEvent(QKeyEvent* event)
{ {
this->KeyPressed({event->key(), keyboard_id}); KeyMap::PressKey(*this, { event->key(), keyboard_id });
} }
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
{ {
this->KeyReleased({event->key(), keyboard_id}); KeyMap::ReleaseKey(*this, { event->key(), keyboard_id });
} }
void GRenderWindow::mousePressEvent(QMouseEvent *event) void GRenderWindow::mousePressEvent(QMouseEvent *event)
@ -270,8 +270,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
void GRenderWindow::ReloadSetKeymaps() void GRenderWindow::ReloadSetKeymaps()
{ {
KeyMap::ClearKeyMapping(keyboard_id);
for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]); KeyMap::SetKeyMapping({ Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id }, KeyMap::mapping_targets[i]);
} }
} }

View file

@ -22,12 +22,16 @@ Config::Config() {
} }
static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = { static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
// directly mapped keys
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
Qt::Key_M, Qt::Key_N, Qt::Key_B, Qt::Key_M, Qt::Key_N, Qt::Key_B,
Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
Qt::Key_I, 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,
Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L Qt::Key_D,
}; };
void Config::ReadValues() { void Config::ReadValues() {
@ -36,6 +40,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[i]] = Settings::values.input_mappings[Settings::NativeInput::All[i]] =
qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt(); qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt();
} }
Settings::values.pad_circle_modifier_scale = qt_config->value("pad_circle_modifier_scale", 0.5).toFloat();
qt_config->endGroup(); qt_config->endGroup();
qt_config->beginGroup("Core"); qt_config->beginGroup("Core");
@ -126,6 +131,7 @@ void Config::SaveValues() {
qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]), qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]),
Settings::values.input_mappings[Settings::NativeInput::All[i]]); Settings::values.input_mappings[Settings::NativeInput::All[i]]);
} }
qt_config->setValue("pad_circle_modifier_scale", (double)Settings::values.pad_circle_modifier_scale);
qt_config->endGroup(); qt_config->endGroup();
qt_config->beginGroup("Core"); qt_config->beginGroup("Core");

View file

@ -11,12 +11,28 @@
#include "emu_window.h" #include "emu_window.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
pad_state.hex |= KeyMap::GetPadKey(key).hex; pad_state.hex |= pad.hex;
} }
void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
pad_state.hex &= ~KeyMap::GetPadKey(key).hex; 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);
} }
/** /**

View file

@ -12,10 +12,6 @@
#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid.h"
namespace KeyMap {
struct HostDeviceKey;
}
/** /**
* Abstraction class used to provide an interface between emulation code and the frontend * Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...). * (e.g. SDL, QGLWidget, GLFW, etc...).
@ -76,11 +72,27 @@ public:
virtual void ReloadSetKeymaps() = 0; virtual void ReloadSetKeymaps() = 0;
/// Signals a key press action to the HID module /**
void KeyPressed(KeyMap::HostDeviceKey key); * 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 key release action to the HID module /**
void KeyReleased(KeyMap::HostDeviceKey key); * 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) * Signal that a touch pressed event has occurred (e.g. mouse click pressed)
@ -100,8 +112,9 @@ public:
void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
/** /**
* Gets the current pad state (which buttons are pressed and the circle pad direction). * 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 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. * @todo Fix this function to be thread-safe.
* @return PadState object indicating the current pad state * @return PadState object indicating the current pad state
*/ */
@ -109,6 +122,16 @@ public:
return pad_state; 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). * 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. * @note This should be called by the core emu thread to get a state set by the window thread.
@ -200,6 +223,8 @@ protected:
pad_state.hex = 0; pad_state.hex = 0;
touch_x = 0; touch_x = 0;
touch_y = 0; touch_y = 0;
circle_pad_x = 0;
circle_pad_y = 0;
touch_pressed = false; touch_pressed = false;
} }
virtual ~EmuWindow() {} virtual ~EmuWindow() {}
@ -260,6 +285,9 @@ private:
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) 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) 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)
/** /**
* Clip the provided coordinates to be inside the touchscreen area. * Clip the provided coordinates to be inside the touchscreen area.
*/ */

View file

@ -2,24 +2,138 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "key_map.h"
#include <map> #include <map>
#include "common/emu_window.h"
#include "common/key_map.h"
namespace KeyMap { namespace KeyMap {
static std::map<HostDeviceKey, Service::HID::PadState> key_map; // TODO (wwylele): currently we treat c-stick as four direction buttons
// and map it directly to EmuWindow::ButtonPressed.
// It should go the analog input way like circle pad does.
const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT,
IndirectTarget::CirclePadUp,
IndirectTarget::CirclePadDown,
IndirectTarget::CirclePadLeft,
IndirectTarget::CirclePadRight,
IndirectTarget::CirclePadModifier,
}};
static std::map<HostDeviceKey, KeyTarget> key_map;
static int next_device_id = 0; static int next_device_id = 0;
static bool circle_pad_up = false;
static bool circle_pad_down = false;
static bool circle_pad_left = false;
static bool circle_pad_right = false;
static bool circle_pad_modifier = false;
static void UpdateCirclePad(EmuWindow& emu_window) {
constexpr float SQRT_HALF = 0.707106781;
int x = 0, y = 0;
if (circle_pad_right)
++x;
if (circle_pad_left)
--x;
if (circle_pad_up)
++y;
if (circle_pad_down)
--y;
float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0;
emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
}
int NewDeviceId() { int NewDeviceId() {
return next_device_id++; return next_device_id++;
} }
void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) { void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
key_map[key].hex = padState.hex; key_map[key] = target;
} }
Service::HID::PadState GetPadKey(HostDeviceKey key) { void ClearKeyMapping(int device_id) {
return key_map[key]; auto iter = key_map.begin();
while (iter != key_map.end()) {
if (iter->first.device_id == device_id)
key_map.erase(iter++);
else
++iter;
}
}
void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
auto target = key_map.find(key);
if (target == key_map.end())
return;
if (target->second.direct) {
emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
} else {
switch (target->second.target.indirect_target) {
case IndirectTarget::CirclePadUp:
circle_pad_up = true;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadDown:
circle_pad_down = true;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadLeft:
circle_pad_left = true;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadRight:
circle_pad_right = true;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadModifier:
circle_pad_modifier = true;
UpdateCirclePad(emu_window);
break;
}
}
}
void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
auto target = key_map.find(key);
if (target == key_map.end())
return;
if (target->second.direct) {
emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
} else {
switch (target->second.target.indirect_target) {
case IndirectTarget::CirclePadUp:
circle_pad_up = false;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadDown:
circle_pad_down = false;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadLeft:
circle_pad_left = false;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadRight:
circle_pad_right = false;
UpdateCirclePad(emu_window);
break;
case IndirectTarget::CirclePadModifier:
circle_pad_modifier = false;
UpdateCirclePad(emu_window);
break;
}
}
} }
} }

View file

@ -4,11 +4,50 @@
#pragma once #pragma once
#include <array>
#include <tuple> #include <tuple>
#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid.h"
class EmuWindow;
namespace KeyMap { namespace KeyMap {
/**
* Represents key mapping targets that are not real 3DS buttons.
* They will be handled by KeyMap and translated to 3DS input.
*/
enum class IndirectTarget {
CirclePadUp,
CirclePadDown,
CirclePadLeft,
CirclePadRight,
CirclePadModifier,
};
/**
* Represents a key mapping target. It can be a PadState that represents real 3DS buttons,
* or an IndirectTarget.
*/
struct KeyTarget {
bool direct;
union {
u32 direct_target_hex;
IndirectTarget indirect_target;
} target;
KeyTarget() : direct(true) {
target.direct_target_hex = 0;
}
KeyTarget(Service::HID::PadState pad) : direct(true) {
target.direct_target_hex = pad.hex;
}
KeyTarget(IndirectTarget i) : direct(false) {
target.indirect_target = i;
}
};
/** /**
* Represents a key for a specific host device. * Represents a key for a specific host device.
*/ */
@ -27,19 +66,31 @@ struct HostDeviceKey {
} }
}; };
extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
/** /**
* Generates a new device id, which uniquely identifies a host device within KeyMap. * Generates a new device id, which uniquely identifies a host device within KeyMap.
*/ */
int NewDeviceId(); int NewDeviceId();
/** /**
* Maps a device-specific key to a PadState. * Maps a device-specific key to a target (a PadState or an IndirectTarget).
*/ */
void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState); void SetKeyMapping(HostDeviceKey key, KeyTarget target);
/** /**
* Gets the PadState that's mapped to the provided device-specific key. * Clears all key mappings belonging to one device.
*/ */
Service::HID::PadState GetPadKey(HostDeviceKey key); void ClearKeyMapping(int device_id);
/**
* Maps a key press action and call the corresponding function in EmuWindow
*/
void PressKey(EmuWindow& emu_window, HostDeviceKey key);
/**
* Maps a key release action and call the corresponding function in EmuWindow
*/
void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
} }

View file

@ -19,8 +19,6 @@
namespace Service { namespace Service {
namespace HID { namespace HID {
static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
// Handle to shared memory region designated to HID_User service // Handle to shared memory region designated to HID_User service
static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
@ -39,38 +37,48 @@ static u32 next_gyroscope_index;
static int enable_accelerometer_count = 0; // positive means enabled static int enable_accelerometer_count = 0; // positive means enabled
static int enable_gyroscope_count = 0; // positive means enabled static int enable_gyroscope_count = 0; // positive means enabled
const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, PadState state;
Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, state.hex = 0;
Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT,
Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT
}};
if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) {
float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x);
// TODO(peachum): if (circle_pad_x != 0 && t < TAN60) {
// Add a method for setting analog input from joystick device for the circle Pad. if (circle_pad_x > 0)
// state.circle_right.Assign(1);
// This method should: else
// * Be called after both PadButton<Press, Release>(). state.circle_left.Assign(1);
// * Be called before PadUpdateComplete() }
// * Set current PadEntry.circle_pad_<axis> using analog data
// * Set PadData.raw_circle_pad_data if (circle_pad_x == 0 || t > TAN30) {
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 if (circle_pad_y > 0)
// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 state.circle_up.Assign(1);
// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 else
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 state.circle_down.Assign(1);
}
}
return state;
}
void Update() { void Update() {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) { if (mem == nullptr) {
LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
return; return;
} }
PadState state = VideoCore::g_emu_window->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();
state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
mem->pad.current_state.hex = state.hex; mem->pad.current_state.hex = state.hex;
mem->pad.index = next_pad_index; mem->pad.index = next_pad_index;
next_pad_index = (next_pad_index + 1) % mem->pad.entries.size(); next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
@ -88,13 +96,9 @@ void Update() {
// Update entry properties // Update entry properties
pad_entry.current_state.hex = state.hex; pad_entry.current_state.hex = state.hex;
pad_entry.delta_additions.hex = changed.hex & state.hex; pad_entry.delta_additions.hex = changed.hex & state.hex;
pad_entry.delta_removals.hex = changed.hex & old_state.hex;; pad_entry.delta_removals.hex = changed.hex & old_state.hex;
pad_entry.circle_pad_x = circle_pad_x;
// Set circle Pad pad_entry.circle_pad_y = circle_pad_y;
pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
// If we just updated index 0, provide a new timestamp // If we just updated index 0, provide a new timestamp
if (mem->pad.index == 0) { if (mem->pad.index == 0) {

View file

@ -215,9 +215,6 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
const PadState PAD_CIRCLE_UP = {{1u << 30}}; const PadState PAD_CIRCLE_UP = {{1u << 30}};
const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
/** /**
* HID::GetIPCHandles service function * HID::GetIPCHandles service function
* Inputs: * Inputs:

View file

@ -13,29 +13,40 @@ namespace Settings {
namespace NativeInput { namespace NativeInput {
enum Values { enum Values {
// directly mapped keys
A, B, X, Y, A, B, X, Y,
L, R, ZL, ZR, L, R, ZL, ZR,
START, SELECT, HOME, START, SELECT, HOME,
DUP, DDOWN, DLEFT, DRIGHT, DUP, DDOWN, DLEFT, DRIGHT,
SUP, SDOWN, SLEFT, SRIGHT,
CUP, CDOWN, CLEFT, CRIGHT, CUP, CDOWN, CLEFT, CRIGHT,
// indirectly mapped keys
CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
CIRCLE_MODIFIER,
NUM_INPUTS NUM_INPUTS
}; };
static const std::array<const char*, NUM_INPUTS> Mapping = {{ static const std::array<const char*, NUM_INPUTS> Mapping = {{
// directly mapped keys
"pad_a", "pad_b", "pad_x", "pad_y", "pad_a", "pad_b", "pad_x", "pad_y",
"pad_l", "pad_r", "pad_zl", "pad_zr", "pad_l", "pad_r", "pad_zl", "pad_zr",
"pad_start", "pad_select", "pad_home", "pad_start", "pad_select", "pad_home",
"pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
"pad_sup", "pad_sdown", "pad_sleft", "pad_sright", "pad_cup", "pad_cdown", "pad_cleft", "pad_cright",
"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 = {{ static const std::array<Values, NUM_INPUTS> All = {{
A, B, X, Y, A, B, X, Y,
L, R, ZL, ZR, L, R, ZL, ZR,
START, SELECT, HOME, START, SELECT, HOME,
DUP, DDOWN, DLEFT, DRIGHT, DUP, DDOWN, DLEFT, DRIGHT,
SUP, SDOWN, SLEFT, SRIGHT, CUP, CDOWN, CLEFT, CRIGHT,
CUP, CDOWN, CLEFT, CRIGHT CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT,
CIRCLE_MODIFIER,
}}; }};
} }
@ -46,6 +57,7 @@ struct Values {
// Controls // Controls
std::array<int, NativeInput::NUM_INPUTS> input_mappings; std::array<int, NativeInput::NUM_INPUTS> input_mappings;
float pad_circle_modifier_scale;
// Core // Core
int frame_skip; int frame_skip;