Biu~笔记:高通蓝牙ADK(2)-- 按键功能之多击

        Biu~小伙伴们大家好,又到了不知什么时候会更新但一更新又带来一大堆看似能懂但不知道你懂不懂的东西的《Biu~笔记》, 续上回分解,有小伙伴在评论留言想知道怎么获取开发资料。

对于初学者来说,我能理解你的感受。但也想在这说清楚一下,高通开发资料不是开放的,需要交一定的费用才能得到开发者权限,这个开发过高通平台的人应该都清楚,账号有权限和没有权限能看到的东西差别相当大。所以这部分教程也不能在公众平台放出 ,望见谅,但如果有交入场费的我们的客户,可以直接找到我们,我们一对一,手把手的教学,包你满意

        下面我们圆规正转,看看我们今天要讲的内容-- --自定义多击按键输入功能。像上期说的,新版本ADK这个框架都修改了,那么按键这个功能也逃不过魔爪,在使用上和改动上都难以下手,这个多击功能,也是最近有好多客户问我该怎么做。最简单的方法就是数single click,但小编这次带来的不是这个,而是在底层加入多击的处理。最后实现的效果是让开发者,像以前一样在xml里面定义按键事件,在earbud_ui_config.c中加入按键事件处理即可。并且这个多久次数可以自定义,从1~n都可以定义,满足各ui需求 。下面我们说说实现的细节。

在这个功能里小编修改了五个文件,三个lib里的源代码:input_event_manager.c,input_event_manager.h,input_event_manager_private.h;两个脚本文件,在\earbud\adk\tools\buttonparsexml里:ButtonParseXML.py,ButtonParseXml.xsd。而他们的关系就如下图所示

为了更容易去配置多击按键,这里就需要修改编译脚本和xml模板,使自定义的设置数据合理化。ButtonParseXml.xsd是buttonxml的模板定义,在这里需要进入一个新的buttonEvent -- REPEAT_CLICK,用来区分按键事件触发类型

再加多一个标签 -- repeat_click,表示需要多少次点击才能触发事件

ButtonParseXML.py是将xml的数据输出成.c和.h文件的脚本,里面加上repeat_click标签的识别

在输出数组内容是加入repeat_click标签的内容输出


修改x_button.buttonxml,加入想要的多击事件

最后编译会生成一个x_button.c的文件,里面有个数组default_message_group,就包含了xml里面的设置数据,这个数组也是后面程序识别要用到的

而在这里REPEAT_CLICK是不被系统认可的,因为这只是脚本按配置来输出,还没有经过声明的。所以在input_event_manager.h里面对这个按键事件动作声明一下,并且这个数组的类型比原来的类型多了一个重复次数的参数,这也要在这个数组类型的声明里加进去

做完以上的操作之后再编译就不会提示错误了,剩下的就是要做这部分的处理。

        inputEventsChanged这个函数是处理按键变化的函数,首先他会遍历default_message_group这个数组,也就是前面说的buttonxml生成的数组,去对比哪一个事件的触发引脚和这次改变的引脚一样,如果找到了一样的,就会按照他的按键事件触发类型去触发相应的操作。在这里原本是没有REPEAT_CLICK按键事件触发类型,所以要加上这部分处理(WARNING:多击事件是仿写双击事件,多击过程也是超过双击的次数,代码没有对源代码删除,所以使用了多击之后,如果还保留双击就变成,每次多击都触发一次双击事件,不要再使用双击触发类型,用多击触发类型替代

在这处理函数里面用记录按键变化次数的方式,记录按下次数,并设置检查超时为500ms


但因为会遍历这个配置表,有多个多击事件时,会在一次按键变化后多次进入REPEAT_CLICK的处理,导致计数不准确,所这里要加入个变量去记录是否已经计数

如果超时没有识别到按键再次按下,就会根据default_message_group每个事件的多击数和已检测的多击数对比,如果一致就执行对应的按键事件

同时在input_event_manager_private.h里加入所需要的变量和消息申明即可

short_press:已短按的IO

long_press;  已长按的IO

repeated_times;   已记录的多击次数

has_counted;   已被计数

完成以上操作,底层处理的代码就加完了,下面举个食用栗子

在buttonmxl加入要定义的按键消息

在earbud_ui_config.c中加入消息的处理




完成!!!

 

鞠躬!!!

谢谢!!!

以上是本期博文的全部内容,如有疑问请在博文下方评论留言,或者有什么想了解的都可以留言,我会挑选一些做后面几期的博文,谢谢大家,我们下期再见。

(预告:下期我还是讲按键功能的本地执行 (#^.^#))

下面有个视频

下面有个视频

下面有个视频

下面给答案

下面给代码

上面给我小心心

 

Follows: r00066.1

------------ adk/src/libs/input_event_manager/input_event_manager.c ------------
index bf393a11..b1ee9e66 100755
@@ -228,17 +228,70 @@ static void doubleClickAction(InputEventState_t *state,
doubleClickFirstReleaseAction(state, input_action);
}
}
}

+static void repeatClickFirstReleaseAction(InputEventState_t *state, const InputActionMessage_t *input_action)
+{
+ const InputActionMessage_t **m = PanicUnlessNew(const InputActionMessage_t *);
+ *m = input_action;
+ /* This is the first press, make a note */
+ state->repeat_click_tracker.short_press |= (input_action->bits);
+ state->repeat_click_tracker.repeated_times =1;
+ MessageSendLater(&state->task, IEM_INTERNAL_REPEAT_CLICK_TIMER, (void*)m, SINGLE_CLICK_TIMEOUT);
+}
+
+static void repeatClickSubsequentReleaseAction(InputEventState_t *state, const InputActionMessage_t *input_action)
+{
+ const InputActionMessage_t **m = PanicUnlessNew(const InputActionMessage_t *);
+ *m = input_action;
+ if(!state->repeat_click_tracker.has_counted)
+ {
+ MessageCancelAll(&state->task, IEM_INTERNAL_SINGLE_CLICK_TIMER);
+ MessageCancelAll(&state->task, IEM_INTERNAL_REPEAT_CLICK_TIMER);
+ state->repeat_click_tracker.repeated_times++;
+ }
+ MessageSendLater(&state->task, IEM_INTERNAL_REPEAT_CLICK_TIMER, (void*)m, SINGLE_CLICK_TIMEOUT);
+}
+
+static void repeatClickAction(InputEventState_t *state,
+ const InputActionMessage_t *input_action,
+ input_event_bits_t input_event_bits)
+{
+ bool prev_bit_state_is_high = (input_action->bits == (state->input_event_bits & input_action->mask));
+ bool bit_state_is_low = (input_action->bits != (input_event_bits & input_action->mask));
+ bool single_press_detected = (input_action->bits == (state->repeat_click_tracker.short_press & input_action->mask ));
+ bool held_release_detected = (input_action->bits == (state->repeat_click_tracker.long_press & input_action->mask ));
+
+ if (prev_bit_state_is_high && bit_state_is_low)
+ {
+ if(held_release_detected)
+ {
+ /* A held release has been detected, do not process a repeat click.
+ * Clear the repeat click tracker */
+ state->repeat_click_tracker.short_press &= ~(input_action->bits);
+ state->repeat_click_tracker.long_press &= ~(input_action->bits);
+ MessageCancelAll(&state->task, IEM_INTERNAL_REPEAT_CLICK_TIMER);
+ }
+ else
+ {
+ if(single_press_detected)
+ repeatClickSubsequentReleaseAction(state, input_action);
+ else
+ repeatClickFirstReleaseAction(state, input_action);
+ }
+ }
+}
+
static void inputEventsChanged(InputEventState_t *state, input_event_bits_t input_event_bits)
{
input_event_bits_t changed_bits = state->input_event_bits ^ input_event_bits;
const InputActionMessage_t *input_action = state->action_table;
const uint32 size = state->num_action_messages;

IEM_DEBUG(("IEM: Updated input events %08x\n", input_event_bits));
+ state->repeat_click_tracker.has_counted = FALSE;

/* Go through the action table to determine what action to do and
what message may need to be sent. */
for (;input_action != &(state->action_table[size]); input_action++)
{
@@ -260,10 +313,15 @@ static void inputEventsChanged(InputEventState_t *state, input_event_bits_t inpu

case DOUBLE_CLICK:
doubleClickAction(state, input_action, input_event_bits);
break;

+ case REPEAT_CLICK:
+ repeatClickAction(state, input_action, input_event_bits);
+ state->repeat_click_tracker.has_counted = TRUE;
+ break;
+
case HELD:
heldAction(state, input_action, input_event_bits);
break;

case HELD_RELEASE:
@@ -362,10 +420,11 @@ static void iemHandler(Task task, MessageId id, Message message)
const InputActionMessage_t *input_action = *m;

/* Keep the trackers informed that this is now a held release */
state->single_click_tracker.long_press |= (input_action->bits);
state->double_click_tracker.long_press |= (input_action->bits);
+ state->repeat_click_tracker.long_press |= (input_action->bits);

TaskList_MessageSendId(state->client_tasks, input_action->message);

/* Cancel any existing repeat timer that may be running */
(void)MessageCancelAll(&state->task, IEM_INTERNAL_REPEAT_TIMER);
@@ -427,10 +486,27 @@ static void iemHandler(Task task, MessageId id, Message message)
/* Clear the stored input_action */
state->double_click_tracker.short_press &= ~(input_action->bits);
}
break;

+ case IEM_INTERNAL_REPEAT_CLICK_TIMER:
+ {
+ const InputActionMessage_t **m = (const InputActionMessage_t **)message;
+ const InputActionMessage_t *input_action = *m;
+
+ if(input_action->repeat_times == state->repeat_click_tracker.repeated_times )
+ {
+ IEM_DEBUG(("Sending single click message, %p", input_action));
+ TaskList_MessageSendId(state->client_tasks, input_action->message);
+ MessageCancelAll(&state->task, IEM_INTERNAL_REPEAT_CLICK_TIMER);
+ }
+
+ /* Clear the stored input_action */
+ state->repeat_click_tracker.short_press &= ~(input_action->bits);
+ }
+ break;
+
default:
break;
}
}


------------ adk/src/libs/input_event_manager/input_event_manager.h ------------
index b1b5ac9c..f38cccd8 100755
@@ -18,11 +18,12 @@ typedef enum
ENTER,
HELD,
RELEASE,
SINGLE_CLICK,
HELD_RELEASE,
- DOUBLE_CLICK
+ DOUBLE_CLICK,
+ REPEAT_CLICK
} InputEventAction_t;

/* Used as the type name of a data structure in ButtonParseXML.py */
/* The member names are not used, but the order is assumed. */
typedef struct
@@ -30,10 +31,11 @@ typedef struct
input_event_bits_t bits;
input_event_bits_t mask;
InputEventAction_t action;
uint16 timeout;
uint16 repeat; /* Only used for HELD and ENTER actions */
+ uint16 repeat_times;
MessageId message;
} InputActionMessage_t;

/* Used as the type name of a data structure in ButtonParseXML.py */
/* The member names are not used, but the order is assumed. */

-------- adk/src/libs/input_event_manager/input_event_manager_private.h --------
index 7e40e015..e3e79b3f 100755
@@ -21,10 +21,18 @@ typedef struct InputPressTracker
{
input_event_bits_t short_press;
input_event_bits_t long_press;
} InputPressTracker_t;

+typedef struct InputRepeatPressTracker
+{
+ input_event_bits_t short_press;
+ input_event_bits_t long_press;
+ uint8 repeated_times;
+ bool has_counted;
+} InputRepeatPressTracker_t;
+
typedef struct
{
TaskData task;
task_list_t * client_tasks;

@@ -33,10 +41,11 @@ typedef struct

/* Separate trackers for the two press types so they can be configured
independent of one another */
InputPressTracker_t single_click_tracker;
InputPressTracker_t double_click_tracker;
+ InputRepeatPressTracker_t repeat_click_tracker;

/* The input event bits as last read or indicated */
input_event_bits_t input_event_bits;

/* PAM state stored for timers */
@@ -57,9 +66,10 @@ enum
{
IEM_INTERNAL_HELD_TIMER,
IEM_INTERNAL_REPEAT_TIMER,
IEM_INTERNAL_HELD_RELEASE_TIMER,
IEM_INTERNAL_SINGLE_CLICK_TIMER,
- IEM_INTERNAL_DOUBLE_CLICK_TIMER
+ IEM_INTERNAL_DOUBLE_CLICK_TIMER,
+ IEM_INTERNAL_REPEAT_CLICK_TIMER
};

#endif /* INPUT_EVENT_MANAGER_PRIVATE_H_ */

------------------ adk/tools/buttonparsexml/ButtonParseXML.py ------------------
index 06dda7e2..8c15e6d3 100755
@@ -43,10 +43,16 @@ class Message:
if _repeat_ms != None:
self.repeat_ms = int(_repeat_ms.text)
else:
self.repeat_ms = 0

+ _repeat_click = element.find("repeat_click")
+ if _repeat_click != None:
+ self.repeat_click = int(_repeat_click.text)
+ else:
+ self.repeat_click = 0
+
self.active_hi_pio_list = []
for _active_hi_pio in element.findall('activePinFriendlyName'):
self.active_hi_pio_list.append(pio_dict[_active_hi_pio.text])

self.active_lo_pio_list = []
@@ -214,11 +220,12 @@ def OutputButtonTable(message_group_dict):
pio_str += pio.name
pio_str += ","
button_str += "\t\t" + format(pio_str, "40s") + "/* Input event mask */\n"
button_str += "\t\t" + format(v.event + ",", "40s") + "/* Action */\n"
button_str += "\t\t" + format(str(v.timeout_ms) + ",", "40s") + "/* Timeout */\n"
- button_str += "\t\t" + format(str(v.repeat_ms) + ",", "40s") + "/* Repeat */\n"
+ button_str += "\t\t" + format(str(v.repeat_ms) + ",", "40s") + "/* Repeat ms*/\n"
+ button_str += "\t\t" + format(str(v.repeat_click) + ",", "40s") + "/* Repeat click times*/\n"
button_str += "\t\t" + format(v.name + ",", "40s") + "/* Message */\n"
button_str += "\t},\n"
return button_str

table_str = ""
@@ -230,10 +237,11 @@ def OutputButtonTable(message_group_dict):
table_str += OutputButtonAction(message_dict, "HELD")
table_str += OutputButtonAction(message_dict, "SINGLE_CLICK")
table_str += OutputButtonAction(message_dict, "HELD_RELEASE")
table_str += OutputButtonAction(message_dict, "DOUBLE_CLICK")
table_str += OutputButtonAction(message_dict, "RELEASE")
+ table_str += OutputButtonAction(message_dict, "REPEAT_CLICK")
table_str += "};\n"

return table_str

def generate_header(args, pio_dict, message_group_dict):
----------------- adk/tools/buttonparsexml/ButtonParseXml.xsd -----------------
index 11518f35..5aa305fe 100755
@@ -54,10 +54,17 @@

send a message when the PIO state changes to not match, twice before the timeout for a single press (500ms)



+
+
+
+ send a message when the PIO state changes to not match, N times before the timeout for last press (500ms)
+
+
+





@@ -169,10 +176,17 @@

Optional: The message, while the event is active, will be posted at every repeat_ms interval



+
+
+
+ Optional: The count to the click times
+
+
+








Example:(!!!!!!!!!!DONT USE DOUBLE CLICK EVENT MORE!!!!!!!!!!!!!!)
diff -r E:\qcc514x-qcc304x-src-1-0_qtil_standard_oem_earbud\earbud\src\buttons\2_button.buttonxml E:\ADK\qcc304x_514x\earbud\earbud\src\buttons\2_button.buttonxml
8a9,29
> APP_MFB_BUTTON_2_CLICK
> REPEAT_CLICK
> SYS_CTRL
> 2
>
>
>
> APP_MFB_BUTTON_3_CLICK
> REPEAT_CLICK
> SYS_CTRL
> 3
>
>
>
> APP_MFB_BUTTON_5_CLICK
> REPEAT_CLICK
> SYS_CTRL
> 5
>
>
>

diff -r E:\qcc514x-qcc304x-src-1-0_qtil_standard_oem_earbud\earbud\src\earbud_ui_config.c E:\ADK\qcc304x_514x\earbud\earbud\src\earbud_ui_config.c
> {APP_MFB_BUTTON_2_CLICK, ui_provider_media_player, context_av_is_streaming, ui_input_toggle_play_pause },
> {APP_MFB_BUTTON_2_CLICK, ui_provider_media_player, context_av_connected, ui_input_toggle_play_pause },
> {APP_MFB_BUTTON_3_CLICK, ui_provider_media_player, context_av_is_streaming, ui_input_av_forward },
> {APP_MFB_BUTTON_5_CLICK, ui_provider_media_player, context_av_is_streaming, ui_input_av_backward },

多看文档,多上官网

多看文档,多上官网

多看文档,多上官网

 


 

相关视频

Biu~笔记:高通蓝牙ADK(2)-- 按键功能之多击

还在数单击数吗?快来围观如何优雅得在ADK中添加多击功能吧

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论

我很菜

我很菜

2021年6月16日
想拜你为师,可否给个联系方式
Sam Chiu

Sam Chiu

2021年4月13日
看不到視頻?
发芽韭菜

发芽韭菜

2021年3月25日
改了后报错:F:\QTProject\qcc512x-qcc302x-src-1-0_qtil_standard_oem_earbud_00040.1\adk\src\libs\Makefile:602: error: recipe for target '../installed_libs/lib/default_qcc512x_qcc302x/native/libinput_event_manager.a' failed
发芽韭菜

发芽韭菜

2021年3月5日
还需要会用python啊,太难了,博主真高手
发芽韭菜

发芽韭菜

2021年3月5日
怎么交入场费?买开发板 吗? 有链接吗?
Footprint

Footprint

2020年12月21日
你好! 为什么配置 三击功能会触发双击
Tina。

Tina。

2020年12月17日
为什么用目前最新的版本按照上述方法修改,编译总是无法生成x_button.h和x_button.c?
Biu~

Biu~

2020年10月28日
要点中左下角的圈圈才能播放。。。。。。。。。。。。。。。。。
Alasi

Alasi

2020年10月27日
你好,为什么看不了视频里面的内容呢?
Biu~

Biu~

2020年10月21日
emmm,没听说过有V73的版本