diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index 9fd4455e..326198ad 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -199,24 +199,35 @@ public class Controller { // ignore event return false; } - Finger finger = fingersState.get(fingerId); - if (finger == null) { + + int fingerIndex = fingersState.getFingerIndex(fingerId); + if (fingerIndex == -1) { Ln.w("Too many fingers for touch event"); return false; } + Finger finger = fingersState.get(fingerIndex); finger.setPoint(point); finger.setPressure(pressure); finger.setUp(action == MotionEvent.ACTION_UP); // FAIL: action_up will always remove the finger, and the event will not be written! int pointerCount = fingersState.update(touchPointerProperties, touchPointerCoords); + fingersState.cleanUp(); Ln.d("pointerCount = " + pointerCount); for (int i = 0; i < pointerCount; ++i) { Ln.d("props = " + touchPointerProperties[i].id); Ln.d("coords = " + touchPointerCoords[i].x + "," + touchPointerCoords[i].y); } - MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action | (finger.getLocalId() << 8), pointerCount, touchPointerProperties, touchPointerCoords, 0, 0, 1f, 1f, 0, 0, + + if (pointerCount > 1) { + if (action == MotionEvent.ACTION_UP) { + action = MotionEvent.ACTION_POINTER_UP | (fingerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT); + } else if (action == MotionEvent.ACTION_DOWN) { + action = MotionEvent.ACTION_POINTER_DOWN | (fingerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT); + } + } + MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, touchPointerProperties, touchPointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); return injectEvent(event); } diff --git a/server/src/main/java/com/genymobile/scrcpy/FingersState.java b/server/src/main/java/com/genymobile/scrcpy/FingersState.java index c08fff6a..1961e1f2 100644 --- a/server/src/main/java/com/genymobile/scrcpy/FingersState.java +++ b/server/src/main/java/com/genymobile/scrcpy/FingersState.java @@ -2,56 +2,70 @@ package com.genymobile.scrcpy; import android.view.MotionEvent; +import java.util.ArrayList; +import java.util.List; + public class FingersState { - /** - * Array of enabled fingers (can contain "null" holes). - *

- * Once a Finger (identified by its id received from the client) is enabled, it is never moved. - *

- * Its index is its local identifier injected into MotionEvents. - */ - private final Finger[] fingers; + private final List fingers = new ArrayList<>(); + private int maxFingers; public FingersState(int maxFingers) { - fingers = new Finger[maxFingers]; + this.maxFingers = maxFingers; } private int indexOf(long id) { - for (int i = 0; i < fingers.length; ++i) { - Finger finger = fingers[i]; - if (finger != null && finger.getId() == id) { + for (int i = 0; i < fingers.size(); ++i) { + Finger finger = fingers.get(i); + if (finger.getId() == id) { return i; } } return -1; } - private int indexOfFirstEmpty() { - for (int i = 0; i < fingers.length; ++i) { - if (fingers[i] == null) { - return i; + private boolean isLocalIdAvailable(int localId) { + for (int i = 0; i < fingers.size(); ++i) { + Finger finger = fingers.get(i); + if (finger.getLocalId() == localId) { + return false; + } + } + return true; + } + + private int nextUnusedLocalId() { + for (int localId = 0; localId < maxFingers; ++localId) { + if (isLocalIdAvailable(localId)) { + return localId; } } return -1; } - public Finger get(long id) { + public Finger get(int index) { + return fingers.get(index); + } + + public int getFingerIndex(long id) { int index = indexOf(id); if (index != -1) { // already exists, return it - return fingers[index]; + return index; } - index = indexOfFirstEmpty(); - if (index == -1) { + if (fingers.size() >= maxFingers) { // it's full - return null; + return -1; } // id 0 is reserved for mouse events - int localId = index;// + 1; + int localId = nextUnusedLocalId(); + if (localId == -1) { + throw new AssertionError("fingers.size() < maxFingers implies that a local id is available"); + } Finger finger = new Finger(id, localId); - fingers[index] = finger; - return finger; + fingers.add(finger); + // return the index of the finger + return fingers.size() - 1; } /** @@ -62,27 +76,26 @@ public class FingersState { * @return The number of items initialized (the number of fingers). */ public int update(MotionEvent.PointerProperties[] props, MotionEvent.PointerCoords[] coords) { - int count = 0; - for (int i = 0; i < fingers.length; ++i) { - Finger finger = fingers[i]; - if (finger != null) { - // id 0 is reserved for mouse events - props[count].id = finger.getLocalId(); - Ln.d("update id = " + finger.getLocalId()); + for (int i = 0; i < fingers.size(); ++i) { + Finger finger = fingers.get(i); - Point point = finger.getPoint(); - coords[count].x = point.getX(); - coords[count].y = point.getY(); - coords[count].pressure = finger.getPressure(); + // id 0 is reserved for mouse events + props[i].id = finger.getLocalId(); - if (finger.isUp()) { - // remove it - fingers[i] = null; - } + Point point = finger.getPoint(); + coords[i].x = point.getX(); + coords[i].y = point.getY(); + coords[i].pressure = finger.getPressure(); + } + return fingers.size(); + } - ++count; + public void cleanUp() { + for (int i = fingers.size() - 1; i >= 0; --i) { + Finger finger = fingers.get(i); + if (finger.isUp()) { + fingers.remove(i); } } - return count; } }