2 #include <sigc++/bind_return.h>
3 #include "gesturedetector.h"
4 #include "touchscreen.h"
11 GestureDetector::GestureDetector(Touchscreen &ts):
13 current_gesture(GESTURE_NONE),
15 invalid_gesture(false)
19 touchscreen.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_down), false));
20 touchscreen.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_up), false));
21 touchscreen.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_move), false));
22 Graphics::Window &window = touchscreen.get_window();
23 window.signal_resize.connect(sigc::mem_fun(this, &GestureDetector::window_resized));
24 window_resized(window.get_width(), window.get_height());
27 string GestureDetector::get_button_name(unsigned btn) const
29 if(btn==GESTURE_SWIPE_DOWN)
31 else if(btn==GESTURE_SWIPE_UP)
33 else if(btn==GESTURE_SWIPE_LEFT)
35 else if(btn==GESTURE_SWIPE_RIGHT)
37 else if(btn==GESTURE_PINCH)
40 return Device::get_button_name(btn);
43 string GestureDetector::get_axis_name(unsigned axis) const
52 return Device::get_axis_name(axis);
55 void GestureDetector::touch_down(unsigned btn)
60 TouchPoint &p = points[btn];
66 p.threshold_exceeded = false;
69 void GestureDetector::touch_up(unsigned btn)
74 TouchPoint &p = points[btn];
79 if(active_points&(1<<btn))
82 if(current_gesture==GESTURE_NONE)
84 // New gesture can't start until all points have been released.
85 invalid_gesture = false;
86 for(unsigned i=0; (i<MAX_POINTS && !invalid_gesture); ++i)
87 invalid_gesture = points[i].down;
91 void GestureDetector::touch_move(unsigned axis, float value, float)
93 if(axis>=MAX_POINTS*2)
97 TouchPoint &p = points[i];
98 // Track relative position when pressed, absolute when not.
100 p.y = (p.down ? value-p.down_y : value);
102 p.x = (p.down ? value-p.down_x : value);
106 if(p.x*p.x/threshold_x_sq+p.y*p.y/threshold_y_sq>=1)
107 p.threshold_exceeded = true;
109 if(current_gesture==GESTURE_NONE && !invalid_gesture)
111 else if(active_points&(1<<i))
116 void GestureDetector::start_gesture()
118 TouchPoint &p = points[0];
122 /* At least one point needs to have moved more than the threshold to start
124 bool threshold_exceeded = false;
125 for(unsigned i=0; (i<MAX_POINTS && !threshold_exceeded); ++i)
126 threshold_exceeded = (points[i].down && points[i].threshold_exceeded);
127 if(!threshold_exceeded)
130 invalid_gesture = false;
133 TouchPoint &p2 = points[1];
134 float ddx = p.down_x-p2.down_x;
135 float ddy = p.down_y-p2.down_y;
136 if(p.x*p2.x+p.y*p2.y<0 && (p.x*ddx+p.y*ddy)*(p2.x*ddx+p2.y*ddy)<0)
137 /* If the points moved in different directions and also both away from
138 or towards the other, it's a pinch gesture. */
139 current_gesture = GESTURE_PINCH;
141 invalid_gesture = true;
143 if(current_gesture!=GESTURE_NONE)
146 set_axis_value(0, (p.down_x+p2.down_x)/2, true);
147 set_axis_value(1, (p.down_y+p2.down_y)/2, true);
152 // Allow a maximum deviation of about 26° to recognize a swipe gesture.
153 if(abs(p.x)>2*abs(p.y))
154 current_gesture = (p.x>0 ? GESTURE_SWIPE_RIGHT : GESTURE_SWIPE_LEFT);
155 else if(abs(p.y)>2*abs(p.x))
156 current_gesture = (p.y>0 ? GESTURE_SWIPE_UP : GESTURE_SWIPE_DOWN);
158 invalid_gesture = true;
160 if(current_gesture!=GESTURE_NONE)
163 set_axis_value(0, p.down_x, true);
164 set_axis_value(1, p.down_y, true);
170 if(current_gesture!=GESTURE_NONE)
171 set_button_state(current_gesture, true, true);
174 void GestureDetector::update_progress()
176 TouchPoint &p = points[0];
178 if(current_gesture==GESTURE_SWIPE_DOWN)
179 set_axis_value(2, -p.y, true);
180 else if(current_gesture==GESTURE_SWIPE_UP)
181 set_axis_value(2, p.y, true);
182 else if(current_gesture==GESTURE_SWIPE_LEFT)
183 set_axis_value(2, -p.x, true);
184 else if(current_gesture==GESTURE_SWIPE_RIGHT)
185 set_axis_value(2, p.x, true);
186 else if(current_gesture==GESTURE_PINCH)
188 TouchPoint &p2 = points[1];
189 /* Pinch progress is the ratio between the current distance of the points
190 and their distance when they were pressed. */
191 float ddx = p.down_x-p2.down_x;
192 float ddy = p.down_y-p2.down_y;
193 float dx = ddx+p.x-p2.x;
194 float dy = ddy+p.y-p2.y;
195 set_axis_value(2, sqrt(dx*dx+dy*dy)/sqrt(ddx*ddx+ddy*ddy)-1, true);
199 void GestureDetector::end_gesture()
201 set_button_state(current_gesture, false, true);
202 set_axis_value(2, 0, false);
203 current_gesture = GESTURE_NONE;
207 void GestureDetector::window_resized(unsigned w, unsigned h)
209 threshold_x_sq = 2500.0/(w*w);
210 threshold_y_sq = 2500.0/(h*h);
214 GestureDetector::TouchPoint::TouchPoint():