Skip to content

Instantly share code, notes, and snippets.

@mgood7123
Last active June 6, 2021 21:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgood7123/5d339da06fb2fd32f1df732996b5fdaf to your computer and use it in GitHub Desktop.
Save mgood7123/5d339da06fb2fd32f1df732996b5fdaf to your computer and use it in GitHub Desktop.
MotionEvent Java->JNI
//
// Created by Matthew Good on 7/6/21.
//
#include "MotionEventSerializer.h"
MotionEventSerializer::IndexInfo::IndexInfo() {}
MotionEventSerializer::IndexInfo::IndexInfo(int pointerIndex, int segment_length, int reserved) {
idx_pointerId = (pointerIndex*segment_length)+reserved;
idx_ptrIndex = (pointerIndex*segment_length)+reserved+1;
idx_active = (pointerIndex*segment_length)+reserved+2;
idx_action = (pointerIndex*segment_length)+reserved+3;
idx_moved = (pointerIndex*segment_length)+reserved+4;
idx_x = (pointerIndex*segment_length)+reserved+5;
idx_y = (pointerIndex*segment_length)+reserved+6;
idx_pressure = (pointerIndex*segment_length)+reserved+7;
idx_size = (pointerIndex*segment_length)+reserved+8;
}
void MotionEventSerializer::acquire(JNIEnv *jenv, jfloatArray motionEventData) {
jboolean isCopy;
data = jenv->GetFloatArrayElements(motionEventData, &isCopy);
dataLength = data[idx_dataLength];
reserved = data[idx_dataReserved];
segment_length = data[idx_dataSegmentLength];
maxSupportedPointers = data[idx_maxSupportedPointers];
int c = pointerCount();
indexInfo = new IndexInfo[c];
for (int i = 0; i < c; i++) {
indexInfo[i] = IndexInfo(i, segment_length, reserved);
}
}
void MotionEventSerializer::release(JNIEnv *jenv, jfloatArray motionEventData) {
delete[] indexInfo;
jenv->ReleaseFloatArrayElements(motionEventData, data, 0);
data = nullptr;
}
int MotionEventSerializer::pointerCount() {
return data[idx_ptrCount];
}
int MotionEventSerializer::currentPointerIndex() {
return data[idx_ptrCurrentIdx];
}
int MotionEventSerializer::getActionIndex() {
return currentPointerIndex();
}
int MotionEventSerializer::getPointerId(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_pointerId];
}
bool MotionEventSerializer::isPointerActive(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_active] == MOTION_EVENT_ACTIVE;
}
int MotionEventSerializer::getAction(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_action];
}
bool MotionEventSerializer::didPointerMove(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_moved] == MOTION_EVENT_MOVED;
}
float MotionEventSerializer::getX(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_x];
}
float MotionEventSerializer::getY(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_y];
}
float MotionEventSerializer::getPressure(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_pressure];
}
float MotionEventSerializer::getSize(int pointerIndex) {
return data[indexInfo[pointerIndex].idx_size];
}
//
// Created by Matthew Good on 7/6/21.
//
#ifndef CRAFTER_MOTIONEVENTSERIALIZER_H
#define CRAFTER_MOTIONEVENTSERIALIZER_H
#include <jni.h>
class MotionEventSerializer {
private:
class IndexInfo {
public:
int idx_pointerId;
int idx_ptrIndex;
int idx_active;
int idx_action;
int idx_moved;
int idx_x;
int idx_y;
int idx_pressure;
int idx_size;
IndexInfo();
IndexInfo(int pointerIndex, int segment_length, int reserved);
};
IndexInfo * indexInfo;
int reserved;
int segment_length;
int maxSupportedPointers;
int dataLength;
float * data = nullptr;
// THESE MUSE BE KEPT IN SYNC WITH JAVA SIDE
static const int idx_dataLength = 0;
static const int idx_dataReserved = 1;
static const int idx_dataSegmentLength = 2;
static const int idx_maxSupportedPointers = 3;
static const int idx_ptrCount = 4;
static const int idx_ptrCurrentIdx = 5;
public:
// THESE MUSE BE KEPT IN SYNC WITH JAVA SIDE
static const int MOTION_EVENT_ACTIVE = 1;
static const int MOTION_EVENT_NOT_ACTIVE = 2;
static const int MOTION_EVENT_ACTION_UNKNOWN = -1;
static const int MOTION_EVENT_ACTION_DOWN = 1;
static const int MOTION_EVENT_ACTION_UP = 2;
static const int MOTION_EVENT_ACTION_MOVE = 3;
static const int MOTION_EVENT_MOVED = 1;
static const int MOTION_EVENT_DID_NOT_MOVE = 2;
void acquire(JNIEnv *jenv, jfloatArray motionEventData);
void release(JNIEnv *jenv, jfloatArray motionEventData);
int pointerCount();
int currentPointerIndex();
bool isPointerActive(int pointerIndex);
bool didPointerMove(int pointerIndex);
int getPointerId(int pointerIndex);
int getAction(int pointerIndex);
int getActionIndex();
float getX(int pointerIndex);
float getY(int pointerIndex);
float getPressure(int pointerIndex);
float getSize(int pointerIndex);
};
#endif //CRAFTER_MOTIONEVENTSERIALIZER_H
import android.view.MotionEvent;
import java.util.Arrays;
public class MotionEventSerializer {
private static final String TAG = "MotionEventSerializer";
private final int reserved = 6;
private final int segment_length = 9;
private final int maxSupportedPointers;
private final int dataLength;
public final float[] data;
/**
* @param maxSupportedPointers must be kept equal with JNI Side
*/
MotionEventSerializer(int maxSupportedPointers) {
this.maxSupportedPointers = maxSupportedPointers;
dataLength = reserved + (segment_length * maxSupportedPointers);
data = new float[dataLength];
Arrays.fill(data, 0.0f);
}
// THESE MUSE BE KEPT IN SYNC WITH JNI SIDE
private static final int MOTION_EVENT_ACTIVE = 1;
private static final int MOTION_EVENT_NOT_ACTIVE = 2;
private static final int MOTION_EVENT_ACTION_UNKNOWN = -1;
private static final int MOTION_EVENT_ACTION_DOWN = 1;
private static final int MOTION_EVENT_ACTION_UP = 2;
private static final int MOTION_EVENT_ACTION_MOVE = 3;
private static final int MOTION_EVENT_MOVED = 1;
private static final int MOTION_EVENT_DID_NOT_MOVE = 2;
private static final int idx_dataLength = 0;
private static final int idx_dataReserved = 1;
private static final int idx_dataSegmentLength = 2;
private static final int idx_maxSupportedPointers = 3;
private static final int idx_ptrCount = 4;
private static final int idx_ptrCurrentIdx = 5;
/**
* MotionEvent <br>
* MOTION_EVENT_ACTION_UP and MOTION_EVENT_ACTION_DOWN
* always happen sequentially <br><br>
*
* MotionEvent <br>
* MOTION_EVENT_ACTION_MOVE can occur at the same time
* and are merged into single events when possible<br><br>
*
* provides basic pointer tracking by marking which pointers
* are currently active and which pointers have moved<br><br>
*
* public functions in jni side:<br>
* <li> void acquire(JNIEnv *jenv, jfloatArray motionEventData);
* <li> void release(JNIEnv *jenv, jfloatArray motionEventData);
* <br><br>
* <li> int pointerCount();
* <li> int currentPointerIndex();
* <br><br>
* <li> bool isPointerActive(int pointerIndex);
* <li> bool didPointerMove(int pointerIndex);
* <br><br>
* <li> int getPointerId(int pointerIndex);
* <li> int getAction(int pointerIndex);
* <li> int getActionIndex();
* <li> float getX(int pointerIndex);
* <li> float getY(int pointerIndex);
* <li> float getPressure(int pointerIndex);
* <li> float getSize(int pointerIndex);
*/
public float[] process(MotionEvent event) {
int pointerCount = event.getPointerCount();
int action = event.getActionMasked();
int pointerIndex = event.getActionIndex();
int pointerId = event.getPointerId(pointerIndex);
data[idx_dataLength] = dataLength;
data[idx_dataReserved] = reserved;
data[idx_dataSegmentLength] = segment_length;
data[idx_maxSupportedPointers] = maxSupportedPointers;
data[idx_ptrCount] = pointerCount;
data[idx_ptrCurrentIdx] = pointerIndex;
int idx_pointerId = (pointerIndex*segment_length)+reserved;
int idx_ptrIndex = (pointerIndex*segment_length)+reserved+1;
int idx_action = (pointerIndex*segment_length)+reserved+3;
int idx_active = (pointerIndex*segment_length)+reserved+2;
data[idx_pointerId] = pointerId;
data[idx_ptrIndex] = pointerIndex;
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
data[idx_active] = MOTION_EVENT_ACTIVE;
data[idx_action] = MOTION_EVENT_ACTION_DOWN;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
data[idx_active] = MOTION_EVENT_NOT_ACTIVE;
data[idx_action] = MOTION_EVENT_ACTION_UP;
break;
default:
data[idx_action] = MOTION_EVENT_ACTION_UNKNOWN;
break;
}
for (int i = 0; i < pointerCount; i++) {
if (data[(i*segment_length)+reserved+2] == MOTION_EVENT_ACTIVE) {
int idx_moved = (i*segment_length)+reserved+4;
int idx_x = (i*segment_length)+reserved+5;
int idx_y = (i*segment_length)+reserved+6;
int idx_pressure = (i*segment_length)+reserved+7;
int idx_size = (i*segment_length)+reserved+8;
float x = event.getX(i);
float y = event.getY(i);
if (data[idx_x] != x || data[idx_y] != y) {
data[idx_x] = x;
data[idx_y] = y;
data[(i*segment_length)+reserved+3] = MOTION_EVENT_ACTION_MOVE;
data[idx_moved] = MOTION_EVENT_MOVED;
} else {
data[idx_moved] = MOTION_EVENT_DID_NOT_MOVE;
}
data[idx_pressure] = event.getPressure(i);
data[idx_size] = event.getSize(i);
}
}
return data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment