From f9ebab54c3debe98e108790be9c21f43f4de116f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 19 Dec 2014 04:56:33 +0200 Subject: [PATCH] Add a gesture detector input device --- source/input/device.h | 2 +- source/input/gesturedetector.cpp | 210 +++++++++++++++++++++++++++++++ source/input/gesturedetector.h | 67 ++++++++++ source/input/touchscreen.h | 2 + 4 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 source/input/gesturedetector.cpp create mode 100644 source/input/gesturedetector.h diff --git a/source/input/device.h b/source/input/device.h index e356bea..7df388b 100644 --- a/source/input/device.h +++ b/source/input/device.h @@ -11,7 +11,7 @@ namespace Input { /** Base class for input devices. Input devices have two types of controls: buttons and axes. Buttons are either on or off. Axes have a floating point -value in the range [-1, 1]. +value nominally in the range [-1, 1]. Event handlers return a boolean indicating whether the event is considered processed. If a handler returns true, no further handlers are invoked. diff --git a/source/input/gesturedetector.cpp b/source/input/gesturedetector.cpp new file mode 100644 index 0000000..c43e65a --- /dev/null +++ b/source/input/gesturedetector.cpp @@ -0,0 +1,210 @@ +#include +#include +#include "gesturedetector.h" +#include "touchscreen.h" + +using namespace std; + +namespace Msp { +namespace Input { + +GestureDetector::GestureDetector(Touchscreen &ts): + touchscreen(ts), + current_gesture(GESTURE_NONE), + active_points(0), + invalid_gesture(false) +{ + name = "Gesture"; + + touchscreen.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_down), false)); + touchscreen.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_up), false)); + touchscreen.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &GestureDetector::touch_move), false)); + Graphics::Window &window = touchscreen.get_window(); + window.signal_resize.connect(sigc::mem_fun(this, &GestureDetector::window_resized)); + window_resized(window.get_width(), window.get_height()); +} + +string GestureDetector::get_button_name(unsigned btn) const +{ + if(btn==GESTURE_SWIPE_DOWN) + return "Swipe down"; + else if(btn==GESTURE_SWIPE_UP) + return "Swipe up"; + else if(btn==GESTURE_SWIPE_LEFT) + return "Swipe left"; + else if(btn==GESTURE_SWIPE_RIGHT) + return "Swipe right"; + else if(btn==GESTURE_PINCH) + return "Pinch"; + else + return Device::get_button_name(btn); +} + +string GestureDetector::get_axis_name(unsigned axis) const +{ + if(axis==0) + return "X"; + else if(axis==1) + return "Y"; + else if(axis==2) + return "Progress"; + else + return Device::get_axis_name(axis); +} + +void GestureDetector::touch_down(unsigned btn) +{ + if(btn<3) + { + TouchPoint &p = points[btn]; + p.down = true; + p.down_x = p.x; + p.down_y = p.y; + } +} + +void GestureDetector::touch_up(unsigned btn) +{ + if(btn<3) + { + TouchPoint &p = points[btn]; + p.down = false; + + if(active_points&(1<>1; + TouchPoint &p = points[i]; + if(axis&1) + p.y = value; + else + p.x = value; + + if(p.down) + { + if(current_gesture==GESTURE_NONE && !invalid_gesture) + start_gesture(); + else if(active_points&(1<2*abs(dy)) + current_gesture = (dx>0 ? GESTURE_SWIPE_RIGHT : GESTURE_SWIPE_LEFT); + else if(abs(dy)>2*abs(dx)) + current_gesture = (dy>0 ? GESTURE_SWIPE_UP : GESTURE_SWIPE_DOWN); + else + invalid_gesture = true; + + if(current_gesture!=GESTURE_NONE) + { + set_axis_value(0, p.down_x, true); + set_axis_value(1, p.down_y, true); + } + } + + update_progress(); + + if(current_gesture!=GESTURE_NONE) + set_button_state(current_gesture, true, true); +} + +void GestureDetector::update_progress() +{ + TouchPoint &p = points[0]; + + if(current_gesture==GESTURE_SWIPE_DOWN) + set_axis_value(2, p.down_y-p.y, true); + else if(current_gesture==GESTURE_SWIPE_UP) + set_axis_value(2, p.y-p.down_y, true); + else if(current_gesture==GESTURE_SWIPE_LEFT) + set_axis_value(2, p.down_x-p.x, true); + else if(current_gesture==GESTURE_SWIPE_RIGHT) + set_axis_value(2, p.x-p.down_x, true); + else if(current_gesture==GESTURE_PINCH) + { + TouchPoint &p2 = points[1]; + float dx = p.x-p2.x; + float dy = p.y-p2.y; + float ddx = p.down_x-p2.down_x; + float ddy = p.down_y-p2.down_y; + set_axis_value(2, sqrt(dx*dx+dy*dy)/sqrt(ddx*ddx+ddy*ddy)-1, true); + } +} + +void GestureDetector::window_resized(unsigned w, unsigned h) +{ + threshold_x_sq = 2500.0/(w*w); + threshold_y_sq = 2500.0/(h*h); +} + + +GestureDetector::TouchPoint::TouchPoint(): + down(false), + down_x(0), + down_y(0), + x(0), + y(0) +{ } + +} // namespace Input +} // namespace Msp diff --git a/source/input/gesturedetector.h b/source/input/gesturedetector.h new file mode 100644 index 0000000..2b5ea3c --- /dev/null +++ b/source/input/gesturedetector.h @@ -0,0 +1,67 @@ +#ifndef MSP_INPUT_GESTUREDETECTOR_H_ +#define MSP_INPUT_GESTUREDETECTOR_H_ + +#include "device.h" + +namespace Msp { +namespace Input { + +class Touchscreen; + +enum Gesture +{ + GESTURE_NONE, + GESTURE_SWIPE_DOWN, + GESTURE_SWIPE_UP, + GESTURE_SWIPE_LEFT, + GESTURE_SWIPE_RIGHT, + GESTURE_PINCH +}; + +/** +Interprets events from a Touchscreen as high-level gestures. One button is +provided for each type of gesture. Axes 0 and 1 indicate the starting position +of the gesture; axis 2 tracks its progress. The progress axis may exhibit +absolute values greater than one. +*/ +class GestureDetector: public Device +{ +private: + struct TouchPoint + { + bool down; + float down_x; + float down_y; + float x; + float y; + + TouchPoint(); + }; + + Touchscreen &touchscreen; + TouchPoint points[3]; + Gesture current_gesture; + unsigned active_points; + bool invalid_gesture; + float threshold_x_sq; + float threshold_y_sq; + +public: + GestureDetector(Touchscreen &); + + virtual std::string get_button_name(unsigned) const; + virtual std::string get_axis_name(unsigned) const; + +private: + void touch_down(unsigned); + void touch_up(unsigned); + void touch_move(unsigned, float, float); + void start_gesture(); + void update_progress(); + void window_resized(unsigned, unsigned); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/touchscreen.h b/source/input/touchscreen.h index 363111c..99432d2 100644 --- a/source/input/touchscreen.h +++ b/source/input/touchscreen.h @@ -23,6 +23,8 @@ public: Touchscreen(Graphics::Window &); ~Touchscreen(); + Graphics::Window &get_window() const { return window; } + virtual std::string get_button_name(unsigned) const; virtual std::string get_axis_name(unsigned) const; private: -- 2.43.0