Updated: October 28, 2024 |
This tutorial shows you the basics for creating a gesture application using system-supported gesture recognizers.
The gesture callback function defines what the application does when a gesture is recognized or updated:
void(*gesture_callback_f)(struct gesture_base* gesture, mtouch_event_t* event, void* param, int async);
The argument gesture contains information about the gesture and the parameter event contains information about the mtouch event that caused the gesture. The parameter async identifies whether this callback was invoked from an event (async = 0) or from a timer (async = 1).
If you have gestures that are transitioning based on timer events, this callback function could be invoked as a result of either a timer event (from the context of the timer thread) or an mtouch event. Your application code needs to implement the synchronization mechanism between mtouch callback functions and timer-event callback functions. Your application needs to check the async parameter and implement synchronization accordingly.
switch (gesture->type) { case GESTURE_TWO_FINGER_PAN: { gesture_tfpan_t* tfpan = (gesture_tfpan_t*)gesture; if (tfpan->base.state == GESTURE_STATE_COMPLETE) { printf("Two-finger pan gesture detected: %d, %d", tfpan->centroid.x, tfpan->centroid.y); } break; } case GESTURE_ROTATE: { gesture_rotate_t* rotate = (gesture_rotate_t*)gesture; if (rotate->base.state == GESTURE_STATE_COMPLETE) { if (rotate->angle != rotate->last_angle) { printf("Rotate: %d degs", rotate->angle - rotate->last_angle); } } break; } case GESTURE_SWIPE: { gesture_swipe_t* swipe = (gesture_swipe_t*)gesture; if (swipe->base.state == GESTURE_STATE_COMPLETE) { if (swipe->direction & GESTURE_DIRECTION_UP) { printf("up %d", swipe->last_coords.y - swipe->coords.y); } else if (swipe->direction & GESTURE_DIRECTION_DOWN) { printf("down %d", swipe->coords.y - swipe->last_coords.y); } else if (swipe->direction & GESTURE_DIRECTION_LEFT) { printf("left %d", swipe->last_coords.x - swipe->coords.x); } else if (swipe->direction & GESTURE_DIRECTION_RIGHT) { printf("right %d", swipe->coords.x - swipe->last_coords.x); } } break; } case GESTURE_PINCH: { gesture_pinch_t* pinch = (gesture_pinch_t*)gesture; if (pinch->base.state == GESTURE_STATE_COMPLETE) { printf("Pinch %d, %d", (pinch->last_distance.x - pinch->distance.x), (pinch->last_distance.y - pinch->distance.y)); } break; } case GESTURE_TAP: { gesture_tap_t* tap = (gesture_tap_t*)gesture; if (tap->base.state == GESTURE_STATE_COMPLETE) { printf("Tap x:%d y:%d",tap->touch_coords.x, tap->touch_coords.y); } break; } case GESTURE_DOUBLE_TAP: { gesture_double_tap_t* d_tap = (gesture_double_tap_t*)gesture; if (d_tap->base.state == GESTURE_STATE_COMPLETE) { printf("Double tap first_touch x:%d y:%d", d_tap->first_touch.x, d_tap->first_touch.y); printf("Double tap first_release x:%d y:%d", d_tap->first_release.x, d_tap->first_release.y); printf("Double tap second_touch x:%d y:%d", d_tap->second_touch.x, d_tap->second_touch.y); printf("Double tap second_release x:%d y:%d", d_tap->second_touch.x, d_tap->second_release.y); } break; } case GESTURE_TRIPLE_TAP: { gesture_triple_tap_t* t_tap = (gesture_triple_tap_t*)gesture; if (t_tap->base.state == GESTURE_STATE_COMPLETE) { printf("Triple tap first_touch x:%d y:%d", t_tap->first_touch.x, t_tap->first_touch.y); printf("Triple tap first_release x:%d y:%d", t_tap->first_release.x, t_tap->first_release.y); printf("Triple tap second_touch x:%d y:%d", t_tap->second_touch.x, t_tap->second_touch.y); printf("Triple tap second_release x:%d y:%d", t_tap->second_touch.x, t_tap->second_release.y); printf("Triple tap third_touch x:%d y:%d", t_tap->third_touch.x, t_tap->second_touch.y); printf("Triple tap third_release x:%d y:%d", t_tap->third_touch.x, t_tap->second_release.y); } break; } case GESTURE_PRESS_AND_TAP: { gesture_pt_t* pt_t = (gesture_pt_t*)gesture; if (pt_t->base.state == GESTURE_STATE_COMPLETE) { printf("Initial press x:%d y:%d", pt_t->initial_coords[0].x, pt_t->initial_coords[0].y); printf("Initial tap x:%d y:%d", pt_t->initial_coords[1].x, pt_t->initial_coords[1].y); printf("Press x:%d y:%d", pt_t->coords[0].x, pt_t->coords[0].y); printf("Tap x:%d y:%d", pt_t->coords[1].x, pt_t->coords[1].y); } break; } case GESTURE_TWO_FINGER_TAP: { gesture_tft_t* tft_t = (gesture_tft_t*)gesture; if (tft_t->base.state == GESTURE_STATE_COMPLETE) { printf("Coordinates of touch event (finger 1) x:%d y:%d", tft_t->touch_coords[0].x, tft_t->touch_coords[0].y); printf("Coordinates of touch event (finger 2) x:%d y:%d", tft_t->touch_coords[1].x, tft_t->touch_coords[1].y); printf("Coordinates of release event (finger 1) x:%d y:%d", tft_t->release_coords[0].x, tft_t->release_coords[0].y); printf("Coordinates of release event (finger 2) x:%d y:%d", tft_t->release_coords[1].x, tft_t->release_coords[1].y); printf("Midpoint between two touches x:%d y:%d", tft_t->centroid.x, tft_t->centroid.y); } break; } case GESTURE_LONG_PRESS: { gesture_long_press_t* lp_t = (gesture_long_press_t*)gesture; if (lp_t->base.state == GESTURE_STATE_COMPLETE) { printf("Long press x:%d y:%d",lp_t->coords.x, lp_t->coords.y); printf("Timer ID:%d",lp_t->success_timer); } break; } case GESTURE_USER: { printf("User-defined gesture detected."); break; } default: printf("Unknown"); break; }
void(*gestures_set_fail_f)(struct gestures_set* set, struct event_list* list, int async);
void fail_callback(struct gestures_set* set, struct event_list* list, int async) { /* first_set should be defined in your application as * struct gestures_set* first_set; * and then be allocated and initialized in your application. */ if (set == first_set) { /* An example of list copy. * This isn't necessary if events don't need to be kept following the * call to gestures_set_process_event_list() */ struct event_list* new_list = event_list_alloc(0, 0, 0, 1); if (new_list) { event_list_copy(list, new_list); gestures_set_process_event_list(second_set, new_list, NULL); event_list_free(new_list); } } }
Your application needs to register the callback function with the Gestures library so that it can be invoked when a gesture occurs.
To register the gesture callback function, your application needs to first allocate the gesture set. If you have defined a failure callback for your gesture set, then you must call:
gestures_set_register_fail_cb(struct gestures_set* set, gestures_set_fail_f callback);
to register your failure callback function with your gesture set.
struct gestures_set* first_set; struct gestures_set* second_set; static void init_gestures() { gesture_tap_t* tap; gesture_double_tap_t* double_tap; gesture_triple_tap_t* triple_tap; gesture_tft_t* tft; first_set = gestures_set_alloc(); long_press_gesture_alloc(NULL, gesture_callback, first_set); tap = tap_gesture_alloc(NULL, gesture_callback, first_set); double_tap = double_tap_gesture_alloc(NULL, gesture_callback, first_set); triple_tap = triple_tap_gesture_alloc(NULL, gesture_callback, first_set); tft = tft_gesture_alloc(NULL, gesture_callback, first_set); gesture_add_mustfail(&tap->base, &double_tap->base); gesture_add_mustfail(&double_tap->base, &triple_tap->base); gestures_set_register_fail_cb(first_set, fail_callback); second_set = gestures_set_alloc(); swipe_gesture_alloc(NULL, gesture_callback, second_set); pinch_gesture_alloc(NULL, gesture_callback, second_set); rotate_gesture_alloc(NULL, gesture_callback, second_set); pt_gesture_alloc(NULL, gesture_callback, second_set); tfpan_gesture_alloc(NULL, gesture_callback, second_set); tft_gesture_alloc(NULL, gesture_callback, second_set); }
If you're using custom gestures that you have defined yourself, then you need to allocate your custom gesture recognizer and add it to the gesture set as part of the gesture-set initialization using the alloc() function you've defined. For example, in the code snippet shown, you can add your custom gesture recognizer to your second gesture set by calling your custom_gesture_alloc() function in init_gestures():
static void init_gestures() { ... second_set = gestures_set_alloc(); ... gesture_custom_t* user_gesture = custom_gesture_alloc(custom_params, gesture_callback, set); }
Now, your application needs a way of triggering the gesture callback function when a touch event occurs. When such a touch event is detected, your application calls gestures_set_process_event().
while (1) { while (screen_get_event(screen_ctx, screen_ev, ~0L) == EOK) { rc = screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_TYPE, &screen_val); if (rc || screen_val == SCREEN_EVENT_NONE) { break; } switch (screen_val) { case SCREEN_EVENT_MTOUCH_TOUCH: case SCREEN_EVENT_MTOUCH_MOVE: case SCREEN_EVENT_MTOUCH_RELEASE: rc = screen_get_mtouch_event(screen_ev, &mtouch_event, 0); if (rc) { fprintf(stderr, "Error: failed to get mtouch event\n"); continue; } gestures_set_process_event(first_set, &mtouch_event, NULL); break; } } }
Before exiting your application, you need to free the memory associated with your gesture sets:
static void gestures_cleanup() { if (NULL != first_set) { gestures_set_free(first_set); first_set = NULL; } if (NULL != second_set) { gestures_set_free(second_set); second_set = NULL; } }