---
title: "Gesture recognizers (touch SDK)"
canonical_url: https://developer.repebble.com/pebbleos/docs/sdk/recognizers/
last_updated: 2026-10-21
sdk_version: 4.33.1
---
# Gesture recognizers (touch SDK)

Source: https://developer.repebble.com/pebbleos/docs/sdk/recognizers/

Gesture recognizers let a third-party app react to raw touch gestures — tap, pan (single-axis drag) and swipe — on touch-capable hardware. They are the building block for a fully custom scroll or drag interaction, as opposed to the fixed behaviour of the built-in `ScrollLayer` / `MenuLayer`.

A recognizer is an opaque object created by one of the constructor functions, attached to a `Window`, and driven by the touch service. When the gesture it watches for progresses, it invokes the `RecognizerEventCb` you supplied with a `RecognizerEvent` describing the transition (`Started`, `Updated`, `Completed`, `Cancelled`). Inside the callback you read the current gesture data with the per-recognizer getters.

## Exported API

Constructors (each returns an owned `Recognizer *`):

- `tap_recognizer_create(event_cb, user_data)`

- `pan_recognizer_create(event_cb, user_data, axis)` — `axis` is `PanAxis_Horizontal` or `PanAxis_Vertical`

- `swipe_recognizer_create(event_cb, user_data, direction_mask)` — a bitwise-OR of `SwipeDirection` values

Gesture data getters (call from the event callback):

- Tap: `tap_recognizer_get_tap_point()`

- Pan: `pan_recognizer_get_total_delta()`, `pan_recognizer_get_delta_since_start()`, `pan_recognizer_get_delta_since_prev()`, `pan_recognizer_get_velocity()`

- Swipe: `swipe_recognizer_get_direction()`, `swipe_recognizer_get_velocity()`

Lifecycle and configuration:

- `window_attach_recognizer(window, recognizer)` / `window_detach_recognizer(window, recognizer)`

- `recognizer_destroy(recognizer)` — destroys an _un-owned_ recognizer; a recognizer owned by a window is destroyed with the window

- `recognizer_set_simultaneous_with(recognizer, cb)` — allow this recognizer to be evaluated at the same time as another

- `recognizer_set_fail_after(recognizer, other)` — only evaluate this recognizer once `other` has failed (e.g. run a tap only after a pan fails)

## Custom live scroll example

A pan recognizer locked to the vertical axis drives a scroll offset that follows the finger in real time. `pan_recognizer_get_delta_since_start()` is exactly `(0, 0)` at the instant the pan Starts, so the content does not jump when the gesture begins.

```
#include \<pebble.h\>static Window \*s\_window;static Layer \*s\_content\_layer;static Recognizer \*s\_pan;static int16\_t s\_scroll\_base;// committed offset (updated on Complete)static int16\_t s\_scroll\_offset; // live offset shown while draggingstatic void content\_update\_proc(Layer \*layer, GContext \*ctx) {// Draw your content shifted by s\_scroll\_offset (negative scrolls up).// ... application-specific drawing ...}static void pan\_handler(const Recognizer \*recognizer, RecognizerEvent event) {switch (event) {case RecognizerEvent\_Started:// Nothing to do: delta\_since\_start is (0, 0) here.break;case RecognizerEvent\_Updated: {GPoint d = pan\_recognizer\_get\_delta\_since\_start(recognizer);s\_scroll\_offset = s\_scroll\_base + d.y;layer\_mark\_dirty(s\_content\_layer);break;}case RecognizerEvent\_Completed:// Commit the live offset. You could also kick off inertial scrolling// here using pan\_recognizer\_get\_velocity().s\_scroll\_base = s\_scroll\_offset;break;case RecognizerEvent\_Cancelled:// Roll back to the last committed position.s\_scroll\_offset = s\_scroll\_base;layer\_mark\_dirty(s\_content\_layer);break;}}static void window\_load(Window \*window) {Layer \*root = window\_get\_root\_layer(window);GRect bounds = layer\_get\_bounds(root);s\_content\_layer = layer\_create(bounds);layer\_set\_update\_proc(s\_content\_layer, content\_update\_proc);layer\_add\_child(root, s\_content\_layer);// Create a vertical pan and let the window own it.s\_pan = pan\_recognizer\_create(pan\_handler, NULL, PanAxis\_Vertical);window\_attach\_recognizer(window, s\_pan);// Attaching alone is not enough while the system recognizer set is live: see// "The competition contract" below for opting the window out of the bridge.}static void window\_unload(Window \*window) {// The window owns s\_pan and destroys it; just drop our own layer.layer\_destroy(s\_content\_layer);}int main(void) {s\_window = window\_create();window\_set\_window\_handlers(s\_window, (WindowHandlers) {.load = window\_load,.unload = window\_unload,});window\_stack\_push(s\_window, true);app\_event\_loop();window\_destroy(s\_window);}
```

## The competition contract

Touch input is dispatched to a single, ordered set of recognizers at a time. The system installs a **global system recognizer set** (the back-swipe, the built-in scrolling, etc.) and that set is evaluated **first**. Because the first set to claim a touch sequence wins, simply attaching your own recognizers to a window is **not enough** while the system set is live — the system recognizers consume the gesture before your app ever sees it, and your recognizers sit in a dead zone.

To take over touch input, an app must opt out of the system set for its window using `window_set_touch_bridge_disabled()`. With the touch bridge disabled on a window, the system recognizer set **fails on Touchdown** for touches on that window, which lets evaluation fall through to the app’s own recognizers — they then receive the full gesture from the first touch event.

The contract in short:

1. System recognizer set is evaluated before app recognizers.

2. While it is live, app recognizers attached to a window never win.

3. `window_set_touch_bridge_disabled()` fails the system set on Touchdown for that window, handing every touch to the app’s recognizers.

Note

`window_set_touch_bridge_disabled()` is exported in this same SDK revision as the recognizer API above, so a live-scroll app can call it in `window_load` to opt its window out of the system bridge and take over touch input.

Generated from PebbleOS [3a7b71785](https://github.com/coredevices/pebbleos/commit/3a7b71785fd439666c4a8bc116f561140e8dec01). This page is maintained in the pebbleos repository: [docs/sdk/recognizers.md](https://github.com/coredevices/pebbleos/blob/3a7b71785fd439666c4a8bc116f561140e8dec01/docs/sdk/recognizers.md).
