從校正方法來看,
Android
系統觸控螢幕的校正一般分兩種:線性校準與三點(一般用五點)校準;從校正的位置來看,也分兩種,驅動層校準和
android
層校準。一般來講,從
android
層校正由應用軟體配合
android
層完成,靈活度比較高,也比較智能化。隨時不準隨時校正。在這裡,詳細介紹
android
層的校正過程。
為了更好的瞭解校正的詳細過程,有必要瞭解一下觸控螢幕資料的運動過程,至少校正的原則,由於涉及到特定的演算法,因此不在此報告中提及。
觸控螢幕資料產生於
Linux
核心,在觸控螢幕驅動中,通過
AD
轉換,把觸摸點記錄為一組組資料(觸控螢幕座標),這個資料我們稱之為未經處理資料。這個未經處理資料非常的重要,畢竟我們的目標就是把這樣的一組組觸控螢幕座標轉換為
LCD
座標。未經處理資料產生後,通過
input_report_abs
上報到
android
層。在
android
層會能過
getX
和
getY
捕捉到這一資料,再將捕捉到的資料通過
reportData
分發到視窗。
從資料的運動過程,我們大概知道校正要從哪入手了吧。校正的過程其它就是資料的截獲
-
修改過程。因為這裡介紹的是
android
層的校正,因此,我們需要在
android
層資料將資料截取。
android
層觸控螢幕的資料是在
/frameworks/base/services/java/com/android/server/
目錄中的檔案
InputDevice.java
截取的,因此需要在這個檔案中增加一些代碼,用於截取未經處理資料並將未經處理資料進行校正。
到這裡,我們一直有一個大前提,那就是:
1
、
Linux
驅動層上報的是未經處理資料;
2
、對未經處理資料進行校正的校正係數已經產生。因此,在
InputDevice.java
中增加代碼之前,我們應該解決掉這兩個問題。
校正過程分四步完成:
1
、觸控螢幕驅動的修改
對第一個問題,我們需要對
Linux
層的觸控螢幕驅動進行改動,以保證
report
的資料是原汁原味沒有進行過任何修改的資料
如果你使用的是進行過校正的觸控螢幕驅動,需要注意兩個地方的修改:
第一處是:
if(xtmp < 0) xtmp = 0; else if(xtmp > TS_RESOLUTION_X-1) xtmp = TS_RESOLUTION_X-1; if(ytmp < 0) ytmp = 0; else if(ytmp > TS_RESOLUTION_Y-1) ytmp =TS_RESOLUTION_Y-1; |
以上代碼需要全部注釋掉,不注掉的結果就是當你用五點校準時,不管你怎麼點擊觸控螢幕,觸控螢幕都不會有反應。仔細看看這段代碼就知道了,這段代碼保證上報的資料在
LCD
座標範圍之內,這是在驅動層校正必寫的一段代碼,卻是我們進行軟體校正的綁腳石呵。
第二處是
__init s3c_ts_probe
中的一段代碼代碼:
if (s3c_ts_cfg->resol_bit= =12) { input_set_abs_params(ts->dev, ABS_X, 0, TS_RESOLUTION_X, 0, 0); input_set_abs_params(ts->dev, ABS_Y, 0, TS_RESOLUTION_Y, 0, 0);
}
|
需要修改成如下:()
if (s3c_ts_cfg->resol_bit= =12) { input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF , 0, 0); input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF , 0, 0);
}
|
道理跟上一段代碼一樣。如,我調試的
6410
板子採用的是
12
位轉換的,在系統啟動過程中,會看到這個的列印資訊:
I/KeyInputQueue( 58): X: min=0 max=4095 flat=0 fuzz=0 I/KeyInputQueue( 58): Y: min=0 max=4095 flat=0 fuzz=0 |
由此我們可以看出,對驅動進行修改的原則就是:保證驅動上報的資料是原汁原味沒有進行過任何修改的資料。
2
、校正係數的產生
核下係數的產生是靠軟體來實現的,由於觸控螢幕的校正演算法特定,因此校正應用程式是通用的。在這個應用程式裡要修改的地方有兩個,一是別忘了把螢幕的解析度改成需要的解析度。二是根據驅動層採用的轉換精度調整一下資料:
final int UI_SCREEN_WIDTH = TS_RESOLUTION_X;
final int UI_SCREEN_HEIGHT = TS_RESOLUTION_Y;
x1 = (int)(( event.getX() * 4095 ) / (TS_RESOLUTION_X-1)); //2^12-1=4095
y1 = (int)(( event.getY() * 4095 ) / (TS_RESOLUTION_Y-1)); |
這個部分需要注意的問題就是校正係數檔案
pointercal
許可權的問題,需要在
init.rc
中給該檔案的產生提供許可權:
chmod 0777 /data/etc chmod 0644 /data/etc/pointercal |
第一句是允許中
/data/etc
中產生
pointercal
檔案,第二句是保證
pointercal
檔案能被讀取。
現在可以在
InputDevice.java
中增加代碼了:
3
、讀取校本文件
static void ReadPointercalFile(){ TransformInfo t = null; try { FileInputStream is; if(custom_file_exist) { Log.i("TS_DBG", "InputDevice.ReadPointercalFile:read CALIBRATION_FILE from /data/etc"); is = new FileInputStream(CALIBRATION_FILE2); } else { Log.i("TS_DBG", "InputDevice.ReadPointercalFile:read CALIBRATION_FILE from /system/etc"); is = new FileInputStream(CALIBRATION_FILE1); } byte[] mBuffer = new byte[64]; int len = is.read(mBuffer); is.close();
if (len > 0) { int i; for (i = 0 ; i < len ; i++) { if (mBuffer[i] == '/n' || mBuffer[i] == 0) { break; } } len = i; }
StringTokenizer st = new StringTokenizer( new String(mBuffer, 0, 0, len) );
t = new TransformInfo (); t.x1 = Integer.parseInt( st.nextToken() ); t.y1 = Integer.parseInt( st.nextToken() ); t.z1 = Integer.parseInt( st.nextToken() ); t.x2 = Integer.parseInt( st.nextToken() ); t.y2 = Integer.parseInt( st.nextToken() ); t.z2 = Integer.parseInt( st.nextToken() ); t.s = Integer.parseInt( st.nextToken() ); Log.i("InputDevice.ReadPointercalFile: ", "t.x1=" + t.x1 + " t.y1=" + t.y1 + " t.z1=" + t.z1 + "t.x2=" + t.x2 + " t.y2=" + t.y2 + " t.z2=" + t.z2 + "t.s=" + t.s); } catch (java.io.FileNotFoundException e) { custom_file_exist = false; Log.i("TS_DBG", "FileNotFound!"); } catch (java.io.IOException e) { Log.i("TS_DBG", "IOException"); } tInfo = t; |
4
、截取未經處理資料,用校正係數進行校準
if (device.tInfo != null) reportData[j + MotionEvent.SAMPLE_X] = (device.tInfo.x1 * x_tmp + device.tInfo.y1 * y_tmp + device.tInfo.z1) / device.tInfo.s; else reportData[j + MotionEvent.SAMPLE_X] = ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue) / absX.range) * w;
if (device.tInfo != null) reportData[j + MotionEvent.SAMPLE_Y] = (device.tInfo.x2 * x_tmp + device.tInfo.y2 * y_tmp + device.tInfo.z2) / device.tInfo.s; else reportData[j + MotionEvent.SAMPLE_Y] = ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue) / absY.range) * h; |
備忘:為了保證
pointercal
順便的產生,還要保證鍵盤的正常工作。因為第一次用軟體校正,觸控螢幕不好使,至少要有方向鍵我確定鍵保證能順利進行校正程式(當然第二次和以後就不需要了)。除此之外,還要保證
MENU
鍵的正常工作,因為校正程式最後一步需要
MEUN
鍵確認,只有觸認後才會產生
pointercal
檔案。當然,如果你的按鍵本來就不夠用,確認的按鍵可以通過修改校正應用程式換成其它鍵。