输入子系统
UI系统可以接收设备中其他外设的输入,典型的输入设备有触摸板和按钮。
本章节详细介绍了如何在UI系统中使用输入设备,并详细描述了输入信息的处理过程。
触摸板
触摸板是最常用的输入设备之一,大部分情况下,触摸板会集成在显示面板中。触摸信息的工作流程如下图所示。
触摸板硬件和驱动程序
尽管不同的触摸板芯片具有不同的消息数据结构,但消息始终包含触摸状态和触摸点的坐标。为了传输坐标信息,需要一个数据总线,而 I2C 是触摸芯片和微处理器之间最常用的数据总线。
此外,根据规格要求,不同的触摸芯片需要使用不同的驱动程序,需要进行移植。
获取触摸板数据
在 port_touchpad_get_data
函数中,触摸信息将在 drv_touch_read
中获取,经过简单处理后,作为原始数据供触摸算法处理程序使用。
port_touchpad_get_data
struct gui_touch_port_data *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轴坐标数据的变化以及触摸时间,进行手势识别。
经过算法处理后得到的输入类型如下:
T_GUI_INPUT_TYPE
typedef enum
{
TOUCH_INIT = 0x100,
TOUCH_HOLD_X = 0x101,
TOUCH_HOLD_Y = 0x102,
TOUCH_SHORT = 0x103,
TOUCH_LONG = 0x104,
TOUCH_ORIGIN_FROM_X = 0x105,
TOUCH_ORIGIN_FROM_Y = 0x106,
TOUCH_LEFT_SLIDE = 0x107,
TOUCH_RIGHT_SLIDE = 0x108,
TOUCH_UP_SLIDE = 0x109,
TOUCH_DOWN_SLIDE = 0x10A,
TOUCH_SHORT_BUTTON = 0x10B,
TOUCH_LONG_BUTTON = 0x10C,
TOUCH_UP_SLIDE_TWO_PAGE = 0x10D,
TOUCH_DOWN_SLIDE_TWO_PAGE = 0x10E,
TOUCH_INVALIDE = 0x10F,
KB_INIT = 0x200,
KB_SHORT = 0x201,
KB_LONG = 0x202,
KB_INVALIDE = 0x203,
WHEEL_INIT = 0x300,
WHEEL_ING = 0x301,
WHEEL_FINISHED = 0x302,
WHEEL_INVALIDE = 0x303,
} T_GUI_INPUT_TYPE;
算法处理器将填充 touch_info_t
结构体,该结构体对所有控件可用。
控件响应
一些控件可以对触摸板信息做出响应,例如窗口控件、按钮控件、选项卡控件、窗帘控件和进度条控件。其中,窗口和按钮主要响应点击事件,选项卡、窗帘和进度条主要响应滑动事件。此外,选项卡、窗帘和进度条的显示也取决于 touch_info_t
结构体中的实时触摸坐标。
大多数控件在相应的准备函数中处理触摸信息,比如 win_prepare
。使用 tp_get_info
函数获取触摸信息。
在应用程序层面,可以根据不同类型的事件绑定不同的回调函数,示例如下:
示例
gui_img_t *hour;
gui_img_t *minute;
gui_img_t *second;
void show_clock(void *obj, gui_event_t e)
{
if (GET_BASE(hour) == false)
{
gui_obj_show(hour, false);
gui_obj_show(minute, false);
gui_obj_show(second, false);
gui_img_set_attribute((gui_img_t *)home_bg, "home_bg", home[1], 0, 0);
}
else
{
gui_obj_show(hour, true);
gui_obj_show(minute, true);
gui_obj_show(second, true);
gui_img_set_attribute((gui_img_t *)home_bg, "home_bg", home[0], 0, 0);
}
}
void enter_homelist(void *obj, gui_event_t e)
{
gui_log("enter_tablist \n");
gui_switch_app(gui_current_app(), get_app_homelist());
}
void design_tab_home(void *parent)
{
hour = gui_img_create_from_mem(parent, "hour", TIME_HOUR_BIN, 160, 192, 0, 0);
minute = gui_img_create_from_mem(parent, "minute", TIME_MUNITE_BIN, 160, 192, 0, 0);
second = gui_img_create_from_mem(parent, "second", TIME_SECOND_BIN, 160, 192, 0, 0);
gui_win_t *clock = gui_win_create(parent, "clock", 0, 84, 320, 300);
gui_obj_add_event_cb(clock, (gui_event_cb_t)show_clock, GUI_EVENT_TOUCH_CLICKED, NULL);
gui_obj_add_event_cb(clock, (gui_event_cb_t)enter_homelist, GUI_EVENT_TOUCH_LONG, NULL);
}
在这个例子中,首先创建了一个名为clock的窗口,在点击时执行 show_clock
函数,在长按时执行 enter_homelist
函数。
键盘
键盘信息的工作流程如下图所示:
硬件和驱动程序
键盘的硬件设计和驱动程序比较简单,本章将通过一个单独的 GPIO 来说明。有关如何使用 GPIO 的说明,请参考 SDK 中的说明。您可以使用 rtl87x2g_gpio.c 中的通用 API 或 drv_gpio.c 中的封装 API 来完成相同的操作。
获取键盘数据
在 port_kb_get_data
函数中,会获取键盘信息。 用户根据自己的功能需求填写 port_kb_get_data
,并将结构体填充为键盘输入信息。
键盘算法处理器
键盘算法的代码实现在 kb_algo_process
函数中。
通过按压时间的长短来确定输入的类型是短按还是长按。
算法处理器将填充 kb_info_t
结构体,该结构体对所有控件都可用。
响应
对键盘的响应有两种方式,一种是在控件(如窗口)中响应经过处理的按键信息,另一种是在接收到按键时直接响应按下动作。
第一种方式示例如下所示。
static void win_prepare(gui_obj_t *obj)
{
gui_dispdev_t *dc = gui_get_dc();
touch_info_t *tp = tp_get_info();
kb_info_t *kb = kb_get_info();
if (kb->pressed == true)
{
gui_obj_event_set(obj, GUI_EVENT_KB_DOWN_PRESSED);
}
......
}
对于第二种方式,请参考 GPIO 用户手册。