summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/yuzu/bootmanager.cpp71
-rw-r--r--src/yuzu/bootmanager.h10
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp48
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h12
4 files changed, 131 insertions, 10 deletions
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 4e4c108ab..e8ab23326 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -110,6 +110,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name,
Common::g_scm_branch, Common::g_scm_desc);
setWindowTitle(QString::fromStdString(window_title));
+ setAttribute(Qt::WA_AcceptTouchEvents);
InputCommon::Init();
InputCommon::StartJoystickEventHandler();
@@ -190,11 +191,17 @@ QByteArray GRenderWindow::saveGeometry() {
return geometry;
}
-qreal GRenderWindow::windowPixelRatio() {
+qreal GRenderWindow::windowPixelRatio() const {
// windowHandle() might not be accessible until the window is displayed to screen.
return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
}
+std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const {
+ const qreal pixel_ratio = windowPixelRatio();
+ return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
+ static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
+}
+
void GRenderWindow::closeEvent(QCloseEvent* event) {
emit Closed();
QWidget::closeEvent(event);
@@ -209,31 +216,81 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
}
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
+ if (event->source() == Qt::MouseEventSynthesizedBySystem)
+ return; // touch input is handled in TouchBeginEvent
+
auto pos = event->pos();
if (event->button() == Qt::LeftButton) {
- qreal pixelRatio = windowPixelRatio();
- this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio),
- static_cast<unsigned>(pos.y() * pixelRatio));
+ const auto [x, y] = ScaleTouch(pos);
+ this->TouchPressed(x, y);
} else if (event->button() == Qt::RightButton) {
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
}
}
void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
+ if (event->source() == Qt::MouseEventSynthesizedBySystem)
+ return; // touch input is handled in TouchUpdateEvent
+
auto pos = event->pos();
- qreal pixelRatio = windowPixelRatio();
- this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u),
- std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
+ const auto [x, y] = ScaleTouch(pos);
+ this->TouchMoved(x, y);
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
}
void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
+ if (event->source() == Qt::MouseEventSynthesizedBySystem)
+ return; // touch input is handled in TouchEndEvent
+
if (event->button() == Qt::LeftButton)
this->TouchReleased();
else if (event->button() == Qt::RightButton)
InputCommon::GetMotionEmu()->EndTilt();
}
+void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
+ // TouchBegin always has exactly one touch point, so take the .first()
+ const auto [x, y] = ScaleTouch(event->touchPoints().first().pos());
+ this->TouchPressed(x, y);
+}
+
+void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
+ QPointF pos;
+ int active_points = 0;
+
+ // average all active touch points
+ for (const auto tp : event->touchPoints()) {
+ if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) {
+ active_points++;
+ pos += tp.pos();
+ }
+ }
+
+ pos /= active_points;
+
+ const auto [x, y] = ScaleTouch(pos);
+ this->TouchMoved(x, y);
+}
+
+void GRenderWindow::TouchEndEvent() {
+ this->TouchReleased();
+}
+
+bool GRenderWindow::event(QEvent* event) {
+ if (event->type() == QEvent::TouchBegin) {
+ TouchBeginEvent(static_cast<QTouchEvent*>(event));
+ return true;
+ } else if (event->type() == QEvent::TouchUpdate) {
+ TouchUpdateEvent(static_cast<QTouchEvent*>(event));
+ return true;
+ } else if (event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) {
+ TouchEndEvent();
+ return true;
+ }
+
+ return QWidget::event(event);
+}
+
void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event);
InputCommon::GetKeyboard()->ReleaseAllKeys();
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index f133bfadf..873985564 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -15,6 +15,7 @@
class QKeyEvent;
class QScreen;
+class QTouchEvent;
class GGLWidgetInternal;
class GMainWindow;
@@ -119,7 +120,7 @@ public:
void restoreGeometry(const QByteArray& geometry); // overridden
QByteArray saveGeometry(); // overridden
- qreal windowPixelRatio();
+ qreal windowPixelRatio() const;
void closeEvent(QCloseEvent* event) override;
@@ -130,6 +131,8 @@ public:
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
+ bool event(QEvent* event) override;
+
void focusOutEvent(QFocusEvent* event) override;
void OnClientAreaResized(unsigned width, unsigned height);
@@ -148,6 +151,11 @@ signals:
void Closed();
private:
+ std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
+ void TouchBeginEvent(const QTouchEvent* event);
+ void TouchUpdateEvent(const QTouchEvent* event);
+ void TouchEndEvent();
+
void OnMinimalClientAreaChangeRequest(
const std::pair<unsigned, unsigned>& minimal_size) override;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 155095095..a9ad92a80 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -40,6 +40,35 @@ void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
}
}
+std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
+ int w, h;
+ SDL_GetWindowSize(render_window, &w, &h);
+
+ touch_x *= w;
+ touch_y *= h;
+
+ return {static_cast<unsigned>(std::max(std::round(touch_x), 0.0f)),
+ static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
+}
+
+void EmuWindow_SDL2::OnFingerDown(float x, float y) {
+ // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind
+ // This isn't critical because the best we can do when we have that is to average them, like the
+ // 3DS does
+
+ const auto [px, py] = TouchToPixelPos(x, y);
+ TouchPressed(px, py);
+}
+
+void EmuWindow_SDL2::OnFingerMotion(float x, float y) {
+ const auto [px, py] = TouchToPixelPos(x, y);
+ TouchMoved(px, py);
+}
+
+void EmuWindow_SDL2::OnFingerUp() {
+ TouchReleased();
+}
+
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) {
InputCommon::GetKeyboard()->PressKey(key);
@@ -219,11 +248,26 @@ void EmuWindow_SDL2::PollEvents() {
OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
break;
case SDL_MOUSEMOTION:
- OnMouseMotion(event.motion.x, event.motion.y);
+ // ignore if it came from touch
+ if (event.button.which != SDL_TOUCH_MOUSEID)
+ OnMouseMotion(event.motion.x, event.motion.y);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
- OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y);
+ // ignore if it came from touch
+ if (event.button.which != SDL_TOUCH_MOUSEID) {
+ OnMouseButton(event.button.button, event.button.state, event.button.x,
+ event.button.y);
+ }
+ break;
+ case SDL_FINGERDOWN:
+ OnFingerDown(event.tfinger.x, event.tfinger.y);
+ break;
+ case SDL_FINGERMOTION:
+ OnFingerMotion(event.tfinger.x, event.tfinger.y);
+ break;
+ case SDL_FINGERUP:
+ OnFingerUp();
break;
case SDL_QUIT:
is_open = false;
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index d34902109..b0d4116cc 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -40,6 +40,18 @@ private:
/// Called by PollEvents when a mouse button is pressed or released
void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
+ /// Translates pixel position (0..1) to pixel positions
+ std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const;
+
+ /// Called by PollEvents when a finger starts touching the touchscreen
+ void OnFingerDown(float x, float y);
+
+ /// Called by PollEvents when a finger moves while touching the touchscreen
+ void OnFingerMotion(float x, float y);
+
+ /// Called by PollEvents when a finger stops touching the touchscreen
+ void OnFingerUp();
+
/// Called by PollEvents when any event that may cause the window to be resized occurs
void OnResize();