| /** |
| ******************************************************************************* |
| * |
| * @file atm_vkey.h |
| * |
| * @brief Virtual key event modeling |
| * |
| * Copyright (C) Atmosic 2021-2023 |
| * |
| ******************************************************************************* |
| */ |
| #pragma once |
| |
| #include "co_math.h" |
| |
| /** |
| ******************************************************************************* |
| * @defgroup ATM_DEV_VKEY Virtual key models |
| * @ingroup DRIVERS |
| * @brief ATM virtual key handling module |
| * |
| * This module contains the necessary procedure to deal with keys based user |
| * events. In general, application registers interesting events initially and |
| * provids virtual key number with pressed(or released) information when user |
| * operated via some physical input like key matrixes and gpio buttons. If some |
| * event condition matched, callback function which was registered will be called. |
| * |
| * ## Register event table |
| * The Application could define preferred key events by atm_vk_reg_t type and |
| * form them as atm_vk_reg_t array table. Each array entry could be easily |
| * declared by macro such as @ref VKEY_CLICK, @ref VKEY_DB_CLICK, and so on. |
| * By calling @ref atm_vkey_add_table function, application could add the event |
| * table into atm_vkey module. Application could add many event tables and each |
| * table adding would return a handle to application. |
| * |
| * Below is two sets of event array registered in a HID keyboard example: |
| * @code |
| * // Key event on connected state |
| * static const atm_vk_reg_t kbd_conn_vkeys[] = { |
| * VKEY_DOWN_FIRST(kbd_send_rpt, atm_vk_any), |
| * VKEY_DOWN_MORE (kbd_send_rpt_more, atm_vk_any), |
| * VKEY_UP_INTER (kbd_send_rpt_more, atm_vk_any), |
| * VKEY_UP_LAST (kbd_send_rpt, atm_vk_any), |
| * VKEY_HOLD_1KEY (kbd_hold_test1, NULL, 1000, VK_FN), |
| * VKEY_HOLD_2KEY (kbd_hold_test2, NULL, 1000, VK_FN, VK_F1), |
| * VKEY_HOLD_1KEY_CLICK(kbd_clear_all_bond, VK_U, VK_FN), |
| * VKEY_HOLD_2KEY_CLICK(kbd_enter_rftest, VK_ENTER, VK_FN, VK_F1), |
| * }; |
| * |
| * // Key event on disconnected state |
| * static const atm_vk_reg_t kbd_unconn_vkeys[] = { |
| * VKEY_DOWN_FIRST(kbd_save_key, atm_vk_any), |
| * VKEY_DOWN_MORE (kbd_save_key_more, atm_vk_any), |
| * VKEY_UP_INTER (kbd_save_key_more, atm_vk_any), |
| * VKEY_UP_LAST (kbd_save_key, atm_vk_any), |
| * VKEY_HOLD_1KEY (kbd_hold_test1, NULL, 1000, VK_FN), |
| * VKEY_HOLD_2KEY (kbd_hold_test2, NULL, 1000, VK_FN, VK_F1), |
| * VKEY_HOLD_1KEY_CLICK(kbd_clear_all_bond, VK_U, VK_FN), |
| * VKEY_HOLD_2KEY_CLICK(kbd_enter_rftest, VK_ENTER, VK_FN, VK_F1), |
| * }; |
| * |
| * ... |
| * |
| * // Register events for connected state |
| * vkey_handles[0] = atm_vkey_add_table(kbd_unconn_vkeys, |
| * ARRAY_LEN(kbd_unconn_vkeys), &mmi_vkey_ctx); |
| * // Register events for disconnected state |
| * vkey_handles[1] = atm_vkey_add_table(kbd_conn_vkeys, |
| * ARRAY_LEN(kbd_conn_vkeys), &mmi_vkey_ctx); |
| * @endcode |
| * |
| * ## Feed virtual key |
| * When application was triggered by user input, it could use @ref atm_vkey_feed |
| * to provide the virtual key index and its pressed or release state. |
| * |
| * Below is the example of feeding virtual key into atm_vkey module: |
| * @code |
| * |
| * // key matrix callback function |
| * static void key_matrix_event(bool pressed, uint32_t idx) |
| * { |
| * switch (atm_asm_get_current_state(MMI_S_TBL_IDX)) { |
| * // Feed key when state is disconnected |
| * case MMI_S_BOOTED: |
| * case MMI_S_INITING: |
| * case MMI_S_IDLE: { |
| * atm_vkey_feed(vkey_handles[0], idx, pressed); |
| * } break; |
| * ... |
| * // Feed key when state is connected |
| * case MMI_S_HID_ONLY: { |
| * atm_vkey_feed(vkey_handles[1], idx, pressed); |
| * } break; |
| * ... |
| * } |
| * } |
| * @endcode |
| * |
| * @{ |
| * |
| ******************************************************************************* |
| */ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #ifndef ATM_VKEY_MAX |
| #define ATM_VKEY_MAX 32 |
| #endif |
| |
| /** |
| ******************************************************************************* |
| * @brief Create double click event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_dck_reg_t.cb |
| * @param[in] vkey Key index to monitor. @ref atm_vk_dck_reg_t.vkey |
| * @param[in] max_ms Maximal triggered interval within two clicks. |
| * @ref atm_vk_dck_reg_t.max_ms |
| * |
| * Here is the example of monitoring double click events on key index x or |
| * y while the time between two clicks is shorter than 100 milliseconds: |
| * - Method one: |
| * @code |
| * |
| * // Handler for double click event |
| * static void vkey_any_dbclick(atm_vk_dck_evt_t *evt, void const *ctx) |
| * { |
| * DEBUG_TRACE("Key (%03u) double clicked", evt->vkey); |
| * |
| * if (evt->vkey == x) { |
| * // Doing things when key x was double clicked |
| * ... |
| * } else if (evt->vkey == y) { |
| * // Doing things when key y was double clicked |
| * ... |
| * } |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_DB_CLICK(vkey_any_dbclick, atm_vk_any, 100), |
| * ... |
| * }; |
| * @endcode |
| * - Method two: |
| * @code |
| * |
| * // Handler for double click event of key 3 |
| * static void vkey_x_dbclick(atm_vk_dck_evt_t *evt, void const *ctx) |
| * { |
| * DEBUG_TRACE("Key (%03u) double clicked", evt->vkey); |
| * // Doing things when key x was double clicked |
| * ... |
| * } |
| * |
| * // Handler for double click event of key y |
| * static void vkey_y_dbclick(atm_vk_dck_evt_t *evt, void const *ctx) |
| * { |
| * DEBUG_TRACE("Key (%03u) double clicked", evt->vkey); |
| * // Doing things when key y was double clicked |
| * ... |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_DB_CLICK(vkey_x_dbclick, x, 100), |
| * VKEY_DB_CLICK(vkey_y_dbclick, y, 100), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_DB_CLICK(fn, vkey, max_ms) { \ |
| atm_vk_db_click, .db_click = {fn, vkey, max_ms} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create click event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_ck_reg_t.cb |
| * @param[in] vkey Key index to monitor. @ref atm_vk_ck_reg_t.vkey |
| * @param[in] min_ms Minimal triggered interval within up and down. |
| * @ref atm_vk_ck_reg_t.min_ms |
| * @param[in] max_ms Maximal triggered interval within up and down. |
| * @ref atm_vk_ck_reg_t.max_ms |
| * |
| * Here is the example of monitoring click event on key index x with click interval |
| * within 50 to 100 millisecond and 500 to 1000 millisecond correspondingly: |
| * - Method one |
| * @code |
| * // Handler for key x quick click event |
| * static void vkey_x_quick_click(atm_vk_ck_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey shall be x |
| * // evt->time_ms shall be from 50 to 100. |
| * DEBUG_TRACE("Key (%03u) quick clicked in %ld ms", evt->vkey, evt->time_ms); |
| * // Do things of quick clicking |
| * ... |
| * } |
| * |
| * // Handler for key x slow click event |
| * static void vkey_x_slow_click(atm_vk_ck_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey shall be x |
| * // evt->time_ms shall be from 500 to 1000. |
| * DEBUG_TRACE("Key (%03u) slow clicked in %ld ms", evt->vkey, evt->time_ms); |
| * // Do things of slow clicking |
| * ... |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_CLICK(vkey_3_quick_click, x, 50, 100), |
| * ... |
| * VKEY_CLICK(vkey_3_slow_click, x, 500, 1000), |
| * ... |
| * }; |
| * @endcode |
| * - Method two |
| * @code |
| * // Handler for key x quick click event |
| * static void vkey_x_click(atm_vk_ck_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey shall be x |
| * // evt->time_ms shall be from 50 to 1000. |
| * DEBUG_TRACE("Key (%03u) clicked in %ld ms", evt->vkey, evt->time_ms); |
| * if (evt->time_ms <= 100) { |
| * // Do things of quick clicking |
| * ... |
| * } else if(evt->time_ms >= 500) { |
| * // Do things of slow clicking |
| * ... |
| * } |
| * } |
| * |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_CLICK(vkey_x_click, x, 50, 1000), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_CLICK(fn, vkey, min_ms, max_ms) { \ |
| atm_vk_click, .click = {fn, vkey, min_ms, max_ms} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold click event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_hc_reg_t.cb |
| * @param[in] vkey Virtual key index for clicking monitor. |
| * @param[in] ... Held keys' mask. |
| * @note VKEY_HOLD_CLICK don't support ATM_MASK_ANY |
| * |
| * Here is the example of monitoring click events on key index x clicking with |
| * key indexes a,b and c (where a < 32, b < 32, 32 < c < 64) held and key index |
| * y clicking with key index d (where d < 32) held: |
| * @code |
| * |
| * // Handler for key index x clicking with key indexes a,b and c held. |
| * static void vkey_x_click_in_abc(atm_vk_hc_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey shall be x |
| * DEBUG_TRACE("Key (%03u) clicked", evt->vkey); |
| * // evt->held.mask[0] should equal to (1 << a) | (1 << b) |
| * DEBUG_TRACE("Key held mask[0] = %l#x", evt->held.mask[0]); |
| * // evt->held.mask[1] should equal to (1 << (c-32)) |
| * DEBUG_TRACE("Key held mask[1] = %l#x", evt->held.mask[1]); |
| * } |
| * |
| * // Handler for key index y click with key index d held. |
| * static void vkey_y_click_in_d(atm_vk_hc_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey will be y |
| * DEBUG_TRACE("Key (%03u) clicked", evt->vkey); |
| * // evt->held.mask[0] should equal to (1 << d) |
| * DEBUG_TRACE("Key held mask[0] = %l#x", evt->held.mask[0]); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_HOLD_CLICK(vkey_x_click_in_abc, x, (1 << a) | (1 << b), (1 << (c - 32))), |
| * ... |
| * VKEY_HOLD_CLICK(vkey_y_click_in_d, y, (1 << d)), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD_CLICK(fn, vkey, ...) { \ |
| atm_vk_hold_click, .hold_click = {fn, vkey, {__VA_ARGS__}} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold click event entry with 1 key holding. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. This is convenient version |
| * of @ref VKEY_HOLD_CLICK with 1 key holding. |
| * @param[in] fn Callback function |
| * @ref atm_vk_hc_reg_t.cb |
| * @param[in] vkey Virtual key index for clicking monitor. |
| * @param[in] mk Virtual key index for holding. |
| * |
| * Here is the example of monitoring click event on key index x clicking with |
| * key index a held: |
| * @code |
| * |
| * // Handler for key x click with key index a held. |
| * static void vkey_x_click_with_a(atm_vk_hc_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey will be x |
| * DEBUG_TRACE("Key (%03u) clicked", evt->vkey); |
| * // evt->held.mask[a/32] should equal to (1 << (a%32)) |
| * DEBUG_TRACE("Key held mask[%x] = %l#x", a/32, evt->held.mask[a/32]); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * // If a < 32, this equals to VKEY_HOLD_CLICK(vkey_x_click_with_a, x, (1 << a)) |
| * // If a < 64, this equals to VKEY_HOLD_CLICK(vkey_x_click_with_a, x, 0, (1 << a % 32)) |
| * // If a < 96, this equals to VKEY_HOLD_CLICK(vkey_x_click_with_a, x, 0, 0, (1 << a % 32)) |
| * // Etc,. |
| * VKEY_HOLD_1KEY_CLICK(vkey_x_click_with_a, x, a), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD_1KEY_CLICK(fn, vkey, mk) \ |
| VKEY_HOLD_CLICK(fn, vkey, VKEY_1KEY_MASK(mk)) |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold click event entry with 2 key holding. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. This is the convenient version |
| * of @ref VKEY_HOLD_CLICK with 2 key holding. |
| * @param[in] fn Callback function |
| * @ref atm_vk_hc_reg_t.cb |
| * @param[in] vkey Virtual key index for clicking monitor. |
| * @param[in] mk1 First virtual key index for holding. |
| * @param[in] mk2 Second virtual key index for holding. |
| * Here is the example of monitoring click event on key index x clicking with |
| * key index a and key index b held: |
| * @code |
| * |
| * // Handler for key index x click with key index a and b held. |
| * static void vkey_x_click_with_ab(atm_vk_hc_evt_t *evt, void const *ctx) |
| * { |
| * // evt->vkey shall be x |
| * DEBUG_TRACE("Key (%03u) clicked", evt->vkey); |
| * // evt->held.mask[a/32] bit a%32 shall be 1 |
| * // evt->held.mask[b/32] bit b%32 shall be 1 |
| * DEBUG_TRACE("mask %d = %l#x mask %d = %l#x", a/32, evt->held.mask[a/32], b/32, |
| * evt->held.mask[b/32]); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_HOLD_2KEY_CLICK(vkey_x_click_with_ab, x, a, b), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD_2KEY_CLICK(fn, vkey, mk1, mk2) \ |
| VKEY_HOLD_CLICK(fn, vkey, VKEY_2KEY_MASK(mk1, mk2)) |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_hd_reg_t.cb |
| * @param[in] fn1 Callback function |
| * @ref atm_vk_hd_reg_t.status_cb |
| * @param[in] min_ms Minimal hold time to trigger the event. |
| * @ref atm_vk_hd_reg_t.time_ms |
| * @param[in] ... Held keys' mask. |
| * |
| * Here is the example of monitoring click events on key a, b, and c held for |
| * 500 milliseconds and key index d held for 1000 milliseconds. |
| * @code |
| * |
| * // Handler for key index a,b and c held. |
| * static void vkey_abc_hold(atm_vk_hd_evt_t *evt, void const *ctx) |
| * { |
| * // evt->held.mask[a/32] bit a%32 shall be 1 |
| * // evt->held.mask[b/32] bit b%32 shall be 1 |
| * // evt->held.mask[c/32] bit c%32 shall be 1 |
| * DEBUG_TRACE("mask %d = %l#x mask %d = %l#x", a/32, evt->held.mask[a/32], b/32, |
| * evt->held.mask[b/32], c/32, evt->held.mask[c/32]); |
| * // evt->time_ms should be longer than 500 milliseconds |
| * DEBUG_TRACE("time = %ld", evt->time_ms); |
| * } |
| * |
| * // Handler for key index d held. |
| * static void vkey_d_hold(atm_vk_hd_evt_t *evt, void const *ctx) |
| * { |
| * // evt->held.mask[d/32] bit d%32 shall be 1 |
| * DEBUG_TRACE("mask %d = %l#x", d/32, evt->held.mask[d/32]); |
| * // evt->time_ms should be longer than 1000 milliseconds |
| * DEBUG_TRACE("time = %ld", evt->time_ms); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * // The (1 << (a%32)), (1 << (b%32)) and (1 << (c%32)) would be located in |
| * // mask a/32, b/32, c/32 respectively |
| * VKEY_HOLD(vkey_abc_hold, NULL, 500, ... (1 << (a%32)) ... (1 << (b%32)) ... (1 << (c%32))), |
| * ... |
| * // The (1 << (d%32)) would be located in mask d/32 |
| * VKEY_HOLD(vkey_d_hold, NULL, 1000, ...(1 << (d%32)...), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD(fn, fn1, min_ms, ...) { \ |
| atm_vk_hold, .hold = {fn, fn1, min_ms, {__VA_ARGS__}} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold event entry with 1 key holding. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. This is convenient version of |
| * @ref VKEY_HOLD with 1 key holding |
| * @param[in] fn Callback function |
| * @ref atm_vk_hd_reg_t.cb |
| * @param[in] fn1 Callback function |
| * @ref atm_vk_hd_reg_t.status_cb |
| * @param[in] min_ms Minimal hold time to trigger the event. |
| * @param[in] mk Virtual key index for holding. |
| * |
| * Here is the example of monitoring click event on and key index x holding for |
| * 1000 ms. |
| * @code |
| * |
| * // Handler for key x held. |
| * static void vkey_x_hold(atm_vk_hd_evt_t *evt, void const *ctx) |
| * { |
| * // evt->held.mask[x/32] bit x%32 shall be 1 |
| * DEBUG_TRACE("Holding key mask[%d] = %l#x", x/32,evt->held.mask[x/32]); |
| * // evt->time_ms shall be longer than 1000 |
| * DEBUG_TRACE("time = %ld", evt->time_ms); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_HOLD_1KEY(vkey_x_hold, NULL, 1000, x), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD_1KEY(fn, fn1, min_ms, mk) \ |
| VKEY_HOLD(fn, fn1, min_ms, VKEY_1KEY_MASK(mk)) |
| |
| /** |
| ******************************************************************************* |
| * @brief Create hold click event entry with 2 key holding. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. This is convenient version |
| * of @ref VKEY_HOLD with 2 keys holding. |
| * @param[in] fn Callback function |
| * @ref atm_vk_hd_reg_t.cb |
| * @param[in] fn1 Callback function |
| * @ref atm_vk_hd_reg_t.status_cb |
| * @param[in] min_ms Minimal hold time to trigger the event. |
| * @param[in] mk1 First virtual key index for holding. |
| * @param[in] mk2 Second virtual key index for holding. |
| * |
| * Here is the example of monitoring click event on and key index x and y holding for |
| * 1500 ms. |
| * @code |
| * |
| * // Handler for key index x and y held. |
| * static void vkey_xy_hold(atm_vk_hd_evt_t *evt, void const *ctx) |
| * { |
| * // evt->held.mask[x/32] bit x%32 shall be 1 |
| * DEBUG_TRACE("Holding key mask[%d] = %l#x", x/32, evt->held.mask[x/32]); |
| * // evt->held.mask[y/32] bit y%32 shall be 1 |
| * DEBUG_TRACE("Holding key mask[%d] = %l#x", y/32, evt->held.mask[y/32]); |
| * // evt->time_ms shall be longer than 1000 |
| * DEBUG_TRACE("time = %ld", evt->time_ms); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_HOLD_2KEY(vkey_xy_hold, NULL, 1500, x, y), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_HOLD_2KEY(fn, fn1, min_ms, mk1, mk2) \ |
| VKEY_HOLD(fn, fn1, min_ms, VKEY_2KEY_MASK(mk1, mk2)) |
| |
| /** |
| ******************************************************************************* |
| * @brief Create non-first down event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_dnup_reg_t.cb |
| * @param[in] vkey Virtual key index for down monitor. |
| * |
| * @anchor down_more_example |
| * Here is the example of monitoring all kinds of down and up events and report |
| * them to a single callback: |
| * @code |
| * |
| * static void vkey_any_up_down_inter(atm_vk_dnup_inter_evt_t *evt, void const *ctx) |
| * { |
| * if(evt->eid == atm_vk_down_1st || evt->eid == atm_vk_down_more) { |
| * DEBUG_TRACE("vkey %d is pressed", evt->vkey); |
| * } else { |
| * DEBUG_TRACE("vkey %d is release", evt->vkey); |
| * } |
| * |
| * if(evt->eid == atm_vk_down_more || evt->eid == atm_vk_up_inter) { |
| * DEBUG_TRACE("Some key held mask:") |
| * for (int i = 0; i < VKEY_MASK_NUM; i++) { |
| * DEBUG_TRACE("mask[%d] = %lu", evt->held.mask[i]); |
| * } |
| * } |
| * } |
| * |
| * static void vkey_any_up_down(atm_vk_dnup_evt_t *evt, void const *ctx) |
| * { |
| * atm_vk_dnup_inter_evt_t new_evt; |
| * memcpy(&new_evt, &evt, sizeof(atm_vk_dnup_evt_t)); |
| * vkey_any_up_down_inter(&new_evt, ctx); |
| * } |
| * |
| * // Key event array |
| * static const atm_vk_reg_t key_event_array[] = { |
| * ... |
| * VKEY_DOWN_MORE(vkey_any_up_down, atm_vk_any), |
| * VKEY_DOWN_FIRST(vkey_any_up_down_inter, atm_vk_any), |
| * VKEY_UP_INTER(vkey_any_up_down_inter, atm_vk_any), |
| * VKEY_UP_LAST(vkey_any_up_down, atm_vk_any), |
| * ... |
| * }; |
| * @endcode |
| ******************************************************************************* |
| */ |
| #define VKEY_DOWN_MORE(fn, vkey) { \ |
| atm_vk_down_more, .dn = {fn, vkey} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create first down event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_dnup_reg_t.cb |
| * @param[in] vkey Virtual key index for down monitor. |
| * @note Please refer example @ref down_more_example "here" |
| ******************************************************************************* |
| */ |
| #define VKEY_DOWN_FIRST(fn, vkey) { \ |
| atm_vk_down_1st, .dn_fst = {fn, vkey} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create non-last up event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_dnup_reg_t.cb |
| * @param[in] vkey Virtual key index for up monitor. |
| * @note Please refer example @ref down_more_example "here" |
| ******************************************************************************* |
| */ |
| #define VKEY_UP_INTER(fn, vkey) { \ |
| atm_vk_up_inter, .up = {fn, vkey} \ |
| } |
| |
| /** |
| ******************************************************************************* |
| * @brief Create last up event entry. |
| * The entry is part of a @ref atm_vk_reg_t array which is used to |
| * registered into @ref atm_vkey_add_table function. |
| * @param[in] fn Callback function |
| * @ref atm_vk_dnup_reg_t.cb |
| * @param[in] vkey Virtual key index for up monitor. |
| * @note Please refer example @ref down_more_example "here" |
| ******************************************************************************* |
| */ |
| #define VKEY_UP_LAST(fn, vkey) { \ |
| atm_vk_up_last, .up_lst = {fn, vkey} \ |
| } |
| |
| /// Internal macro used by VKEY_1KEY_MASK |
| #define _MK_N(n, v) ((v / 32 == n) ? CO_BIT(v % 32) : 0) |
| /// Internal macro used by VKEY_2KEY_MASK |
| #define _MK_N2(n, v1, v2) (_MK_N(n,v1) | _MK_N(n,v2)) |
| /// Vkey index to vkey mask conversion by maximum vkey number |
| #define _MK_N_64(v) _MK_N(0, v), _MK_N(1, v) |
| #define _MK_N_96(v) _MK_N_64(v), _MK_N(2, v) |
| #define _MK_N_128(v) _MK_N_96(v), _MK_N(3, v) |
| #define _MK_N_160(v) _MK_N_128(v), _MK_N(4, v) |
| #define _MK_N_192(v) _MK_N_160(v), _MK_N(5, v) |
| #define _MK_N2_64(v1, v2) _MK_N2(0, v1, v2), _MK_N2(1, v1, v2) |
| #define _MK_N2_96(v1, v2) _MK_N2_64(v1, v2), _MK_N2(2, v1, v2) |
| #define _MK_N2_128(v1, v2) _MK_N2_96(v1, v2), _MK_N2(3, v1, v2) |
| #define _MK_N2_160(v1, v2) _MK_N2_128(v1, v2), _MK_N2(4, v1, v2) |
| #define _MK_N2_192(v1, v2) _MK_N2_160(v1, v2), _MK_N2(5, v1, v2) |
| #if (ATM_VKEY_MAX <= 32) |
| #define VKEY_1KEY_MASK(v) _MK_N(0, v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2(0, v1, v2) |
| #elif (ATM_VKEY_MAX <= 64) |
| #define VKEY_1KEY_MASK(v) _MK_N_64(v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2_64(v1, v2) |
| #elif (ATM_VKEY_MAX <= 96) |
| #define VKEY_1KEY_MASK(v) _MK_N_96(v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2_96(v1, v2) |
| #elif (ATM_VKEY_MAX <= 128) |
| #define VKEY_1KEY_MASK(v) _MK_N_128(v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2_128(v1, v2) |
| #elif (ATM_VKEY_MAX <= 160) |
| #define VKEY_1KEY_MASK(v) _MK_N_160(v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2_160(v1, v2) |
| #else |
| #define VKEY_1KEY_MASK(v) _MK_N_192(v) |
| #define VKEY_2KEY_MASK(v1, v2) _MK_N2_192(v1, v2) |
| #endif // (ATM_VKEY_MAX <= 32) |
| /// Check if a key is in mask array |
| #define VKEY_IS_MASK_HIT(m, k) (m[k / 32] & CO_BIT(k % 32)) |
| /// Check if two mask array is equal |
| #define VKEY_IS_MASK_EQU(m1, m2) \ |
| (!memcmp(m1, m2, sizeof(uint32_t) * VKEY_MASK_NUM)) |
| /// Special number for any mask |
| #define ATM_MASK_ANY 0xFFFFFFFF |
| /// Number for vkey mask |
| #define VKEY_MASK_NUM CO_DIVIDE_CEIL(ATM_VKEY_MAX, 32) |
| |
| /// Key event ID |
| typedef enum { |
| /// First key down event. |
| atm_vk_down_1st, |
| /// Non-first key down event. Other pressed key(s) exist. |
| atm_vk_down_more, |
| /// Key held event. |
| atm_vk_hold, |
| /// Non-last Key up event. Other pressed key(s) exist. |
| atm_vk_up_inter, |
| /// Last key up event. |
| atm_vk_up_last, |
| /// Event for key clicking. |
| atm_vk_click, |
| /// Event for key clicking with some key(s) held. |
| atm_vk_hold_click, |
| /// Event for key double clicking. |
| atm_vk_db_click, |
| } atm_vk_eid_t; |
| |
| /// key index: 0 to 254 is valid index. |
| /// Here defined is special usage. |
| typedef enum { |
| /// any keys |
| atm_vk_any = 0xff |
| } atm_vk_idx_t; |
| |
| /// Held keys |
| typedef struct { |
| /// Masks of current held keys. |
| uint32_t mask[VKEY_MASK_NUM]; |
| } atm_vk_held_keys_t; |
| |
| |
| /// Event structure header |
| typedef struct { |
| /// Event id |
| atm_vk_eid_t eid; |
| union { |
| /// Key index have been acted. @ref atm_vk_idx_t |
| atm_vk_idx_t vkey; |
| /// Key index of uint8_t type. |
| uint8_t u8vkey; |
| }; |
| } atm_vk_basic_evt_t; |
| |
| /// Event structure for atm_vk_down_fist and atm_vk_up_last. |
| typedef struct { |
| /// Basic event |
| atm_vk_basic_evt_t top; |
| } atm_vk_dnup_evt_t; |
| |
| /// Event structure for atm_vk_hold |
| typedef struct atm_vk_hd_evt_s { |
| /// Basic event |
| /// @note the vkey in top is unused in atm_vk_hold |
| atm_vk_basic_evt_t top; |
| /// Minimal time of holding. Unit is millisecond. Zero for ignoring. |
| uint16_t time_ms; |
| /// Current held key |
| atm_vk_held_keys_t held; |
| } atm_vk_hd_evt_t; |
| |
| /// Event structure for atm_vk_hold_click, atm_vk_down_more and |
| /// atm_vk_up_inter |
| typedef struct { |
| /// Basic event; |
| atm_vk_basic_evt_t top; |
| /// Masks of current held key. |
| atm_vk_held_keys_t held; |
| } atm_vk_hc_evt_t, atm_vk_dnup_inter_evt_t; |
| |
| /// Click and double click event structure |
| typedef struct atm_vk_ck_evt_s { |
| /// Basic event; |
| atm_vk_basic_evt_t top; |
| /// Measured time for click and double click |
| /// click: time between press and release. |
| /// double click: time between two clicks. |
| uint16_t time_ms; |
| } atm_vk_ck_evt_t, atm_vk_dck_evt_t; |
| |
| /// Entry structure for hold detection. |
| typedef struct atm_vk_hd_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if hold condition matched. |
| /// @param[in] evt Event for hold and click structure |
| /// @param[in] ctx Context data. |
| /// @return Return true to keep detecting this hold. otherwise, false. |
| bool (*cb)(atm_vk_hd_evt_t const *evt, void const *ctx); |
| /// @brief This function will be called if hold key has been pressed or |
| /// released. |
| /// @param[in] pressed Indicate the hold key is pressed and a timer is |
| /// starting to count. |
| /// @param[in] ctx Context data. |
| void (*status_cb)(bool pressed, void const *ctx); |
| /// Minimal time of holding. Unit is millisecond. Zero for ignoring. |
| uint16_t time_ms; |
| /// Masks of expecting held keys. |
| uint32_t mask[VKEY_MASK_NUM]; |
| } atm_vk_hd_reg_t; |
| |
| /// Entry structure for hold and click |
| typedef struct atm_vk_hc_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if hold and click condition matched. |
| /// @param[in] evt Event for hold structure |
| /// @param[in] ctx Context data. |
| void (*cb)(atm_vk_hc_evt_t const *evt, void const *ctx); |
| /// Key index of clicking. @ref atm_vk_idx_t |
| uint8_t vkey; |
| /// Masks of expecting held keys. |
| uint32_t mask[VKEY_MASK_NUM]; |
| } atm_vk_hc_reg_t; |
| |
| /// Entry structure of click event |
| typedef struct atm_vk_ck_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if click condition matched. |
| /// @param[in] evt Event for click structure |
| /// @note min_ms and max_ms represent the real click interval and they should |
| /// equal. |
| /// @param[in] ctx Context data. |
| void (*cb)(atm_vk_ck_evt_t const *evt, void const *ctx); |
| /// Key index of clicking. @ref atm_vk_idx_t |
| uint8_t vkey; |
| /// Minimal time between press and release. zero for ignoring. |
| uint16_t min_ms; |
| /// Maximal time between press and release. zero for ignoring. |
| uint16_t max_ms; |
| } atm_vk_ck_reg_t; |
| |
| /// Entry structure for double click detection |
| typedef struct atm_vk_dck_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if double click condition matched. |
| /// @param[in] evt Event for double click structure |
| /// @param[in] ctx Context data. |
| void (*cb)(atm_vk_dck_evt_t const *evt, void const *ctx); |
| /// Listening key index of double clicking. @ref atm_vk_idx_t |
| uint8_t vkey; |
| /// Maximal time between two clicks. zero for ignoring. |
| uint16_t max_ms; |
| } atm_vk_dck_reg_t; |
| |
| /// Entry structure for down and up |
| typedef struct atm_vk_dnup_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if down or up condition matched. |
| /// @param[in] evt Event for down or up structure |
| /// @param[in] ctx Context data. |
| void (*cb)(atm_vk_dnup_evt_t const *evt, void const *ctx); |
| /// Key listen index for atm_vk_down_fist, atm_vk_up_last |
| /// @ref atm_vk_idx_t |
| uint8_t vkey; |
| } atm_vk_dnup_reg_t; |
| |
| /// Event structure for non-lonely down and up |
| typedef struct atm_vk_dnup_inter_reg_s { |
| /// callback while event happen |
| /// @brief This function will be called if down or up condition matched. |
| /// @param[in] evt Event for non-lonely down or up structure |
| /// @param[in] ctx Context data. |
| void (*cb)(atm_vk_dnup_inter_evt_t const *evt, void const *ctx); |
| /// Key index for atm_vk_down_more, atm_vk_up_inter |
| /// @ref atm_vk_idx_t |
| uint8_t vkey; |
| } atm_vk_dnup_inter_reg_t; |
| |
| /// Event union for table |
| typedef struct { |
| /// Event id |
| atm_vk_eid_t eid; |
| union { |
| /// Non-first down event |
| atm_vk_dnup_inter_reg_t dn; |
| /// Non-last up event |
| atm_vk_dnup_inter_reg_t up; |
| /// First down event |
| atm_vk_dnup_reg_t dn_fst; |
| /// Last up event |
| atm_vk_dnup_reg_t up_lst; |
| /// Hold event |
| atm_vk_hd_reg_t hold; |
| /// Hold and click event |
| atm_vk_hc_reg_t hold_click; |
| /// click event |
| atm_vk_ck_reg_t click; |
| /// double click event |
| atm_vk_dck_reg_t db_click; |
| }; |
| } atm_vk_reg_t; |
| |
| /** |
| ******************************************************************************* |
| * @brief Add a virtual key event table |
| * @param[in] table Virtual key event table |
| * @param[in] ent_cnt Entry count of event table |
| * @param[in] ctx application context |
| * @return Handle of this table. This handle is used to feed virtual key while |
| * some user input happened. |
| ******************************************************************************* |
| */ |
| __NONNULL(1) |
| struct vkll_ctx_s *atm_vkey_add_table(atm_vk_reg_t const *table, uint16_t ent_cnt, |
| void const *ctx); |
| |
| /** |
| ******************************************************************************* |
| * @brief Virtual key feed. |
| * When some user input happened, use this function to put virtual key into |
| * system. |
| * @param[in] handle Handle of virtual key event table. |
| * @param[in] vkey Virtual key to be inputted. |
| * @param[in] is_pressed True for key pressing. Otherwise for releasing. |
| ******************************************************************************* |
| */ |
| __NONNULL(1) |
| void atm_vkey_feed(struct vkll_ctx_s *handle, uint8_t vkey, bool is_pressed); |
| |
| /** |
| ******************************************************************************* |
| * @brief Virtual key flush. |
| * @param[in] handle Handle of virtual key event table. |
| ******************************************************************************* |
| */ |
| __NONNULL_ALL |
| void atm_vkey_flush(struct vkll_ctx_s *handle); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /// @} ATM_BTFM_PVKEY |