diff options
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 71 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 10 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 48 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.h | 12 | 
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(); | 
