首先说下思路,本文采用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上层封装代码
package android.wf;
public final class MotionEvent { public MotionEvent(){
int fd = initEvent();
System.out.println("fd = %d\n");
} public final float getX() {
return getXX();
} public final float getY() {
return getYY();
} public final float getWidth() {
return getH();
} public final float getHight() {
return getW();
} static
{
System.loadLibrary("MotionEvent");
} private static native float getW();
private static native float getH();
private static native int initEvent();
private static native float getXX();
private static native float getYY(); }
使用javah编译生成CPP的头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_wf_MotionEvent */ #ifndef _Included_android_wf_MotionEvent
#define _Included_android_wf_MotionEvent
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_wf_MotionEvent
* Method: initEvent
* Signature: ()F
*/
JNIEXPORT jint JNICALL Java_android_wf_MotionEvent_initEvent
(JNIEnv *, jclass); /*
* Class: android_wf_MotionEvent
* Method: getXX
* Signature: ()F
*/
JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX
(JNIEnv *, jclass); /*
* Class: android_wf_MotionEvent
* Method: getYY
* Signature: ()F
*/
JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY
(JNIEnv *, jclass);
JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW
(JNIEnv *, jclass);
JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH
(JNIEnv *, jclass );
#ifdef __cplusplus
}
#endif
#endif
接着在CPP文件中实现java的native函数:
#include <linux/input.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <jni.h>
#include "android_wf_MotionEvent.h"
#include<android/log.h> //LCD和触摸框转换比例
float xScale = 1920.0/;
float yScale = 1080.0/; int fd ; // dev的文件描述符
int fds[]; //管道 jfloat x;
jfloat y;
jfloat pressure;
jfloat touchMajor;
jfloat touchMinor; static int getTouchEventNum() //判断触摸框事件是哪一个event
{
char name[]; /* RATS: Use ok, but could be better */
char buf[] = { , }; /* RATS: Use ok */
int fd = ;
int i;
for (i = ; i < ; i++)
{
sprintf(name, "/dev/input/event%d", i);
if ((fd = open(name, O_RDONLY, )) >= )
{
ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
if(strstr(buf, "MTOUC Touch"))
{
close(fd);
return i;
}
//printf("%s\n", name);
//printf("name: %s\n", buf);
close(fd);
}
}
return -;
} static void* readInput(void *data)
{
struct input_event inputEvent;
while()
{
read(fd, &inputEvent, sizeof(struct input_event));
// 向管道中写数据
write(fds[], &inputEvent, sizeof(struct input_event));
}
return NULL;
} static void* dispatchInput(void *data)
{
struct input_event inputEvent;
int flag = ;
while()
{
//从管道中读取数据
read(fds[], &inputEvent, sizeof(struct input_event)); if(inputEvent.type == EV_ABS && inputEvent.code == ABS_X ){
float fv = inputEvent.value * 1.0;
x = fv * xScale;
continue;
}
if(inputEvent.type == EV_ABS && inputEvent.code == ABS_Y ){
float fv = inputEvent.value * 1.0;
y = fv * yScale;
continue;
}
if(inputEvent.type == EV_KEY && inputEvent.code == BTN_TOUCH ){
pressure = inputEvent.value;
if( == pressure && flag)
{
flag = ;
}
else if( == pressure)
{
flag = ;
}
continue;
}
//增加flag的判断作用是touchMajor和toushMinor事件在pressure事件之前的比较准确
if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MAJOR && flag ){
float fv = inputEvent.value * 1.0;
touchMajor = fv ;
continue;
}
if(inputEvent.type == EV_ABS && inputEvent.code == ABS_MT_TOUCH_MINOR && flag ){
float fv = inputEvent.value * 1.0;
touchMinor = fv;
continue;
}
}
return NULL;
} JNIEXPORT jint JNICALL Java_android_wf_MotionEvent_initEvent(JNIEnv *env, jclass clazz)
{
int num = getTouchEventNum();
if( num == -)
{
printf("No Touch Event\n");
return -;
}
char name[];
sprintf(name, "/dev/input/event%d", num);
fd = open(name, O_RDWR);
if(fd < )
{
//LOGI("Open dev Error");
return fd;
} //创建无名管道
if(- == pipe(fds))
{
printf("pipe\n");
exit(-);
} pthread_t readId, disPatchId;
pthread_create(&readId, NULL, readInput, NULL);
sleep();
pthread_create(&disPatchId, NULL, dispatchInput, NULL); return fd;
} JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getXX(JNIEnv *env, jclass clazz)
{
return x;
} JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getYY(JNIEnv *env, jclass clazz)
{
return y;
} JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getW(JNIEnv *env, jclass clazz)
{
return touchMajor;
} JNIEXPORT jfloat JNICALL Java_android_wf_MotionEvent_getH(JNIEnv *env, jclass clazz)
{
return touchMinor;
}
最后在来个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)