Compare commits

..

6 Commits

Author SHA1 Message Date
Romain Vimont
907e55a66b WIP ignore duplicate mouse events 2019-09-22 21:42:43 +02:00
Romain Vimont
6d98ab5d29 WIP process touch events on client 2019-09-22 21:42:43 +02:00
Romain Vimont
91ba44b653 WIP handle touch events on server 2019-09-22 21:42:42 +02:00
Romain Vimont
7b143b8fbd WIP Add "inject touch" event 2019-09-22 21:38:17 +02:00
Romain Vimont
8d1f58278e Rename "pointer" to "mouse pointer"
This will help to distinguish them from "touch pointers".
2019-09-22 21:38:14 +02:00
Romain Vimont
b2d815bfc7 Add buffer_write64be()
Add a function to write 64 bits in big-endian from a uint64_t.
2019-09-22 21:35:10 +02:00
49 changed files with 79 additions and 178 deletions

View File

@@ -43,7 +43,7 @@ Install the required packages from your package manager.
sudo apt install ffmpeg libsdl2-2.0-0
# client build dependencies
sudo apt install gcc git pkg-config meson ninja-build \
sudo apt install make gcc git pkg-config meson ninja-build \
libavcodec-dev libavformat-dev libavutil-dev \
libsdl2-dev

View File

@@ -4,8 +4,6 @@
#include <stdbool.h>
#include <stdint.h>
#include "config.h"
static inline void
buffer_write16be(uint8_t *buf, uint16_t value) {
buf[0] = value >> 8;

View File

@@ -5,8 +5,6 @@
#include <stdbool.h>
#include <unistd.h>
#include "config.h"
// To define a circular buffer type of 20 ints:
// struct cbuf_int CBUF(int, 20);
//

View File

@@ -5,7 +5,6 @@
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "common.h"
#include "log.h"
#include "str_util.h"

View File

@@ -33,8 +33,6 @@
#endif
#include "config.h"
# define NO_EXIT_CODE -1
enum process_result {

View File

@@ -3,8 +3,6 @@
#include <stdint.h>
#include "config.h"
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define MIN(X,Y) (X) < (Y) ? (X) : (Y)
#define MAX(X,Y) (X) > (Y) ? (X) : (Y)

View File

@@ -1,9 +1,8 @@
#include "control_msg.h"
#include <string.h>
#include <SDL2/SDL_assert.h>
#include <SDL_assert.h>
#include "config.h"
#include "buffer_util.h"
#include "log.h"
#include "str_util.h"

View File

@@ -5,7 +5,6 @@
#include <stddef.h>
#include <stdint.h>
#include "config.h"
#include "android/input.h"
#include "android/keycodes.h"
#include "common.h"

View File

@@ -5,7 +5,6 @@
#include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
#include "cbuf.h"
#include "control_msg.h"
#include "net.h"

View File

@@ -8,8 +8,8 @@
#include <SDL2/SDL_thread.h>
#include <unistd.h>
#include "config.h"
#include "compat.h"
#include "config.h"
#include "buffer_util.h"
#include "events.h"
#include "lock_util.h"

View File

@@ -4,8 +4,6 @@
#include <stdbool.h>
#include <libavformat/avformat.h>
#include "config.h"
struct video_buffer;
struct decoder {

View File

@@ -1,6 +1,4 @@
#include "device.h"
#include "config.h"
#include "log.h"
bool

View File

@@ -3,7 +3,6 @@
#include <stdbool.h>
#include "config.h"
#include "common.h"
#include "net.h"

View File

@@ -3,7 +3,6 @@
#include <string.h>
#include <SDL2/SDL_assert.h>
#include "config.h"
#include "buffer_util.h"
#include "log.h"

View File

@@ -5,8 +5,6 @@
#include <stdint.h>
#include <unistd.h>
#include "config.h"
#define DEVICE_MSG_TEXT_MAX_LENGTH 4093
#define DEVICE_MSG_SERIALIZED_MAX_SIZE (3 + DEVICE_MSG_TEXT_MAX_LENGTH)

View File

@@ -1,7 +1,5 @@
#include "event_converter.h"
#include "config.h"
#define MAP(FROM, TO) case FROM: *to = TO; return true
#define FAIL default: return false
@@ -230,7 +228,7 @@ convert_touch(const SDL_TouchFingerEvent *from, struct size screen_size,
to->inject_touch_event.position.screen_size = screen_size;
// SDL touch event coordinates are normalized in the range [0; 1]
to->inject_touch_event.position.point.x = from->x * screen_size.width;
to->inject_touch_event.position.point.y = from->y * screen_size.height;
to->inject_touch_event.position.point.y = from->x * screen_size.height;
to->inject_touch_event.pressure = from->pressure;
return true;
}

View File

@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <SDL2/SDL_events.h>
#include "config.h"
#include "control_msg.h"
struct complete_mouse_motion_event {

View File

@@ -5,7 +5,6 @@
#include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
#include "cbuf.h"
#include "command.h"

View File

@@ -3,7 +3,6 @@
#include <SDL2/SDL_assert.h>
#include <SDL2/SDL_timer.h>
#include "config.h"
#include "lock_util.h"
#include "log.h"

View File

@@ -7,8 +7,6 @@
#include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
struct fps_counter {
SDL_Thread *thread;
SDL_mutex *mutex;

View File

@@ -1,8 +1,6 @@
#include "input_manager.h"
#include <SDL2/SDL_assert.h>
#include "config.h"
#include "event_converter.h"
#include "lock_util.h"
#include "log.h"
@@ -104,7 +102,7 @@ press_back_or_turn_screen_on(struct controller *controller) {
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'press back or turn screen on'");
LOGW("Could not request 'turn screen on'");
}
}

View File

@@ -3,7 +3,6 @@
#include <stdbool.h>
#include "config.h"
#include "common.h"
#include "controller.h"
#include "fps_counter.h"

View File

@@ -4,7 +4,6 @@
#include <stdint.h>
#include <SDL2/SDL_mutex.h>
#include "config.h"
#include "log.h"
static inline void

View File

@@ -8,8 +8,8 @@
#define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem
#include <SDL2/SDL.h>
#include "config.h"
#include "compat.h"
#include "config.h"
#include "log.h"
#include "recorder.h"
@@ -328,7 +328,7 @@ parse_args(struct args *args, int argc, char *argv[]) {
{"push-target", required_argument, NULL,
OPT_PUSH_TARGET},
{"record", required_argument, NULL, 'r'},
{"record-format", required_argument, NULL, 'F'},
{"record-format", required_argument, NULL, 'f'},
{"render-expired-frames", no_argument, NULL,
OPT_RENDER_EXPIRED_FRAMES},
{"serial", required_argument, NULL, 's'},

View File

@@ -2,7 +2,6 @@
#include <stdio.h>
#include "config.h"
#include "log.h"
#ifdef __WINDOWS__

View File

@@ -17,8 +17,6 @@
typedef int socket_t;
#endif
#include "config.h"
bool
net_init(void);

View File

@@ -6,8 +6,6 @@
#include <stddef.h>
#include <SDL2/SDL_assert.h>
#include "config.h"
// To define a queue type of "struct foo":
// struct queue_foo QUEUE(struct foo);
#define QUEUE(TYPE) { \

View File

@@ -5,7 +5,6 @@
#include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
#include "net.h"
// receive events from the device

View File

@@ -3,8 +3,8 @@
#include <libavutil/time.h>
#include <SDL2/SDL_assert.h>
#include "config.h"
#include "compat.h"
#include "config.h"
#include "lock_util.h"
#include "log.h"

View File

@@ -6,7 +6,6 @@
#include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
#include "common.h"
#include "queue.h"

View File

@@ -7,7 +7,6 @@
#include <sys/time.h>
#include <SDL2/SDL.h>
#include "config.h"
#include "command.h"
#include "common.h"
#include "compat.h"

View File

@@ -5,8 +5,6 @@
#include <stdint.h>
#include <recorder.h>
#include "config.h"
struct scrcpy_options {
const char *serial;
const char *crop;

View File

@@ -3,7 +3,6 @@
#include <string.h>
#include <SDL2/SDL.h>
#include "config.h"
#include "common.h"
#include "compat.h"
#include "icon.xpm"

View File

@@ -5,7 +5,6 @@
#include <SDL2/SDL.h>
#include <libavformat/avformat.h>
#include "config.h"
#include "common.h"
struct video_buffer;

View File

@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <stdint.h>
#include "config.h"
#include "command.h"
#include "net.h"

View File

@@ -10,8 +10,6 @@
#include <SDL2/SDL_stdinc.h>
#include "config.h"
size_t
xstrncpy(char *dest, const char *src, size_t n) {
size_t i;

View File

@@ -3,8 +3,6 @@
#include <stddef.h>
#include "config.h"
// like strncpy, except:
// - it copies at most n-1 chars
// - the dest string is nul-terminated

View File

@@ -8,8 +8,8 @@
#include <SDL2/SDL_thread.h>
#include <unistd.h>
#include "config.h"
#include "compat.h"
#include "config.h"
#include "buffer_util.h"
#include "decoder.h"
#include "events.h"

View File

@@ -7,7 +7,6 @@
#include <SDL2/SDL_atomic.h>
#include <SDL2/SDL_thread.h>
#include "config.h"
#include "net.h"
struct video_buffer;

View File

@@ -7,8 +7,6 @@
#include "command.h"
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>

View File

@@ -2,8 +2,6 @@
#include <unistd.h>
#include "config.h"
bool
net_init(void) {
// do nothing

View File

@@ -1,6 +1,5 @@
#include "net.h"
#include "config.h"
#include "log.h"
bool

View File

@@ -5,7 +5,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "log.h"
struct index {

View File

@@ -3,8 +3,6 @@
#include <SDL2/SDL.h>
#include "config.h"
SDL_Surface *
read_xpm(char *xpm[]);

View File

@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <SDL2/SDL_mutex.h>
#include "config.h"
#include "fps_counter.h"
// forward declarations

View File

@@ -57,9 +57,6 @@ public class Controller {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
coords.orientation = 0;
coords.size = 1;
touchPointerProperties[i] = props;
touchPointerCoords[i] = coords;
}
}
@@ -112,9 +109,6 @@ public class Controller {
case ControlMessage.TYPE_INJECT_MOUSE_EVENT:
injectMouse(msg.getAction(), msg.getButtons(), msg.getPosition());
break;
case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
injectTouch(msg.getAction(), msg.getFingerId(), msg.getPosition(), msg.getPressure());
break;
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll());
break;
@@ -189,45 +183,29 @@ public class Controller {
return injectEvent(event);
}
private boolean injectTouch(int action, long fingerId, Position position, float pressure) {
private boolean injectTouch(int action, int fingerId, Position position, float pressure) {
long now = SystemClock.uptimeMillis();
if (action == MotionEvent.ACTION_DOWN) {
lastTouchDown = now;
}
Point point = device.getPhysicalPoint(position);
if (point == null) {
// ignore event
return false;
}
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);
}
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);
if (action == MotionEvent.ACTION_UP) {
if (!fingersState.unset(fingerId)) {
Ln.w("Unexpected ACTION_UP on unknown finger");
return false;
}
} else {
// ACTION_DOWN or ACTION_MOVE
if (!fingersState.set(fingerId, point, pressure)) {
Ln.w("Too many fingers for touch event");
return false;
}
} else if (action == MotionEvent.ACTION_DOWN) {
lastTouchDown = now;
}
int pointerCount = fingersState.update(touchPointerProperties, touchPointerCoords);
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, touchPointerProperties, touchPointerCoords, 0, 0, 1f, 1f, 0, 0,
InputDevice.SOURCE_TOUCHSCREEN, 0);
return injectEvent(event);

View File

@@ -3,24 +3,17 @@ package com.genymobile.scrcpy;
public class Finger {
private final long id;
private final int localId;
private Point point;
private float pressure;
private boolean up;
public Finger(long id, int localId) {
public Finger(long id) {
this.id = id;
this.localId = localId;
}
public long getId() {
return id;
}
public int getLocalId() {
return localId;
}
public Point getPoint() {
return point;
}
@@ -36,12 +29,4 @@ public class Finger {
public void setPressure(float pressure) {
this.pressure = pressure;
}
public boolean isUp() {
return up;
}
public void setUp(boolean up) {
this.up = up;
}
}

View File

@@ -2,70 +2,73 @@ package com.genymobile.scrcpy;
import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.List;
public class FingersState {
private final List<Finger> fingers = new ArrayList<>();
private int maxFingers;
/**
* Array of enabled fingers (can contain "null" holes).
* <p>
* Once a Finger (identified by its id received from the client) is enabled, it is never moved.
* <p>
* Its index is its local identifier injected into MotionEvents.
*/
private final Finger[] fingers;
public FingersState(int maxFingers) {
this.maxFingers = maxFingers;
fingers = new Finger[maxFingers];
}
private int indexOf(long id) {
for (int i = 0; i < fingers.size(); ++i) {
Finger finger = fingers.get(i);
if (finger.getId() == id) {
for (int i = 0; i < fingers.length; ++i) {
Finger finger = fingers[i];
if (finger != null && finger.getId() == id) {
return i;
}
}
return -1;
}
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;
private int indexOfFirstEmpty() {
for (int i = 0; i < fingers.length; ++i) {
if (fingers[i] == null) {
return i;
}
}
return -1;
}
public Finger get(int index) {
return fingers.get(index);
}
public int getFingerIndex(long id) {
private Finger create(long id) {
int index = indexOf(id);
if (index != -1) {
// already exists, return it
return index;
return fingers[index];
}
if (fingers.size() >= maxFingers) {
int firstEmpty = indexOfFirstEmpty();
if (firstEmpty == -1) {
// it's full
return -1;
return null;
}
// id 0 is reserved for mouse events
int localId = nextUnusedLocalId();
if (localId == -1) {
throw new AssertionError("fingers.size() < maxFingers implies that a local id is available");
Finger finger = new Finger(id);
fingers[firstEmpty] = finger;
return finger;
}
public boolean unset(int id) {
int index = indexOf(id);
if (index == -1) {
return false;
}
Finger finger = new Finger(id, localId);
fingers.add(finger);
// return the index of the finger
return fingers.size() - 1;
fingers[index] = null;
return true;
}
public boolean set(int id, Point point, float pressure) {
Finger finger = create(id);
if (finger == null) {
return false;
}
finger.setPoint(point);
finger.setPressure(pressure);
return true;
}
/**
@@ -76,26 +79,21 @@ public class FingersState {
* @return The number of items initialized (the number of fingers).
*/
public int update(MotionEvent.PointerProperties[] props, MotionEvent.PointerCoords[] coords) {
for (int i = 0; i < fingers.size(); ++i) {
Finger finger = fingers.get(i);
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 = i + 1;
// id 0 is reserved for mouse events
props[i].id = finger.getLocalId();
Point point = finger.getPoint();
coords[i].x = point.getX();
coords[i].y = point.getY();
coords[i].pressure = finger.getPressure();
Point point = finger.getPoint();
coords[i].x = point.getX();
coords[i].y = point.getY();
coords[i].pressure = finger.getPressure();
}
return fingers.size();
}
public void cleanUp() {
for (int i = fingers.size() - 1; i >= 0; --i) {
Finger finger = fingers.get(i);
if (finger.isUp()) {
fingers.remove(i);
++count;
}
}
return count;
}
}

View File

@@ -77,7 +77,6 @@ public class ControlMessageReaderTest {
}
@Test
@SuppressWarnings("checkstyle:MagicNumber")
public void testParseMouseEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
@@ -106,7 +105,6 @@ public class ControlMessageReaderTest {
}
@Test
@SuppressWarnings("checkstyle:MagicNumber")
public void testParseTouchEvent() throws IOException {
ControlMessageReader reader = new ControlMessageReader();