JBR-5673: Wayland: support touch scrolling.

- Adding information to WLPointerEvent about wl_pointer::axis* events along the X axis;
- Introducing 'WLComponentPeer#convertPointerEventToMWEParameters' - a routine for converting WLPointerEvent parameters to parameters required for MouseWheelEvent s;
- Handling both X and Y axes within the WLPointerEvent dispatching routine.

(cherry picked from commit 6afbc34d4b)
(cherry picked from commit 8b091f52d1)
This commit is contained in:
Nikita Provotorov
2024-08-04 18:05:12 +02:00
committed by jbrbot
parent 62e2894e15
commit 81ce9ab0db
3 changed files with 311 additions and 84 deletions

View File

@@ -101,9 +101,6 @@ public class WLComponentPeer implements ComponentPeer {
{"move"}, // MOVE_CURSOR
};
// Changing this constant may require adjustments in convertAxisVectorToPreciseWheelRotations
private static final int WHEEL_SCROLL_AMOUNT = 3;
private static final int MINIMUM_WIDTH = 1;
private static final int MINIMUM_HEIGHT = 1;
@@ -1157,49 +1154,125 @@ public class WLComponentPeer implements ComponentPeer {
}
if (e.hasAxisEvent()) {
final int scrollAmount;
final double wheelPreciseRotations;
final int wheelRoundRotations;
convertPointerEventToMWEParameters(e, xAxisWheelRoundRotationsAccumulator, yAxisWheelRoundRotationsAccumulator, mweConversionInfo);
// wl_pointer::axis_discrete/axis_value120 are preferred over wl_pointer::axis because
// they're closer to MouseWheelEvent by their nature.
if (e.axis0HasSteps120Value()) {
final var steps120Value = e.getAxis0Steps120Value();
wheelPreciseRotations = steps120Value / 120.0d;
wheelRoundRotations = wheelRoundRotationsAccumulator.accumulateSteps120Rotations(steps120Value);
// TODO: It would be probably better to calculate the scrollAmount here taking getAxis0VectorValue() into
// consideration, so that the wheel scrolling speed could be adjusted via some system settings.
// However, neither Gnome nor KDE currently provide such a setting, making it difficult to test
// how well such an approach would work. So leaving it as is for now.
scrollAmount = WHEEL_SCROLL_AMOUNT;
} else if (e.axis0HasVectorValue()) {
final var vectorValue = e.getAxis0VectorValue();
wheelPreciseRotations = convertAxisVectorToPreciseWheelRotations(vectorValue);
wheelRoundRotations = wheelRoundRotationsAccumulator.accumulateFractionalRotations(wheelPreciseRotations);
scrollAmount = 1;
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("{0} -> {1}", e, mweConversionInfo);
}
// macOS's and Windows' AWT implement the following logic, so do we:
// Shift + a vertical scroll means a horizontal scroll.
// AWT/Swing components are also aware of it.
final boolean isShiftPressed = (newInputState.getModifiers() & KeyEvent.SHIFT_DOWN_MASK) != 0;
// These values decide whether a horizontal scrolling MouseWheelEvent will be created and posted
final int horizontalMWEScrollAmount;
final double horizontalMWEPreciseRotations;
final int horizontalMWERoundRotations;
// These values decide whether a vertical scrolling MouseWheelEvent will be created and posted
final int verticalMWEScrollAmount;
final double verticalMWEPreciseRotations;
final int verticalMWERoundRotations;
if (isShiftPressed) {
// Pressing Shift makes only a horizontal scrolling MouseWheelEvent possible
verticalMWEScrollAmount = 0;
verticalMWEPreciseRotations = 0;
verticalMWERoundRotations = 0;
// Now we're deciding values of which axis will be used to generate a horizontal MouseWheelEvent
if (mweConversionInfo.xAxisDirectionSign == mweConversionInfo.yAxisDirectionSign) {
// The scrolling directions don't contradict each other.
// Let's pick the more influencing axis.
final var xAxisUnitsToScroll = mweConversionInfo.xAxisMWEScrollAmount * (
Math.abs(mweConversionInfo.xAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.xAxisMWERoundRotations)
? mweConversionInfo.xAxisMWEPreciseRotations
: mweConversionInfo.xAxisMWERoundRotations );
final var yAxisUnitsToScroll = mweConversionInfo.yAxisMWEScrollAmount * (
Math.abs(mweConversionInfo.yAxisMWEPreciseRotations) > Math.abs(mweConversionInfo.yAxisMWERoundRotations)
? mweConversionInfo.yAxisMWEPreciseRotations
: mweConversionInfo.yAxisMWERoundRotations );
if (xAxisUnitsToScroll > yAxisUnitsToScroll) {
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
} else {
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
}
} else if (mweConversionInfo.yAxisMWERoundRotations != 0 || mweConversionInfo.yAxisMWEPreciseRotations != 0) {
// The scrolling directions contradict.
// I think consistently choosing the Y axis values (unless they're zero) provides the most expected UI behavior here.
horizontalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
horizontalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
horizontalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
} else {
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
}
} else {
wheelRoundRotations = 0;
wheelPreciseRotations = 0;
scrollAmount = 0;
// Shift is not pressed, so both horizontal and vertical MouseWheelEvent s are possible.
horizontalMWEScrollAmount = mweConversionInfo.xAxisMWEScrollAmount;
horizontalMWEPreciseRotations = mweConversionInfo.xAxisMWEPreciseRotations;
horizontalMWERoundRotations = mweConversionInfo.xAxisMWERoundRotations;
verticalMWEScrollAmount = mweConversionInfo.yAxisMWEScrollAmount;
verticalMWEPreciseRotations = mweConversionInfo.yAxisMWEPreciseRotations;
verticalMWERoundRotations = mweConversionInfo.yAxisMWERoundRotations;
}
if (e.axis0HasStopEvent()) {
wheelRoundRotationsAccumulator.reset();
if (e.xAxisHasStopEvent()) {
xAxisWheelRoundRotationsAccumulator.reset();
}
if (e.yAxisHasStopEvent()) {
yAxisWheelRoundRotationsAccumulator.reset();
}
if ((wheelRoundRotations != 0) || (wheelPreciseRotations != 0)) {
if (verticalMWERoundRotations != 0 || verticalMWEPreciseRotations != 0) {
assert(verticalMWEScrollAmount > 0);
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
MouseEvent.MOUSE_WHEEL,
timestamp,
newInputState.getModifiers(),
// Making sure the event will cause scrolling along the vertical axis
newInputState.getModifiers() & ~KeyEvent.SHIFT_DOWN_MASK,
x, y,
xAbsolute, yAbsolute,
1,
isPopupTrigger,
MouseWheelEvent.WHEEL_UNIT_SCROLL,
scrollAmount,
wheelRoundRotations,
wheelPreciseRotations);
verticalMWEScrollAmount,
verticalMWERoundRotations,
verticalMWEPreciseRotations);
postMouseEvent(mouseEvent);
}
if (horizontalMWERoundRotations != 0 || horizontalMWEPreciseRotations != 0) {
assert(horizontalMWEScrollAmount > 0);
final MouseEvent mouseEvent = new MouseWheelEvent(getTarget(),
MouseEvent.MOUSE_WHEEL,
timestamp,
// Making sure the event will cause scrolling along the horizontal axis
newInputState.getModifiers() | KeyEvent.SHIFT_DOWN_MASK,
x, y,
xAbsolute, yAbsolute,
1,
isPopupTrigger,
MouseWheelEvent.WHEEL_UNIT_SCROLL,
horizontalMWEScrollAmount,
horizontalMWERoundRotations,
horizontalMWEPreciseRotations);
postMouseEvent(mouseEvent);
}
}
@@ -1288,13 +1361,107 @@ public class WLComponentPeer implements ComponentPeer {
private double accumulatedFractionalRotations = 0;
private int accumulatedSteps120Rotations = 0;
}
private final MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
private final MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
private final MouseWheelRoundRotationsAccumulator wheelRoundRotationsAccumulator = new MouseWheelRoundRotationsAccumulator();
private static final class PointerEventToMWEConversionInfo {
public double xAxisVector = 0;
public int xAxisSteps120 = 0;
public int xAxisDirectionSign = 0;
public double xAxisMWEPreciseRotations = 0;
public int xAxisMWERoundRotations = 0;
public int xAxisMWEScrollAmount = 0;
private double convertAxisVectorToPreciseWheelRotations(double axisVector) {
public double yAxisVector = 0;
public int yAxisSteps120 = 0;
public int yAxisDirectionSign = 0;
public double yAxisMWEPreciseRotations = 0;
public int yAxisMWERoundRotations = 0;
public int yAxisMWEScrollAmount = 0;
private final StringBuilder toStringBuf = new StringBuilder(1024);
@Override
public String toString() {
toStringBuf.setLength(0);
toStringBuf.append("PointerEventToMWEConversionInfo[")
.append("xAxisVector=" ).append(xAxisVector ).append(", ")
.append("xAxisSteps120=" ).append(xAxisSteps120 ).append(", ")
.append("xAxisDirectionSign=" ).append(xAxisDirectionSign ).append(", ")
.append("xAxisMWEPreciseRotations=").append(xAxisMWEPreciseRotations).append(", ")
.append("xAxisMWERoundRotations=" ).append(xAxisMWERoundRotations ).append(", ")
.append("xAxisMWEScrollAmount=" ).append(xAxisMWEScrollAmount ).append(", ")
.append("yAxisVector=" ).append(yAxisVector ).append(", ")
.append("yAxisSteps120=" ).append(yAxisSteps120 ).append(", ")
.append("yAxisDirectionSign=" ).append(yAxisDirectionSign ).append(", ")
.append("yAxisMWEPreciseRotations=").append(yAxisMWEPreciseRotations).append(", ")
.append("yAxisMWERoundRotations=" ).append(yAxisMWERoundRotations ).append(", ")
.append("yAxisMWEScrollAmount=" ).append(yAxisMWEScrollAmount )
.append(']');
return toStringBuf.toString();
}
}
private final PointerEventToMWEConversionInfo mweConversionInfo = new PointerEventToMWEConversionInfo();
private static void convertPointerEventToMWEParameters(
WLPointerEvent dispatchingEvent,
MouseWheelRoundRotationsAccumulator xAxisWheelRoundRotationsAccumulator,
MouseWheelRoundRotationsAccumulator yAxisWheelRoundRotationsAccumulator,
PointerEventToMWEConversionInfo mweConversionInfo) {
// WLPointerEvent -> MouseWheelEvent conversion constants.
// Please keep in mind that they're all related, so that changing one may require adjusting the others
// (or altering this conversion routine).
// XToolkit uses 3 units per a wheel step, so do we here to preserve the user experience
final int STEPS120_MWE_SCROLL_AMOUNT = 3;
// For touchpad scrolling, it's worth being able to scroll the minimum possible number of units (i.e. 1)
final int VECTOR_MWE_SCROLL_AMOUNT = 1;
// 0.28 has experimentally been found as providing a good balance between
// wheel scrolling sensitivity and touchpad scrolling sensitivity
return axisVector * 0.28;
final double VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR = 0.28;
mweConversionInfo.xAxisVector = dispatchingEvent.xAxisHasVectorValue() ? dispatchingEvent.getXAxisVectorValue() : 0;
mweConversionInfo.xAxisSteps120 = dispatchingEvent.xAxisHasSteps120Value() ? dispatchingEvent.getXAxisSteps120Value() : 0;
// Converting the X axis Wayland values to MouseWheelEvent parameters.
// wl_pointer::axis_discrete/axis_value120 are preferred over wl_pointer::axis because
// they're closer to MouseWheelEvent by their nature.
if (mweConversionInfo.xAxisSteps120 != 0) {
mweConversionInfo.xAxisDirectionSign = Integer.signum(mweConversionInfo.xAxisSteps120);
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisSteps120 / 120d;
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.xAxisSteps120);
// It would be probably better to calculate the scrollAmount taking the xAxisVector value into
// consideration, so that the wheel scrolling speed could be adjusted via some system settings.
// However, neither Gnome nor KDE currently provide such a setting, making it difficult to test
// how well such an approach would work. So leaving it as is for now.
mweConversionInfo.xAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
} else {
mweConversionInfo.xAxisDirectionSign = (int)Math.signum(mweConversionInfo.xAxisVector);
mweConversionInfo.xAxisMWEPreciseRotations = mweConversionInfo.xAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
mweConversionInfo.xAxisMWERoundRotations = xAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.xAxisMWEPreciseRotations);
mweConversionInfo.xAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
}
mweConversionInfo.yAxisVector = dispatchingEvent.yAxisHasVectorValue() ? dispatchingEvent.getYAxisVectorValue() : 0;
mweConversionInfo.yAxisSteps120 = dispatchingEvent.yAxisHasSteps120Value() ? dispatchingEvent.getYAxisSteps120Value() : 0;
// Converting the Y axis Wayland values to MouseWheelEvent parameters.
// (Currently, the routine is exactly like for X axis)
if (mweConversionInfo.yAxisSteps120 != 0) {
mweConversionInfo.yAxisDirectionSign = Integer.signum(mweConversionInfo.yAxisSteps120);
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisSteps120 / 120d;
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateSteps120Rotations(mweConversionInfo.yAxisSteps120);
mweConversionInfo.yAxisMWEScrollAmount = STEPS120_MWE_SCROLL_AMOUNT;
} else {
mweConversionInfo.yAxisDirectionSign = (int)Math.signum(mweConversionInfo.yAxisVector);
mweConversionInfo.yAxisMWEPreciseRotations = mweConversionInfo.yAxisVector * VECTOR_LENGTH_TO_MWE_ROTATIONS_FACTOR;
mweConversionInfo.yAxisMWERoundRotations = yAxisWheelRoundRotationsAccumulator.accumulateFractionalRotations(mweConversionInfo.yAxisMWEPreciseRotations);
mweConversionInfo.yAxisMWEScrollAmount = VECTOR_MWE_SCROLL_AMOUNT;
}
}

View File

@@ -57,12 +57,19 @@ class WLPointerEvent {
private int buttonCode; // pointer button code corresponding to PointerButtonCodes.linuxCode
private boolean isButtonPressed; // true if button was pressed, false if released
private boolean axis_0_hasVectorValue; // whether axis_0_vectorValue is valid
private boolean axis_0_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
private boolean axis_0_hasSteps120Value; // whether axis_0_steps120Value is valid
private double axis_0_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
private int axis_0_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
private boolean xAxis_hasVectorValue; // whether xAxis_vectorValue is valid
private boolean xAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
private boolean xAxis_hasSteps120Value; // whether xAxis_steps120Value is valid
private double xAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
private int xAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
private boolean yAxis_hasVectorValue; // whether yAxis_vectorValue is valid
private boolean yAxis_hasStopEvent; // whether wl_pointer::axis_stop event has been received for this axis
private boolean yAxis_hasSteps120Value; // whether yAxis_steps120Value is valid
private double yAxis_vectorValue; // "length of vector in surface-local coordinate space" (source: wayland.xml)
private int yAxis_steps120Value; // "high-resolution wheel scroll information, with each multiple of 120
// representing one logical scroll step (a wheel detent)" (source: wayland.xml)
private WLPointerEvent() {}
@@ -178,7 +185,7 @@ class WLPointerEvent {
}
public boolean hasAxisEvent() {
return axis0HasEvents();
return xAxisHasEvents() || yAxisHasEvents();
}
/**
@@ -244,32 +251,60 @@ class WLPointerEvent {
return isButtonPressed;
}
public boolean axis0HasEvents() {
return axis0HasVectorValue() ||
axis0HasStopEvent() ||
axis0HasSteps120Value();
public boolean xAxisHasEvents() {
return xAxisHasVectorValue() ||
xAxisHasStopEvent() ||
xAxisHasSteps120Value();
}
public boolean axis0HasVectorValue() {
return axis_0_hasVectorValue;
public boolean xAxisHasVectorValue() {
return xAxis_hasVectorValue;
}
public boolean axis0HasStopEvent() {
return axis_0_hasStopEvent;
public boolean xAxisHasStopEvent() {
return xAxis_hasStopEvent;
}
public boolean axis0HasSteps120Value() {
return axis_0_hasSteps120Value;
public boolean xAxisHasSteps120Value() {
return xAxis_hasSteps120Value;
}
public double getAxis0VectorValue() {
assert axis0HasVectorValue();
return axis_0_vectorValue;
public double getXAxisVectorValue() {
assert xAxisHasVectorValue();
return xAxis_vectorValue;
}
public int getAxis0Steps120Value() {
assert axis0HasSteps120Value();
return axis_0_steps120Value;
public int getXAxisSteps120Value() {
assert xAxisHasSteps120Value();
return xAxis_steps120Value;
}
public boolean yAxisHasEvents() {
return yAxisHasVectorValue() ||
yAxisHasStopEvent() ||
yAxisHasSteps120Value();
}
public boolean yAxisHasVectorValue() {
return yAxis_hasVectorValue;
}
public boolean yAxisHasStopEvent() {
return yAxis_hasStopEvent;
}
public boolean yAxisHasSteps120Value() {
return yAxis_hasSteps120Value;
}
public double getYAxisVectorValue() {
assert yAxisHasVectorValue();
return yAxis_vectorValue;
}
public int getYAxisSteps120Value() {
assert yAxisHasSteps120Value();
return yAxis_steps120Value;
}
@Override
@@ -305,16 +340,29 @@ class WLPointerEvent {
if (hasAxisEvent()) {
builder.append(" axis");
if (axis0HasEvents()) {
if (yAxisHasEvents()) {
builder.append(" vertical-scroll:");
if (axis0HasVectorValue()) {
builder.append(" ").append(getAxis0VectorValue());
if (yAxisHasVectorValue()) {
builder.append(" ").append(getYAxisVectorValue());
}
if (axis0HasSteps120Value()) {
builder.append(" ").append(getAxis0Steps120Value()).append("/120 steps");
if (yAxisHasSteps120Value()) {
builder.append(" ").append(getYAxisSteps120Value()).append("/120 steps");
}
if (axis0HasStopEvent()) {
if (yAxisHasStopEvent()) {
builder.append(" stop");
}
}
if (xAxisHasEvents()) {
builder.append(" horizontal-scroll:");
if (xAxisHasVectorValue()) {
builder.append(" ").append(getXAxisVectorValue());
}
if (xAxisHasSteps120Value()) {
builder.append(" ").append(getXAxisSteps120Value()).append("/120 steps");
}
if (xAxisHasStopEvent()) {
builder.append(" stop");
}
}

View File

@@ -113,11 +113,16 @@ static jfieldID surfaceXFID;
static jfieldID surfaceYFID;
static jfieldID buttonCodeFID;
static jfieldID isButtonPressedFID;
static jfieldID axis_0_hasVectorValueFID;
static jfieldID axis_0_hasStopEventFID;
static jfieldID axis_0_hasSteps120ValueFID;
static jfieldID axis_0_vectorValueFID;
static jfieldID axis_0_steps120ValueFID;
static jfieldID xAxis_hasVectorValueFID;
static jfieldID xAxis_hasStopEventFID;
static jfieldID xAxis_hasSteps120ValueFID;
static jfieldID xAxis_vectorValueFID;
static jfieldID xAxis_steps120ValueFID;
static jfieldID yAxis_hasVectorValueFID;
static jfieldID yAxis_hasStopEventFID;
static jfieldID yAxis_hasSteps120ValueFID;
static jfieldID yAxis_vectorValueFID;
static jfieldID yAxis_steps120ValueFID;
static jmethodID dispatchKeyboardKeyEventMID;
static jmethodID dispatchKeyboardModifiersEventMID;
@@ -307,11 +312,17 @@ fillJavaPointerEvent(JNIEnv* env, jobject pointerEventRef)
(*env)->SetBooleanField(env, pointerEventRef, isButtonPressedFID,
(pointer_event.state == WL_POINTER_BUTTON_STATE_PRESSED));
(*env)->SetBooleanField(env, pointerEventRef, axis_0_hasVectorValueFID, pointer_event.axes[0].has_vector_value);
(*env)->SetBooleanField(env, pointerEventRef, axis_0_hasStopEventFID, pointer_event.axes[0].has_stop_event);
(*env)->SetBooleanField(env, pointerEventRef, axis_0_hasSteps120ValueFID, pointer_event.axes[0].has_steps120_value);
(*env)->SetDoubleField(env, pointerEventRef, axis_0_vectorValueFID, wl_fixed_to_double(pointer_event.axes[0].vector_value));
(*env)->SetIntField(env, pointerEventRef, axis_0_steps120ValueFID, pointer_event.axes[0].steps120_value);
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasVectorValueFID, pointer_event.axes[1].has_vector_value);
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasStopEventFID, pointer_event.axes[1].has_stop_event);
(*env)->SetBooleanField(env, pointerEventRef, xAxis_hasSteps120ValueFID, pointer_event.axes[1].has_steps120_value);
(*env)->SetDoubleField (env, pointerEventRef, xAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[1].vector_value));
(*env)->SetIntField (env, pointerEventRef, xAxis_steps120ValueFID, pointer_event.axes[1].steps120_value);
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasVectorValueFID, pointer_event.axes[0].has_vector_value);
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasStopEventFID, pointer_event.axes[0].has_stop_event);
(*env)->SetBooleanField(env, pointerEventRef, yAxis_hasSteps120ValueFID, pointer_event.axes[0].has_steps120_value);
(*env)->SetDoubleField (env, pointerEventRef, yAxis_vectorValueFID, wl_fixed_to_double(pointer_event.axes[0].vector_value));
(*env)->SetIntField (env, pointerEventRef, yAxis_steps120ValueFID, pointer_event.axes[0].steps120_value);
}
static void
@@ -669,16 +680,17 @@ initJavaRefs(JNIEnv *env, jclass clazz)
CHECK_NULL_RETURN(buttonCodeFID = (*env)->GetFieldID(env, pointerEventClass, "buttonCode", "I"), JNI_FALSE);
CHECK_NULL_RETURN(isButtonPressedFID = (*env)->GetFieldID(env, pointerEventClass, "isButtonPressed", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(axis_0_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_hasVectorValue", "Z"),
JNI_FALSE);
CHECK_NULL_RETURN(axis_0_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_hasStopEvent", "Z"),
JNI_FALSE);
CHECK_NULL_RETURN(axis_0_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_hasSteps120Value", "Z"),
JNI_FALSE);
CHECK_NULL_RETURN(axis_0_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_vectorValue", "D"),
JNI_FALSE);
CHECK_NULL_RETURN(axis_0_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "axis_0_steps120Value", "I"),
JNI_FALSE);
CHECK_NULL_RETURN(xAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasVectorValue", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(xAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasStopEvent", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(xAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_hasSteps120Value", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(xAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_vectorValue", "D"), JNI_FALSE);
CHECK_NULL_RETURN(xAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "xAxis_steps120Value", "I"), JNI_FALSE);
CHECK_NULL_RETURN(yAxis_hasVectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasVectorValue", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(yAxis_hasStopEventFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasStopEvent", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(yAxis_hasSteps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_hasSteps120Value", "Z"), JNI_FALSE);
CHECK_NULL_RETURN(yAxis_vectorValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_vectorValue", "D"), JNI_FALSE);
CHECK_NULL_RETURN(yAxis_steps120ValueFID = (*env)->GetFieldID(env, pointerEventClass, "yAxis_steps120Value", "I"), JNI_FALSE);
CHECK_NULL_RETURN(dispatchKeyboardEnterEventMID = (*env)->GetStaticMethodID(env, tkClass,
"dispatchKeyboardEnterEvent",