Add contact area and orientation for pen/touch events

This commit is contained in:
Cameron Gutman 2023-07-22 17:18:57 -05:00
parent 0e29e13d03
commit 67b2853ef0
5 changed files with 124 additions and 21 deletions

View File

@ -1532,6 +1532,100 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return new float[] { normalizedX, normalizedY };
}
private static float normalizeValueInRange(float value, InputDevice.MotionRange range) {
return (value - range.getMin()) / range.getRange();
}
private static float getPressureOrDistance(MotionEvent event) {
InputDevice dev = event.getDevice();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_HOVER_EXIT:
// Hover events report distance
if (dev != null) {
InputDevice.MotionRange distanceRange = dev.getMotionRange(MotionEvent.AXIS_DISTANCE, event.getSource());
if (distanceRange != null) {
return normalizeValueInRange(event.getAxisValue(MotionEvent.AXIS_DISTANCE, event.getActionIndex()), distanceRange);
}
}
return 0.0f;
default:
// Other events report pressure
return event.getPressure(event.getActionIndex());
}
}
private static short getRotationDegrees(MotionEvent event) {
InputDevice dev = event.getDevice();
if (dev != null) {
if (dev.getMotionRange(MotionEvent.AXIS_ORIENTATION, event.getSource()) != null) {
short rotationDegrees = (short) Math.toDegrees(event.getOrientation(event.getActionIndex()));
if (rotationDegrees < 0) {
rotationDegrees += 360;
}
return rotationDegrees;
}
}
return MoonBridge.LI_ROT_UNKNOWN;
}
private static float[] polarToCartesian(float r, float theta) {
return new float[] { (float)(r * Math.cos(theta)), (float)(r * Math.sin(theta)) };
}
private static float cartesianToR(float[] point) {
return (float)Math.sqrt(Math.pow(point[0], 2) + Math.pow(point[1], 2));
}
private float[] getStreamViewNormalizedContactArea(MotionEvent event) {
float orientation;
// If the orientation is unknown, we'll just assume it's at a 45 degree angle and scale it by
// X and Y scaling factors evenly.
if (event.getDevice() == null || event.getDevice().getMotionRange(MotionEvent.AXIS_ORIENTATION, event.getSource()) == null) {
orientation = (float)(Math.PI / 4);
}
else {
orientation = event.getOrientation(event.getActionIndex());
}
float contactAreaMajor, contactAreaMinor;
switch (event.getActionMasked()) {
// Hover events report the tool size
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_HOVER_EXIT:
contactAreaMajor = event.getToolMajor(event.getActionIndex());
contactAreaMinor = event.getToolMinor(event.getActionIndex());
break;
// Other events report contact area
default:
contactAreaMajor = event.getTouchMajor(event.getActionIndex());
contactAreaMinor = event.getTouchMinor(event.getActionIndex());
break;
}
// The contact area major axis is parallel to the orientation, so we simply convert
// polar to cartesian coordinates using the orientation as theta.
float[] contactAreaMajorCartesian = polarToCartesian(contactAreaMajor, orientation);
// The contact area minor axis is perpendicular to the contact area major axis (and thus
// the orientation), so rotate the orientation angle by 90 degrees.
float[] contactAreaMinorCartesian = polarToCartesian(contactAreaMinor, (float)(orientation + (Math.PI / 2)));
// Normalize the contact area to the stream view size
contactAreaMajorCartesian[0] = Math.min(Math.abs(contactAreaMajorCartesian[0]), streamView.getWidth()) / streamView.getWidth();
contactAreaMinorCartesian[0] = Math.min(Math.abs(contactAreaMinorCartesian[0]), streamView.getWidth()) / streamView.getWidth();
contactAreaMajorCartesian[1] = Math.min(Math.abs(contactAreaMajorCartesian[1]), streamView.getHeight()) / streamView.getHeight();
contactAreaMinorCartesian[1] = Math.min(Math.abs(contactAreaMinorCartesian[1]), streamView.getHeight()) / streamView.getHeight();
// Convert the normalized values back into polar coordinates
return new float[] { cartesianToR(contactAreaMajorCartesian), cartesianToR(contactAreaMinorCartesian) };
}
private boolean trySendPenEvent(View view, MotionEvent event) {
byte eventType = getLiTouchTypeFromEvent(event);
if (eventType < 0) {
@ -1558,26 +1652,21 @@ public class Game extends Activity implements SurfaceHolder.Callback,
penButtons |= MoonBridge.LI_PEN_BUTTON_SECONDARY;
}
short rotationDegrees = MoonBridge.LI_ROT_UNKNOWN;
byte tiltDegrees = MoonBridge.LI_TILT_UNKNOWN;
InputDevice dev = event.getDevice();
if (dev != null) {
if (dev.getMotionRange(MotionEvent.AXIS_ORIENTATION, event.getSource()) != null) {
rotationDegrees = (short)Math.toDegrees(event.getOrientation(event.getActionIndex()));
if (rotationDegrees < 0) {
rotationDegrees += 360;
}
}
if (dev.getMotionRange(MotionEvent.AXIS_TILT, event.getSource()) != null) {
tiltDegrees = (byte)Math.toDegrees(event.getAxisValue(MotionEvent.AXIS_TILT, event.getActionIndex()));
}
}
float[] normalizedCoords = getStreamViewRelativeNormalizedXY(view, event);
float[] normalizedContactArea = getStreamViewNormalizedContactArea(event);
return conn.sendPenEvent(eventType, toolType, penButtons,
normalizedCoords[0], normalizedCoords[1],
event.getPressure(event.getActionIndex()),
rotationDegrees, tiltDegrees) != MoonBridge.LI_ERR_UNSUPPORTED;
getPressureOrDistance(event),
normalizedContactArea[0], normalizedContactArea[1],
getRotationDegrees(event), tiltDegrees) != MoonBridge.LI_ERR_UNSUPPORTED;
}
private boolean trySendTouchEvent(View view, MotionEvent event) {
@ -1587,9 +1676,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
float[] normalizedCoords = getStreamViewRelativeNormalizedXY(view, event);
float[] normalizedContactArea = getStreamViewNormalizedContactArea(event);
return conn.sendTouchEvent(eventType, event.getPointerId(event.getActionIndex()),
normalizedCoords[0], normalizedCoords[1],
event.getPressure(event.getActionIndex())) != MoonBridge.LI_ERR_UNSUPPORTED;
getPressureOrDistance(event),
normalizedContactArea[0], normalizedContactArea[1],
getRotationDegrees(event)) != MoonBridge.LI_ERR_UNSUPPORTED;
}
// Returns true if the event was consumed

View File

@ -530,9 +530,11 @@ public class NvConnection {
}
}
public int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressure) {
public int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressureOrDistance,
float contactAreaMajor, float contactAreaMinor, short rotation) {
if (!isMonkey) {
return MoonBridge.sendTouchEvent(eventType, pointerId, x, y, pressure);
return MoonBridge.sendTouchEvent(eventType, pointerId, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;
@ -540,9 +542,11 @@ public class NvConnection {
}
public int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
float pressure, short rotation, byte tilt) {
float pressureOrDistance, float contactAreaMajor, float contactAreaMinor,
short rotation, byte tilt) {
if (!isMonkey) {
return MoonBridge.sendPenEvent(eventType, toolType, penButtons, x, y, pressure, rotation, tilt);
return MoonBridge.sendPenEvent(eventType, toolType, penButtons, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation, tilt);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;

View File

@ -372,10 +372,12 @@ public class MoonBridge {
short leftStickX, short leftStickY,
short rightStickX, short rightStickY);
public static native int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressure);
public static native int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressure,
float contactAreaMajor, float contactAreaMinor, short rotation);
public static native int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
float pressure, short rotation, byte tilt);
float pressure, float contactAreaMajor, float contactAreaMinor,
short rotation, byte tilt);
public static native int sendControllerArrivalEvent(byte controllerNumber, short activeGamepadMask, byte type, int supportedButtonFlags, short capabilities);

@ -1 +1 @@
Subproject commit 2d0badde9aa9a48480e24a289569de1046c6acba
Subproject commit 70a2e305bc7170eccbd48d8c49b64a814e64ecb7

View File

@ -45,16 +45,21 @@ Java_com_limelight_nvstream_jni_MoonBridge_sendMultiControllerInput(JNIEnv *env,
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendTouchEvent(JNIEnv *env, jclass clazz,
jbyte eventType, jint pointerId,
jfloat x, jfloat y, jfloat pressure) {
return LiSendTouchEvent(eventType, pointerId, x, y, pressure);
jfloat x, jfloat y, jfloat pressureOrDistance,
jfloat contactAreaMajor, jfloat contactAreaMinor,
jshort rotation) {
return LiSendTouchEvent(eventType, pointerId, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendPenEvent(JNIEnv *env, jclass clazz, jbyte eventType,
jbyte toolType, jbyte penButtons,
jfloat x, jfloat y, jfloat pressure,
jfloat x, jfloat y, jfloat pressureOrDistance,
jfloat contactAreaMajor, jfloat contactAreaMinor,
jshort rotation, jbyte tilt) {
return LiSendPenEvent(eventType, toolType, penButtons, x, y, pressure, rotation, tilt);
return LiSendPenEvent(eventType, toolType, penButtons, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation, tilt);
}
JNIEXPORT jint JNICALL