/* * InputSourceTouch.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #pragma once #include "../../lib/Point.h" // Debug option. If defined, mouse events will instead generate touch events, allowing testing of touch input on desktop // #define VCMI_EMULATE_TOUCHSCREEN_WITH_MOUSE enum class MouseButton; struct SDL_TouchFingerEvent; /// Enumeration that describes current state of gesture recognition enum class TouchState { // special state that allows no transitions // used when player selects "relative mode" in Launcher // in this mode touchscreen acts like touchpad, moving cursor at certains speed // and generates events for positions below cursor instead of positions below touch events RELATIVE_MODE, // no active touch events // DOWN -> transition to TAP_DOWN_SHORT // MOTION / UP -> not expected IDLE, // single finger is touching the screen for a short time // DOWN -> transition to TAP_DOWN_DOUBLE // MOTION -> transition to TAP_DOWN_PANNING // UP -> transition to IDLE, emit onLeftClickDown and onLeftClickUp // on timer -> transition to TAP_DOWN_LONG, emit showPopup() event TAP_DOWN_SHORT, // single finger is moving across screen // DOWN -> transition to TAP_DOWN_DOUBLE // MOTION -> emit panning event // UP -> transition to IDLE TAP_DOWN_PANNING, // single finger is moving across screen // DOWN -> ignored // MOTION -> emit panning event // UP -> transition to TAP_DOWN_LONG_AWAIT TAP_DOWN_PANNING_POPUP, // two fingers are touching the screen // DOWN -> ??? how to handle 3rd finger? Ignore? // MOTION -> emit pinch event // UP -> transition to TAP_DOWN TAP_DOWN_DOUBLE, // single finger is down for long period of time // DOWN -> ignored // MOTION -> ignored // UP -> transition to TAP_DOWN_LONG_AWAIT TAP_DOWN_LONG, // right-click popup is active, waiting for new tap to hide popup // DOWN -> ignored // MOTION -> transition to TAP_DOWN_PANNING_POPUP // UP -> transition to IDLE, generate closePopup() event TAP_DOWN_LONG_AWAIT, }; struct TouchInputParameters { /// Speed factor of mouse pointer when relative mode is used double relativeModeSpeedFactor = 1.0; /// tap for period longer than specified here will be qualified as "long tap", triggering corresponding gesture uint32_t longTouchTimeMilliseconds = 750; /// time span in where the second tap has to happen for qualifing as "double click" uint32_t doubleTouchTimeMilliseconds = 500; /// max distance in where the second tap has to happen for qualifing as "double click" uint32_t doubleTouchToleranceDistance = 50; /// moving finger for distance larger than specified will be qualified as panning gesture instead of long press uint32_t panningSensitivityThreshold = 15; /// gesture will be qualified as pinch if distance between fingers is at least specified here uint32_t pinchSensitivityThreshold = 10; /// touch event will trigger clicking of elements up to X pixels away from actual touch position uint32_t touchToleranceDistance = 20; bool useRelativeMode = false; bool hapticFeedbackEnabled = false; }; /// Class that handles touchscreen input from SDL events class InputSourceTouch { TouchInputParameters params; TouchState state; uint32_t lastTapTimeTicks; Point lastTapPosition; uint32_t lastLeftClickTimeTicks; Point lastLeftClickPosition; Point convertTouchToMouse(const SDL_TouchFingerEvent & current); Point convertTouchToMouse(float x, float y); void emitPanningEvent(const SDL_TouchFingerEvent & tfinger); void emitPinchEvent(const SDL_TouchFingerEvent & tfinger); public: InputSourceTouch(); void handleEventFingerMotion(const SDL_TouchFingerEvent & current); void handleEventFingerDown(const SDL_TouchFingerEvent & current); void handleEventFingerUp(const SDL_TouchFingerEvent & current); void hapticFeedback(); void handleUpdate(); bool hasTouchInputDevice() const; };