最近一段时间在搞android的触摸屏校正,想把心得记下来与大家分享,废话不多说,开始讲解.
注:调试使用的是
一、修改内核驱动
修改触摸屏驱动(kernel/drivers/input/touchscreen/s3c-ts.c)
-input_set_abs_params(ts->dev,
ABS_X, X_COOR_MIN, X_COOR_MAX, X_COOR_FUZZ, 0);
-input_set_abs_params(ts->dev, ABS_Y,
Y_COOR_MIN, Y_COOR_MAX, Y_COOR_FUZZ, 0);
+input_set_abs_params(ts->dev, ABS_X, 0,
0xFFF, 0, 0);
+input_set_abs_params(ts->dev, ABS_Y, 0,
0xFFF, 0, 0);
-input_set_abs_params(ts->dev,
ABS_MT_POSITION_X, X_COOR_MIN,X_COOR_MAX, 0, 0);
-input_set_abs_params(ts->dev,
ABS_MT_POSITION_Y, Y_COOR_MIN,Y_COOR_MAX, 0, 0);
+input_set_abs_params(ts->dev,
ABS_MT_POSITION_X, 0, 0xFFF, 0, 0);
+input_set_abs_params(ts->dev,
ABS_MT_POSITION_Y, 0, 0xFFF, 0, 0);
if(m_status == 1){
input_report_abs(ts->dev,
ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev,
ABS_MT_POSITION_X, m_lx);
input_report_abs(ts->dev,
ABS_MT_POSITION_Y, m_ly);
+input_report_abs(ts->dev, ABS_PRESSURE,
1);
printk("X1:%d
Y1:%d/n",m_lx,m_ly);
input_mt_sync(ts->dev);
input_report_abs(ts->dev,
ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev,
ABS_MT_POSITION_X, press_x);
input_report_abs(ts->dev,
ABS_MT_POSITION_Y, press_y);
+ input_report_abs(ts->dev, ABS_PRESSURE,
1);
input_mt_sync(ts->dev);
}
else {
input_report_abs(ts->dev,
ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev,
ABS_MT_POSITION_X, x);
input_report_abs(ts->dev,
ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->dev, ABS_PRESSURE,
1);
printk("X2:%d
Y2:%d/n",x,y);
input_mt_sync(ts->dev);
}
#if 1
+ input_report_abs(ts->dev, ABS_PRESSURE,
0);
#endif
-input_set_abs_params(ts->dev, ABS_X, X_COOR_MIN, X_COOR_MAX, X_COOR_FUZZ, 0);
-input_set_abs_params(ts->dev, ABS_Y, Y_COOR_MIN, Y_COOR_MAX, Y_COOR_FUZZ, 0);
+input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);
+input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);
-input_set_abs_params(ts->dev, ABS_MT_POSITION_X, X_COOR_MIN,X_COOR_MAX, 0, 0);
-input_set_abs_params(ts->dev, ABS_MT_POSITION_Y, Y_COOR_MIN,Y_COOR_MAX, 0, 0);
+input_set_abs_params(ts->dev, ABS_MT_POSITION_X, 0, 0xFFF, 0, 0);
+input_set_abs_params(ts->dev, ABS_MT_POSITION_Y, 0, 0xFFF, 0, 0);
if(m_status == 1){
input_report_abs(ts->dev, ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev, ABS_MT_POSITION_X, m_lx);
input_report_abs(ts->dev, ABS_MT_POSITION_Y, m_ly);
+input_report_abs(ts->dev, ABS_PRESSURE, 1);
printk("X1:%d Y1:%d/n",m_lx,m_ly);
input_mt_sync(ts->dev);
input_report_abs(ts->dev, ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev, ABS_MT_POSITION_X, press_x);
input_report_abs(ts->dev, ABS_MT_POSITION_Y, press_y);
+ input_report_abs(ts->dev, ABS_PRESSURE, 1);
input_mt_sync(ts->dev);
}
else {
input_report_abs(ts->dev, ABS_MT_TOUCH_MAJOR, 500);
input_report_abs(ts->dev, ABS_MT_POSITION_X, x);
input_report_abs(ts->dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->dev, ABS_PRESSURE, 1);
printk("X2:%d Y2:%d/n",x,y);
input_mt_sync(ts->dev);
}
#if 1
+ input_report_abs(ts->dev, ABS_PRESSURE, 0);
#endif
这样做的目的是根据使内核不使用限定好的坐标范围,x,y的坐标范围还原成0-4095
二、修改property_service.c(android2_2/system/core/init/property_service.c)
在property_perms增加
{ "ts.config.calibrate" ,
AID_SYSTEM, 0 }
这样做的目的是为可以了后面使用触摸屏校正程序可以对ts.config.calibrate这个系统属性进行操作,后面会说到.
三、修改InputDevice.java(android2_2/frameworks/base/services/java/com/android/server/InputDevice.java)
在generateAbsMotion函数中增加
String prop =
SystemProperties.get("ts.config.calibrate");
if
(prop!=null)
{
if
(prop.equalsIgnoreCase("start")){
Slog.d("XXW prop",
prop);
Slog.d("XXW",
"prop.equalsIgnoreCase start");
device.tInfo =
null;
}
else if
(prop.equalsIgnoreCase("done")){
Slog.d("XXW prop",
prop);
Slog.d("XXW",
"prop.equalsIgnoreCase done");
readCalibrate();
device.tInfo=tInfo;
SystemProperties.set("ts.config.calibrate",
"end");
}
else{
Slog.i("XXW prop",
prop);
Slog.i("XXW",
"prop.equalsIgnoreCase else");
}
}
String prop = SystemProperties.get("ts.config.calibrate");
if (prop!=null)
{
if (prop.equalsIgnoreCase("start")){
Slog.d("XXW prop", prop);
Slog.d("XXW", "prop.equalsIgnoreCase start");
device.tInfo = null;
}
else if (prop.equalsIgnoreCase("done")){
Slog.d("XXW prop", prop);
Slog.d("XXW", "prop.equalsIgnoreCase done");
readCalibrate();
device.tInfo=tInfo;
SystemProperties.set("ts.config.calibrate", "end");
}
else{
Slog.i("XXW prop", prop);
Slog.i("XXW", "prop.equalsIgnoreCase else");
}
}
这里使用到系统属性ts.config.calibrate,当系统判断为现在处于触摸屏校正模式的时候(也就是ts.config.calibrate值为start的时候),不对驱动传递上来的坐标值进行转换.
上面第二点在在property_perms增加{
"ts.config.calibrate" , AID_SYSTEM, 0
}是为了系统有权限可以设置/读取这个属性
增加函数
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
static void
readCalibrate(){
//xxw added
Slog.i("XXW","readCalibrate!");
TransformInfo t =
null;
try {
FileInputStream is = new
FileInputStream(CALIBRATION_FILE);
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() );
} catch
(java.io.FileNotFoundException e) {
Slog.i("XXW",
"FileNotFound!");
} catch (java.io.IOException e)
{
Slog.i("XXW",
"IOException");
}
tInfo = t;
Slog.i("XXW","readCalibrate
done!");
}
static void readCalibrate(){
//xxw added
Slog.i("XXW","readCalibrate!");
TransformInfo t = null;
try {
FileInputStream is = new FileInputStream(CALIBRATION_FILE);
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() );
} catch (java.io.FileNotFoundException e) {
Slog.i("XXW", "FileNotFound!");
} catch (java.io.IOException e) {
Slog.i("XXW", "IOException");
}
tInfo = t;
Slog.i("XXW","readCalibrate done!");
}
修改InputDevice函数
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
InputDevice(int
_id, int _classes, String
_name,
AbsoluteInfo _absX, AbsoluteInfo _absY,
AbsoluteInfo _absPressure, AbsoluteInfo _absSize)
{
id = _id;
classes = _classes;
name = _name;
absX = _absX;
absY = _absY;
absPressure = _absPressure;
absSize = _absSize;
readCalibrate();
InputDevice(int _id, int _classes, String _name,
AbsoluteInfo _absX, AbsoluteInfo _absY,
AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
id = _id;
classes = _classes;
name = _name;
absX = _absX;
absY = _absY;
absPressure = _absPressure;
absSize = _absSize;
readCalibrate();
编译后生成services.jar,须替换android文件系统里面的system/framwork里面的services.jar
四、修改触摸屏校正程序
修改onTouchEvent(CalibrationTest.java)
CalibrationTest.java这里是我使用的触摸屏校正程序,我的屏的分辨率为800*480,所以改成
mResultPts[(STEP -1) * mPtsLength] =
event.getX()*4095/(800-1);
mResultPts[(STEP -1) * mPtsLength + 1] =
event.getY()*4095/(480-1);
修改AndroidManifest.xml 增加
android:sharedUserId="android.uid.system"
xmlns:android="http://schemas.android.com/apk/res/android"
package="touchscreen.test"
android:sharedUserId="android.uid.system">
修改 Android.mk增加
LOCAL_CERTIFICATE := platform
五、修改init.rc增加
#create tslib
mkdir /data/system/tslib/ 0777
chmod 0666 /data/system/tslib/pointercal
触摸屏校正看来起貌似简单,但要改的东西确实太多,我自己也是摸索了好几天才搞定的,呵呵!
————————————————————————————————————————————————
话接上回,我们发现了手工利用tslib校验触摸屏的缺点。那么这一回 我们就来一次稍微高级一点的校验吧。
我们其实只需要相对的x,y以及lcd的x,y就可以把校验系数算出来。这里要说的是lcd的x,y是绝对的准确的
比如我们要在(50,50)画一个十字
那么这个50,50就是我们认为的绝对坐标。我们要的只是从android通过getX()和getY()拿到我们需要的相对坐标。
其实一切我们打算做的事情可以都在InputDevice里面做完
下面我把完整之后整个的InputDevice贴出来,源代码在下面(除了linux驱动配置,还要完成C和JAVA的接口层)