? ? 大家好,我是ST。
? ? 今天主要和大家聊一聊,如何使用tslib庫來完成對應(yīng)的功能。
第一:tslib庫基本簡介
? ? 上篇文章為了獲取觸摸點,主要是對讀取到的struct input_event類型數(shù)據(jù)進行分析,得到各個觸摸點坐標。接下來,主要使用tslib庫進行學習,這是Linux系統(tǒng)下,專門為觸摸屏開發(fā)的應(yīng)用層函數(shù)庫。
? ? ?tslib庫是開源的,也就是可以直接獲取到tslib的源代碼。tslib為觸摸屏驅(qū)動和應(yīng)用層之間的適配層,它把應(yīng)用程序中讀取觸摸屏struct input_event類型數(shù)據(jù)(這是輸入設(shè)備上報給應(yīng)用層的原始數(shù)據(jù))并進行解析的操作過程進行了封裝,向使用者提供了封裝好的API接口。tslib從觸摸屏中獲得原始的坐標數(shù)據(jù),并通過一系列的去抖、坐標變換等操作,來去除噪聲并將原始的觸摸屏坐標轉(zhuǎn)換為相應(yīng)的屏幕坐標。
? ? tslib可以作為Qt的觸摸屏輸入插件,為Qt提供觸摸輸入支持,如果在嵌入式Linux硬件平臺上開發(fā)過Qt應(yīng)用程序應(yīng)該知道,并不是只有 tslib 才能作為 Qt 的插件、為其提供觸摸輸入支持,還有很多插件都可以。
第二:tslib安裝目錄下的文件夾介紹
? ? ?進入到tslib安裝目錄下:
? ? ?bin目錄
? ? ?bin目錄下有一些tslib提供的小工具,可以用于測試觸摸屏,如下所示:
? ? ?etc目錄
? ? ?etc目錄下有一個配置文件ts.conf,前面給大家提到過:
? ???打開ts.conf文件看看它有哪些配置選項:
? ? ? module_raw input:取消注釋,使能支持input輸入事件;
module pthres pmin=1:如果我們的設(shè)備支持按壓力大小測試,那么可以把它的注釋取消,pmin 用于調(diào)節(jié)按壓力靈敏度,默認就是等于 1。
module dejitter delta=100:tslib 提供了觸摸屏去噪算法插件,如果需要過濾噪聲樣本,取消注釋,默認參數(shù) delta=100。
module linear:tslib 提供了觸摸屏坐標變換的功能,譬如將 X、Y 坐標互換、坐標旋轉(zhuǎn)等之類,如果我們需要實現(xiàn)坐標變換,可以把注釋去掉。
這里就不去改動了,直接使用默認的配置就行了。
? ? ?include?目錄
? ? ?include目錄下只有一個頭文件tslib.h,該頭文件中包含了一些結(jié)構(gòu)體數(shù)據(jù)結(jié)構(gòu)以及API接口的聲明,使用tslib提供的API就需要包含該頭文件。
? ? ?lib目錄
? ? ?lib目錄下包含了編譯tslib源碼所得到的庫文件,默認這些都是動態(tài)庫文件,也可以通過配置tslib工程使其生成靜態(tài)庫文件;ts目錄下存放的是一些插件庫。
第三:在開發(fā)板上測試tslib庫
? ? ??使用tslib提供的API接口來編寫觸摸屏的應(yīng)用程序,使用tslib庫函數(shù)需要在我們的應(yīng)用程序中包含tslib的頭文件tslib.h,使用tslib編程其實非常簡單,基本步驟如下所示:
? ? ?? 第一步打開觸摸屏設(shè)備;
?? ? ? 第二步配置觸摸屏設(shè)備;
? ? ? ?第三步讀取觸摸屏數(shù)據(jù);
?1、打開觸摸屏設(shè)備
? ? ??使用tslib提供的庫函數(shù)ts_open打開觸摸屏設(shè)備,其函數(shù)原型如下所示:
?
#include "tslib.h" struct?tsdev?*ts_open(const?char?*dev_name,int?nonblock);
?
? ? ? 參數(shù)dev_name 指定了觸摸屏的設(shè)備節(jié)點;參數(shù)nonblock表示是否以非阻塞方式打開觸摸屏設(shè)備,如果nonblock等于0表示阻塞方式,如果為非0值則表示以非阻塞方式打開。
? ? ??調(diào)用成功返回一個struct sdev *指針,指向觸摸屏設(shè)備句柄;如果打開設(shè)備失敗,將返回NULL。除了使用ts_open()打開設(shè)備外,還可以使用ts_setup()函數(shù),其函數(shù)原型如下所示:
?
#inlcude "tslib.h"
?
? ?參數(shù) dev_name 指定觸摸屏的設(shè)備節(jié)點,與 ts_open()函數(shù)中的 dev_name 參數(shù)意義相同;但對于 ts_setup()來說,參數(shù) dev_name 可以設(shè)置為 NULL,當 dev_name 設(shè)置為 NULL 時,ts_setup()函數(shù)內(nèi)部會讀取TSLIB_TSDEVICE 環(huán)境變量,獲取該環(huán)境變量的內(nèi)容以得知觸摸屏的設(shè)備節(jié)點。
? ? ?ts_setup()相比ts_open(),除了打開觸摸屏設(shè)備外,還可以對觸摸屏設(shè)備進行配置。
2、配置觸摸屏設(shè)備
? ? ?調(diào)用ts_config()函數(shù)進行配置,其函數(shù)原型如下所示:
?
#include?"tslib.h" int ts_config(struct tsdev *ts)
?
? ? ?參數(shù)ts指向觸摸屏句柄。
? ? ?成功返回0,失敗返回-1。
? ? ?所謂配置其實指的就是解析ts.conf文件中的配置信息,加載相應(yīng)的插件。
第四:讀取觸摸屏數(shù)據(jù)
? ? ?讀取觸摸屏數(shù)據(jù)使用 ts_read()或 ts_read_mt()函數(shù),區(qū)別在于 ts_read 用于讀取單點觸摸數(shù)據(jù),而ts_read_mt 則用于讀取多點觸摸數(shù)據(jù),其函數(shù)原型如下所示:
?
#include "tslib.h" int ts_read(struct tsdev *ts,struct ts_sample *samp,int nr) int ts_read_mt(struct tsdev *ts, struct ts_sample_mt **samp, int max_slots, int nr)
?
? ? ? 參數(shù)ts指向一個觸摸屏設(shè)備句柄,參數(shù)nr表示對一個觸摸點的采樣數(shù),設(shè)置為1即可。
? ? ? ts_read_mt()函數(shù)有一個 max_slots 參數(shù),表示觸摸屏支持的最大觸摸點數(shù),應(yīng)用程序可以通過調(diào)用 ioctl()函數(shù)來獲取觸摸屏支持的最大觸摸點數(shù)以及觸摸屏坐標的最大分辨率等信息,稍后向大家介紹。
? ? ? ts_read()函數(shù)的 samp 參數(shù)是一個 struct ts_sample *類型的指針,指向一個 struct ts_sample 對象,struct ts_sample 數(shù)據(jù)結(jié)構(gòu)描述了觸摸點的信息;調(diào)用 ts_read()函數(shù)獲取到的數(shù)據(jù)會存放在 samp 指針所指向的內(nèi)存中。struct ts_sample 結(jié)構(gòu)體內(nèi)容如下所示:
?
struct ts_sample{ int x; //X坐標 int y; //Y坐標 unsigned int pressure; //按壓力大小 ?????struct timeval tv; //時間 };
?
? ? ? ts_read_mt()函數(shù)的 samp 參數(shù)是一個 struct ts_sample_mt **類型的指針,多點觸摸應(yīng)用程序,每一個觸摸點的信息使用 struct ts_sample_mt 數(shù)據(jù)結(jié)構(gòu)來描述;一個觸摸點的數(shù)據(jù)使用一個 struct ts_sample_mt 對象來裝載,將它們組織成一個 struct ts_sample_mt 數(shù)組,調(diào)用 ts_read_mt()時,將數(shù)組地址賦值給 samp 參數(shù)。
? ? ?struct ts_sample結(jié)構(gòu)體內(nèi)容如下所示:
?
struct ts_sample_mt { /* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h * has the definitions. */ int x; //X 坐標 int y; //Y 坐標 unsigned int pressure; //按壓力大小 int slot; //觸摸點 slot int tracking_id; //ID int tool_type; int tool_x; int tool_y; unsigned int touch_major; unsigned int width_major; unsigned int touch_minor; unsigned int width_minor; int orientation; int distance; int blob_id; struct timeval tv; //時間 /* BTN_TOUCH state */ short pen_down; //BTN_TOUCH 的狀態(tài) ?short?valid;??//此次樣本是否有效標志 ?};
?
第五:單點觸摸應(yīng)用程序?qū)崿F(xiàn)
?
#include#include #include? ????//包含tslib.h的頭文件 int main(int argc, char *argv[]) { struct tsdev *ts = NULL; struct ts_sample samp; int pressure = 0;//用于保存上一次的按壓力,初始為 0,表示松開 /* 打開并配置觸摸屏設(shè)備 */ ts = ts_setup(NULL, 0); if (NULL == ts) { fprintf(stderr, "ts_setup error"); exit(EXIT_FAILURE); } /* 讀數(shù)據(jù) */ for ( ; ; ) { if (0 > ts_read(ts, &samp, 1)) { fprintf(stderr, "ts_read error"); ts_close(ts); exit(EXIT_FAILURE); } if (samp.pressure) {//按壓力>0 if (pressure) //若上一次的按壓力>0 ?????printf("移動(%d,%d) ",samp.x,samp.y); ?????else ?????printf("按下(%d,%d) ",samp.x,samp.y); ?????} ?????else printf("松開 ");//打印坐標 pressure = samp.pressure; } ts_close(ts); exit(EXIT_SUCCESS); }
?
分析:利用代碼直接打開、配置設(shè)備、接著讀取數(shù)據(jù),通過判斷按壓大小確定觸摸的狀態(tài)。
?
${CC} -I /home/dt/tools/tslib/include -L /home/dt/tools/tslib/lib -lts -o testApp testApp.c
?
? ??-I選項指定頭文件的路徑,也就是指定tslib安裝目錄下的include目錄,如果不指定頭文件路徑,編譯時將會找不到tslib.h頭文件;-L 選項用于指定庫文件的路徑,也就是指定 tslib 安裝目錄下的 lib 目錄;我們將 tslib 編譯成了動態(tài)庫文件,以庫文件的形式提供,編譯時需要鏈接到這些庫文件;而-l 選項則用于指定鏈接庫(也可寫成-l ts,也就是 libts.so 庫文件,Linux 中,動態(tài)庫文件的命名方式為 lib+名字+.so)。
? ? ? 將編譯得到的可執(zhí)行文件拷貝到開發(fā)板 Linux 系統(tǒng)的用戶家目錄下,執(zhí)行應(yīng)用程序,進行測試:
第六:多點觸摸應(yīng)用程序?qū)崿F(xiàn)
? ??接下來基于tslib的多點觸摸應(yīng)用程序,使用ts_read_mt()函數(shù)讀取多點觸摸數(shù)據(jù)。
?
#include#include #include #include #include int main(int argc, char *argv[]) { struct tsdev *ts = NULL; struct ts_sample_mt *mt_ptr = NULL; struct input_absinfo slot; int max_slots; unsigned int pressure[12] = {0}; //用于保存每一個觸摸點上一次的按壓力,初始為 0,表示松開 int i; /* 打開并配置觸摸屏設(shè)備 */ ts = ts_setup(NULL, 0); if (NULL == ts) { fprintf(stderr, "ts_setup error"); exit(EXIT_FAILURE); } /* 獲取觸摸屏支持的最大觸摸點數(shù) */ if (0 > ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot)) { perror("ioctl error"); ts_close(ts); exit(EXIT_FAILURE); } max_slots = slot.maximum + 1 - slot.minimum; printf("max_slots: %d ", max_slots); /* 內(nèi)存分配 */ mt_ptr = calloc(max_slots, sizeof(struct ts_sample_mt)); /* 讀數(shù)據(jù) */ for ( ; ; ) { if (0 > ts_read_mt(ts, &mt_ptr, max_slots, 1)) { perror("ts_read_mt error"); ts_close(ts); free(mt_ptr); exit(EXIT_FAILURE); } for (i = 0; i < max_slots; i++) { if (mt_ptr[i].valid) {//有效表示有更新! if (mt_ptr[i].pressure) { //如果按壓力>0 if (pressure[mt_ptr[i].slot])//如果上一次的按壓力>0 printf("slot<%d>, 移動(%d, %d) ", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y); else printf("slot<%d>, 按下(%d, %d) ", mt_ptr[i].slot, mt_ptr[i].x, mt_ptr[i].y); } else printf("slot<%d>, 松開 ", mt_ptr[i].slot); pressure[mt_ptr[i].slot] = mt_ptr[i].pressure; } } } /* 關(guān)閉設(shè)備、釋放內(nèi)存、退出 */ ts_close(ts); free(mt_ptr); exit(EXIT_SUCCESS); }
?
? ??? 整個思路與單點觸摸應(yīng)用程序相同,通過ts_read_mt()函數(shù)讀取觸摸點數(shù)據(jù),將這些數(shù)據(jù)存放在 mt_ptr 數(shù)組中,接著在 for()循環(huán)中判斷每一個觸摸點數(shù)據(jù)是否有效,有效則表示該觸摸點信息發(fā)生更新。
?
${CC} -I /home/dt/tools/tslib/include -L /home/dt/tools/tslib/lib -lts -o testApp testApp.c
?
?將編譯得到的可執(zhí)行文件復(fù)制到開發(fā)板Linux系統(tǒng)用戶家目錄下,執(zhí)行程序:
總結(jié):觸摸屏在很多場合下都會使用到,掌握tslib庫的使用方法,對未來個人的開發(fā)具有重要作用。
審核編輯:湯梓紅
評論