From 99af46c719329e9e22036e1a10e02243342c275f Mon Sep 17 00:00:00 2001 From: xianjimli Date: Tue, 15 Sep 2020 09:23:54 +0800 Subject: [PATCH] support key long press event --- awtk_config.py | 2 +- docs/changes.md | 3 ++ src/base/events.h | 5 ++ src/base/input_device_status.c | 86 ++++++++++++++++++++++++++++++++++ src/base/input_device_status.h | 11 +++++ src/base/widget.c | 19 +++++--- 6 files changed, 118 insertions(+), 8 deletions(-) diff --git a/awtk_config.py b/awtk_config.py index 5df171ae5..3b9b58ee8 100644 --- a/awtk_config.py +++ b/awtk_config.py @@ -162,7 +162,7 @@ OS_PROJECTS=[] OS_WHOLE_ARCHIVE='' if OS_NAME == 'Darwin': TOOLS_NAME = '' - OS_FLAGS='-g -Wall -fPIC ' + OS_FLAGS='-g -Wall -fPIC -DWITHOUT_GLAD=1 ' OS_LIBS = ['stdc++', 'iconv','pthread', 'm', 'dl'] OS_LINKFLAGS='-framework IOKit -framework Cocoa -framework QuartzCore -framework OpenGL -weak_framework Metal -weak_framework MetalKit' COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DHAS_SEM_OPEN ' diff --git a/docs/changes.md b/docs/changes.md index 55fad6aa7..621e81bd9 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,4 +1,7 @@ # 最新动态 +* 2020/09/15 + * 支持长按键事件 + * 2020/09/11 * 支持 packed 图片。 * 增加 [如何使用 packed 图](docs/how_to_use_packed_image.md) diff --git a/src/base/events.h b/src/base/events.h index 660eb6320..aef297db9 100644 --- a/src/base/events.h +++ b/src/base/events.h @@ -121,6 +121,11 @@ typedef enum _event_type_t { * 键按下事件名(key_event_t)。 */ EVT_KEY_DOWN, + /** + * @const EVT_KEY_LONG_PRESS + * 键长按事件名(key_event_t)。 + */ + EVT_KEY_LONG_PRESS, /** * @const EVT_KEY_DOWN_BEFORE_CHILDREN * 键按下事件名,在子控件处理之前触发(key_event_t)。 diff --git a/src/base/input_device_status.c b/src/base/input_device_status.c index 3cc266a68..2ad439c7d 100644 --- a/src/base/input_device_status.c +++ b/src/base/input_device_status.c @@ -20,6 +20,7 @@ */ #include "tkc/mem.h" +#include "tkc/time_now.h" #include "base/keys.h" #include "base/system_info.h" #include "base/input_device_status.h" @@ -31,6 +32,89 @@ input_device_status_t* input_device_status_init(input_device_status_t* ids) { return ids; } +static key_pressed_info_t* input_device_status_find_press_info(input_device_status_t* ids, + uint32_t key) { + uint32_t i = 0; + for (i = 0; i < MAX_PRESSED_KEYS_NR; i++) { + key_pressed_info_t* iter = ids->pressed_info + i; + if (iter->key == key) { + return iter; + } + } + + return NULL; +} + +static bool_t input_device_status_has_pressed_key(input_device_status_t* ids) { + uint32_t i = 0; + for (i = 0; i < MAX_PRESSED_KEYS_NR; i++) { + key_pressed_info_t* iter = ids->pressed_info + i; + if (iter->key) { + return TRUE; + } + } + + return FALSE; +} + +static ret_t input_device_status_dispatch_long_press(input_device_status_t* ids) { + uint32_t i = 0; + key_event_t evt; + uint64_t now = time_now_ms(); + widget_t* widget = ids->widget; + + for (i = 0; i < MAX_PRESSED_KEYS_NR; i++) { + key_pressed_info_t* iter = ids->pressed_info + i; + if (iter->key && !iter->emitted) { + uint64_t t = now - iter->time; + if (t >= TK_LONG_PRESS_TIME) { + key_event_init(&evt, EVT_KEY_LONG_PRESS, widget, iter->key); + widget_on_keydown(widget, &evt); + log_debug("long press:%d\n", iter->key); + iter->emitted = TRUE; + } + } + } + + return RET_OK; +} + +static ret_t long_press_check_on_timer(const timer_info_t* info) { + input_device_status_t* ids = (input_device_status_t*)(info->ctx); + + input_device_status_dispatch_long_press(ids); + + if (input_device_status_has_pressed_key(ids)) { + return RET_REPEAT; + } else { + ids->long_press_check_timer = TK_INVALID_ID; + return RET_REMOVE; + } +} + +static ret_t input_device_status_update_key_press_info(input_device_status_t* ids, uint32_t key, + bool_t down) { + key_pressed_info_t* info = input_device_status_find_press_info(ids, key); + + if (down) { + if (info == NULL) { + info = input_device_status_find_press_info(ids, 0); + return_value_if_fail(info != NULL, RET_BAD_PARAMS); + info->key = key; + info->time = time_now_ms(); + } + + if (ids->long_press_check_timer == TK_INVALID_ID) { + ids->long_press_check_timer = timer_add(long_press_check_on_timer, ids, TK_LONG_PRESS_TIME); + } + } else { + return_value_if_fail(info != NULL, RET_BAD_PARAMS); + memset(info, 0x00, sizeof(key_pressed_info_t)); + } + + return RET_OK; +} + static ret_t input_device_status_update_key_status(input_device_status_t* ids, uint32_t key, bool_t down) { if (key == TK_KEY_LSHIFT) { @@ -62,6 +146,7 @@ static ret_t input_device_status_update_key_status(input_device_status_t* ids, u ids->capslock = !(ids->capslock); } } + input_device_status_update_key_press_info(ids, key, down); return RET_OK; } @@ -148,6 +233,7 @@ static ret_t input_device_status_init_key_event(input_device_status_t* ids, key_ ret_t input_device_status_on_input_event(input_device_status_t* ids, widget_t* widget, event_t* e) { return_value_if_fail(ids != NULL && e != NULL, RET_BAD_PARAMS); + ids->widget = widget; switch (e->type) { case EVT_POINTER_DOWN: { pointer_event_t* evt = (pointer_event_t*)e; diff --git a/src/base/input_device_status.h b/src/base/input_device_status.h index f37210935..5a930f588 100644 --- a/src/base/input_device_status.h +++ b/src/base/input_device_status.h @@ -26,6 +26,14 @@ BEGIN_C_DECLS +#define MAX_PRESSED_KEYS_NR 16 + +typedef struct _key_pressed_info_t { + uint32_t key; + uint32_t emitted; + uint64_t time; +} key_pressed_info_t; + /** * @class input_device_status_t * 输入设备状态管理器。本类仅供窗口管理器内部使用。 @@ -47,6 +55,9 @@ typedef struct _input_device_status_t { xy_t last_x; xy_t last_y; bool_t pressed; + widget_t* widget; + uint32_t long_press_check_timer; + key_pressed_info_t pressed_info[MAX_PRESSED_KEYS_NR + 1]; } input_device_status_t; /** diff --git a/src/base/widget.c b/src/base/widget.c index 8d07c264f..90bca2bec 100644 --- a/src/base/widget.c +++ b/src/base/widget.c @@ -2198,14 +2198,19 @@ ret_t widget_on_keydown(widget_t* widget, key_event_t* e) { widget_ref(widget); widget_map_key(widget, e); - ret = widget_on_keydown_impl(widget, e); - if (widget->feedback) { - ui_feedback_request(widget, (event_t*)e); - } + if (e->e.type == EVT_KEY_DOWN) { + ret = widget_on_keydown_impl(widget, e); + if (widget->feedback) { + ui_feedback_request(widget, (event_t*)e); + } - e->key = key; - if (ret != RET_STOP) { - ret = widget_on_keydown_general(widget, e); + e->key = key; + if (ret != RET_STOP) { + ret = widget_on_keydown_general(widget, e); + } + } else if (e->e.type == EVT_KEY_LONG_PRESS) { + return_if_equal(widget_on_keydown_children(widget, e), RET_STOP); + ret = widget_on_keydown_after_children(widget, e); } widget_unref(widget);