黑暗模式
如何使用多点触控
AWTK 提供的多点触控功能主要是为了给用户提供多点触控的基本数据,方便用户开发多点触控的控件或者应用。
一,多点触控的类型
AWTK 一共提供了两种多点触控的类型,分别是获取手指 ID 的可识别手指类型的多点触控和不可以获取手指 ID 的不可识别手指类型的多点触控,下表为两者的区别:
可识别手指类型 | 不可识别手指类型的 | |
---|---|---|
是否需要提供手指 ID | 是 | 否 |
触摸消息是否提供距离增量 | 是 | 是 |
触摸消息是否提供中心点 | 是 | 是 |
触摸消息是否提供旋转角度 | 是 | 只支持两个手指头 |
备注:因为某些触摸硬件是无法提供具体的手指 ID 的,所以 AWTK 特别提供一种不需要手指 ID 的多点触控机制,但是这个机制提供出来的消息是只能支持两个手指头的旋转数据,所以用户需要更加具体情况来旋转使用。
二,多点触控的API
1.可识别手指类型
c
/**
* @method multi_gesture_gesture_touch_fingers_destroy
* 释放可识别手指类型的对象
* @param {multi_gesture_touch_fingers_t*} touch 可识别手指类型的对象。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t multi_gesture_gesture_touch_fingers_destroy(multi_gesture_touch_fingers_t* touch);
/**
* @method multi_gesture_touch_fingers_create
* 创建可识别手指类型的对象
* @param {int32_t} finger_size 可识别手指个数。
*
* @return {multi_gesture_touch_fingers_t*} 成功返回可识别手指类型的对象,失败返回NULL。
*/
multi_gesture_touch_fingers_t* multi_gesture_touch_fingers_create(int32_t finger_size);
/**
* @method multi_gesture_post_event_from_fingers
* 发送多点触控消息
* @param {main_loop_t*} loop 主循环对象
* @param {multi_gesture_touch_fingers_t*} touch 可识别手指类型的对象。
* @param {uint32_t} point_size 手指个数
* @param {multi_touch_point_event_t*} points 手指数据数组
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t multi_gesture_post_event_from_fingers(main_loop_t* loop, multi_gesture_touch_fingers_t* touch, uint32_t point_size, multi_touch_point_event_t* points);
2.不可识别手指类型
c
/**
* @method multi_gesture_gesture_touch_points_destroy
* 释放不可识别手指类型的对象
* @param {multi_gesture_touch_points_t*} touch 不可识别手指类型的对象。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t multi_gesture_gesture_touch_points_destroy(multi_gesture_touch_points_t* touch);
/**
* @method multi_gesture_touch_points_create
* 创建不可识别手指类型的对象
* @param {uint32_t} last_dist_lenght 均值滤波的缓冲长度。
*
* @return {multi_gesture_touch_points_t*} 成功返回不可识别手指类型的对象,失败返回NULL。
*/
multi_gesture_touch_points_t* multi_gesture_touch_points_create(uint32_t last_dist_lenght);
/**
* @method multi_gesture_post_event_from_points
* 发送多点触控消息
* @param {main_loop_t*} loop 主循环对象
* @param {multi_gesture_touch_points_t*} touch 不可识别手指类型的对象。
* @param {uint32_t} point_size 手指个数
* @param {multi_touch_point_event_t*} points 手指数据数组
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t multi_gesture_post_event_from_points(main_loop_t* loop, multi_gesture_touch_points_t* touch, uint32_t point_size, multi_touch_point_event_t* points);
具体用法请参考
三,如何使用
本文使用 github 中 stm32f429 项目为例子,来讲述如何使用 awtk 提供的多点触控方案。
1.适配层
stm32f429 项目中的适配层,把触摸数据发送到 AWTK 消息循环中。
c
/* main_loop_stm32_raw.c */
/* 省略了一部分无关代码 */
#include "base/multi_gesture.inc"
static multi_gesture_touch_points_t* touch_points = NULL;
static multi_gesture_touch_fingers_t* touch_fingers = NULL;
static multi_touch_point_event_t s_points[CT_MAX_TOUCH];
static int last_x = 0;
static int last_y = 0;
static bool_t one_press = FALSE;
static bool_t mult_press = FALSE;
void platform_disaptch_input_down(main_loop_t* loop, int32_t fingers, int32_t last_fingers) {
int32_t i = 0;
uint8_t num_down_fingers = 0;
/* 当前手指个数为 1,并且之前的手指格式为 0 或者 1 的时候,发送普通点击消息 */
if (fingers == 1 && (last_fingers == 0 || last_fingers == 1)) {
if (tp_dev.sta & TP_PRES_DOWN) {
/* 记录已经触发了普通点击 */
one_press = TRUE;
last_x = tp_dev.y[0];
last_y = lcdltdc.pheight - tp_dev.x[0];
main_loop_post_pointer_event(loop, TRUE, last_x, last_y);
}
} else {
/* 把数据转为多点触控的结构体 */
for(i = 0; i < CT_MAX_TOUCH; i++) {
s_points[i].touch_id = 0;
s_points[i].finger_id = i;
if (tp_dev.sta & (1<<i) && (!(tp_dev.y[i] == 0 && tp_dev.x[i] == 0))) {
num_down_fingers++;
if (!(tp_dev.y[i] == 0 && tp_dev.x[i] == 0)) {
s_points[i].x = tp_dev.y[i];
s_points[i].y = lcdltdc.pheight - tp_dev.x[i];
}
s_points[i].type = (s_points[i].type == EVT_MULTI_TOUCH_UP) ? EVT_MULTI_TOUCH_DOWN : EVT_MULTI_TOUCH_MOVE;
} else {
if (s_points[i].type == EVT_MULTI_TOUCH_MOVE || s_points[i].type == EVT_MULTI_TOUCH_DOWN) {
num_down_fingers++;
}
s_points[i].x = 0;
s_points[i].y = 0;
s_points[i].type = EVT_MULTI_TOUCH_UP;
}
}
/* 记录已经触发了多点触控 */
mult_press = TRUE;
/* 使用可识别手指类型发送多点触控消息 */
multi_gesture_post_event_from_fingers(loop, touch_fingers, num_down_fingers, s_points);
/* 使用不可识别手指类型发送多点触控消息 */
//multi_gesture_post_event_from_points(loop, touch_points, num_down_fingers, s_points);
}
}
void platform_disaptch_input_up(main_loop_t* loop, int32_t last_fingers) {
/* 如果触发了普通点击,就发送普通点击控弹起事件 */
if (one_press) {
/* 复位 */
one_press = FALSE;
/* 发送普通点击弹起事件 */
main_loop_post_pointer_event(loop, FALSE, last_x, last_y);
}
/* 如果触发了多点触控,就发送多点触控弹起事件 */
if (mult_press) {
int i = 0;
for(i = 0; i < CT_MAX_TOUCH; i++) {
s_points[i].type = EVT_MULTI_TOUCH_UP;
}
/* 复位 */
mult_press = FALSE;
/* 使用可识别手指类型发送多点触控弹起事件消息 */
multi_gesture_post_event_from_fingers(loop, touch_fingers, last_fingers, s_points);
/* 使用不可识别手指类型发送多点触控弹起事件消息 */
//multi_gesture_post_event_from_points(loop, touch_points, last_fingers, s_points);
}
}
uint8_t platform_disaptch_input(main_loop_t* loop) {
int32_t i = 0;
uint8_t touch_number = 0;
static uint8_t last_touch_number = 0;
tp_dev.scan(0);
/* 计算当前有多少只手指按下 */
for(i = 0; i < CT_MAX_TOUCH; i++) {
if (tp_dev.sta & (1<<i)) {
touch_number++;
}
}
/* 手指个数变化了,所以发送弹起事件 */
if (touch_number != last_touch_number) {
platform_disaptch_input_up(loop, last_touch_number);
}
/* 手指个数大于 0 需要发送按下消息 */
if (touch_number > 0) {
platform_disaptch_input_down(loop, touch_number, last_touch_number);
}
last_touch_number = touch_number;
return 0;
}
extern lcd_t* stm32f429_create_lcd(wh_t w, wh_t h);
lcd_t* platform_create_lcd(wh_t w, wh_t h) {
/* 创建不可识别手指类型的多点触控句柄 */
touch_points = multi_gesture_touch_points_create(15);
/* 创建可识别手指类型的多点触控句柄 */
touch_fingers = multi_gesture_touch_fingers_create(CT_MAX_TOUCH);
memset(s_points, 0x0, sizeof(multi_touch_point_event_t) * CT_MAX_TOUCH);
return stm32f429_create_lcd(w, h);
}
#include "main_loop/main_loop_raw.inc"
备注:
- 上面的代码有两个 for 循环,一个是计算当前按下的手指个数,一个是把硬件的手指坐标数据转换为 multi_touch_point_event_t 类型。
- 只需要把上面 multi_gesture_post_event_form_points 函数取消注释,然后把 multi_gesture_post_event_form_fingers 函数加上注释就可以实现使用不可识别手指类型的多点触控,本例子默认为可识别手指类型的多点触控。
2.应用层
由于多点触控无法通过手指点击坐标来确定具体的控件,所以 AWTK 的多点触控默认会发送给当前选中的窗口上面,所以用户想获取具体的消息,需要通过给当前的窗口注册多点触控消息事件(EVT_MULTI_GESTURE 事件)来获取对应消息,如下代码:
c
static ret_t multi_gesture_view_on_event_multi_gesture(void* ctx, event_t* e) {
multi_gesture_event_t* event = (multi_gesture_event_t*)e;
return_value_if_fail(multi_gesture_view != NULL && e != NULL, RET_BAD_PARAMS);
/* centroid 为中心点
* distance为两点间的距离增量,(-1,0)表示缩小,(0-1)表示增加。
* rotation为旋转角度(幅度)增量,(单位弧度)。
*/
printf("centroid:(%d, %d), distance:%f, rotation:%f \r\n", event->x, event->y, event->distance, event->rotation);
return RET_OK;
}
static ret_t multi_gesture_view_init_multi_gesture_event(widget_t* widget) {
widget_t* win = NULL;
multi_gesture_view_t* multi_gesture_view = MULTI_GESTURE_VIEW(widget);
return_value_if_fail(widget != NULL && multi_gesture_view != NULL, RET_BAD_PARAMS);
if (widget->parent != NULL) {
/* 获取控件的父集窗口,当焦点在控件上面时,父集窗口肯定也是选中的 */
win = widget_get_window(widget);
}
if (win != NULL && multi_gesture_view->event_win != win) {
if (multi_gesture_view->event_id != TK_INVALID_ID) {
/* 切换父集窗口的时候,移除消息,以免父集窗口不一样,导致出错 */
multi_gesture_view_deint_multi_gesture_event(widget);
}
multi_gesture_view->event_win = win;
/* 注册多点触控消息事件 */
multi_gesture_view->event_id = widget_on(win, EVT_MULTI_GESTURE, multi_gesture_view_on_event_multi_gesture, widget);
return multi_gesture_view->event_id != TK_INVALID_ID ? RET_OK : RET_FAIL;
}
return RET_FAIL;
}
备注:用户可以自行根据需求自行写上述代码来获取多点触控消息。