mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-20 21:35:19 +08:00
feat(indev): add multi touch gestures (#7078)
This commit is contained in:
@@ -123,7 +123,6 @@ If you did some action on a gesture you can call
|
||||
:cpp:expr:`lv_indev_wait_release(lv_indev_active())` in the event handler to
|
||||
prevent LVGL sending further input-device-related events.
|
||||
|
||||
|
||||
.. _indev_crown:
|
||||
|
||||
Crown Behavior
|
||||
@@ -157,6 +156,72 @@ For example, if both the indev and widget sensitivity is set to 128 (0.5), the i
|
||||
diff will be multiplied by 0.25. The value of the Widget will be incremented by that
|
||||
value or the Widget will be scrolled that amount of pixels.
|
||||
|
||||
Multi-touch gestures
|
||||
====================
|
||||
|
||||
LVGL has the ability to recognize multi-touch gestures, when a gesture
|
||||
is detected a ``LV_EVENT_GESTURE`` is passed to the object on which the
|
||||
gesture occurred. Currently, only the pinch gesture is supported
|
||||
more gesture types will be implemented soon.
|
||||
|
||||
To enable the multi-touch gesture recognition set the
|
||||
``LV_USE_GESTURE_RECOGNITION`` option in the ``lv_conf.h`` file.
|
||||
|
||||
Touch event collection
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The driver or application collects touch events until the indev read callback
|
||||
is called. It is the responsibility of the driver to call
|
||||
the gesture recognition function of the appropriate type. For example
|
||||
to recognise pinch gestures call ``lv_indev_gesture_detect_pinch``.
|
||||
|
||||
After calling the gesture detection function, it's necessary to call
|
||||
the ``lv_indev_set_gesture_data`` function to set the ``gesture_data``
|
||||
and ``gesture_type`` fields of the structure ``lv_indev_data_t``
|
||||
|
||||
.. code-block::
|
||||
|
||||
/* The recognizer keeps the state of the gesture */
|
||||
static lv_indev_gesture_recognizer_t recognizer;
|
||||
|
||||
/* An array that stores the collected touch events */
|
||||
static lv_indev_touch_data_t touches[10];
|
||||
|
||||
/* A counter that needs to be incremented each time a touch event is recieved */
|
||||
static uint8_t touch_cnt;
|
||||
|
||||
static void touch_read_callback(lv_indev_t * drv, lv_indev_data_t * data)
|
||||
{
|
||||
|
||||
lv_indev_touch_data_t * touch;
|
||||
uint8_t i;
|
||||
|
||||
|
||||
touch = &touches[0];
|
||||
lv_indev_gesture_detect_pinch(recognizer, &touches[0],
|
||||
touch_cnt);
|
||||
|
||||
touch_cnt = 0;
|
||||
|
||||
/* Set the gesture information, before returning to LVGL */
|
||||
lv_indev_set_gesture_data(data, recognizer);
|
||||
|
||||
}
|
||||
|
||||
A touch event is represented by the ``lv_indev_touch_data_t`` structure, the fields
|
||||
being 1:1 compatible with events emitted by the `libinput <https://wayland.freedesktop.org/libinput/doc/latest/>`_ library
|
||||
|
||||
Handling touch events
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Touch events are handled like any other event. First, setup a listener for the ``LV_EVENT_GESTURE`` event type by defining and setting the callback function.
|
||||
|
||||
The state or scale of the pinch gesture can be retrieved by
|
||||
calling the ``lv_event_get_pinch_scale`` and ``lv_indev_get_gesture_state`` from within the
|
||||
callback.
|
||||
|
||||
An example of such an application is available in
|
||||
the source tree ``examples/others/gestures/lv_example_gestures.c``
|
||||
|
||||
Keypad or Keyboard
|
||||
------------------
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* @file lv_example_gestures.c
|
||||
*
|
||||
* This is a simple example program that demonstrates how to use
|
||||
* the gesture recognition API, please refer to lv_indev_gesture.h or the documentation
|
||||
* for more details
|
||||
*
|
||||
* The application starts with a single rectangle that is scaled when a pinch gesture
|
||||
* is detected. A single finger moves the rectangle around,
|
||||
*
|
||||
* Copyright (c) 2024 EDGEMTech Ltd
|
||||
*
|
||||
* Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch)
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_examples.h"
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION && \
|
||||
LV_USE_FLOAT
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define RECT_INIT_WIDTH 300.0
|
||||
#define RECT_INIT_HEIGHT 300.0
|
||||
#define RECT_COLOR 0xC1BCFF
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void label_scale(lv_event_t * gesture_event);
|
||||
static void label_move(lv_event_t * event);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static lv_obj_t * label;
|
||||
static lv_style_t label_style;
|
||||
static float label_width;
|
||||
static float label_height;
|
||||
static float label_x;
|
||||
static float label_y;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Entry point it creates the screen, and the label
|
||||
* Set event callbacks on the label
|
||||
*/
|
||||
void lv_example_gestures(void)
|
||||
{
|
||||
lv_obj_t * rectangle;
|
||||
lv_obj_t * root_view;
|
||||
|
||||
label_width = RECT_INIT_WIDTH;
|
||||
label_height = RECT_INIT_HEIGHT;
|
||||
label_y = label_x = 300;
|
||||
|
||||
root_view = lv_screen_active();
|
||||
|
||||
lv_obj_set_style_bg_color(root_view, lv_color_hex(0xFFFFFF), LV_PART_MAIN);
|
||||
label = lv_label_create(root_view);
|
||||
lv_obj_remove_flag(root_view, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_label_set_text(label, "Zoom or move");
|
||||
lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
lv_style_init(&label_style);
|
||||
lv_style_set_bg_color(&label_style, lv_color_hex(RECT_COLOR));
|
||||
lv_style_set_bg_opa(&label_style, LV_OPA_COVER);
|
||||
|
||||
lv_style_set_width(&label_style, (int)label_width);
|
||||
lv_style_set_height(&label_style, (int)label_height);
|
||||
|
||||
lv_style_set_x(&label_style, (int)label_x);
|
||||
lv_style_set_y(&label_style, (int)label_y);
|
||||
|
||||
lv_obj_add_style(label, &label_style, LV_STATE_DEFAULT);
|
||||
|
||||
lv_obj_add_event_cb(label, label_scale, LV_EVENT_GESTURE, label);
|
||||
lv_obj_add_event_cb(label, label_move, LV_EVENT_PRESSING, label);
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called when a pinch event occurs - scales the label
|
||||
* @param gesture_event point to a LV_EVENT_PINCH event
|
||||
*/
|
||||
static void label_scale(lv_event_t * gesture_event)
|
||||
{
|
||||
|
||||
static int initial_w = -1;
|
||||
static int initial_h = -1;
|
||||
lv_indev_gesture_state_t state;
|
||||
lv_point_t center_pnt;
|
||||
float scale;
|
||||
|
||||
scale = lv_event_get_pinch_scale(gesture_event);
|
||||
state = lv_event_get_gesture_state(gesture_event);
|
||||
|
||||
lv_indev_get_point(lv_indev_active(), ¢er_pnt);
|
||||
|
||||
if(state == LV_INDEV_GESTURE_STATE_ENDED) {
|
||||
/* Pinch gesture has ended - reset the width/height for the next pinch gesture*/
|
||||
initial_w = -1;
|
||||
initial_h = -1;
|
||||
|
||||
LV_LOG_TRACE("label end scale: %g %d\n", scale, state);
|
||||
return;
|
||||
}
|
||||
|
||||
if(initial_h == -1 || initial_w == -1) {
|
||||
|
||||
LV_ASSERT(state == LV_INDEV_GESTURE_STATE_RECOGNIZED);
|
||||
|
||||
/* Pinch gesture has been recognized - this is the first event in a series of recognized events */
|
||||
/* The scaling is applied relative to the original width/height of the rectangle */
|
||||
initial_w = label_width;
|
||||
initial_h = label_height;
|
||||
|
||||
LV_LOG_TRACE("label start scale: %g\n", scale);
|
||||
}
|
||||
|
||||
/* The gesture has started or is on-going */
|
||||
|
||||
/* Avoids a situation where the rectangle becomes too small,
|
||||
* do not perform the scaling - leave straight away */
|
||||
if(scale < 0.4) {
|
||||
return;
|
||||
}
|
||||
|
||||
label_width = initial_w * scale;
|
||||
label_height = initial_h * scale;
|
||||
label_x = center_pnt.x - label_width / 2;
|
||||
label_y = center_pnt.y - label_height / 2;
|
||||
|
||||
LV_LOG_TRACE("label scale: %g label x: %g label y: %g w: %g h: %g\n",
|
||||
scale, label_x, label_y, label_width, label_height);
|
||||
|
||||
/* Update position and size */
|
||||
lv_style_set_width(&label_style, (int)label_width);
|
||||
lv_style_set_height(&label_style, (int)label_height);
|
||||
lv_style_set_x(&label_style, (int)label_x);
|
||||
lv_style_set_y(&label_style, (int)label_y);
|
||||
|
||||
lv_obj_add_style(label, &label_style, LV_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a LV_EVENT_PRESSING occurs on the rectangle - moves the label
|
||||
* @param event pointer to the event
|
||||
*/
|
||||
static void label_move(lv_event_t * event)
|
||||
{
|
||||
lv_point_t pnt;
|
||||
lv_indev_gesture_state_t state;
|
||||
|
||||
state = lv_event_get_gesture_state(event);
|
||||
lv_indev_get_point(lv_indev_active(), &pnt);
|
||||
|
||||
/* Do not move and when a pinch gesture is ongoing */
|
||||
if(state == LV_INDEV_GESTURE_STATE_RECOGNIZED) {
|
||||
return;
|
||||
}
|
||||
|
||||
LV_LOG_TRACE("label move %p x: %d y: %d\n", event, pnt.x, pnt.y);
|
||||
|
||||
label_x = pnt.x - label_width / 2;
|
||||
label_y = pnt.y - label_height / 2;
|
||||
|
||||
/* Update position */
|
||||
lv_style_set_x(&label_style, (int)label_x);
|
||||
lv_style_set_y(&label_style, (int)label_y);
|
||||
|
||||
lv_obj_add_style(label, &label_style, LV_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
#endif /* LV_USE_GESTURE_RECOGNITION && LV_USE_FLOAT */
|
||||
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************
|
||||
* @file lv_example_gestures.h
|
||||
*
|
||||
* Copyright (c) 2024 EDGEMTech Ltd.
|
||||
*
|
||||
* Author: EDGEMTech Ltd, Erik Tagirov (erik.tagirov@edgemtech.ch)
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef LV_EXAMPLE_GESTURES_H
|
||||
#define LV_EXAMPLE_GESTURES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/* Example entry point */
|
||||
void lv_example_gestures(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_EXAMPLE_GESTURES_H*/
|
||||
@@ -22,6 +22,7 @@ extern "C" {
|
||||
#include "monkey/lv_example_monkey.h"
|
||||
#include "observer/lv_example_observer.h"
|
||||
#include "snapshot/lv_example_snapshot.h"
|
||||
#include "gestures/lv_example_gestures.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
||||
@@ -475,6 +475,10 @@
|
||||
#define LV_VG_LITE_THORVG_THREAD_RENDER 0
|
||||
#endif
|
||||
|
||||
/* Enable the multi-touch gesture recognition feature */
|
||||
/* Gesture recognition requires the use of floats */
|
||||
#define LV_USE_GESTURE_RECOGNITION 0
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
||||
@@ -43,6 +43,7 @@ extern "C" {
|
||||
#include "src/core/lv_obj.h"
|
||||
#include "src/core/lv_group.h"
|
||||
#include "src/indev/lv_indev.h"
|
||||
#include "src/indev/lv_indev_gesture.h"
|
||||
#include "src/core/lv_refr.h"
|
||||
#include "src/display/lv_display.h"
|
||||
|
||||
@@ -130,6 +131,7 @@ extern "C" {
|
||||
#include "src/lvgl_private.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* @file lv_wayland.c - The Wayland client for LVGL applications
|
||||
*
|
||||
* Based on the original file from the repository.
|
||||
*
|
||||
* Porting to LVGL 9.1
|
||||
@@ -43,7 +42,6 @@ typedef int dummy_t; /* Make GCC on windows happy, avoid empty translation un
|
||||
|
||||
#include "lvgl.h"
|
||||
|
||||
|
||||
#if !LV_WAYLAND_WL_SHELL
|
||||
#include "wayland_xdg_shell.h"
|
||||
#define LV_WAYLAND_XDG_SHELL 1
|
||||
@@ -101,6 +99,7 @@ enum object_type {
|
||||
#define LAST_DECORATION (OBJECT_BORDER_RIGHT)
|
||||
#define NUM_DECORATIONS (LAST_DECORATION-FIRST_DECORATION+1)
|
||||
|
||||
|
||||
struct window;
|
||||
struct input {
|
||||
struct {
|
||||
@@ -117,11 +116,12 @@ struct input {
|
||||
lv_indev_state_t state;
|
||||
} keyboard;
|
||||
|
||||
struct {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
lv_indev_state_t state;
|
||||
} touch;
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
lv_indev_touch_data_t touches[10];
|
||||
uint8_t touch_event_cnt;
|
||||
uint8_t primary_id;
|
||||
lv_indev_gesture_recognizer_t recognizer;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct seat {
|
||||
@@ -878,11 +878,14 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
||||
.modifiers = keyboard_handle_modifiers,
|
||||
};
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
|
||||
static void touch_handle_down(void * data, struct wl_touch * wl_touch,
|
||||
uint32_t serial, uint32_t time, struct wl_surface * surface,
|
||||
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
|
||||
{
|
||||
struct application * app = data;
|
||||
uint8_t i;
|
||||
|
||||
LV_UNUSED(id);
|
||||
LV_UNUSED(time);
|
||||
@@ -894,11 +897,16 @@ static void touch_handle_down(void * data, struct wl_touch * wl_touch,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the touch down event */
|
||||
app->touch_obj = wl_surface_get_user_data(surface);
|
||||
i = app->touch_obj->input.touch_event_cnt;
|
||||
|
||||
app->touch_obj->input.touch.x = wl_fixed_to_int(x_w);
|
||||
app->touch_obj->input.touch.y = wl_fixed_to_int(y_w);
|
||||
app->touch_obj->input.touch.state = LV_INDEV_STATE_PRESSED;
|
||||
app->touch_obj->input.touches[i].point.x = wl_fixed_to_int(x_w);
|
||||
app->touch_obj->input.touches[i].point.y = wl_fixed_to_int(y_w);
|
||||
app->touch_obj->input.touches[i].id = id;
|
||||
app->touch_obj->input.touches[i].timestamp = time;
|
||||
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_PRESSED;
|
||||
app->touch_obj->input.touch_event_cnt++;
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
struct window * window = app->touch_obj->window;
|
||||
@@ -927,17 +935,25 @@ static void touch_handle_up(void * data, struct wl_touch * wl_touch,
|
||||
uint32_t serial, uint32_t time, int32_t id)
|
||||
{
|
||||
struct application * app = data;
|
||||
uint8_t i;
|
||||
|
||||
LV_UNUSED(serial);
|
||||
LV_UNUSED(time);
|
||||
LV_UNUSED(id);
|
||||
LV_UNUSED(wl_touch);
|
||||
|
||||
if(!app->touch_obj) {
|
||||
return;
|
||||
}
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
/* Create a released event */
|
||||
i = app->touch_obj->input.touch_event_cnt;
|
||||
|
||||
app->touch_obj->input.touch.state = LV_INDEV_STATE_RELEASED;
|
||||
app->touch_obj->input.touches[i].point.x = 0;
|
||||
app->touch_obj->input.touches[i].point.y = 0;
|
||||
app->touch_obj->input.touches[i].id = id;
|
||||
app->touch_obj->input.touches[i].timestamp = time;
|
||||
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_RELEASED;
|
||||
|
||||
app->touch_obj->input.touch_event_cnt++;
|
||||
#endif
|
||||
|
||||
#if LV_WAYLAND_WINDOW_DECORATIONS
|
||||
struct window * window = app->touch_obj->window;
|
||||
@@ -962,30 +978,56 @@ static void touch_handle_up(void * data, struct wl_touch * wl_touch,
|
||||
xdg_toplevel_set_minimized(window->xdg_toplevel);
|
||||
window->flush_pending = true;
|
||||
}
|
||||
#endif // LV_WAYLAND_XDG_SHELL
|
||||
#endif /* LV_WAYLAND_XDG_SHELL */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif // LV_WAYLAND_WINDOW_DECORATIONS
|
||||
#endif /* LV_WAYLAND_WINDOW_DECORATIONS */
|
||||
|
||||
app->touch_obj = NULL;
|
||||
}
|
||||
|
||||
static void touch_handle_motion(void * data, struct wl_touch * wl_touch,
|
||||
uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
|
||||
{
|
||||
struct application * app = data;
|
||||
lv_indev_touch_data_t * touch;
|
||||
lv_indev_touch_data_t * cur;
|
||||
uint8_t i;
|
||||
|
||||
LV_UNUSED(time);
|
||||
LV_UNUSED(id);
|
||||
LV_UNUSED(wl_touch);
|
||||
|
||||
if(!app->touch_obj) {
|
||||
return;
|
||||
/* Update the contact point of the corresponding id with the latest coordinate */
|
||||
touch = &app->touch_obj->input.touches[0];
|
||||
cur = NULL;
|
||||
|
||||
for(i = 0; i < app->touch_obj->input.touch_event_cnt; i++) {
|
||||
if(touch->id == id) {
|
||||
cur = touch;
|
||||
}
|
||||
touch++;
|
||||
}
|
||||
|
||||
if(cur == NULL) {
|
||||
|
||||
i = app->touch_obj->input.touch_event_cnt;
|
||||
app->touch_obj->input.touches[i].point.x = wl_fixed_to_int(x_w);
|
||||
app->touch_obj->input.touches[i].point.y = wl_fixed_to_int(y_w);
|
||||
app->touch_obj->input.touches[i].id = id;
|
||||
app->touch_obj->input.touches[i].timestamp = time;
|
||||
app->touch_obj->input.touches[i].state = LV_INDEV_STATE_PRESSED;
|
||||
app->touch_obj->input.touch_event_cnt++;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
cur->point.x = wl_fixed_to_int(x_w);
|
||||
cur->point.y = wl_fixed_to_int(y_w);
|
||||
cur->id = id;
|
||||
cur->timestamp = time;
|
||||
}
|
||||
|
||||
app->touch_obj->input.touch.x = wl_fixed_to_int(x_w);
|
||||
app->touch_obj->input.touch.y = wl_fixed_to_int(y_w);
|
||||
}
|
||||
|
||||
static void touch_handle_frame(void * data, struct wl_touch * wl_touch)
|
||||
@@ -1009,6 +1051,8 @@ static const struct wl_touch_listener touch_listener = {
|
||||
.cancel = touch_handle_cancel,
|
||||
};
|
||||
|
||||
#endif /* END LV_USE_GESTURE_RECOGNITION */
|
||||
|
||||
static void seat_handle_capabilities(void * data, struct wl_seat * wl_seat, enum wl_seat_capability caps)
|
||||
{
|
||||
struct application * app = data;
|
||||
@@ -1039,10 +1083,12 @@ static void seat_handle_capabilities(void * data, struct wl_seat * wl_seat, enum
|
||||
seat->wl_keyboard = NULL;
|
||||
}
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
if((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->wl_touch) {
|
||||
seat->wl_touch = wl_seat_get_touch(wl_seat);
|
||||
wl_touch_add_listener(seat->wl_touch, &touch_listener, app);
|
||||
}
|
||||
#endif
|
||||
else if(!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch) {
|
||||
wl_touch_destroy(seat->wl_touch);
|
||||
seat->wl_touch = NULL;
|
||||
@@ -2223,6 +2269,7 @@ skip:
|
||||
static void _lv_wayland_handle_input(void)
|
||||
{
|
||||
int prepare_read = wl_display_prepare_read(application.display);
|
||||
|
||||
while(prepare_read != 0) {
|
||||
wl_display_dispatch_pending(application.display);
|
||||
}
|
||||
@@ -2249,13 +2296,6 @@ static void _lv_wayland_handle_output(void)
|
||||
window->shall_close = false;
|
||||
shall_flush = true;
|
||||
|
||||
window->body->input.touch.x = 0;
|
||||
window->body->input.touch.y = 0;
|
||||
window->body->input.touch.state = LV_INDEV_STATE_RELEASED;
|
||||
if(window->application->touch_obj == window->body) {
|
||||
window->application->touch_obj = NULL;
|
||||
}
|
||||
|
||||
window->body->input.pointer.x = 0;
|
||||
window->body->input.pointer.y = 0;
|
||||
window->body->input.pointer.left_button = LV_INDEV_STATE_RELEASED;
|
||||
@@ -2331,18 +2371,40 @@ static void _lv_wayland_keyboard_read(lv_indev_t * drv, lv_indev_data_t * data)
|
||||
data->state = window->body->input.keyboard.state;
|
||||
}
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
|
||||
static void _lv_wayland_touch_read(lv_indev_t * drv, lv_indev_data_t * data)
|
||||
{
|
||||
|
||||
struct window * window = lv_display_get_user_data(lv_indev_get_display(drv));
|
||||
lv_indev_touch_data_t * touch;
|
||||
bool is_active;
|
||||
lv_indev_gesture_recognizer_t * recognizer;
|
||||
uint8_t touch_cnt;
|
||||
uint8_t i;
|
||||
|
||||
if(!window || window->closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->point.x = window->body->input.touch.x;
|
||||
data->point.y = window->body->input.touch.y;
|
||||
data->state = window->body->input.touch.state;
|
||||
/* Collect touches if there are any - send them to the gesture recognizer */
|
||||
recognizer = &window->body->input.recognizer;
|
||||
touch = &window->body->input.touches[0];
|
||||
|
||||
LV_LOG_TRACE("collected touch events: %d", window->body->input.touch_event_cnt);
|
||||
|
||||
lv_indev_gesture_detect_pinch(recognizer, &window->body->input.touches[0],
|
||||
window->body->input.touch_event_cnt);
|
||||
|
||||
window->body->input.touch_event_cnt = 0;
|
||||
|
||||
/* Set the gesture information, before returning to LVGL */
|
||||
lv_indev_set_gesture_data(data, recognizer);
|
||||
|
||||
}
|
||||
|
||||
#endif /* END LV_USE_GESTURE_RECOGNITION */
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
@@ -2569,6 +2631,8 @@ lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char
|
||||
LV_LOG_ERROR("failed to register pointeraxis indev");
|
||||
}
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
|
||||
window->lv_indev_touch = lv_indev_create();
|
||||
lv_indev_set_type(window->lv_indev_touch, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(window->lv_indev_touch, _lv_wayland_touch_read);
|
||||
@@ -2578,6 +2642,8 @@ lv_display_t * lv_wayland_window_create(uint32_t hor_res, uint32_t ver_res, char
|
||||
LV_LOG_ERROR("failed to register touch indev");
|
||||
}
|
||||
|
||||
#endif /* END LV_USE_GESTURE_RECOGNITION */
|
||||
|
||||
window->lv_indev_keyboard = lv_indev_create();
|
||||
lv_indev_set_type(window->lv_indev_keyboard, LV_INDEV_TYPE_KEYPAD);
|
||||
lv_indev_set_read_cb(window->lv_indev_keyboard, _lv_wayland_keyboard_read);
|
||||
|
||||
@@ -27,6 +27,7 @@ extern "C" {
|
||||
|
||||
#include "../../display/lv_display.h"
|
||||
#include "../../indev/lv_indev.h"
|
||||
#include "../../indev/lv_indev_gesture.h"
|
||||
|
||||
#if LV_USE_WAYLAND
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* INCLUDES
|
||||
********************/
|
||||
#include "lv_indev_scroll.h"
|
||||
#include "lv_indev_gesture.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../core/lv_obj_private.h"
|
||||
@@ -728,6 +729,9 @@ static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
i->pointer.act_point.y = data->point.y;
|
||||
i->pointer.diff = data->enc_diff;
|
||||
|
||||
i->gesture_type = data->gesture_type;
|
||||
i->gesture_data = data->gesture_data;
|
||||
|
||||
/*Process the diff first as scrolling will be processed in indev_proc_release*/
|
||||
indev_proc_pointer_diff(i);
|
||||
|
||||
@@ -1277,13 +1281,24 @@ static void indev_proc_press(lv_indev_t * indev)
|
||||
indev->pointer.press_moved = 1;
|
||||
}
|
||||
|
||||
/* Send a gesture event to a potential indev cb callback, even if no object was found */
|
||||
if(indev->gesture_type != LV_INDEV_GESTURE_NONE) {
|
||||
lv_indev_send_event(indev, LV_EVENT_GESTURE, indev_act);
|
||||
}
|
||||
|
||||
if(indev_obj_act) {
|
||||
const bool is_enabled = !lv_obj_has_state(indev_obj_act, LV_STATE_DISABLED);
|
||||
|
||||
if(indev->gesture_type != LV_INDEV_GESTURE_NONE) {
|
||||
/* NOTE: hardcoded to pinch for now */
|
||||
if(send_event(LV_EVENT_GESTURE, indev_act) == LV_RESULT_INVALID) return;
|
||||
}
|
||||
|
||||
if(is_enabled) {
|
||||
if(send_event(LV_EVENT_PRESSING, indev_act) == LV_RESULT_INVALID) return;
|
||||
}
|
||||
|
||||
|
||||
if(indev_act->wait_until_release) return;
|
||||
|
||||
lv_indev_scroll_handler(indev);
|
||||
@@ -1363,11 +1378,20 @@ static void indev_proc_release(lv_indev_t * indev)
|
||||
lv_timer_pause(indev->read_timer);
|
||||
}
|
||||
|
||||
/* Send a gesture event to a potential indev cb callback, even if no object was found */
|
||||
if(indev->gesture_type != LV_INDEV_GESTURE_NONE) {
|
||||
lv_indev_send_event(indev, LV_EVENT_GESTURE, indev_act);
|
||||
}
|
||||
|
||||
if(indev_obj_act) {
|
||||
LV_LOG_INFO("released");
|
||||
|
||||
const bool is_enabled = !lv_obj_has_state(indev_obj_act, LV_STATE_DISABLED);
|
||||
|
||||
if(is_enabled && indev->gesture_type != LV_INDEV_GESTURE_NONE) {
|
||||
if(send_event(LV_EVENT_GESTURE, indev_act) == LV_RESULT_INVALID) return;
|
||||
}
|
||||
|
||||
if(is_enabled) {
|
||||
if(send_event(LV_EVENT_RELEASED, indev_act) == LV_RESULT_INVALID) return;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,17 @@ typedef enum {
|
||||
LV_INDEV_MODE_EVENT,
|
||||
} lv_indev_mode_t;
|
||||
|
||||
|
||||
/* Supported types of gestures */
|
||||
typedef enum {
|
||||
LV_INDEV_GESTURE_NONE = 0,
|
||||
LV_INDEV_GESTURE_PINCH,
|
||||
LV_INDEV_GESTURE_SWIPE,
|
||||
LV_INDEV_GESTURE_ROTATE,
|
||||
LV_INDEV_GESTURE_SCROLL, /* Used with scrollwheels */
|
||||
LV_INDEV_GESTURE_CNT, /* Total number of gestures types */
|
||||
} lv_indev_gesture_type_t;
|
||||
|
||||
/** Data structure passed to an input driver to fill*/
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
@@ -56,6 +67,10 @@ typedef struct {
|
||||
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_RELEASED or LV_INDEV_STATE_PRESSED*/
|
||||
bool continue_reading; /**< If set to true, the read callback is invoked again, unless the device is in event-driven mode*/
|
||||
|
||||
lv_indev_gesture_type_t gesture_type;
|
||||
void * gesture_data;
|
||||
|
||||
} lv_indev_data_t;
|
||||
|
||||
typedef void (*lv_indev_read_cb_t)(lv_indev_t * indev, lv_indev_data_t * data);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* @file lv_indev_gesture.h
|
||||
*
|
||||
* Copyright (c) 2024 EDGEMTech Ltd.
|
||||
*
|
||||
* Author EDGEMTech Ltd, (erik.tagirov@edgemtech.ch)
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef LV_INDEV_GESTURE_H
|
||||
#define LV_INDEV_GESTURE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../core/lv_obj.h"
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
|
||||
#if LV_USE_FLOAT == 0
|
||||
#error "LV_USE_FLOAT is required for gesture detection."
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* Opaque types defined in the private header */
|
||||
struct lv_indev_gesture;
|
||||
struct lv_indev_gesture_configuration;
|
||||
|
||||
typedef struct lv_indev_gesture lv_indev_gesture_t;
|
||||
typedef struct lv_indev_gesture_configuration lv_indev_gesture_configuration_t;
|
||||
|
||||
/* The states of a gesture recognizer */
|
||||
typedef enum {
|
||||
LV_INDEV_GESTURE_STATE_NONE = 0, /* Beginning & end */
|
||||
LV_INDEV_GESTURE_STATE_ONGOING, /* Set when there is a probability */
|
||||
LV_INDEV_GESTURE_STATE_RECOGNIZED, /* Recognized, the event will contain touch info */
|
||||
LV_INDEV_GESTURE_STATE_ENDED, /* A recognized gesture has ended */
|
||||
LV_INDEV_GESTURE_STATE_CANCELED, /* Canceled - usually a finger is lifted */
|
||||
} lv_indev_gesture_state_t;
|
||||
|
||||
/* Data structures for touch events - used to repsensent a libinput event */
|
||||
/* Emitted by devices capable of tracking identifiable contacts (type B) */
|
||||
typedef struct {
|
||||
lv_point_t point; /* Coordinates of the touch */
|
||||
lv_indev_state_t state; /* The state i.e PRESSED or RELEASED */
|
||||
uint8_t id; /* Identification/slot of the contact point */
|
||||
uint32_t timestamp; /* Timestamp in milliseconds */
|
||||
} lv_indev_touch_data_t;
|
||||
|
||||
/* Gesture recognizer */
|
||||
typedef struct {
|
||||
lv_indev_gesture_type_t type; /* The detected gesture type */
|
||||
lv_indev_gesture_state_t state; /* The gesture state ongoing, recognized */
|
||||
lv_indev_gesture_t * info; /* Information on the motion of each touch point */
|
||||
float scale; /* Relevant for the pinch gesture */
|
||||
float rotation; /* Relevant for rotation */
|
||||
float distance; /* Relevant for swipes */
|
||||
float speed;
|
||||
|
||||
lv_indev_gesture_configuration_t * config;
|
||||
|
||||
} lv_indev_gesture_recognizer_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
|
||||
/* PINCH Gesture */
|
||||
|
||||
/**
|
||||
* Detects a pinch gesture
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
* @param touches pointer to the first element of the collected touch events
|
||||
* @param touch_cnt length of passed touch event array.
|
||||
*/
|
||||
void lv_indev_gesture_detect_pinch(lv_indev_gesture_recognizer_t * recognizer, lv_indev_touch_data_t * touches,
|
||||
uint16_t touch_cnt);
|
||||
|
||||
|
||||
/**
|
||||
* Set the threshold for the pinch gesture scale up, when the scale factor of gesture
|
||||
* reaches the threshold events get sent
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
* @param touches pointer to the first element of the collected touch events
|
||||
* @param touch_cnt length of passed touch event array.
|
||||
*/
|
||||
void lv_indev_set_pinch_up_threshold(lv_indev_gesture_recognizer_t * recognizer, float threshold);
|
||||
|
||||
/**
|
||||
* Set the threshold for the pinch gesture scale down, when the scale factor of gesture
|
||||
* reaches the threshold events get sent
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
* @param touches pointer to the first element of the collected touch events
|
||||
* @param touch_cnt length of passed touch event array.
|
||||
*/
|
||||
void lv_indev_set_pinch_down_threshold(lv_indev_gesture_recognizer_t * recognizer, float threshold);
|
||||
|
||||
/**
|
||||
* Obtains the current scale of a pinch gesture
|
||||
* @param gesture_event pointer to a gesture recognizer event
|
||||
* @return the scale of the current gesture
|
||||
*/
|
||||
float lv_event_get_pinch_scale(lv_event_t * gesture_event);
|
||||
|
||||
/**
|
||||
* Sets the state of the recognizer to a indev data structure,
|
||||
* it is usually called from the indev read callback
|
||||
* @param data the indev data
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
*/
|
||||
void lv_indev_set_gesture_data(lv_indev_data_t * data, lv_indev_gesture_recognizer_t * recognizer);
|
||||
|
||||
/**
|
||||
* Obtains the center point of a gesture
|
||||
* @param gesture_event pointer to a gesture recognizer event
|
||||
* @param point pointer to a point
|
||||
*/
|
||||
void lv_indev_get_gesture_center_point(lv_indev_gesture_recognizer_t * recognizer, lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Obtains the current state of the gesture recognizer attached to an event
|
||||
* @param gesture_event pointer to a gesture recognizer event
|
||||
* @return current state of the gesture recognizer
|
||||
*/
|
||||
lv_indev_gesture_state_t lv_event_get_gesture_state(lv_event_t * gesture_event);
|
||||
|
||||
/**
|
||||
* Obtains the coordinates of the current primary point
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
* @param point pointer to a point
|
||||
*/
|
||||
void lv_indev_get_gesture_primary_point(lv_indev_gesture_recognizer_t * recognizer, lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Allows to determine if there is an are ongoing gesture
|
||||
* @param recognizer pointer to a gesture recognizer
|
||||
* @return false if there are no contact points, or the gesture has ended - true otherwise
|
||||
*/
|
||||
bool lv_indev_recognizer_is_active(lv_indev_gesture_recognizer_t * recognizer);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* END LV_USE_RECOGNITION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /* END LV_INDEV_GESTURE_H */
|
||||
@@ -0,0 +1,93 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* @file lv_indev_gesture_private.h
|
||||
*
|
||||
* Contains declarations and definition that are internal
|
||||
* to the gesture detection logic
|
||||
*
|
||||
* Copyright (c) 2024 EDGEMTech Ltd.
|
||||
*
|
||||
* Author EDGEMTech Ltd, (erik.tagirov@edgemtech.ch)
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef LV_INDEV_GESTURE_PRIVATE_H
|
||||
#define LV_INDEV_GESTURE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../core/lv_obj.h"
|
||||
|
||||
#if LV_USE_GESTURE_RECOGNITION
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_GESTURE_MAX_POINTS 2
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* Represent the motion of a finger */
|
||||
struct lv_indev_gesture_motion {
|
||||
int8_t finger; /* The ID of the tracked finger */
|
||||
lv_point_t start_point; /* The coordinates where the DOWN event occured */
|
||||
lv_point_t point; /* The current coordinates */
|
||||
lv_indev_state_t state; /* DEBUG: The state i.e PRESSED or RELEASED */
|
||||
};
|
||||
|
||||
typedef struct lv_indev_gesture_motion lv_indev_gesture_motion_t;
|
||||
|
||||
/* General descriptor for a gesture, used by recognizer state machines to track
|
||||
* the scale, rotation, and translation NOTE: (this will likely become private) */
|
||||
struct lv_indev_gesture {
|
||||
|
||||
/* Motion descriptor, stores the coordinates and velocity of a contact point */
|
||||
lv_indev_gesture_motion_t motions[LV_GESTURE_MAX_POINTS];
|
||||
|
||||
lv_point_t center; /* Center point */
|
||||
float scale; /* Scale factor & previous scale factor */
|
||||
float p_scale;
|
||||
float scale_factors_x[LV_GESTURE_MAX_POINTS]; /* Scale factor relative to center for each point */
|
||||
float scale_factors_y[LV_GESTURE_MAX_POINTS];
|
||||
|
||||
float delta_x; /* Translation & previous translation */
|
||||
float delta_y;
|
||||
float p_delta_x;
|
||||
float p_delta_y;
|
||||
float rotation; /* Rotation & previous rotation*/
|
||||
float p_rotation;
|
||||
uint8_t finger_cnt; /* Current number of contact points */
|
||||
|
||||
};
|
||||
|
||||
struct lv_indev_gesture_configuration {
|
||||
|
||||
float pinch_up_threshold; /* When the gesture reaches the threshold - start sending events */
|
||||
float pinch_down_threshold; /* When the gesture reaches the threshold - start sending events */
|
||||
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* END LV_USE_RECOGNITION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /* END LV_INDEV_GESTURE_PRIVATE_H */
|
||||
@@ -112,6 +112,9 @@ struct _lv_indev_t {
|
||||
here by the buttons*/
|
||||
lv_event_list_t event_list;
|
||||
lv_anim_t * scroll_throw_anim;
|
||||
|
||||
lv_indev_gesture_type_t gesture_type;
|
||||
void * gesture_data;
|
||||
};
|
||||
|
||||
/**********************
|
||||
|
||||
@@ -1367,6 +1367,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable the multi-touch gesture recognition feature */
|
||||
/* Gesture recognition requires the use of floats */
|
||||
#ifndef LV_USE_GESTURE_RECOGNITION
|
||||
#ifdef CONFIG_LV_USE_GESTURE_RECOGNITION
|
||||
#define LV_USE_GESTURE_RECOGNITION CONFIG_LV_USE_GESTURE_RECOGNITION
|
||||
#else
|
||||
#define LV_USE_GESTURE_RECOGNITION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
||||
Reference in New Issue
Block a user