输入子系统

UI 系统可以接收设备中其他外设的输入,典型的输入设备有触摸板和按钮。

本章节详细介绍了如何在 UI 系统中使用输入设备,并详细描述了输入信息的处理过程。

触摸板

触摸板是最常用的输入设备之一,大部分情况下,触摸板会集成在显示面板中。触摸信息的工作流程如下图所示。

https://foruda.gitee.com/images/1703054242639518699/13e78a92_9325830.png

触摸板工作流程

触摸板硬件和驱动程序

尽管不同的触摸板芯片具有不同的消息数据结构,但消息始终包含触摸状态和触摸点的坐标。为了传输坐标信息,需要一个数据总线,而 I2C 是触摸芯片和微处理器之间最常用的数据总线。

此外,根据规格要求,不同的触摸芯片需要使用不同的驱动程序,需要进行移植。

获取触摸板数据

在 port_touchpad_get_data 函数中,触摸信息将在 drv_touch_read 中获取,经过简单处理后,作为原始数据供触摸算法处理程序使用。

gui_touch_port_data_t *port_touchpad_get_data()
{
    uint16_t x = 0;
    uint16_t y = 0;
    bool pressing = 0;
    if (drv_touch_read(&x, &y, &pressing) == false)
    {
        return NULL;
    }
    if (pressing == true)
    {
        raw_data.event = 2;
    }
    else
    {
        raw_data.event = 1;
    }
    raw_data.timestamp_ms = os_sys_tick_get();
    raw_data.width = 0;
    raw_data.x_coordinate = x;
    raw_data.y_coordinate = y;
    //gui_log("event = %d, x = %d, y = %d, \n", raw_data.event, raw_data.x_coordinate, raw_data.y_coordinate);
    return &raw_data;
}

原始数据的数据结构是 gui_touch_port_data_t。

触摸板算法处理器

触摸板算法处理的代码实现在 tp_algo_process 函数中。通过判断 X 轴和 Y 轴坐标数据的变化以及触摸时间,进行手势识别。经过算法处理后得到的输入类型如下:

typedef enum
{
    TOUCH_INIT                  = 0x100,
    TOUCH_HOLD_X,
    TOUCH_HOLD_Y,
    TOUCH_SHORT,
    TOUCH_LONG,
    TOUCH_DOUBLE,
    TOUCH_TRIPLE,
    TOUCH_ORIGIN_FROM_X,
    TOUCH_ORIGIN_FROM_Y,
    TOUCH_LEFT_SLIDE,
    TOUCH_RIGHT_SLIDE,
    TOUCH_UP_SLIDE,
    TOUCH_DOWN_SLIDE,
    TOUCH_LEFT_SLIDE_QUICK,
    TOUCH_RIGHT_SLIDE_QUICK,
    TOUCH_UP_SLIDE_QUICK,
    TOUCH_DOWN_SLIDE_QUICK,
    TOUCH_SHORT_BUTTON,
    TOUCH_LONG_BUTTON,
    TOUCH_UP_SLIDE_TWO_PAGE,
    TOUCH_DOWN_SLIDE_TWO_PAGE,
    TOUCH_INVALID              = 0x1FF,

    KB_INIT                     = 0x200,
    KB_SHORT                    = 0x201,
    KB_LONG                     = 0x202,
    KB_INVALID                 = 0x2FF,

    WHEEL_INIT                  = 0x300,
    WHEEL_ING,
    WHEEL_FINISHED,
    WHEEL_INVALID              = 0x3FF,
} T_GUI_INPUT_TYPE;

算法处理器将填充 touch_info_t 结构体,该结构体对所有控件可用。

控件响应

由于所有控件都继承自基类 gui_obj ,几乎所有控件都可以通过 gui_obj_add_event_cb 绑定回调函数来响应触摸事件。触摸事件类型丰富,例如点击 GUI_EVENT_TOUCH_CLICKED 、长按 GUI_EVENT_TOUCH_LONG ,以及上下左右各方向的滑动等。此外,控件也可以根据 touch_info_t 结构体中的实时触摸坐标来调整自身的显示。

控件内部会在其准备函数(如 gui_win_prepare )中通过 tp_get_info 函数获取触摸信息并进行处理。

在应用程序层面,可以为控件绑定事件回调函数。例如,下面的回调函数会在被触发时置位来电标志:

static void switch_call_incoming(void *obj, gui_event_t *e)
{
    (void)obj;
    (void)e;

    *gui_call_incoming_flag_get() = true;
}

创建控件后,通过 gui_obj_add_event_cb 将该回调绑定到控件的点击事件 GUI_EVENT_TOUCH_CLICKED 上:

// compass icon
gui_img_t *img = gui_img_create_from_mem(win_watch, "CLOCK_COMPASS_DIAL",
                                         UI_CLOCK_COMPASS_DIAL_ICON_BIN, 155, 348, 0, 0);
gui_img_set_quality(img, true);
gui_obj_add_event_cb(img, (gui_event_cb_t)switch_call_incoming, GUI_EVENT_TOUCH_CLICKED,
                     NULL);

在这个例子中,创建了一个图片控件后,通过 gui_obj_add_event_cb 将其点击事件绑定到回调函数 switch_call_incoming ,当该控件被点击时便会执行此回调函数。

键盘

键盘信息的工作流程如下图所示:

https://foruda.gitee.com/images/1703054218572846675/2cd18af7_9325830.png

键盘工作流程

硬件和驱动程序

键盘的硬件设计和驱动程序比较简单,本章将通过一个单独的 GPIO 来说明。有关如何使用 GPIO,请参考 SDK 中的说明。您可以使用 rtl87x2g_gpio.c 中的通用 API 或 drv_gpio.c 中的封装 API 来完成相同的操作。

获取键盘数据

键盘输入通过 gui_kb_create 注册。每个物理按键调用一次 gui_kb_create ,传入按键名称,以及按键状态、按下时间戳和释放时间戳的变量指针:

gui_kb_create("Home", &home_state,
              &home_timestamp_ms_press,
              &home_timestamp_ms_release);
gui_kb_create("Back", &back_state,
              &back_timestamp_ms_press,
              &back_timestamp_ms_release);
gui_kb_create("Menu", &menu_state,
              &menu_timestamp_ms_press,
              &menu_timestamp_ms_release);
gui_kb_create("Power", &power_state,
              &power_timestamp_ms_press,
              &power_timestamp_ms_release);

移植时,用户需要在按键状态发生变化时(例如在 GPIO 中断中)更新这些状态变量和时间戳,系统会通过注册的指针读取按键信息。

键盘算法处理器

键盘算法的代码实现在 kb_algo_process 函数中。当按键释放时,通过按压时长来判断输入类型是短按还是长按,并向当前焦点控件派发 GUI_EVENT_KB_SHORT_PRESSED 或 GUI_EVENT_KB_LONG_PRESSED 事件。算法处理器还会填充 kb_info_t 结构体,该结构体对所有控件都可用。

响应

控件通过 gui_obj_add_event_cb 绑定回调函数来响应键盘事件,短按对应 GUI_EVENT_KB_SHORT_PRESSED 事件,长按对应 GUI_EVENT_KB_LONG_PRESSED 事件。例如,为控件绑定短按事件的回调:

gui_obj_add_event_cb(view, click_button_back_2_watchface_or_menu, GUI_EVENT_KB_SHORT_PRESSED, NULL);