使用JNI封装底层input系统提供的event事件

时间:2022-10-18 20:56:50

  首先说下思路,本文采用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不支持消息队列。

                                         使用JNI封装底层input系统提供的event事件

直接上代码:

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)