为了正常的体验网站,请在浏览器设置里面开启Javascript功能!
首页 > 基于ARMlinux平台的Qte自定义键盘实现

基于ARMlinux平台的Qte自定义键盘实现

2018-03-21 9页 doc 48KB 14阅读

用户头像

is_954223

暂无简介

举报
基于ARMlinux平台的Qte自定义键盘实现基于ARMlinux平台的Qte自定义键盘实现 基于 ARM linux 平台的 Qt/e自定义键盘实现 吴俊杰,谭勇 (武汉理工大学 光纤传感技术国家工程实验室,湖北 武汉 430070) 摘 要:随着嵌入式系统的发展,对用户图像界面(GUI)的需求越来越高,具有跨平台特性的 Qt/e 被广泛应用 于嵌入式 GUI 应用开发,底层设备的实现成为我们设计系统最关键的一步。文中深入分析了 Qt/e 的事件驱动原理 和 Qt 的插件机制,结合 s3c2410 的键盘驱动,在 ARM Linux 平台下以插件的形式实现了...
基于ARMlinux平台的Qte自定义键盘实现
基于ARMlinux平台的Qte自定义键盘实现 基于 ARM linux 平台的 Qt/e自定义键盘实现 吴俊杰,谭勇 (武汉理工大学 光纤传感技术国家实验室,湖北 武汉 430070) 摘 要:随着嵌入式系统的发展,对用户图像界面(GUI)的需求越来越高,具有跨平台特性的 Qt/e 被广泛应用 于嵌入式 GUI 应用开发,底层设备的实现成为我们设计系统最关键的一步。文中深入分析了 Qt/e 的事件驱动原理 和 Qt 的插件机制,结合 s3c2410 的键盘驱动,在 ARM Linux 平台下以插件的形式实现了自定义键盘的输入。特 别是分析了键盘事件中插件的加载流程并给出了实现该插件的详细软件设计。 关键词:Qt/e;GUI;ARM;插件 中图分类号:TP316文献标识码:A文章编号:1006-7973(2011)02-0070-03 前言二、Qt/e 事件驱动 Qt 是诺基亚开发的一个跨平台的 C++图形用户界面应 当 Server 收到一个 event 的时候,它需要判断应该发 用程序框架,Qt/e 是面向嵌入式系统的 Qt 版本。Qt/e 是 送给那一个窗口,这时候它就会从 QWSWindow 列表中去 Client/Server 结 构 的 , 不 仅 继 承 了 Qt 在 X Window 查找,然后根据这个窗口去找对应的 client application,然 System 上的强大功能, 而且在底层摒弃了 XIib, 仅采用帧 缓后用一个 QWSEvent 对象来封装这个 event,通过 socket 存作为底层图形接口加快了显示速度。同时, 将外部输入 设机制发送给具体的 client application。如果当前系统安装了 备抽象为 keyboard 和 mouse 输入事件, 底层接口支持 键一个输入法,那么每一次键盘事件产生的时候,都会去调用 盘、鼠标、触摸屏以及用户自定义的设备。输入设备是嵌 入输入法的相应方法。如图 2 所示: 式系统进行友好人机交互时不可或缺的设备, 如鼠标、小 键 盘、触摸屏等, 要让 Qt/e 支持特定的嵌入式输入设备, 需 要 对设备驱动和 Qt/e 的事件驱动非常熟悉, 虽然关于键盘 驱动 方面已有很多的介绍,但都没有结合 Qt 的事件驱动原理 深入 分析键盘的工作流程。本文主要从自己设计的键盘出发 深入 分析了 Qt/e 的事件驱动原理和键盘事件中插件的加载 流程, 并给出了详细的源代码分析,最后实现了该插件的详细 设 计, 对基于嵌入式 Qt 的工程开发有一定的参考价值。 一、Qt/e 的实现结构 Qt/e 不像 Qt 构建在 X Windows 之上,而是构建在 Linux 的 Framebuffer 之上,这样就可以把需要显示的内容 直接写入 framebuffer ,不仅省略了 X Windows 所带来的 系 图 2 输入法事件流程统开销,而且直接写 framebuffer ,加快了显示的速度。 Qt/e 实现的结构图如图 1 所示。但就是这一个改变,导致在 Qt/E 中多出了 Server 这么一层,这一层负责监听系统事件, 尤其是键盘和鼠标事件屏幕输出、管理 region、管理顶层窗 口、管理光标和屏幕保护程序等等诸多功能。 图 3 键盘事件流程 鼠标事件的处理和键盘事件的处理也符合上面的流程。 鼠标驱动由一个 QWSMouseHandler 对象封装,键盘驱动 由一个 QWSKeyboardHandler 封装。这两个驱动程序对象 都 会通过 Qt 的 plugin 机制加载。具体的鼠标和键盘事件发 生 之后,都会封装成为一个 QWSEvent 对象并发送给具体 的 client。如图 3 所示,其具体的实现流程如下: 1(在 Start application 时,带 GUI 的 main 函数都 会创建一个 QApplication 的实例(在 src/gui/kernel/ qapplication.cpp 中),在其构造过程中会调用 qt_init 来 解析命令行参 数,从而调用 QWSServer::startup ( flag 图 1 Qt/e 结构图 收稿日期:2011-01-17 s)。应用命令行如加入了”-qws”选项,就会以 server模块的卸载:module_exit(s3c2410_kbd_exit); (GuiSever) 方 式 运 行 。 QWSServer 的 具 体 的 实 例 就 是 当通过 rmmod 命令卸载模块时,模块的卸载函数就会 在 QWSServer::startup(flags)中创建的。 自动被内核执行,完成与模块加载函数相反的功能。 2(在 QWSServer 的构造函数中会调用 QWSServer 2(中断函数和读操作函数的实现 当完成系统的初始化操作以后, 系统等待按键中断的到 Private::initServer 完成初始化的工作,其中包括各个硬件 接口的初始化,如鼠标,键盘等外设。其中 openKeyboard 来, 一 旦事 件 发生, 系 统 自 动调用 当前 中断处 理函数 就是用来初 始化键盘接 口的。它负 责解析环境 变量 s3c2410_isr_kbd() 。其实现如下:QWS_KEYBOARD 的设定 ,从中取得键 盘设备的名称 和 static void s3c2410_isr_kbd(int irq, void *dev_id, driver handler 的 类 型 , 并 最 终 调 用 QkbdDriver struct pt_regs *reg) Factory::create 函数载入与之对应的键盘处理插件。{ 3(插件加载成功后,QWSKeyboardHandler 派生的 键 disable_irq(IRQ_KBC_INT);//关中断 盘处理类就可以响应键盘事件,封装成为一个 QWSEvent {读数据} 对象后并发送给具体的 client。 三、Qt 插件机制 插件是提wake_up_interruptible(&KBC_wq);//唤醒阻塞程序 供特定接口的动态库,是一个独立文件中的独 enable_irq(IRQ_KBC_INT);//开中断 立模块,可被多个程序访问。} 而Qt 有两种与插件有关的 API。一种用来扩展 Qt 本身的 s3c2410_kbd_read() 函 数 主 要 调 用 功能,如自定义数据库驱动,图像格式,文本编解码,自定 copy_to_user(buffer,(char*)&kbd_ret, 义分格等,称为 Higher-Level API 。另一种用于应用程序 的sizeof(KBD_RET))把数据从内核拷贝到应用层。 3(s3c2410_kbd_poll函数实现 功能扩展,称为 Lower-Level API。前一种是建立在后一 种 的基础之上的。这里讨论的是后一种,即用来扩展应用程 s3c2410_kbd_poll 函数是根据 Qt/e 事件驱动原理设 计 的 , poll 结 构 在 kernel 中 是 通 过 poll_wait(filp, 序的 Lower-level API。 Qt 插件按编译生成方式的不同又分为静态插件和动态 &(kbddev.wq), wait)来达到阻塞的目的, 当没按键时, 上层 插件,这里主要讨论动态插件的创建和加载使用。 自动进入阻塞状态, 当有按键时当前循环队列中有数据, kbddev.head 与 kbddev.tail 不等,返回 POLLIN |使应用程序支持扩展插件主要包括以下几个步骤: 1.定义一个接口集(只有纯虚函数的类),用来与应用程 POLLRDNORM, 就触发信号。 序交流。 static unsigned int s3c2410_kbd_poll(struct file *filp, struct poll_table_struct *wait)2.用宏 Q_DECLARE_INTERFACE ()将该接口告诉 Qt{ 元对象系统。 poll_wait(filp, &(kbddev.wq), wait); 3.在应用程序中用 QPluginLoader 来装载插件。return (kbddev.head == kbddev.tail) ? 0 : 4.用宏 qobject_cast ()来确定一个插件是否实现了接 (POLLIN POLLRDNORM); | 口。 } 四、s3c2410 键盘驱动设计五、自定义键盘插件的实现 S3c2410, 自 定 义小键盘为 硬件环境为 samsung 写一个插件的步骤: ZLG7289,共 17 个键。当有键按下时产生一个中断,然后1.声明插件类,该类从 QObject 和该插件希望实现的接 通过串行传送数据。下面结合 Qt/e 事件驱动原理介绍本系 口继承而来。 统的键盘驱动结构,具体结构如下: 2.用宏 Q_INTERFACES ()将该接口告诉 Qt 元对象 系 统。 static struct file_operations s3c2410_fops = { open: s3c2410_kbd_open,//打开 3.用宏 Q_EXPORT_PLUGIN2 ()导出插件。 read: s3c2410_kbd_read, //读取4.用适当的.pro 文件构建插件。 程序要能感知插件,需要 release: s3c2410_kbd_release,//释放程序和插件共同遵守某种规则。 poll: s3c2410_kbd_poll,//轮询于是定义一个共同的接口,对于我们要自定义的小键盘插件 };而言,键盘接口类 QT 已经为我们写好了统一的一个接口, 1(模块的加载与卸载现在我们要做的就是实现自定义的小键盘插件,重点是创建 由于裁剪内核较为烦琐,本设计将键盘驱动以模块的方 两个类:键盘处理类(Handler)和键盘插件类(Plugin)。 式加载到系统,更加提高了自定义键盘驱动的灵活性。 键 盘 处 理 类 ( Handler ) 是 基 于 QObject 和 QWSKeyboardHandler 派生的,键盘插件类(Plugin)是 基模块的加载:module_init(s3c2410_kbd_init); 当通过 insmod 或 modprobe 命令加载内核模块时,模 于 QKbdDriverPlugin 派生的。 块的加载函数会自动被内核执行,完成本模块的相关初始化 Handler 类的主要作用是完成对底层键盘设备的打开、 工作读取等操作,并将读取到的键值映射为 Qt 支持的键值。一个 关键的函数 readKpdData()就是用来把我们的硬件值 阻塞,通过前面对 poll 的分析可以看到, 唤醒 poll 等待队列 (hardcode)转换为 Qt 库中定义的键值。的时机是当中断处理程序将当前数据读取到缓冲中之后, 系 键盘处理类 KeypadHandler 声明如下代码所示:统会自动将当前阻塞队列唤醒, 接收此信号的处理函数为 :publicQObject,publicreadKpdData(), 此函数用来实现从设备上读取扫描码, 通 class KeypadHandler QWSKeyboardHandler过唯一的扫描码来调用 processKeyEvent() Qt/e 上层 处理接口,processKeyEvent()根据传递的参数来通知上层函 { Q_OBJECT数所需要显示的数据或需要触发的功能键。当按下某个键以 public:后,我们则可以在基于 QT/e 的应用程序中看到输入的数据。 KeypadHandler(const QString &device=QString("/程序实现如下: dev/mcu/kbd")); void ~KeypadHandler();QWSSKBKeyboardHandler::readKeyboardData() private:{ QSocketNotifier *m_notifier;InputData event; int int n = read(KbdFd, &event, sizeof(InputData));KbdFd; if (n != sizeof(InputData))private slots: void readKpdData();{ qDebug("key pressed: n=%d\n", n);}; 的 设 定 后 , 在 当 环 境 变 量 return; QWS_KEYBOARD QWSServer 的构造 函数 中 就会解 析该 环 境变量 ,并 调 用} KeypadHandler 类的构造函数初始化键盘接口。 {根据读取到的 InputData 中的值按软件需求进行相应 KeypadHandler::KeypadHandler(const QString & 赋值} this->processKeyEvent(unicode,key_code,device) {modifiers, event.value != 0, false); qDebug("button pressed\n");} Plugin 类的主要作用是与外部接口(因为在一个动态链this->KbdFd=open(device.toLocal8Bit().constDat a(),O_RDONLY,0); 接库中,Plugin 类是导出的)交互,在该类中创建一个我们 自己定义的键盘处理类对象。 if(KbdFd>=0) {六、结语 目前,在嵌入式领域 Linux 操作系统和 Qt/e 图形界面 asinput.\n",printf("%sopenedkeyboard 库逐渐成为主流。本文依据在嵌入式软件开发中普遍遇到的 device.toLocal8Bit().constData()); 键盘输入处理问,深入分析了 Qt/e 的事件驱动原理和键 盘事件中插件的加载流程,并给出了实现自定义键盘插件的 this->m_notifier = new QSocketNotifier(KbdFd, 详细设计,对 Qt/e 的输入设备的实现有一定的应用价值和 QSocketNotifier::Read, this); 参考价值。 SIGNAL(activated(int)),connect(this->m_notifier, 参考文献 this, SLOT(readKpdData()));[1] 宋宝华.Linux 设备驱动开发详解[M].北京:人民邮电出版 }社,2008,2. else [2] Jasmin Blanchette, Mark Summerfield. C++ GUI Qt4 编程 {(第二版)[M]. 闫锋欣,曾泉人,张志强,译.北京: qWarning("Cannot open %s for keyboard input\n", 电子工业出版社,2008,8. device.toLocal8Bit().constData()); return; }[3] Inside Qt Series ( 十 三 ) : Qt/e 体 系 结 构 概 述 }[OL](2010-01-21. How to Create Qt Plugins[OL]. 通过 KeypadHandler 的实现可以看到, 完成设备的打 [4] 4.7/plugins-howto.html.开以后,系统会注册一个信号槽。信号的发送者是 QSocketNotifier, QSocketNotifier 类是基于阻塞模式实 Deploying Plugins[OL].[5] ment-plugins.html. 现的。它的实现原理是在初始化过程中调用 poll 函数来达到 file:///D|/我的资料/Desktop/新建文本文 档.txt Appliance Error (configuration_error) Your request could not be processed because of a configuration error: "Could not connect to LDAP server." For assistance, contact your network support team. file:///D|/我的资料/Desktop/新建文本文档.txt2012-07-12 20:42:52
/
本文档为【基于ARMlinux平台的Qte自定义键盘实现】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索