This example contains most of the code snippets that illustrate what you need in order to define a custom gesture.
#include <gestures/types.h> /* The stucture custom_gesture_params_t represents the parameters for the custom gesture. */ typedef struct { unsigned max_displacement; /* The maximum distance the finger can move before the custom gesture fails. */ unsigned max_hold_ms; /* The maximum time the finger can remain touching the screen before the custom gesture fails. */ unsigned max_delay_ms; /* The time between the first release and the second touch. */ } custom_gesture_params_t; /* The enumeration custom_gesture_state_e defines additional states the custom * gesture can transition between. */ typedef enum { CT_STATE_INIT = 0, CT_STATE_FIRST_TOUCH, CT_STATE_FIRST_RELEASE, CT_STATE_SECOND_TOUCH, CT_STATE_SECOND_RELEASE } custom_gesture_state_e; /* The structure gesture_custom_gesture_t carries data about the custom gesture. */ typedef struct { gesture_base_t base; /* The gesture base data structure. */ custom_gesture_params_t params; /* The custom gesture parameters. */ gesture_coords_t first_touch; /* The coordinates of the first touch. */ gesture_coords_t first_release; /* The coordinates of the first release. */ gesture_coords_t second_touch; /* The coordinates of the second touch. */ gesture_coords_t second_release; /* The coordinates of the second release. */ custom_gesture_state_e dt_state; /* The intermediate state of the custom gesture. */ int fail_timer; /* The ID of the timer for this gesture. */ } gesture_custom_gesture_t; /* Allocate and initialize the custom gesture structure */ gesture_custom_gesture_t* custom_gesture_gesture_alloc(custom_gesture_params_t* params, gesture_callback_f callback, struct gestures_set* set); /* Initialize the custom parameters */ void custom_gesture_gesture_default_params(custom_gesture_params_t* params);
/*The example below shows the implementation of a custom user-defined gesture. */ #include <sys/types.h> #include <stdlib.h> #include <malloc.h> #include <string.h> #include <stdio.h> #include <gestures/set.h> #include <gestures/timer.h> #include <custom_gesture.h> #include <input/event_types.h> #include <gestures/defaults.h> /* Custom free() function */ void custom_gesture_gesture_free(gesture_base_t* gesture) { free(gesture); } /* Custom helper function */ static int _check_valid(gesture_coords_t* coords1, gesture_coords_t* coords2, unsigned max_displacement, unsigned max_ms) { return ((max_displacement_abs(coords1, coords2) <= max_displacement) && (diff_time_ms(coords1, coords2) <= max_ms)); } /* Custom process_event() function */ gesture_state_e custom_gesture_gesture_process_event(struct contact_id_map* map, gesture_base_t* gesture, mtouch_event_t* event, int* consumed) { gesture_custom_gesture_t* custom_gesture = (gesture_custom_gesture_t*)gesture; gesture_coords_t coords; gesture_coords_t* compare_coords; int set_id = map_contact_id(map, event->contact_id); if (set_id < 0) { error("process_event() called with event with invalid contact_id"); goto failed; } switch (custom_gesture->base.state) { case GESTURE_STATE_UNRECOGNIZED: switch (event->event_type) { case INPUT_EVENT_MTOUCH_TOUCH: if (set_id > 0) { goto failed; } else if (custom_gesture->dt_state > CT_STATE_FIRST_TOUCH) { gesture_timer_clear(gesture, custom_gesture->fail_timer); save_coords(event, &custom_gesture->second_touch); if (!_check_valid(&custom_gesture->first_release, &custom_gesture->second_touch, custom_gesture->params.max_displacement, custom_gesture->params.max_delay_ms)) { goto failed; } custom_gesture->dt_state = CT_STATE_SECOND_TOUCH; } else { save_coords(event, &custom_gesture->first_touch); custom_gesture->dt_state = CT_STATE_FIRST_TOUCH; } goto nochange; case INPUT_EVENT_MTOUCH_MOVE: save_coords(event, &coords); if (custom_gesture->dt_state >= CT_STATE_SECOND_TOUCH) { compare_coords = &custom_gesture->second_touch; } else { compare_coords = &custom_gesture->first_touch; } if (!_check_valid(compare_coords, &coords, custom_gesture->params.max_displacement, custom_gesture->params.max_hold_ms)) { goto failed; } goto nochange; case INPUT_EVENT_MTOUCH_RELEASE: if (custom_gesture->dt_state >= CT_STATE_SECOND_TOUCH) { save_coords(event, &custom_gesture->second_release); if (!_check_valid(&custom_gesture->second_touch, &custom_gesture->second_release, custom_gesture->params.max_displacement, custom_gesture->params.max_hold_ms)) { goto failed; } custom_gesture->dt_state = CT_STATE_SECOND_RELEASE; goto complete; } else { save_coords(event, &custom_gesture->first_release); if (!_check_valid(&custom_gesture->first_touch, &custom_gesture->first_release, custom_gesture->params.max_displacement, custom_gesture->params.max_hold_ms)) { goto failed; } custom_gesture->dt_state = CT_STATE_FIRST_RELEASE; /* Set a timer in case an event doesn't come in */ gesture_timer_set_event(gesture, custom_gesture->fail_timer, custom_gesture->params.max_delay_ms, event); } goto nochange; default: warn("Unhandled switch/case: %d", event->event_type); goto failed; } case GESTURE_STATE_RECOGNIZED: error("GESTURE_STATE_RECOGNIZED is an invalid state for double tap"); break; case GESTURE_STATE_UPDATING: error("GESTURE_STATE_UPDATING is an invalid state for double tap"); break; case GESTURE_STATE_COMPLETE: error("process_event() called on complete gesture"); break; case GESTURE_STATE_FAILED: error("process_event() called on failed gesture"); break; case GESTURE_STATE_NONE: error("process_event() called on uninitialized gesture"); break; } nochange: *consumed = 0; return custom_gesture->base.state; failed: *consumed = 0; return GESTURE_STATE_FAILED; complete: *consumed = 1; return GESTURE_STATE_COMPLETE; } /* Custom timer callback */ static gesture_state_e timeout(gesture_base_t* base, void* param) { return GESTURE_STATE_FAILED; } /* Custom reset() function */ void custom_gesture_gesture_reset(gesture_base_t* gesture) { gesture_custom_gesture_t* custom_gesture = (gesture_custom_gesture_t*)gesture; custom_gesture->dt_state = CT_STATE_INIT; } /* Initialize custom gesture parameters with default values. */ void custom_gesture_gesture_default_params(custom_gesture_params_t* params) { params->max_displacement = GESTURE_MAX_MOVE_TOLERANCE_PIX; params->max_hold_ms = GESTURE_MAX_TAP_DELAY_MS; params->max_delay_ms = GESTURE_MIN_HOLD_DELAY_MS; } /* Custom alloc() function */ gesture_custom_gesture_t* custom_gesture_gesture_alloc(custom_gesture_params_t* params, gesture_callback_f callback, struct gestures_set* set) { gesture_custom_gesture_t* custom_gesture = calloc(1, sizeof(*custom_gesture)); if (NULL == custom_gesture) { return NULL; } gesture_base_init(&custom_gesture->base); gestures_set_add(set, &custom_gesture->base); custom_gesture->base.type = GESTURE_USER; custom_gesture->base.funcs.free = custom_gesture_gesture_free; custom_gesture->base.funcs.process_event = custom_gesture_gesture_process_event; custom_gesture->base.funcs.reset = custom_gesture_gesture_reset; custom_gesture->base.callback = callback; custom_gesture->fail_timer = gesture_timer_create(&custom_gesture->base, timeout, NULL); custom_gesture_gesture_reset(&custom_gesture->base); if (NULL != params) { custom_gesture->params = *params; } else { custom_gesture_gesture_default_params(&custom_gesture->params); } return custom_gesture; }