summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2016-06-11 04:28:58 +0200
committerGitHub <noreply@github.com>2016-06-11 04:28:58 +0200
commitf99961581ee129c44625dbd8890fab349253271a (patch)
tree9a2610d391d795b533054a91c22763e869bdd62b /src
parentMerge pull request #1896 from citra-emu/revert-1893-interpreter-split (diff)
parentfixup! fixup! Refactor input system (diff)
downloadyuzu-f99961581ee129c44625dbd8890fab349253271a.tar
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.gz
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.bz2
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.lz
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.xz
yuzu-f99961581ee129c44625dbd8890fab349253271a.tar.zst
yuzu-f99961581ee129c44625dbd8890fab349253271a.zip
Diffstat (limited to 'src')
-rw-r--r--src/citra/config.cpp7
-rw-r--r--src/citra/default_ini.h13
-rw-r--r--src/citra/emu_window/emu_window_sdl2.cpp7
-rw-r--r--src/citra_qt/bootmanager.cpp7
-rw-r--r--src/citra_qt/config.cpp8
-rw-r--r--src/common/emu_window.cpp24
-rw-r--r--src/common/emu_window.h46
-rw-r--r--src/common/key_map.cpp126
-rw-r--r--src/common/key_map.h59
-rw-r--r--src/core/hle/service/hid/hid.cpp68
-rw-r--r--src/core/hle/service/hid/hid.h3
-rw-r--r--src/core/settings.h22
12 files changed, 315 insertions, 75 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index c64de8e22..22cb51ea8 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -44,12 +44,16 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
}
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_Q, SDL_SCANCODE_W, SDL_SCANCODE_1, SDL_SCANCODE_2,
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_B,
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_I, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_L
+ SDL_SCANCODE_D,
};
void Config::ReadValues() {
@@ -58,6 +62,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[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
Settings::values.frame_skip = sdl2_config->GetInteger("Core", "frame_skip", 0);
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 49126356f..a9017dcb3 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -23,14 +23,19 @@ pad_l =
pad_r =
pad_zl =
pad_zr =
-pad_sup =
-pad_sdown =
-pad_sleft =
-pad_sright =
pad_cup =
pad_cdown =
pad_cleft =
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]
# The applied frameskip amount. Must be a power of two.
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 12cdd9d95..591f68aa4 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -40,9 +40,9 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) {
- KeyPressed({ key, keyboard_id });
+ KeyMap::PressKey(*this, { key, keyboard_id });
} 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() {
+ KeyMap::ClearKeyMapping(keyboard_id);
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]);
}
}
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 01b81c11c..414b2f8af 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -235,12 +235,12 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
void GRenderWindow::keyPressEvent(QKeyEvent* event)
{
- this->KeyPressed({event->key(), keyboard_id});
+ KeyMap::PressKey(*this, { event->key(), keyboard_id });
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
{
- this->KeyReleased({event->key(), keyboard_id});
+ KeyMap::ReleaseKey(*this, { event->key(), keyboard_id });
}
void GRenderWindow::mousePressEvent(QMouseEvent *event)
@@ -270,8 +270,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
void GRenderWindow::ReloadSetKeymaps()
{
+ KeyMap::ClearKeyMapping(keyboard_id);
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]);
}
}
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 6e4ba3907..ba7edaff9 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -22,12 +22,16 @@ Config::Config() {
}
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_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
Qt::Key_M, Qt::Key_N, Qt::Key_B,
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_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
+ Qt::Key_D,
};
void Config::ReadValues() {
@@ -36,6 +40,7 @@ void Config::ReadValues() {
Settings::values.input_mappings[Settings::NativeInput::All[i]] =
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->beginGroup("Core");
@@ -126,6 +131,7 @@ void Config::SaveValues() {
qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[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->beginGroup("Core");
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index b2807354a..08270dd88 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -11,12 +11,28 @@
#include "emu_window.h"
#include "video_core/video_core.h"
-void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
- pad_state.hex |= KeyMap::GetPadKey(key).hex;
+void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
+ pad_state.hex |= pad.hex;
}
-void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
- pad_state.hex &= ~KeyMap::GetPadKey(key).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);
}
/**
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 7c3486dea..57e303b6d 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -12,10 +12,6 @@
#include "core/hle/service/hid/hid.h"
-namespace KeyMap {
-struct HostDeviceKey;
-}
-
/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -76,11 +72,27 @@ public:
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 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 key release action to the HID module
- void KeyReleased(KeyMap::HostDeviceKey key);
+ /**
+ * 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)
@@ -100,8 +112,9 @@ public:
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 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
*/
@@ -110,6 +123,16 @@ public:
}
/**
+ * 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.
@@ -200,6 +223,8 @@ protected:
pad_state.hex = 0;
touch_x = 0;
touch_y = 0;
+ circle_pad_x = 0;
+ circle_pad_y = 0;
touch_pressed = false;
}
virtual ~EmuWindow() {}
@@ -260,6 +285,9 @@ private:
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)
+
/**
* Clip the provided coordinates to be inside the touchscreen area.
*/
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index 844d5df68..ad311d66b 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,138 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "key_map.h"
#include <map>
+#include "common/emu_window.h"
+#include "common/key_map.h"
+
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 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() {
return next_device_id++;
}
-void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState) {
- key_map[key].hex = padState.hex;
+void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
+ key_map[key] = target;
+}
+
+void ClearKeyMapping(int device_id) {
+ auto iter = key_map.begin();
+ while (iter != key_map.end()) {
+ if (iter->first.device_id == device_id)
+ key_map.erase(iter++);
+ else
+ ++iter;
+ }
}
-Service::HID::PadState GetPadKey(HostDeviceKey key) {
- return key_map[key];
+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;
+ }
+ }
}
}
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 68f7e2f99..b62f017c6 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,12 +4,51 @@
#pragma once
+#include <array>
#include <tuple>
#include "core/hle/service/hid/hid.h"
+class EmuWindow;
+
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.
*/
struct HostDeviceKey {
@@ -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.
*/
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, KeyTarget target);
+
+/**
+ * Clears all key mappings belonging to one device.
+ */
+void ClearKeyMapping(int device_id);
+
+/**
+ * Maps a key press action and call the corresponding function in EmuWindow
*/
-void SetKeyMapping(HostDeviceKey key, Service::HID::PadState padState);
+void PressKey(EmuWindow& emu_window, HostDeviceKey key);
/**
- * Gets the PadState that's mapped to the provided device-specific key.
+ * Maps a key release action and call the corresponding function in EmuWindow
*/
-Service::HID::PadState GetPadKey(HostDeviceKey key);
+void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index d216cecb4..c975433f4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -19,8 +19,6 @@
namespace Service {
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
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_gyroscope_count = 0; // positive means enabled
-const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{
- 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_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
-}};
-
-
-// TODO(peachum):
-// Add a method for setting analog input from joystick device for the circle Pad.
-//
-// This method should:
-// * Be called after both PadButton<Press, Release>().
-// * Be called before PadUpdateComplete()
-// * Set current PadEntry.circle_pad_<axis> using analog data
-// * Set PadData.raw_circle_pad_data
-// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41
-// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41
-// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
-// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
+static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
+ constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
+ constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
+ PadState state;
+ state.hex = 0;
+
+ 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);
+
+ if (circle_pad_x != 0 && t < TAN60) {
+ if (circle_pad_x > 0)
+ state.circle_right.Assign(1);
+ else
+ state.circle_left.Assign(1);
+ }
+
+ if (circle_pad_x == 0 || t > TAN30) {
+ if (circle_pad_y > 0)
+ state.circle_up.Assign(1);
+ else
+ state.circle_down.Assign(1);
+ }
+ }
+
+ return state;
+}
void Update() {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
- const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) {
LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
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.index = next_pad_index;
next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
@@ -88,13 +96,9 @@ void Update() {
// Update entry properties
pad_entry.current_state.hex = state.hex;
pad_entry.delta_additions.hex = changed.hex & state.hex;
- pad_entry.delta_removals.hex = changed.hex & old_state.hex;;
-
- // Set circle Pad
- 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;
+ pad_entry.delta_removals.hex = changed.hex & old_state.hex;
+ pad_entry.circle_pad_x = circle_pad_x;
+ pad_entry.circle_pad_y = circle_pad_y;
// If we just updated index 0, provide a new timestamp
if (mem->pad.index == 0) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 170d19ea8..669b1f723 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -215,9 +215,6 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
const PadState PAD_CIRCLE_UP = {{1u << 30}};
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
-
-extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
-
/**
* HID::GetIPCHandles service function
* Inputs:
diff --git a/src/core/settings.h b/src/core/settings.h
index ea72f4d9c..f95e62390 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -13,29 +13,40 @@ namespace Settings {
namespace NativeInput {
enum Values {
+ // directly mapped keys
A, B, X, Y,
L, R, ZL, ZR,
START, SELECT, HOME,
DUP, DDOWN, DLEFT, DRIGHT,
- SUP, SDOWN, SLEFT, SRIGHT,
CUP, CDOWN, CLEFT, CRIGHT,
+
+ // indirectly mapped keys
+ CIRCLE_UP, 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_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 = {{
A, B, X, Y,
L, R, ZL, ZR,
START, SELECT, HOME,
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
std::array<int, NativeInput::NUM_INPUTS> input_mappings;
+ float pad_circle_modifier_scale;
// Core
int frame_skip;