File size: 5,983 Bytes
dec7e7d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/*
* Copyright 2017-2020 Mark Callow.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @internal
* @class SwipeDetector
* @~English
*
* @brief Definition of a class for detecting swipes.
*
* @author Mark Callow, github.com/MarkCallow.
*/
#include <assert.h>
#include "SwipeDetector.h"
#include <SDL3/SDL_log.h>
#if !defined(SWIPEDETECTOR_LOG_GESTURE_EVENTS)
#define SWIPEDETECTOR_LOG_GESTURE_EVENTS 0
#endif
#if !defined(SWIPEDETECTOR_LOG_GESTURE_DETECTION)
#define SWIPEDETECTOR_LOG_GESTURE_DETECTION 0
#endif
bool
SwipeDetector::doEvent(SDL_Event* event)
{
bool result = false;
switch (event->type) {
case SDL_EVENT_FINGER_UP: {
int numFingers;
SDL_Finger** fingers = SDL_GetTouchFingers(event->tfinger.touchID, &numFingers);
if (SWIPEDETECTOR_LOG_GESTURE_EVENTS) {
SDL_Log("SD: Finger: %" SDL_PRIx64 " UP - fingers: %i, x: %f, y: %f",
event->tfinger.fingerID, numFingers, event->tfinger.x, event->tfinger.y);
}
// SDL_GetTouchFingers appears to return the number of fingers
// down *before* the event was generated, so 1 means the last finger
// just lifted.
if (numFingers == 1 && gestureStart.time != 0) {
gestureStart.time = 0;
gestureSwipe = false;
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION) {
SDL_Log("***************** SD: FINGER_UP, %smultigesture done *****************",
gestureSwipe ? "Swipe complete & " : "");
}
} else {
result = true;
}
SDL_free(fingers);
break;
}
case GESTURE_MULTIGESTURE: {
Gesture_MultiGestureEvent& mgesture = *(Gesture_MultiGestureEvent *)event;
if (SWIPEDETECTOR_LOG_GESTURE_EVENTS) {
SDL_Log("SD: MG Event: x = %f, y = %f, dAng = %f (%f), dR = %f, numFingers = %i, time = %" SDL_PRIu64,
mgesture.x,
mgesture.y,
mgesture.dTheta * 180.0 / M_PI,
mgesture.dTheta,
mgesture.dDist,
mgesture.numFingers,
mgesture.timestamp);
}
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION) {
SDL_Log("SD: mgestureSwipe = %i, time = %" SDL_PRIu64,
gestureSwipe,
(mgesture.timestamp - gestureStart.time) / 1000000);
}
if (gestureStart.time == 0) {
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION) {
SDL_Log("************ SD: Multigesture detection start **************");
}
gestureStart.time = mgesture.timestamp;
gestureStart.point.x = mgesture.x;
gestureStart.point.y = mgesture.y;
lastVector.reset();
gestureSwipe = false;
} else {
if (!gestureSwipe) {
vector sv; // Vector from start point to current position
float velocity;
float theta; // Angle between current vector and previous vector.
float duration;
sv.w = mgesture.x - gestureStart.point.x;
sv.h = mgesture.y - gestureStart.point.y;
float distance = sv.length();
if (lastVector.has_value()) {
// SDL2 timestamps were in milliseconds, SDL3 are nanoseconds. Given the
// normalized distances reported, using nanoseconds leads to 0 velocitySq.
duration = static_cast<float>(
(mgesture.timestamp - gestureStart.time) / 1000000.0);
velocity = distance / duration;
assert(!std::isinf(velocity));
theta = static_cast<float>(lastVector->getAngle(sv));
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION) {
SDL_Log("SD: Detection: distance = %f, velocity = %f, theta = %f, sv angle = %f, sv angle normalized = %f, lastv angle = %f",
distance, velocity, theta,
sv.getAngle(),
sv.getAngleNormalized(),
lastVector->getAngle());
}
lastVector = sv;
// Multiple events with the same timestamp is a possibility
// hence the isinf() check.
if (std::abs(theta) < 3.0 && std::abs(mgesture.dDist) > 0.01 && !std::isinf(velocity) && velocity > 0.0007) {
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION)
SDL_Log("----------------- SD: Swipe %s detected -----------------",
toString(sv.getDirection()).c_str());
gestureSwipe = true;
if (SDL_EventEnabled(SDL_EVENT_USER)) {
SDL_Event user_event;
// SDL will copy this entire struct! Initialize to keep memory
// checkers happy.
SDL_zero(user_event);
user_event.type = SDL_EVENT_USER;
user_event.user.code = swipeGesture;
user_event.user.data1 = SwipeDetector::directionToPointer(sv.getDirection());
user_event.user.data2 = NULL;
SDL_PushEvent(&user_event);
}
} else {
if (SWIPEDETECTOR_LOG_GESTURE_DETECTION) SDL_Log("SD: No swipe detected.");
result = true;
}
} else {
lastVector = sv;
result = true;
}
}
}
break;
}
default:
result = true;
}
return result;
}
|