Unity 8
VirtualTouchPad.qml
1 /*
2  * Copyright (C) 2015 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 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import UInput 0.1
20 
21 Item {
22  property var uinput: UInput {
23  Component.onCompleted: createMouse();
24  Component.onDestruction: removeMouse();
25  }
26 
27  readonly property bool pressed: point1.pressed || point2.pressed
28 
29  MultiPointTouchArea {
30  objectName: "touchPadArea"
31  anchors.fill: parent
32 
33  // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
34  readonly property int clickThreshold: units.gu(1.5)
35  property bool isClick: false
36  property bool isDoubleClick: false
37  property bool isDrag: false
38 
39  onPressed: {
40  // If double-tapping *really* fast, it could happen that we end up having only point2 pressed
41  // Make sure we check for both combos, only point1 or only point2
42  if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
43  && clickTimer.running) {
44  clickTimer.stop();
45  uinput.pressMouse(UInput.ButtonLeft)
46  isDoubleClick = true;
47  }
48  isClick = true;
49  }
50 
51  onUpdated: {
52  switch (touchPoints.length) {
53  case 1:
54  moveMouse(touchPoints);
55  return;
56  case 2:
57  scroll(touchPoints);
58  return;
59  }
60  }
61 
62  onReleased: {
63  if (isDoubleClick || isDrag) {
64  uinput.releaseMouse(UInput.ButtonLeft)
65  isDoubleClick = false;
66  }
67  if (isClick) {
68  clickTimer.scheduleClick(point1.pressed ? UInput.ButtonRight : UInput.ButtonLeft)
69  }
70  isClick = false;
71  isDrag = false;
72  }
73 
74  Timer {
75  id: clickTimer
76  repeat: false
77  interval: 200
78  property int button: UInput.ButtonLeft
79  onTriggered: {
80  uinput.pressMouse(button);
81  uinput.releaseMouse(button);
82  }
83  function scheduleClick(button) {
84  clickTimer.button = button;
85  clickTimer.start();
86  }
87  }
88 
89  function moveMouse(touchPoints) {
90  var tp = touchPoints[0];
91  if (isClick &&
92  (Math.abs(tp.x - tp.startX) > clickThreshold ||
93  Math.abs(tp.y - tp.startY) > clickThreshold)) {
94  isClick = false;
95  isDrag = true;
96  }
97 
98  uinput.moveMouse(tp.x - tp.previousX, tp.y - tp.previousY);
99  }
100 
101  function scroll(touchPoints) {
102  var dh = 0;
103  var dv = 0;
104  var tp = touchPoints[0];
105  if (isClick &&
106  (Math.abs(tp.x - tp.startX) > clickThreshold ||
107  Math.abs(tp.y - tp.startY) > clickThreshold)) {
108  isClick = false;
109  }
110  dh += tp.x - tp.previousX;
111  dv += tp.y - tp.previousY;
112 
113  tp = touchPoints[1];
114  if (isClick &&
115  (Math.abs(tp.x - tp.startX) > clickThreshold ||
116  Math.abs(tp.y - tp.startY) > clickThreshold)) {
117  isClick = false;
118  }
119  dh += tp.x - tp.previousX;
120  dv += tp.y - tp.previousY;
121 
122  // As we added up the movement of the two fingers, let's divide it again by 2
123  dh /= 2;
124  dv /= 2;
125 
126  uinput.scrollMouse(dh, dv);
127  }
128 
129  touchPoints: [
130  TouchPoint {
131  id: point1
132  },
133  TouchPoint {
134  id: point2
135  }
136  ]
137  }
138 }