首先说下思路,本文采用jni技术封装底层触摸事件,封装成MotionEvent类一样,不过没有android系统MotionEvent强大。源码MotionEvent位置:java-->frameworks/base/core/java/android/view/MotionEvent.java ; jni-->frameworks/base/core/jni/android_view_MotionEvent.cpp 原有的MotionEvent封装的事件之多,我所做的就是只封装红外触摸屏所产生的几个简单事件,例如坐标事件以及触摸宽度等等。
1)底层事件来源于/dev/input/event。
2)顶层事件采用java封装为类。
3)jni中使用到了线程 和 管道,最开始打算使用线程和消息队列,可是失败了,android不支持消息队列。
直接上代码:
java上层封装代码
1 packageandroid.wf;2 public final classMotionEvent {3
4 publicMotionEvent(){5 int fd =initEvent();6 System.out.println("fd = %d\n");7 }8
9 public final floatgetX() {10 returngetXX();11 }12
13 public final floatgetY() {14 returngetYY();15 }16
17 public final floatgetWidth() {18 returngetH();19 }20
21 public final floatgetHight() {22 returngetW();23 }24
25 static
26 {27 System.loadLibrary("MotionEvent");28 }29
30 private static native floatgetW();31 private static native floatgetH();32 private static native intinitEvent();33 private static native floatgetXX();34 private static native floatgetYY();35
36 }
使用javah编译生成CPP的头文件:
1 /*DO NOT EDIT THIS FILE - it is machine generated*/
2 #include
3 /*Header for class android_wf_MotionEvent*/
4
5 #ifndef _Included_android_wf_MotionEvent6 #define _Included_android_wf_MotionEvent
7 #ifdef __cplusplus8 extern "C"{9 #endif
10 /*
11 * Class: android_wf_MotionEvent12 * Method: initEvent13 * Signature: ()F14 */
15 JNIEXPORT jint JNICALL Java_android_wf_MotionEvent_initEvent16 (JNIEnv *, jclass);17
18 /*
19 * Class: android_wf_MotionEvent20 * Method: getXX21 * Signature: ()F22 */
23 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX24 (JNIEnv *, jclass);25
26 /*
27 * Class: android_wf_MotionEvent28 * Method: getYY29 * Signature: ()F30 */
31 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY32 (JNIEnv *, jclass);33 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW34 (JNIEnv *, jclass);35 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH36 (JNIEnv *, jclass );37 #ifdef __cplusplus38 }39 #endif
40 #endif
接着在CPP文件中实现java的native函数:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include "android_wf_MotionEvent.h"
12 #include
13
14 //LCD和触摸框转换比例
15 float xScale = 1920.0/32768;16 float yScale = 1080.0/32768;17
18 int fd ; //dev的文件描述符
19 int fds[2]; //管道
20
21 jfloat x;22 jfloat y;23 jfloat pressure;24 jfloat touchMajor;25 jfloat touchMinor;26
27 static int getTouchEventNum() //判断触摸框事件是哪一个event
28 {29 char name[64]; /*RATS: Use ok, but could be better*/
30 char buf[256] = { 0, }; /*RATS: Use ok*/
31 int fd = 0;32 inti;33 for (i = 0; i < 32; i++)34 {35 sprintf(name, "/dev/input/event%d", i);36 if ((fd = open(name, O_RDONLY, 0)) >= 0)37 {38 ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);39 if(strstr(buf, "MTOUC Touch"))40 {41 close(fd);42 returni;43 }44 //printf("%s\n", name);45 //printf("name: %s\n", buf);
46 close(fd);47 }48 }49 return -1;50 }51
52 static void* readInput(void *data)53 {54 structinput_event inputEvent;55 while(1)56 {57 read(fd, &inputEvent, sizeof(structinput_event));58 //向管道中写数据
59 write(fds[1], &inputEvent, sizeof(structinput_event));60 }61 returnNULL;62 }63
64 static void* dispatchInput(void *data)65 {66 structinput_event inputEvent;67 int flag = 1;68 while(1)69 {70 //从管道中读取数据
71 read(fds[0], &inputEvent, sizeof(structinput_event));72
73 if(inputEvent.type == EV_ABS && inputEvent.code ==ABS_X ){74 float fv = inputEvent.value * 1.0;75 x = fv *xScale;76 continue;77 }78 if(inputEvent.type == EV_ABS && inputEvent.code ==ABS_Y ){79 float fv = inputEvent.value * 1.0;80 y = fv *yScale;81 continue;82 }83 if(inputEvent.type == EV_KEY && inputEvent.code ==BTN_TOUCH ){84 pressure =inputEvent.value;85 if(1 == pressure &&flag)86 {87 flag = 0;88 }89 else if(0 ==pressure)90 {91 flag = 1;92 }93 continue;94 }95 //增加flag的判断作用是touchMajor和toushMinor事件在pressure事件之前的比较准确
96 if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MAJOR &&flag ){97 float fv = inputEvent.value * 1.0;98 touchMajor =fv ;99 continue;100 }101 if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MINOR &&flag ){102 float fv = inputEvent.value * 1.0;103 touchMinor =fv;104 continue;105 }106 }107 returnNULL;108 }109
110
111 JNIEXPORT jint JNICALL Java_android_wf_MotionEvent_initEvent(JNIEnv *env, jclass clazz)112 {113 int num =getTouchEventNum();114 if( num == -1)115 {116 printf("No Touch Event\n");117 return -1;118 }119 char name[64];120 sprintf(name, "/dev/input/event%d", num);121 fd =open(name, O_RDWR);122 if(fd < 0)123 {124 //LOGI("Open dev Error");
125 returnfd;126 }127
128 //创建无名管道
129 if(-1 ==pipe(fds))130 {131 printf("pipe\n");132 exit(-1);133 }134
135 pthread_t readId, disPatchId;136 pthread_create(&readId, NULL, readInput, NULL);137 sleep(1);138 pthread_create(&disPatchId, NULL, dispatchInput, NULL);139
140 returnfd;141 }142
143 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX(JNIEnv *env, jclass clazz)144 {145 returnx;146 }147
148 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY(JNIEnv *env, jclass clazz)149 {150 returny;151 }152
153 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW(JNIEnv *env, jclass clazz)154 {155 returntouchMajor;156 }157
158 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH(JNIEnv *env, jclass clazz)159 {160 returntouchMinor;161 }
最后在来个Android的Mk文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
arch := $(TARGET_ARCH)
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_LDLIBS += -lpthread -lrt -ldl -lm #貌似可以不加
LOCAL_MODULE:= libMotionEvent
LOCAL_SRC_FILES += jni/MotionEvent.c
include $(BUILD_SHARED_LIBRARY)