Unity 8
 All Classes Functions Properties
MouseTouchAdaptor.cpp
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
17  */
18 
19 #include "MouseTouchAdaptor.h"
20 
21 #include <qpa/qwindowsysteminterface.h>
22 
23 #include <QtGui/QMouseEvent>
24 #include <QtTest/QTest>
25 
26 using QTest::QTouchEventSequence;
27 
28 namespace {
29 Qt::MouseButton translateMouseButton(xcb_button_t detail)
30 {
31  switch (detail) {
32  case 1: return Qt::LeftButton;
33  case 2: return Qt::MidButton;
34  case 3: return Qt::RightButton;
35  // Button values 4-7 are Wheel events
36  default: return Qt::NoButton;
37  }
38 }
39 } // end of anonymous namespace
40 
41 MouseTouchAdaptor::MouseTouchAdaptor()
42  : m_leftButtonIsPressed(false)
43 {
44  m_touchDevice = new QTouchDevice;
45  m_touchDevice->setType(QTouchDevice::TouchScreen);
46  QWindowSystemInterface::registerTouchDevice(m_touchDevice);
47 }
48 
49 bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
50  void * message, long * /*result*/)
51 {
52  if (eventType != "xcb_generic_event_t") {
53  // wrong backend.
54  qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
55  return false;
56  }
57 
58  xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
59 
60  switch (xcbEvent->response_type & ~0x80) {
61  case XCB_BUTTON_PRESS:
62  return handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(xcbEvent));
63  break;
64  case XCB_BUTTON_RELEASE:
65  return handleButtonRelease(reinterpret_cast<xcb_button_release_event_t *>(xcbEvent));
66  break;
67  case XCB_MOTION_NOTIFY:
68  return handleMotionNotify(reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent));
69  break;
70  default:
71  return false;
72  break;
73  };
74 }
75 
76 bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
77 {
78  Qt::MouseButton button = translateMouseButton(pressEvent->detail);
79 
80  // Just eat the event if it wasn't a left mouse press
81  if (button != Qt::LeftButton)
82  return true;
83 
84  QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
85 
86  QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87 
88  QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
89  false /* autoCommit */);
90  touchEvent.press(0 /* touchId */, windowPos);
91  touchEvent.commit(false /* processEvents */);
92 
93  m_leftButtonIsPressed = true;
94  return true;
95 }
96 
97 bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseEvent)
98 {
99  Qt::MouseButton button = translateMouseButton(releaseEvent->detail);
100 
101  // Just eat the event if it wasn't a left mouse release
102  if (button != Qt::LeftButton)
103  return true;
104 
105  QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
106 
107  QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108 
109  QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
110  false /* autoCommit */);
111  touchEvent.release(0 /* touchId */, windowPos);
112  touchEvent.commit(false /* processEvents */);
113 
114  m_leftButtonIsPressed = false;
115  return true;
116 }
117 
118 bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
119 {
120  if (!m_leftButtonIsPressed) {
121  return true;
122  }
123 
124  QPoint windowPos(event->event_x, event->event_y);
125 
126  QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127 
128  QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
129  false /* autoCommit */);
130  touchEvent.move(0 /* touchId */, windowPos);
131  touchEvent.commit(false /* processEvents */);
132 
133  return true;
134 }
135 
136 QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137 {
138  QWindowList windowList = QGuiApplication::topLevelWindows();
139  QWindow *foundWindow = nullptr;
140 
141  int i = 0;
142  while (!foundWindow && i < windowList.count()) {
143  QWindow *window = windowList[i];
144  if (window->winId() == windowId) {
145  foundWindow = window;
146  } else {
147  ++i;
148  }
149  }
150 
151  Q_ASSERT(foundWindow);
152  return foundWindow;
153 }