diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 997e3bc7d52741f19e0e89e3bdb8bb3f20367121..f879ee7ca731186a09f2ad96addcd94e2dfa3a7b 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -31,7 +31,7 @@ void EmuWindow_GLFW::OnMouseButtonEvent(GLFWwindow* win, int button, int action,
 }
 
 void EmuWindow_GLFW::OnCursorPosEvent(GLFWwindow* win, double x, double y) {
-    GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(x), static_cast<unsigned>(y));
+    GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(std::max(x, 0.0)), static_cast<unsigned>(std::max(y, 0.0)));
 }
 
 /// Called by GLFW when a key event occurs
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index b81bd6167301512ce55c53fbed894726d2d43ee5..a8bff924751c5403eb591e4d09f0a95e09328cc7 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -288,7 +288,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent *event)
 void GRenderWindow::mouseMoveEvent(QMouseEvent *event)
 {
     auto pos = event->pos();
-    this->TouchMoved(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y()));
+    this->TouchMoved(static_cast<unsigned>(std::max(pos.x(), 0)), static_cast<unsigned>(std::max(pos.y(), 0)));
 }
 
 void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 6516fc633d7075f4e9d66d2f46196616f50c9131..f5b6c7301da95a2ba94cbbc283f708491d3dc2fc 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -28,6 +28,17 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi
             framebuffer_x <  layout.bottom_screen.right);
 }
 
+std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
+
+    new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
+    new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
+    
+    new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
+    new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
+
+    return std::make_tuple(new_x, new_y);
+}
+
 void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
     if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
         return;
@@ -52,14 +63,13 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
     if (!touch_pressed)
         return;
 
-    if (IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
-        TouchPressed(framebuffer_x, framebuffer_y);
-    else
-        TouchReleased();
+    if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
+        std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
+
+    TouchPressed(framebuffer_x, framebuffer_y);
 }
 
-EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width,
-    unsigned height) {
+EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
 
     ASSERT(width > 0);
     ASSERT(height > 0);
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index c8e2de04ad27fafcd4e0e021e97212399f3c69e9..e0fc12a483adf84ed80e0018cf4613f91c8845d3 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -206,5 +206,10 @@ 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)
 
+   /**
+    * 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;
 };