Example: Code snippets of a gesture-handling application

Updated: May 06, 2022

This example contains most of the code snippets that illustrate how to create a gesture application and cascade multiple gesture sets using failure callbacks.

#include <stdio.h>
#include <screen/screen.h>
#include <input/screen_helpers.h>
#include <gestures/types.h>
#include <gestures/set.h>
#include <gestures/event_list.h>
#include <gestures/swipe.h>
#include <gestures/pinch.h>
#include <gestures/press_and_tap.h>
#include <gestures/rotate.h>
#include <gestures/two_finger_pan.h>
#include <gestures/tap.h>
#include <gestures/double_tap.h>
#include <gestures/triple_tap.h>
#include <gestures/long_press.h>
#include <gestures/two_finger_tap.h>

/* The callback invoked when a gesture is recognized or updated. */
void gesture_callback(gesture_base_t* gesture, mtouch_event_t* event, void* param, int async)
{
    if (async) {
        printf("[async] ");
    }
    switch (gesture->type) {
        case GESTURE_TWO_FINGER_PAN: {
            gesture_tfpan_t* tfpan = (gesture_tfpan_t*)gesture;
            printf("Two-finger pan: %d, %d", tfpan->centroid.x, tfpan->centroid.y);
            break;
        }
        case GESTURE_ROTATE: {
            gesture_rotate_t* rotate = (gesture_rotate_t*)gesture;
            if (rotate->angle != rotate->last_angle) {
                printf("Rotate: %d degs", rotate->angle - rotate->last_angle);
            } else {
                return;
            }
            break;
        }
        case GESTURE_SWIPE: {
            gesture_swipe_t* swipe = (gesture_swipe_t*)gesture;
            printf("Swipe ");
            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;
            printf("Pinch %d, %d", (pinch->last_distance.x - pinch->distance.x),
                                   (pinch->last_distance.y - pinch->distance.y));
            break;
        }
        case GESTURE_TAP:
            printf("Tap");
            break;
        case GESTURE_DOUBLE_TAP:
            printf("Double tap");
            break;
        case GESTURE_TRIPLE_TAP:
            printf("Triple tap");
            break;
        case GESTURE_PRESS_AND_TAP:
            printf("Press and tap");
            break;
        case GESTURE_TWO_FINGER_TAP:
            printf("Two-finger tap");
            break;
        case GESTURE_LONG_PRESS:
            printf("Long press");
            break;
        case GESTURE_USER:
            printf("User");
            break;
        default:
            printf("Unknown");
            break;
    }
    printf("\n");
}

/**
 * The set failure callback that's invoked when all gestures in the first set have
 * transitioned to the failed state.
 */

void fail_callback(struct gestures_set* set, struct event_list* list, int async)
{
    if (set == first_set) {
        /* Sample list copy - not 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);
        }
    }
}

/** Initialize the gesture sets */
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();
    if (NULL != first_set) {
        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();

        if (NULL != second_set) {
            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);
        } else {
            gestures_set_free(first_set);
            first_set = NULL;
        }
    } else {
        fprintf(stderr, "Failed to allocate gesture sets\n");
    }
}

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;
    }
}

int main(int argc, const char* argv[])
{
    int screen_val;
    screen_event_t screen_ev;
    int rc;
    ...
    mtouch_event_t mtouch_event;
    init_gestures();
    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;
            }
        }
    }
    gestures_cleanup();
    return 0;
}