转载时请注明出处和作者联系方式
文章出处:http://www.limodev.cn/blog
作者联系方式:李先静 <xianjimli@gmail.com>

在《主循环》一节中, 我们介绍了MainLoop 处理各个事件源的方法,它在事件源上等待事件发生,然后调用事件源的处理函数去处理事件。事件源(FtkSource)是对事件来源的一种抽象,事件的来源可能是一个输入设备(如键盘和触摸屏),可能是一个定时器,也可能是一个网络套接字或管道。总之,只要实现FtkSource要求的接口,就可以让 MainLoop来处理了。

FtkSource 要求实现下列接口函数:

* ftk_source_get_fd 用来获取文件描述符,这个文件描述符不一定是真正的文件描述符,只要是能MainLoop挂在上面等待的句柄(Handle)即可。

* ftk_source_check 用来检查事件源要求等待的时间。-1表示不关心等待时间。0表示要马上就有事件发生,正数表示在指定的时间内将有事件发生。

* ftk_source_dispatch 用来处理事件,每个事件源都有自己的处理函数,这样可以简化程序的实现。

目前FTK内部使用的事件源主要有:

1.ftk_source_input(.c/.h)

在Linux下,输入设备文件都在/dev /input/下,并用一致的事件结构(input_event)将事件上报给应用程序,ftk_source_input是针对这些设备文件实现的事件源。

由于是从设备文件读取输入事件,那主循环可以挂在这些设备文件上等待事件发生。所以ftk_source_get_fd只要返回文件描述符,而 ftk_source_check返回-1即可。

static int ftk_source_input_get_fd(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
 
    return priv->fd;
}
 
static int ftk_source_input_check(FtkSource* thiz)
{
    return -1;
}

ftk_source_dispatch中读取事件(input_event),将它转换成FTK的事件结构,然后通过将事件分发(调用 ftk_wnd_manager_queue_event)出去。

键值的映射是放在表 s_key_mapp中的:

static unsigned short s_key_map[0x100] =
{
    [KEY_1]           =  FTK_KEY_1,
    [KEY_2]           =  FTK_KEY_2,
    [KEY_3]           =  FTK_KEY_3,
    [KEY_4]           =  FTK_KEY_4,
    [KEY_5]           =  FTK_KEY_5,
    [KEY_6]           =  FTK_KEY_6,
    [KEY_7]           =  FTK_KEY_7,
   ...
};

如果有特殊键值或其它需求,修改这个结构即可。

2.ftk_source_dfb(.c/.h)

FTK可以用DirectFB作为 backend,ftk_source_dfb是针对DirectFB输入事件实现的事件源。DirectFB可以通从EventBuffer直接读取,也可以从EventBuffer获取一个管道的文件描述符,然后从这个管道读取事件。为了方便,我们使用后者来实现ftk_source_dfb,主循环可以挂在这个文件描述符上等待事件。所以ftk_source_get_fd只要返回文件描述符,而 ftk_source_check返回-1即可。

static int  ftk_source_dfb_get_fd(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
 
    return priv->fd;
}
 
static int  ftk_source_dfb_check(FtkSource* thiz)
{
    return -1;
}

ftk_source_dispatch中读取事件(DFBEvent),将它转换成FTK的事件结构,然后通过将事件分发(调用 ftk_wnd_manager_queue_event)出去。

键值的映射是放在表 s_key_mapp中的:

static const int s_key_map[] =
{
    [DIKI_A-DIKI_UNKNOWN]              =  FTK_KEY_a,
    [DIKI_B-DIKI_UNKNOWN]              =  FTK_KEY_b,
    [DIKI_C-DIKI_UNKNOWN]              =  FTK_KEY_c,
    [DIKI_D-DIKI_UNKNOWN]              =  FTK_KEY_d,
    [DIKI_E-DIKI_UNKNOWN]              =  FTK_KEY_e,
    [DIKI_F-DIKI_UNKNOWN]              =  FTK_KEY_f,
    [DIKI_G-DIKI_UNKNOWN]              =  FTK_KEY_g,
    [DIKI_H-DIKI_UNKNOWN]              =  FTK_KEY_h,
   ...
};

如果有特殊键值或其它需求,修改这个结构即可。

3.ftk_source_tslib(.c/.h)

对于电阻式的触摸屏,虽然通常在Linux下也是通过(/dev/input)下的设备文件上报事件的,但是需要对输入事件进行去抖、滤波和校正之后才能使用,tslib是专门做这些工作的,所以这时我们用tslib读取事件是更明智的选择。

tslib 提供了一个函数用于获取文件描述符,主循环可以挂在这个文件描述符上等待事件。所以ftk_source_get_fd只要返回文件描述符,而 ftk_source_check返回-1即可。

static int ftk_source_tslib_get_fd(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
    return_val_if_fail(priv != NULL && priv->ts != NULL, -1);
 
    return ts_fd(priv->ts);
}
 
static int ftk_source_tslib_check(FtkSource* thiz)
{
    return -1;
}

ftk_source_dispatch中读取事件(ts_sample),将它转换成FTK的事件结构,然后通过将事件分发(调用 ftk_wnd_manager_queue_event)出去。

4.ftk_source_primary(.c/.h)

ftk_source_primary的地位比较特别,相当于其它GUI中的事件队列。

ftk_source_primary 使用管道来实现队列先进先出(FIFO)的特性,这样可以避免引入互斥机制来保护队列,管道有自己的文件描述符,主循环可以挂在这个文件描述符上等待事件。所以ftk_source_get_fd只要返回文件描述符,而 ftk_source_check返回-1即可。

static int ftk_source_primary_get_fd(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
    return_val_if_fail(priv != NULL, -1);
 
    return ftk_pipe_get_read_handle(priv->pipe);
}
 
static int ftk_source_primary_check(FtkSource* thiz)
{
    return -1;
}

ftk_source_primary_dispatch 函数中对FTK_EVT_ADD_SOURCE/FTK_EVT_REMOVE_SOURCE两个事件做了特殊处理,用于增加和移除事件源,对于其余事件只是调用窗口管理器的事件分发函数(ftk_wnd_manager_default_dispatch_event)去处理事件。

ftk_source_primary提供了 ftk_source_queue_event用于向管道中写入事件,向管道中写入事件当于其它GUI向事件队列中增加事件。

5.ftk_source_timer

ftk_source_timer主要用于定时执行一个动作,比如闪动光标和更新时间。它与前面的事件源不同的是,它没有相应的文件描述符,主循环无法通过挂在文件描述符上来等待事件的发生。所以 ftk_source_get_fd始终返回-1:

static int ftk_source_timer_get_fd(FtkSource* thiz)
{
    return -1;
}

ftk_source_check返回下一次事件发生的时间间隔,告诉MainLoop 必须在这个时刻唤醒,并执行处理函数:

static int ftk_source_timer_check(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
    int t = priv->next_time - ftk_get_relative_time();
 
    t = t < 0 ? 0 : t;
 
    return t;
}

ftk_source_timer_dispatch 的实现很简单,它计算下一次timer的时间,然后调用用户设置的回调函数。

tatic Ret ftk_source_timer_dispatch(FtkSource* thiz)
{
    Ret ret = RET_FAIL;
    DECL_PRIV(thiz, priv);
    return_val_if_fail(priv->action != NULL, RET_REMOVE);
 
    if(thiz->disable > 0)
    {
       ftk_source_timer_calc_timer(priv);
       return RET_OK;
    }
 
    ret = priv->action(priv->user_data);
    ftk_source_timer_calc_timer(priv);
 
    return ret;
}

5.ftk_source_idle(.c/.h)

idle的主要用途有:

* 在空闲时执行低优先级任务。有的任务优先级比较低,但费耗时间相对较长,比如屏幕刷新等操作。如果为了避免它阻碍当前操作太久,此时我们把它放到idle 里去做。

* 将同步操作异步化。有的操作你可能不希望它在当前的处理函数中同步执行,这时也可以用idle来异步化 ,让它在后面的dispatch中执行。

* 串行化对GUI的访问。在FTK中,出于效率的考虑, GUI对象是没有加锁保护的,也就是只有GUI线程能访问这些对象。如果其它线程要访问GUI对象,此时就需要用idle来串行化了。idle是GUI线程(主线程)中执行的,所以它能访问GUI对象。

idle的实现有点timeout为0的定时器,把它独立出来主要为了概念上更清楚一点:

static int ftk_source_idle_get_fd(FtkSource* thiz)
{
    return -1;
}
 
static int ftk_source_idle_check(FtkSource* thiz)
{
    return 0;
}

ftk_source_idle_dispatch 只是简单的调用用户设置的回调函数。

static Ret ftk_source_idle_dispatch(FtkSource* thiz)
{
    DECL_PRIV(thiz, priv);
 
    return_val_if_fail(priv->action != NULL, RET_REMOVE);
 
    if(thiz->disable > 0)
    {
       return RET_OK;
    }
 
    return priv->action(priv->user_data);
}

FTK中还有其它一些事件源,比如针对X11模拟运行的事件源,它们的实现都是类似的,这里就不再多说了。

嵌入式GUI FTK设计与实现-事件源(FtkSource)相关推荐

  1. 嵌入式GUI FTK设计与实现-主循环

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 转载时请 ...

  2. 嵌入式GUI FTK 界面设计器

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 嵌入式G ...

  3. 嵌入式GUI FTK支持输入法

    From: http://blog.csdn.net/absurd/article/details/5318285 春节期间给FTK增加输入法支持,目前支持拼音输入法,五笔输入法和手写输入法.手写输入 ...

  4. 费诺编码的gui页面设计_GUI设计和UI设计有什么区别?

    首先从技术的角度分析两者处于包含与被包含的关系. GUI=Graphical User Interface,是指在计算机出现后,在屏幕上使用图形界面来帮助(User)与机器打交道用的界面接口,泛指在计 ...

  5. 嵌入式系统开发设计---嵌入式系统开发设计

    嵌入式系统设计的主要任务是定义系统的功能.决定系统的架构,并将功能映射到系统实现架构上.这里,系统架构既包括软件系统架构也包括硬件系统架构.一种架构可以映射到各种不同的物理实现,每种实现表示不同的取舍 ...

  6. 嵌入式GUI分析详解

    随着手机.智能手表等便携式设备的普及,用户对GUI的要求越来越高,嵌入式系统对GUI的需求也越来越迫切,本文将为大家介绍一个轻型.占用资源少.高性能.高可靠.便于移植.可配置及美观的GUI编程框架. ...

  7. 嵌入式系统软件架构设计

    嵌入式系统软件架构设计 目录 1. 前言 4 2. 决定架构的因素和架构的影响 4 2.1. 常见的误解 5 2.1.1. 小型的系统不需要架构 5 2.1.2. 敏捷开发不需要架构 7 3. 嵌入式 ...

  8. python framebuffer gui_基于Framebuffer的嵌入式GUI系统实现

    摘要:本文研究了基于Framebuffer的嵌入式GUI的系统实现,包括其体系结构层次的建立.驱动机制的分析.微型客户端/服务器模式的实现,以及基于Framebuffer的GAL与GDI的设计等关键内 ...

  9. 当前主流的小型嵌入式GUI有哪些?

    关注+星标公众号,不错过精彩内容 来源 | 安富莱 TouchGFX TouchGFX以界面华丽,流畅以及强劲的TouchGFX Designer著称. 官方地址: ❝ https://www.tou ...

最新文章

  1. select子查询多个字段_SQL复杂查询
  2. 简单使用JDOM解析XML
  3. 回调 that.setdata 数据不更新_重大利空落地,或损上亿利润,乐普医疗回调近四成...
  4. 最短路弗洛伊德(Floyd)算法加保存路径
  5. linux C 应用消息队列在两个进程间通信
  6. go 判断是否域名_Go编程:对不起,你的 CPU 泄露了
  7. 如何打造7*24h持续交付通道?阿里高级技术专家的5点思考
  8. PPT中插入图片背景透明化小技巧
  9. 制作照片边框 初学者 ps
  10. 法人≠法人代表≠法定代表人!
  11. 8.12 腾讯大战360 2133
  12. 局域网共享文件夹现在内存不足_局域网文件夹共享给指定用户的方法
  13. CSS —— 选择器
  14. mysql spatial简介_详细介绍mysql索引类型:FULLTEXT、NORMAL、SPATIAL、UNIQUE
  15. ccf-csp历届第一题题解 (一)14-17年 (ง •_•)ง
  16. (Amazon)亚马逊GIF动态验证码识别,95识别率
  17. python 操作鼠标和键盘
  18. 图像的基本运算——scale, rotation, translation
  19. uni-app -- 改变页面背景颜色
  20. 在做电商网站之前先理清自己建站目的是什么

热门文章

  1. 在腾讯云服务器Linux系统中安装MySQL【完美解决】
  2. ipmitool查看服务器主板信息,86 ipmitools-查看硬件信息工具
  3. VS2017中NCNN使用vulkan
  4. swap、swappiness以及kswapd
  5. TXAA,MSAA,SMAA,FXAA
  6. java 字符数组对象_java-将对象数组转换为字符串数组
  7. 软件验收测试有什么标准和注意事项?
  8. JAVA各种加密与解密方式
  9. matlab 转移矩阵,在Matlab中构造多阶马尔可夫链转移矩阵
  10. Linux页表 - - 启动过程临时页表创建过程