diff options
-rw-r--r-- | src/ui/touch.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/src/ui/touch.c b/src/ui/touch.c index 5bf1b87e..83641ad4 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -32,7 +32,7 @@ iDeclareType(Touch) | |||
32 | iDeclareType(TouchState) | 32 | iDeclareType(TouchState) |
33 | iDeclareType(Momentum) | 33 | iDeclareType(Momentum) |
34 | 34 | ||
35 | #define numHistory_Touch_ 3 | 35 | #define numHistory_Touch_ 5 |
36 | #define lastIndex_Touch_ (numHistory_Touch_ - 1) | 36 | #define lastIndex_Touch_ (numHistory_Touch_ - 1) |
37 | 37 | ||
38 | enum iTouchEdge { | 38 | enum iTouchEdge { |
@@ -41,6 +41,12 @@ enum iTouchEdge { | |||
41 | right_TouchEdge, | 41 | right_TouchEdge, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | enum iTouchAxis { | ||
45 | none_TouchAxis, | ||
46 | x_TouchAxis, | ||
47 | y_TouchAxis | ||
48 | }; | ||
49 | |||
44 | struct Impl_Touch { | 50 | struct Impl_Touch { |
45 | SDL_FingerID id; | 51 | SDL_FingerID id; |
46 | iWidget *affinity; /* widget on which the touch started */ | 52 | iWidget *affinity; /* widget on which the touch started */ |
@@ -49,8 +55,10 @@ struct Impl_Touch { | |||
49 | enum iTouchEdge edge; | 55 | enum iTouchEdge edge; |
50 | uint32_t startTime; | 56 | uint32_t startTime; |
51 | iFloat3 startPos; | 57 | iFloat3 startPos; |
58 | enum iTouchAxis axis; | ||
52 | uint32_t posTime[numHistory_Touch_]; | 59 | uint32_t posTime[numHistory_Touch_]; |
53 | iFloat3 pos[numHistory_Touch_]; | 60 | iFloat3 pos[numHistory_Touch_]; |
61 | size_t posCount; | ||
54 | iFloat3 accum; | 62 | iFloat3 accum; |
55 | }; | 63 | }; |
56 | 64 | ||
@@ -59,6 +67,7 @@ iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) { | |||
59 | memmove(d->pos + 1, d->pos, (numHistory_Touch_ - 1) * sizeof(d->pos[0])); | 67 | memmove(d->pos + 1, d->pos, (numHistory_Touch_ - 1) * sizeof(d->pos[0])); |
60 | d->posTime[0] = time; | 68 | d->posTime[0] = time; |
61 | d->pos[0] = pos; | 69 | d->pos[0] = pos; |
70 | d->posCount++; | ||
62 | } | 71 | } |
63 | 72 | ||
64 | struct Impl_Momentum { | 73 | struct Impl_Momentum { |
@@ -96,11 +105,14 @@ static iTouch *find_TouchState_(iTouchState *d, SDL_FingerID id) { | |||
96 | } | 105 | } |
97 | 106 | ||
98 | static const uint32_t longPressSpanMs_ = 425; | 107 | static const uint32_t longPressSpanMs_ = 425; |
99 | static const int tapRadiusPt_ = 15; | 108 | static const int tapRadiusPt_ = 5; |
109 | |||
110 | iLocalDef float distance_Touch_(const iTouch *d) { | ||
111 | return length_F3(sub_F3(d->pos[0], d->startPos)); | ||
112 | } | ||
100 | 113 | ||
101 | static iBool isStationary_Touch_(const iTouch *d) { | 114 | static iBool isStationary_Touch_(const iTouch *d) { |
102 | return !d->hasMoved && | 115 | return !d->hasMoved && distance_Touch_(d) < tapRadiusPt_ * get_Window()->pixelRatio; |
103 | length_F3(sub_F3(d->pos[0], d->startPos)) < tapRadiusPt_ * get_Window()->pixelRatio; | ||
104 | } | 116 | } |
105 | 117 | ||
106 | static void dispatchMotion_Touch_(iFloat3 pos, int buttonState) { | 118 | static void dispatchMotion_Touch_(iFloat3 pos, int buttonState) { |
@@ -272,15 +284,16 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
272 | }); | 284 | }); |
273 | edge = none_TouchEdge; | 285 | edge = none_TouchEdge; |
274 | } | 286 | } |
275 | pushBack_Array(d->touches, &(iTouch){ | 287 | iTouch newTouch = { |
276 | .id = fing->fingerId, | 288 | .id = fing->fingerId, |
277 | .affinity = aff, | 289 | .affinity = aff, |
278 | .hasMoved = (flags_Widget(aff) & touchDrag_WidgetFlag) != 0, | 290 | .hasMoved = (flags_Widget(aff) & touchDrag_WidgetFlag) != 0, |
279 | .edge = edge, | 291 | .edge = edge, |
280 | .startTime = nowTime, | 292 | .startTime = nowTime, |
281 | .startPos = pos, | 293 | .startPos = pos, |
282 | .pos = pos | 294 | }; |
283 | }); | 295 | pushPos_Touch_(&newTouch, pos, fing->timestamp); |
296 | pushBack_Array(d->touches, &newTouch); | ||
284 | /* Some widgets rely on hover state. */ | 297 | /* Some widgets rely on hover state. */ |
285 | dispatchMotion_Touch_(pos, 0); | 298 | dispatchMotion_Touch_(pos, 0); |
286 | addTicker_App(update_TouchState_, d); | 299 | addTicker_App(update_TouchState_, d); |
@@ -308,8 +321,30 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
308 | iInt2 pixels = initF3_I2(touch->accum); | 321 | iInt2 pixels = initF3_I2(touch->accum); |
309 | /* We're reporting scrolling as full points, so keep track of the precise distance. */ | 322 | /* We're reporting scrolling as full points, so keep track of the precise distance. */ |
310 | subv_F3(&touch->accum, initI2_F3(pixels)); | 323 | subv_F3(&touch->accum, initI2_F3(pixels)); |
311 | if (!touch->hasMoved && !isStationary_Touch_(touch)) { | 324 | if (!touch->hasMoved) { |
312 | touch->hasMoved = iTrue; | 325 | if (!isStationary_Touch_(touch)) { |
326 | touch->hasMoved = iTrue; | ||
327 | /* The first FINGERMOTION seems to be larger than the subsequence ones. | ||
328 | Maybe SDL does its own stationary threshold? We'll counter by reducing | ||
329 | the first one. */ | ||
330 | divvf_F3(&touch->accum, 3); | ||
331 | divfv_I2(&pixels, 3); | ||
332 | } | ||
333 | else { | ||
334 | touch->accum = zero_F3(); | ||
335 | pixels = zero_I2(); | ||
336 | } | ||
337 | } | ||
338 | else if (!touch->axis && | ||
339 | distance_Touch_(touch) > tapRadiusPt_ * 3 * window->pixelRatio) { | ||
340 | /* Lock swipe direction to an axis. */ | ||
341 | if (iAbs(x_F3(touch->startPos) - x_F3(pos)) > | ||
342 | iAbs(y_F3(touch->startPos) - y_F3(pos)) * 1.5f) { | ||
343 | touch->axis = x_TouchAxis; | ||
344 | } | ||
345 | else { | ||
346 | touch->axis = y_TouchAxis; | ||
347 | } | ||
313 | } | 348 | } |
314 | /* Edge swipe aborted? */ | 349 | /* Edge swipe aborted? */ |
315 | if (touch->edge == left_TouchEdge && fing->dx < 0) { | 350 | if (touch->edge == left_TouchEdge && fing->dx < 0) { |
@@ -321,6 +356,12 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
321 | if (touch->edge) { | 356 | if (touch->edge) { |
322 | pixels.y = 0; | 357 | pixels.y = 0; |
323 | } | 358 | } |
359 | if (touch->axis == x_TouchAxis) { | ||
360 | pixels.y = 0; | ||
361 | } | ||
362 | if (touch->axis == y_TouchAxis) { | ||
363 | pixels.x = 0; | ||
364 | } | ||
324 | // printf("%p (%s) py: %i wy: %f acc: %f\n", | 365 | // printf("%p (%s) py: %i wy: %f acc: %f\n", |
325 | // touch->affinity, | 366 | // touch->affinity, |
326 | // class_Widget(touch->affinity)->name, | 367 | // class_Widget(touch->affinity)->name, |
@@ -369,15 +410,16 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
369 | : SDL_BUTTON_X2); | 410 | : SDL_BUTTON_X2); |
370 | } | 411 | } |
371 | else { | 412 | else { |
372 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex_Touch_]; | 413 | const size_t lastIndex = iMin(touch->posCount - 1, lastIndex_Touch_); |
414 | const uint32_t elapsed = fing->timestamp - touch->posTime[lastIndex]; | ||
373 | const float minVelocity = 400.0f; | 415 | const float minVelocity = 400.0f; |
374 | if (elapsed < 75) { | 416 | if (elapsed < 85) { |
375 | velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex_Touch_]), | 417 | velocity = divf_F3(sub_F3(pos, touch->pos[lastIndex]), |
376 | (float) elapsed / 1000.0f); | 418 | (float) elapsed / 1000.0f); |
377 | if (fabsf(x_F3(velocity)) < minVelocity) { | 419 | if (touch->axis == y_TouchAxis || fabsf(x_F3(velocity)) < minVelocity) { |
378 | setX_F3(&velocity, 0.0f); | 420 | setX_F3(&velocity, 0.0f); |
379 | } | 421 | } |
380 | if (fabsf(y_F3(velocity)) < minVelocity) { | 422 | if (touch->axis == x_TouchAxis || fabsf(y_F3(velocity)) < minVelocity) { |
381 | setY_F3(&velocity, 0.0f); | 423 | setY_F3(&velocity, 0.0f); |
382 | } | 424 | } |
383 | } | 425 | } |