summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-10-09 19:02:41 -0400
committerGravatar GitHub2018-10-09 19:02:41 -0400
commit0b3d4db98b5bc6f81a22e4618dbabbdafcec0ada (patch)
treee3574b49f5a9e4c762e709ada72e0c1ba16e2fff /src
parentMerge pull request #1459 from ogniK5377/break (diff)
parentimplemented touch in Qt and SDL (diff)
downloadyuzu-0b3d4db98b5bc6f81a22e4618dbabbdafcec0ada.tar.gz
yuzu-0b3d4db98b5bc6f81a22e4618dbabbdafcec0ada.tar.xz
yuzu-0b3d4db98b5bc6f81a22e4618dbabbdafcec0ada.zip
Merge pull request #1463 from FearlessTobi/port-4310
Port citra-emu/citra#4310: "Handle touch input"
Diffstat (limited to 'src')
-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)
110 std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name, 110 std::string window_title = fmt::format("yuzu {} | {}-{}", Common::g_build_name,
111 Common::g_scm_branch, Common::g_scm_desc); 111 Common::g_scm_branch, Common::g_scm_desc);
112 setWindowTitle(QString::fromStdString(window_title)); 112 setWindowTitle(QString::fromStdString(window_title));
113 setAttribute(Qt::WA_AcceptTouchEvents);
113 114
114 InputCommon::Init(); 115 InputCommon::Init();
115 InputCommon::StartJoystickEventHandler(); 116 InputCommon::StartJoystickEventHandler();
@@ -190,11 +191,17 @@ QByteArray GRenderWindow::saveGeometry() {
190 return geometry; 191 return geometry;
191} 192}
192 193
193qreal GRenderWindow::windowPixelRatio() { 194qreal GRenderWindow::windowPixelRatio() const {
194 // windowHandle() might not be accessible until the window is displayed to screen. 195 // windowHandle() might not be accessible until the window is displayed to screen.
195 return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f; 196 return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
196} 197}
197 198
199std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const {
200 const qreal pixel_ratio = windowPixelRatio();
201 return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
202 static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
203}
204
198void GRenderWindow::closeEvent(QCloseEvent* event) { 205void GRenderWindow::closeEvent(QCloseEvent* event) {
199 emit Closed(); 206 emit Closed();
200 QWidget::closeEvent(event); 207 QWidget::closeEvent(event);
@@ -209,31 +216,81 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
209} 216}
210 217
211void GRenderWindow::mousePressEvent(QMouseEvent* event) { 218void GRenderWindow::mousePressEvent(QMouseEvent* event) {
219 if (event->source() == Qt::MouseEventSynthesizedBySystem)
220 return; // touch input is handled in TouchBeginEvent
221
212 auto pos = event->pos(); 222 auto pos = event->pos();
213 if (event->button() == Qt::LeftButton) { 223 if (event->button() == Qt::LeftButton) {
214 qreal pixelRatio = windowPixelRatio(); 224 const auto [x, y] = ScaleTouch(pos);
215 this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio), 225 this->TouchPressed(x, y);
216 static_cast<unsigned>(pos.y() * pixelRatio));
217 } else if (event->button() == Qt::RightButton) { 226 } else if (event->button() == Qt::RightButton) {
218 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); 227 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
219 } 228 }
220} 229}
221 230
222void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { 231void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
232 if (event->source() == Qt::MouseEventSynthesizedBySystem)
233 return; // touch input is handled in TouchUpdateEvent
234
223 auto pos = event->pos(); 235 auto pos = event->pos();
224 qreal pixelRatio = windowPixelRatio(); 236 const auto [x, y] = ScaleTouch(pos);
225 this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u), 237 this->TouchMoved(x, y);
226 std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
227 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); 238 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
228} 239}
229 240
230void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { 241void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
242 if (event->source() == Qt::MouseEventSynthesizedBySystem)
243 return; // touch input is handled in TouchEndEvent
244
231 if (event->button() == Qt::LeftButton) 245 if (event->button() == Qt::LeftButton)
232 this->TouchReleased(); 246 this->TouchReleased();
233 else if (event->button() == Qt::RightButton) 247 else if (event->button() == Qt::RightButton)
234 InputCommon::GetMotionEmu()->EndTilt(); 248 InputCommon::GetMotionEmu()->EndTilt();
235} 249}
236 250
251void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
252 // TouchBegin always has exactly one touch point, so take the .first()
253 const auto [x, y] = ScaleTouch(event->touchPoints().first().pos());
254 this->TouchPressed(x, y);
255}
256
257void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
258 QPointF pos;
259 int active_points = 0;
260
261 // average all active touch points
262 for (const auto tp : event->touchPoints()) {
263 if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) {
264 active_points++;
265 pos += tp.pos();
266 }
267 }
268
269 pos /= active_points;
270
271 const auto [x, y] = ScaleTouch(pos);
272 this->TouchMoved(x, y);
273}
274
275void GRenderWindow::TouchEndEvent() {
276 this->TouchReleased();
277}
278
279bool GRenderWindow::event(QEvent* event) {
280 if (event->type() == QEvent::TouchBegin) {
281 TouchBeginEvent(static_cast<QTouchEvent*>(event));
282 return true;
283 } else if (event->type() == QEvent::TouchUpdate) {
284 TouchUpdateEvent(static_cast<QTouchEvent*>(event));
285 return true;
286 } else if (event->type() == QEvent::TouchEnd || event->type() == QEvent::TouchCancel) {
287 TouchEndEvent();
288 return true;
289 }
290
291 return QWidget::event(event);
292}
293
237void GRenderWindow::focusOutEvent(QFocusEvent* event) { 294void GRenderWindow::focusOutEvent(QFocusEvent* event) {
238 QWidget::focusOutEvent(event); 295 QWidget::focusOutEvent(event);
239 InputCommon::GetKeyboard()->ReleaseAllKeys(); 296 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 @@
15 15
16class QKeyEvent; 16class QKeyEvent;
17class QScreen; 17class QScreen;
18class QTouchEvent;
18 19
19class GGLWidgetInternal; 20class GGLWidgetInternal;
20class GMainWindow; 21class GMainWindow;
@@ -119,7 +120,7 @@ public:
119 void restoreGeometry(const QByteArray& geometry); // overridden 120 void restoreGeometry(const QByteArray& geometry); // overridden
120 QByteArray saveGeometry(); // overridden 121 QByteArray saveGeometry(); // overridden
121 122
122 qreal windowPixelRatio(); 123 qreal windowPixelRatio() const;
123 124
124 void closeEvent(QCloseEvent* event) override; 125 void closeEvent(QCloseEvent* event) override;
125 126
@@ -130,6 +131,8 @@ public:
130 void mouseMoveEvent(QMouseEvent* event) override; 131 void mouseMoveEvent(QMouseEvent* event) override;
131 void mouseReleaseEvent(QMouseEvent* event) override; 132 void mouseReleaseEvent(QMouseEvent* event) override;
132 133
134 bool event(QEvent* event) override;
135
133 void focusOutEvent(QFocusEvent* event) override; 136 void focusOutEvent(QFocusEvent* event) override;
134 137
135 void OnClientAreaResized(unsigned width, unsigned height); 138 void OnClientAreaResized(unsigned width, unsigned height);
@@ -148,6 +151,11 @@ signals:
148 void Closed(); 151 void Closed();
149 152
150private: 153private:
154 std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
155 void TouchBeginEvent(const QTouchEvent* event);
156 void TouchUpdateEvent(const QTouchEvent* event);
157 void TouchEndEvent();
158
151 void OnMinimalClientAreaChangeRequest( 159 void OnMinimalClientAreaChangeRequest(
152 const std::pair<unsigned, unsigned>& minimal_size) override; 160 const std::pair<unsigned, unsigned>& minimal_size) override;
153 161
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) {
40 } 40 }
41} 41}
42 42
43std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
44 int w, h;
45 SDL_GetWindowSize(render_window, &w, &h);
46
47 touch_x *= w;
48 touch_y *= h;
49
50 return {static_cast<unsigned>(std::max(std::round(touch_x), 0.0f)),
51 static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
52}
53
54void EmuWindow_SDL2::OnFingerDown(float x, float y) {
55 // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind
56 // This isn't critical because the best we can do when we have that is to average them, like the
57 // 3DS does
58
59 const auto [px, py] = TouchToPixelPos(x, y);
60 TouchPressed(px, py);
61}
62
63void EmuWindow_SDL2::OnFingerMotion(float x, float y) {
64 const auto [px, py] = TouchToPixelPos(x, y);
65 TouchMoved(px, py);
66}
67
68void EmuWindow_SDL2::OnFingerUp() {
69 TouchReleased();
70}
71
43void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { 72void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
44 if (state == SDL_PRESSED) { 73 if (state == SDL_PRESSED) {
45 InputCommon::GetKeyboard()->PressKey(key); 74 InputCommon::GetKeyboard()->PressKey(key);
@@ -219,11 +248,26 @@ void EmuWindow_SDL2::PollEvents() {
219 OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); 248 OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
220 break; 249 break;
221 case SDL_MOUSEMOTION: 250 case SDL_MOUSEMOTION:
222 OnMouseMotion(event.motion.x, event.motion.y); 251 // ignore if it came from touch
252 if (event.button.which != SDL_TOUCH_MOUSEID)
253 OnMouseMotion(event.motion.x, event.motion.y);
223 break; 254 break;
224 case SDL_MOUSEBUTTONDOWN: 255 case SDL_MOUSEBUTTONDOWN:
225 case SDL_MOUSEBUTTONUP: 256 case SDL_MOUSEBUTTONUP:
226 OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y); 257 // ignore if it came from touch
258 if (event.button.which != SDL_TOUCH_MOUSEID) {
259 OnMouseButton(event.button.button, event.button.state, event.button.x,
260 event.button.y);
261 }
262 break;
263 case SDL_FINGERDOWN:
264 OnFingerDown(event.tfinger.x, event.tfinger.y);
265 break;
266 case SDL_FINGERMOTION:
267 OnFingerMotion(event.tfinger.x, event.tfinger.y);
268 break;
269 case SDL_FINGERUP:
270 OnFingerUp();
227 break; 271 break;
228 case SDL_QUIT: 272 case SDL_QUIT:
229 is_open = false; 273 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:
40 /// Called by PollEvents when a mouse button is pressed or released 40 /// Called by PollEvents when a mouse button is pressed or released
41 void OnMouseButton(u32 button, u8 state, s32 x, s32 y); 41 void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
42 42
43 /// Translates pixel position (0..1) to pixel positions
44 std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const;
45
46 /// Called by PollEvents when a finger starts touching the touchscreen
47 void OnFingerDown(float x, float y);
48
49 /// Called by PollEvents when a finger moves while touching the touchscreen
50 void OnFingerMotion(float x, float y);
51
52 /// Called by PollEvents when a finger stops touching the touchscreen
53 void OnFingerUp();
54
43 /// Called by PollEvents when any event that may cause the window to be resized occurs 55 /// Called by PollEvents when any event that may cause the window to be resized occurs
44 void OnResize(); 56 void OnResize();
45 57