Note that the Gesture sample application does not work properly on the simulator. You can still code, build, and deploy but the gesture behavior will not work.
This tutorial walks through the Gestures sample application available from the NDK-Samples repository in GitHub.
The sample application needs the appropriate libraries defined for it to work. To verify that they are defined:
This sample application allows users to interact with an image displayed on the screen in the following ways:
| Action | Result |
|---|---|
|
Two-finger pan |
Adjusts the viewport position in the direction of the pan and prints the coordinates to stderr |
|
Pinch the screen |
Adjusts the viewport size in the direction of the pinch and prints the new size to stderr |
|
Tap the screen |
Prints the tap coordinates to stderr |
|
Double-tap the screen |
Prints the double-tap coordinates to stderr |
When a user interacts with the screen, the application should capture the gesture and handle it accordingly. To use the gestures library, you define gesture sets that contain movements, such as pinch, tap, and two-finger pan. The gesture sets receive mtouch events when one or more finger movements are detected on the screen.
When a gesture set receives an event, it invokes a user-defined callback function, where the application-specific behavior is defined. For this to work, the application must register a callback function with the gestures library for every gesture set to be handled.
void(* gesture_callback_f)(struct gesture_base *gesture, mtouch_event_t *event, void *param, int async);When the gestures library invokes this function, gesture will contain information about the gesture, event will contain information about the touch event that caused the gesture, and async will identify whether the callback was invoked from an event (0) or from a timer callback (1).
switch (gesture->type) {
case GESTURE_TWO_FINGER_PAN: {
...
}
case GESTURE_PINCH: {
...
}
gesture_tfpan_t* tfpan = (gesture_tfpan_t*)gesture;
fprintf(stderr,"Two finger pan: %d, %d",
(tfpan->last_centroid.x - tfpan->centroid.x),
(tfpan->last_centroid.y - tfpan->centroid.y));
if (tfpan->last_centroid.x && tfpan->last_centroid.y) {
viewport_pos[0] = (tfpan->last_centroid.x - tfpan->centroid.x) >> 1;
viewport_pos[1] = (tfpan->last_centroid.y - tfpan->centroid.y) >> 1;
}
Here,
the centroid structure member contains the
coordinates of the midpoint between the final two touches and last_centroid contains the coordinates of the midpoint
between the previous two touches.
while (!shutdown) {
/* Handle user input */
handle_events();
}
handle_events() {
...
/* Re-draw the screen after a screen event */
screen_set_window_property_iv(screen_win,
SCREEN_PROPERTY_SOURCE_POSITION, viewport_pos);
screen_set_window_property_iv(screen_win,
SCREEN_PROPERTY_SOURCE_SIZE, viewport_size);
screen_flush_context(screen_ctx,0);
}
gesture_pinch_t* pinch = (gesture_pinch_t*)gesture;
fprintf(stderr,"Pinch %d, %d",
(pinch->last_distance.x - pinch->distance.x),
(pinch->last_distance.y - pinch->distance.y));
int dist_x = pinch->distance.x;
int dist_y = pinch->distance.y;
int last_dist_x = pinch->last_distance.x;
int last_dist_y = pinch->last_distance.y;
int reldist = sqrt((dist_x)*(dist_x) + (dist_y)*(dist_y));
int last_reldist = sqrt((last_dist_x)*(last_dist_x) +
(last_dist_y)*(last_dist_y));
if (reldist && last_reldist) {
viewport_size[0] += last_reldist - reldist >> 1;
viewport_size[1] += last_reldist - reldist >> 1;
If
the new viewport size does not fit within the screen's limits, the viewport is
adjusted:if (viewport_size[0] < MIN_VIEWPORT_SIZE) {
viewport_size[0] = MIN_VIEWPORT_SIZE;
} else if (viewport_size[0] > MAX_VIEWPORT_SIZE) {
viewport_size[0] = MAX_VIEWPORT_SIZE;
}
if (viewport_size[1] < MIN_VIEWPORT_SIZE) {
viewport_size[1] = MIN_VIEWPORT_SIZE;
} else if (viewport_size[1] > MAX_VIEWPORT_SIZE) {
viewport_size[1] = MAX_VIEWPORT_SIZE;
}
A
final check zooms the viewport position to the center of the image if any of the
viewport size parameters are within the
limits:if (viewport_size[0] > MIN_VIEWPORT_SIZE
&& viewport_size[1] > MIN_VIEWPORT_SIZE
&& viewport_size[0] < MAX_VIEWPORT_SIZE
&& viewport_size[1] < MAX_VIEWPORT_SIZE) {
viewport_pos[0] -= (last_reldist - reldist) >> 2;
viewport_pos[1] -= (last_reldist - reldist) >> 2;
case GESTURE_TAP: {
gesture_tap_t* tap = (gesture_tap_t*)gesture;
printf(stderr,"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;
fprintf(stderr,"Double tap first_x:%d first_y:%d second_x:%d
second_y:%d", d_tap->first_touch.x,
d_tap->first_touch.y, d_tap->second_touch.x,
d_tap->second_touch.y);
break;
}
struct gestures_set * set; set = gestures_set_alloc();
if (NULL != set) {
tap = tap_gesture_alloc(NULL, gesture_callback, set);
double_tap = double_tap_gesture_alloc(NULL, gesture_callback, set);
tfpan_gesture_alloc(NULL, gesture_callback, set);
pinch_gesture_alloc(NULL, gesture_callback, set);
} else {
fprintf(stderr, "Failed to allocate gestures set\n");
}
handle_screen_event(bps_event_t *event)
{
int screen_val, rc;
screen_event_t screen_event = screen_event_get_event(event);
mtouch_event_t mtouch_event;
rc = screen_get_event_property_iv(screen_event,
SCREEN_PROPERTY_TYPE, &screen_val);
if(screen_val == SCREEN_EVENT_MTOUCH_TOUCH
|| screen_val == SCREEN_EVENT_MTOUCH_MOVE
|| screen_val == SCREEN_EVENT_MTOUCH_RELEASE) {
rc = screen_get_mtouch_event(screen_event, &mtouch_event, 0);
if (rc) {
fprintf(stderr, "Error: failed to get mtouch event\n");
}
rc = gestures_set_process_event(set, &mtouch_event, NULL);
In
this function, the determination of a gesture event is based on whether the incoming
event is a touch, move, or release event. If it is one of these events, the
application calls gestures_set_process_event().if (!rc) {
if (mtouch_event.contact_id == 0) {
if(last_touch[0] && last_touch[1]) {
fprintf(stderr,"Pan %d %d\n",
(last_touch[0] - mtouch_event.x),
(last_touch[1] - mtouch_event.y));
viewport_pos[0] = (last_touch[0] - mtouch_event.x) >> 1;
viewport_pos[1] = (last_touch[1] - mtouch_event.y) >> 1;
}
last_touch[0] = mtouch_event.x;
last_touch[1] = mtouch_event.y;
}
}
if (NULL != set) {
gestures_set_free(set);
set = NULL;
}
That's it! The application can now set up the gestures library, process gesture events, and clean up after itself.