diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index c5cb4fb383..4f6d0a4644 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -44,12 +44,15 @@ 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
 };
 
 void Config::ReadValues() {
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 49126356fe..d0b258cab7 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -23,14 +23,14 @@ 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 =
 
 [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 12cdd9d954..591f68aa41 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 01b81c11ce..414b2f8af7 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 b5bb75537d..ebee8c821d 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -22,12 +22,15 @@ 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
 };
 
 void Config::ReadValues() {
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index b2807354a5..08270dd886 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 7c3486deac..0ae3ea2aff 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 handle real buttons (A/B/X/Y/...), excluding analog input like 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 handle real buttons (A/B/X/Y/...), excluding analog input like 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)
@@ -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
      */
@@ -109,6 +122,16 @@ public:
         return pad_state;
     }
 
+    /**
+     * Gets the current cirle 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.
@@ -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 844d5df68b..c8f168aa11 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -2,24 +2,124 @@
 // 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::CIRCLE_PAD_UP,
+    IndirectTarget::CIRCLE_PAD_DOWN,
+    IndirectTarget::CIRCLE_PAD_LEFT,
+    IndirectTarget::CIRCLE_PAD_RIGHT,
+}};
+
+static std::map<HostDeviceKey, KeyTarget> key_map;
 static int next_device_id = 0;
 
+static bool circle_pad_up = false, circle_pad_down = false, circle_pad_left = false, circle_pad_right = 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;
+    // TODO: apply modifier here
+    emu_window.CirclePadUpdated(x * (y == 0 ? 1.0 : SQRT_HALF), y * (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;
 }
 
-Service::HID::PadState GetPadKey(HostDeviceKey key) {
-    return key_map[key];
+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;
+    }
+}
+
+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::CIRCLE_PAD_UP:
+            circle_pad_up = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_DOWN:
+            circle_pad_down = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_LEFT:
+            circle_pad_left = true;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_RIGHT:
+            circle_pad_right = 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::CIRCLE_PAD_UP:
+            circle_pad_up = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_DOWN:
+            circle_pad_down = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_LEFT:
+            circle_pad_left = false;
+            UpdateCirclePad(emu_window);
+            break;
+        case IndirectTarget::CIRCLE_PAD_RIGHT:
+            circle_pad_right = false;
+            UpdateCirclePad(emu_window);
+            break;
+        }
+    }
 }
 
 }
diff --git a/src/common/key_map.h b/src/common/key_map.h
index 68f7e2f99a..0438a14e0b 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,11 +4,42 @@
 
 #pragma once
 
+#include <array>
 #include <tuple>
 #include "core/hle/service/hid/hid.h"
 
+class EmuWindow;
+
 namespace KeyMap {
 
+enum class IndirectTarget {
+    CIRCLE_PAD_UP, CIRCLE_PAD_DOWN, CIRCLE_PAD_LEFT, CIRCLE_PAD_RIGHT,
+};
+
+/**
+ * Represents a key mapping target. It can be a PadState that represents 3DS real 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.
  */
@@ -27,19 +58,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, 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 actions and call the corresponding function in EmuWindow
+ */
+void PressKey(EmuWindow& emu_window, HostDeviceKey key);
+
+/**
+ * Maps a key release actions and call the corresponding function in EmuWindow
+ */
+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 d216cecb44..a48184495f 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
-}};
+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);
 
-// 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
+        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 positon 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 170d19ea81..669b1f723a 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 ce2a311641..df59154422 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -13,29 +13,37 @@ 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,
+
     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"
 }};
 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,
 }};
 }