zoukankan      html  css  js  c++  java
  • 让qt应用程序支持触摸

    一.设备驱动

    我的触摸屏是usb接口的
    可以参考下这2篇文件
    http://blog.csdn.net/paomadi/article/details/8754783 usb触摸屏
    http://blog.csdn.net/paomadi/article/details/8309861 输入子系统

    不是usb接口的或者自己想写多一个也可以(需要我的源码的请留邮箱说下,我贴一部分)
    usb子系统部分关键在于urb的数据传递

    input子系统部分关键在于事件的设置及上报

    #define M //多点触摸点数
    在初始化init或者probe方法中
    input_dev=input_allocate_device();//分配初始化输入设备
    //(最好构建一个对象结构体,包含input设备和usb设备,或其他设备,将各个子系统的设备捆绑到一个对象中去)
    
    set_bit(EV_KEY, input_dev->evbit);	//设置事件类型标志位
    set_bit(EV_ABS, input_dev->evbit);
    
    set_bit(BTN_TOUCH, input_dev->keybit);	//设置按键类型标志
    
    #if M
    //多点的这么设置参数(我的屏只支持单点,so没亲测)
    input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,1920, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,1080, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
    #else
    //单点的参数设置
    input_set_abs_params(input_dev, ABS_X, 0, 0x7FFF, 0, 0);	//设置参数
    input_set_abs_params(input_dev, ABS_Y, 0, 0x7FFF, 0, 0);
    input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0);
    #endif
    	
    在接收到数据之后上报事件给input子系统
    #if M
    	//input_report_abs(touch->input, ABS_MT_TOUCH_MAJOR, 0);
    	for(i=0;i<M;i++){
    		input_report_abs(touchkit->input, ABS_MT_TRACKING_ID,0);
    		input_report_key(touchkit->input, BTN_TOUCH, touchkit->press);
    		input_report_abs(touchkit->input, ABS_MT_POSITION_X, touchkit->x);
    		input_report_abs(touchkit->input, ABS_MT_POSITION_Y, touchkit->y);
    		input_report_abs(touchkit->input, ABS_PRESSURE, touchkit->press);
    		input_mt_sync(touchkit->input);	
    	}
    #else
    	input_report_abs(input_dev, ABS_X, touchkit->x);
    	input_report_abs(input_dev, ABS_Y, touchkit->y);
    	input_report_key(input_dev, BTN_TOUCH,touchkit->press);
    	input_report_abs(input_dev, ABS_PRESSURE, touchkit->press);
    #endif
    	input_sync(input_dev);

    usb能匹配直接用hid子系统那是极好的

    可以这样调试hid的设备
    mkidr /tmp/debugfs
    mount -t debugfs debugfs /tmp/debugfs
    cd /tmp/debugfs
    cd hid
    cd 进对应的hid设备文件夹
    cat event

    其他的一些调试查看方法

    ls -l /dev/input查看输入input设备
    其中可以看到 lrwxrwxrwx    1 root     root            6 Jan  1  2000 touchscreen0 -> event1
    /dev/input/touchscreen0是链接文件,链接到对应的触摸屏event1设备

    查看event1是否触摸设备
    cd /sys/class/input
    cd event1
    cd device
    cat name
    或者
    cat /proc/bus/input/devices
    比较Handlers和Name

    cat /dev/input/touchscreen|hexdump 点击触摸屏查看接收到的数据


    二.tslib

    升级工具
    sudo apt-get install autoconf
    sudo apt-get install automake
    sudo apt-get install libtool

    解压tslib
    tar xzf tslib-1.4.tar.gz
    cd tslib
    生产configure文件
    ./autogen.sh
    创建安装目录
    mkdir tmp
    配置生成makefile文件
    echo "ac_cv_func_malloc_0_nonnull=yes" >arm-none-linux-gnueabi.cache
    ./configure --host=arm-none-linux-gnueabi --cache-file=arm-none-linux-gnueabi.cache --prefix=$(pwd)/tmp
    编译tslib
    make
    安装tslib
    make install

    安装完成后生成4个目录
    /bin 目录包含ts_calibrate ts_test ts_harvest ts_print ts_print_raw测试执行文件
    /etc 目录包含ts.conf配置文件
    /include 目录包含 tslib.h头文件
    /lib 目录包含 pkgconfig目录和ts目录和*.so(libts.so等)动态链接库

    检验文件是否用交叉工具链编译的
    file ts_calibrate查看打印的信息

    文件系统配置
    将/bin目录的和/etc目录下的文件复制到目标板文件系统的同样目录下
    /include和/lib目录复制到目标板文件系统的/usr目录下

    配置ts.conf
    module_raw input
    module pthres pmin=1
    module variance delta=30
    module dejitter delta=100
    module linear

    配置环境变量
    打开目标板文件系统/etc/profile文件
    export LD_LIBRARY_PATH=/usr/lib/    --库文件目录
    export TSLIB_ROOT=/usr/       --tslib库文件/头文件根目录
    export TSLIB_TSDEVICE=/dev/input/touchscreen0 --触摸屏设备文件路径
    export TSLIB_CALIBFILE=/etc/pointercal   --校正文件路径 运行ts_calibrates会自动生成
    export TSLIB_CONFFILE=/etc/ts.conf    --配置文件路径
    export TSLIB_CONSOLEDEVICE=none     --
    export TSLIB_FBDEVICE=/dev/fb0     --fb显示设备文件路径
    export TSLIB_TSEVENTTYPE=INPUT     --触摸事件类型 input子系统
    export TSLIB_PLUGINDIR=/usr/lib/ts    --

    tslib测试
    运行ts_calibrate
    打印:
    xres = 1920, yres = 1080
    显示屏出现校正画面
    点击方块(左上角)
    打印:
    Took 1 samples...
    Top left : X =  752 Y = 1248
    再次点击方块(右上角)
    打印:
    Took 2 samples...
    Top right : X = 31938 Y = 1468
    再次点击方块(右下角)
    打印:
    Took 2 samples...
    Bot right : X = 31986 Y = 30926
    再次点击方块(左下角)
    打印:
    Took 1 samples...
    Bot left : X =  728 Y = 31278
    再次点击方块(正中间)
    打印:
    Took 1 samples...
    Center : X = 16387 Y = 16403
    3.813721 0.058434 0.000070
    3.860352 0.000071 0.032752
    Calibration constants: 249936 3829 4 252992 4 2146 65536

    校验完在/etc目录下生成/etc/pointercal

    ts_calibrate可能会遇到一些问题
    提示不是支持的触摸屏:查看TSLIB_TSDEVICE环境变量是否设置对
    没点击方块就自动校正了:1.驱动BTN_TOUCH或者ABS_PRESSURE的值固化成1了(有上报按下事件没上报松开事件)
          2.库文件放错位置

    运行ts_test
    点击Drag按钮 可以拖动小方块
    点击Draw按钮 可以在屏幕上画线
    点击的时候会打印:xxx:[x坐标] [y坐标] [按下1/松开0]
    1345221722.121520:   1920   1074      1
    1345221722.121520:   1920   1074      1
    1345221722.354517:   1920   1078      0
    1345221724.035519:   1851    838      1
    1345221724.045521:   1849    835      1
    1345221724.065520:   1845    829      1
    1345221724.081520:   1840    823      1
    1345221724.091521:   1834    816      1
    1345221724.104521:   1828    810      1
    1345221724.121520:   1821    803      1
    1345221724.137518:   1814    797      1
    1345221724.153520:   1807    790      1

    三.qt everywhere 4.8.1编译

    重新配置tslib
    /configure --host=arm-none-linux-gnueabi --cache-file=arm-none-linux-gnueabi.cache --prefix=/usr/local/tslib
    修改安装目录
    make
    make install

    修改qt-everywhere-opensource-src-4.8.1/mkspecs/qws/【xxx】/qmake.conf文件
    QMAKE_CC = arm-none-linux-gnueabi-gcc -lts
    QMAKE_CXX = arm-none-linux-gnueabi-g++ -lts
    QMAKE_LINK = arm-none-linux-gnueabi-g++ -lts
    QMAKE_LINK_SHLIB = arm-none-linux-gnueabi-g++ -lts

    QMAKE_INCDIR =/usr/local/tslib/include
    QMAKE_LIBDIR =/usr/local/tslib/lib

    配置qt
    .configure 后面加上 -no-mouse-linuxtp -qt-mouse-tslib
    在test的过程中打印
    Mouse driver(qt) ......pc tslib
    表示库安装成功并成功检测到

    编译qt
    make
    make install

    example里面选择应用程序(推荐qt-everywhere-opensource-src-4.8.1/examples/widgets/calculator)
    拷贝到目标板文件系统里
    ldd calculator 查看calculator需要调用的库
    打印:

            libts-0.0.so.0 => /usr/lib/libts-0.0.so.0 (0x2ac3f000)
            libQtGui.so.4 => /usr/lib/libQtGui.so.4 (0x2ac49000)
            libQtNetwork.so.4 => /usr/lib/libQtNetwork.so.4 (0x2b6ae000)
            libQtCore.so.4 => /usr/lib/libQtCore.so.4 (0x2b7d6000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x2ab6a000)
            libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x2bb35000)
            libm.so.6 => /lib/libm.so.6 (0x2ab8a000)
            libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2ab40000)
            libc.so.6 => /lib/libc.so.6 (0x2bc07000)
            libdl.so.2 => /lib/libdl.so.2 (0x2bd31000)
            librt.so.1 => /lib/librt.so.1 (0x2ab10000)
            /lib/ld-linux.so.3 (0x2aaea000)

    看到libts-0.0.so.0说明tslib在qt中移植成功
    ldd是个脚本,交叉工具链里面找

    拷贝库文件到/usr/lib
    在qt-everywhere-opensource-src-4.8.1/lib里面有la、prl、so和so.xxx文件
    拷贝so和so.xxx文件就行

    配置环境变量
    打开目标板文件系统/etc/profile文件,添加以下
    export LD_LIBRARY_PATH=/usr/lib/ ----库文件目录
    export QWS_SIZE=1920x1080   ----分辨率
    export QWS_MOUSE_PROTO="tslib:/dev/input/touchscreen0 mouseman:/dev/input/mouse0" ----"鼠标"类型

    QWS_MOUSE_PROTO指定qt的鼠标,由【”】【第1个设备名字】【:】【设备文件路径】【空格】【第2个设备名字】【:】【设备文件路径】...【“】构成设备名字不区分大小写
    设备名字可以是:(tslib、qnx、integrity、linuxtp、auto、intellimouse、microsoft、mousesystems、mouseman、linuxinput、usb、linuxis...)
    该环境变量在qt源码qt-everywhere-opensource-src-4.8.1/src/gui/embedded/Qwindowsystem_qws.cpp的QWSServer::openMouse()函数中读取
    QString mice=QString::fromLatin1(qgetenv("QWS_MOUSE_PROTO"))语句读入到mice,调试分析可以从这里入手
    打印读取的环境变量:qDebug()<<mice,读取环境变量到mice后会判断mice中有多少个空格" ",也就是判断有多少个“鼠标”设备,个数作为后面for语句的循环因子,
    for语句则调用QWSMouseHandler *handler=d->newMouseHandler(mouse.at(i))创建"鼠标"句柄,-->QMouseDriverFactory::create-->具体“鼠标”设备句柄的创建函数

    QWSMouseHandler *QMouseDriverFactory::create(const QString& key, const QString &device)
    {
        QString driver = key.toLower();
    #if defined(Q_OS_QNX) && !defined(QT_NO_QWS_MOUSE_QNX)
        if (driver == QLatin1String("qnx") || driver.isEmpty())
            return new QQnxMouseHandler(key, device);
    #endif
    #if defined(Q_OS_INTEGRITY) && !defined(QT_NO_MOUSE_INTEGRITY)
        if (driver == QLatin1String("integrity") || driver.isEmpty())
            return new QIntMouseHandler(key, device);
    #endif
    #ifndef QT_NO_QWS_MOUSE_LINUXTP
        if (driver == QLatin1String("linuxtp") || driver.isEmpty())
            return new QWSLinuxTPMouseHandler(key, device);
    #endif
    #ifndef QT_NO_QWS_MOUSE_PC
        if (driver == QLatin1String("auto")
            || driver == QLatin1String("intellimouse")
            || driver == QLatin1String("microsoft")
            || driver == QLatin1String("mousesystems")
            || driver == QLatin1String("mouseman")
            || driver.isEmpty()) {
            return new QWSPcMouseHandler(key, device);					//mice...
        }
    #endif
    #ifndef QT_NO_QWS_MOUSE_TSLIB
        if (driver == QLatin1String("tslib") || driver.isEmpty())		//tslib
            return new QWSTslibMouseHandler(key, device);
    #endif
    # ifndef QT_NO_QWS_MOUSE_LINUXINPUT
        if (driver == QLatin1String("linuxinput") || 
            driver == QLatin1String("usb") || 
            driver == QLatin1String("linuxis"))
            return new QWSLinuxInputMouseHandler(device);
    # endif
    #ifndef QT_NO_QWS_MOUSE_QVFB
        if (driver == QLatin1String("qvfbmouse") || driver == QLatin1String("qvfb"))
            return new QVFbMouseHandler(key, device);
    #endif
    
    #if !defined(Q_OS_WIN32) || defined(QT_MAKEDLL)
    #ifndef QT_NO_LIBRARY
        if (QWSMouseHandlerFactoryInterface *factory = qobject_cast<QWSMouseHandlerFactoryInterface*>(loader()->instance(driver)))
            return factory->create(driver, device);
    #endif
    #endif
        return 0;
    }

    如果鼠标类型没指定(mouseman之类的),则默认会调用/dev/input/mice这样会使你的触摸有点漂移的感觉,其实读取mice的数据时候读出来的数据是绝对位移+相对位移...的值
    所以会漂移,这个情况很多人都碰到过,指定到专用的鼠标例如mouseman:/dev/input/mouse0这样的话就没问题了。
    mice的读方法可以查看内核的mousedev.c文件的mousedev_read方法,其中有一句
    memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
    接着
    copy_to_user(buffer, data, count) //有时间的不烦试试研究下这个

    还有一种情况会引起漂移现象,那就是你的环境变量没读取对,
    也就是QWS_MOUSE_PROTO为空,所以最好添加qDebug()<<mice去调试一下,悲剧的是我就是碰到这种情况,即使用env查看是正确的也不一定说明你读取的环境变量是对的,你的应用程序
    可能是在其他级别的用户或者在其他的bash环境下执行的,你的环境变量不一定对他起效.修改代码调试编译qt时候只需重新make一次,然后把前面说的库文件拷贝过去目标板就行了,
    不费时间的

    这里的QWS_MOUSE_PROTO的设置最好要写个shell脚本测试下是否插了鼠标,是否插了触摸屏根据判断的结果来不同的设置QWS_MOUSE_PROTO环境变量最好

    查看你应用程序调用了那个input设备,使用lsof命令工具
    lsof /dev/input/touchscreen0
    打印:
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    xxxx 1771 root   41r   CHR  13,65      0t0 2326 /dev/input/event1
    就是说xxxx打开了/dev/input/touchscreen0这个设备,这个设备是链接文件链接到/dev/input/event1


    如果设备文件打开正确,但是触摸时候鼠标指针不动,运行一下ts_calibrate生成pointercal文件后再试试
    这里可以添加下面shell脚本,在你打开qt应用程序前先判断是否校正过了,矫正过则执行qt程序,没校正过则校正一下

    if [ ! -f "/etc/pointercal" ]; then 
    	ts_calibrate
    fi


     

  • 相关阅读:
    私有云是伪命题:真正的私有云 ≈ 公有云
    云计算的重新构建架构:优化迁移策略
    五个顶级的大数据架构
    Algorithm Gossip: 费式数列
    Algorithm Gossip: 河内塔
    Mysql连接报错:Unknown system variable 'language'
    ssm整合的时候出现的abstactMethodArror 解决
    java集合整理
    Oracle的序列和索引
    关于java堆栈的理解与说明
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3146738.html
Copyright © 2011-2022 走看看