首先说下思路,本文采用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 package android.wf; 2 public final class MotionEvent { 3 4 public MotionEvent(){ 5 int fd = initEvent(); 6 System.out.println("fd = %d\n"); 7 } 8 9 public final float getX() { 10 return getXX(); 11 } 12 13 public final float getY() { 14 return getYY(); 15 } 16 17 public final float getWidth() { 18 return getH(); 19 } 20 21 public final float getHight() { 22 return getW(); 23 } 24 25 static 26 { 27 System.loadLibrary("MotionEvent"); 28 } 29 30 private static native float getW(); 31 private static native float getH(); 32 private static native int initEvent(); 33 private static native float getXX(); 34 private static native float getYY(); 35 36 }
使用javah编译生成CPP的头文件:
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class android_wf_MotionEvent */ 4 5 #ifndef _Included_android_wf_MotionEvent 6 #define _Included_android_wf_MotionEvent 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: android_wf_MotionEvent 12 * Method: initEvent 13 * Signature: ()F 14 */ 15 JNIEXPORT jint JNICALL Java_android_wf_MotionEvent_initEvent 16 (JNIEnv *, jclass); 17 18 /* 19 * Class: android_wf_MotionEvent 20 * Method: getXX 21 * Signature: ()F 22 */ 23 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX 24 (JNIEnv *, jclass); 25 26 /* 27 * Class: android_wf_MotionEvent 28 * Method: getYY 29 * Signature: ()F 30 */ 31 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY 32 (JNIEnv *, jclass); 33 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW 34 (JNIEnv *, jclass); 35 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH 36 (JNIEnv *, jclass ); 37 #ifdef __cplusplus 38 } 39 #endif 40 #endif
接着在CPP文件中实现java的native函数:
1 #include <linux/input.h> 2 #include <stdio.h> 3 #include <pthread.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 #include <sys/types.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <fcntl.h> 10 #include <jni.h> 11 #include "android_wf_MotionEvent.h" 12 #include<android/log.h> 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 int i; 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 return i; 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 struct input_event inputEvent; 55 while(1) 56 { 57 read(fd, &inputEvent, sizeof(struct input_event)); 58 // 向管道中写数据 59 write(fds[1], &inputEvent, sizeof(struct input_event)); 60 } 61 return NULL; 62 } 63 64 static void* dispatchInput(void *data) 65 { 66 struct input_event inputEvent; 67 int flag = 1; 68 while(1) 69 { 70 //从管道中读取数据 71 read(fds[0], &inputEvent, sizeof(struct input_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 return NULL; 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 return fd; 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 return fd; 141 } 142 143 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX(JNIEnv *env, jclass clazz) 144 { 145 return x; 146 } 147 148 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY(JNIEnv *env, jclass clazz) 149 { 150 return y; 151 } 152 153 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW(JNIEnv *env, jclass clazz) 154 { 155 return touchMajor; 156 } 157 158 JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH(JNIEnv *env, jclass clazz) 159 { 160 return touchMinor; 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)