update:event改为message更恰当

This commit is contained in:
Barry 2019-06-19 16:13:58 +08:00
commit d2e83da5b1
29 changed files with 560 additions and 733 deletions

View file

@ -1,21 +1,21 @@
package com.genymobile.scrcpy;
/**
* Union of all supported event types, identified by their {@code type}.
* Union of all supported msg types, identified by their {@code type}.
*/
public final class ControlEvent {
public final class ControlMessage {
public static final int TYPE_KEYCODE = 0;
public static final int TYPE_TEXT = 1;
public static final int TYPE_MOUSE = 2;
public static final int TYPE_SCROLL = 3;
public static final int TYPE_INJECT_KEYCODE = 0;
public static final int TYPE_INJECT_TEXT = 1;
public static final int TYPE_INJECT_MOUSE = 2;
public static final int TYPE_INJECT_SCROLL = 3;
public static final int TYPE_BACK_OR_SCREEN_ON = 4;
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5;
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6;
public static final int TYPE_GET_CLIPBOARD = 7;
public static final int TYPE_SET_CLIPBOARD = 8;
public static final int TYPE_TOUCH = 9;
public static final int TYPE_INJECT_TOUCH = 9;
private int type;
@ -29,61 +29,61 @@ public final class ControlEvent {
private int hScroll;
private int vScroll;
private ControlEvent() {
private ControlMessage() {
}
public static ControlEvent createKeycodeControlEvent(int action, int keycode, int metaState) {
ControlEvent event = new ControlEvent();
event.type = TYPE_KEYCODE;
public static ControlMessage createInjectKeycode(int action, int keycode, int metaState) {
ControlMessage event = new ControlMessage();
event.type = TYPE_INJECT_KEYCODE;
event.action = action;
event.keycode = keycode;
event.metaState = metaState;
return event;
}
public static ControlEvent createTextControlEvent(String text) {
ControlEvent event = new ControlEvent();
event.type = TYPE_TEXT;
public static ControlMessage createInjectText(String text) {
ControlMessage event = new ControlMessage();
event.type = TYPE_INJECT_TEXT;
event.text = text;
return event;
}
public static ControlEvent createMotionControlEvent(int action, int buttons, Position position) {
ControlEvent event = new ControlEvent();
event.type = TYPE_MOUSE;
public static ControlMessage createInjectMotion(int action, int buttons, Position position) {
ControlMessage event = new ControlMessage();
event.type = TYPE_INJECT_MOUSE;
event.action = action;
event.buttons = buttons;
event.position = position;
return event;
}
public static ControlEvent createMotionTouchEvent(int id, int action, Position position) {
ControlEvent event = new ControlEvent();
event.type = TYPE_TOUCH;
public static ControlMessage createInjectMotionTouch(int id, int action, Position position) {
ControlMessage event = new ControlMessage();
event.type = TYPE_INJECT_TOUCH;
event.action = action;
event.id = id;
event.position = position;
return event;
}
public static ControlEvent createScrollControlEvent(Position position, int hScroll, int vScroll) {
ControlEvent event = new ControlEvent();
event.type = TYPE_SCROLL;
public static ControlMessage createInjectScroll(Position position, int hScroll, int vScroll) {
ControlMessage event = new ControlMessage();
event.type = TYPE_INJECT_SCROLL;
event.position = position;
event.hScroll = hScroll;
event.vScroll = vScroll;
return event;
}
public static ControlEvent createSetClipboardControlEvent(String text) {
ControlEvent event = new ControlEvent();
public static ControlMessage createSetClipboard(String text) {
ControlMessage event = new ControlMessage();
event.type = TYPE_SET_CLIPBOARD;
event.text = text;
return event;
}
public static ControlEvent createSimpleControlEvent(int type) {
ControlEvent event = new ControlEvent();
public static ControlMessage createEmpty(int type) {
ControlMessage event = new ControlMessage();
event.type = type;
return event;
}

View file

@ -6,12 +6,12 @@ import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class ControlEventReader {
public class ControlMessageReader {
private static final int KEYCODE_PAYLOAD_LENGTH = 9;
private static final int MOUSE_PAYLOAD_LENGTH = 13;
private static final int TOUCH_PAYLOAD_LENGTH = 10;
private static final int SCROLL_PAYLOAD_LENGTH = 16;
private static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 9;
private static final int INJECT_MOUSE_PAYLOAD_LENGTH = 13;
private static final int INJECT_SCROLL_PAYLOAD_LENGTH = 16;
private static final int INJECT_TOUCH_PAYLOAD_LENGTH = 10;
public static final int TEXT_MAX_LENGTH = 300;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
@ -21,7 +21,7 @@ public class ControlEventReader {
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
private final byte[] textBuffer = new byte[CLIPBOARD_TEXT_MAX_LENGTH];
public ControlEventReader() {
public ControlMessageReader() {
// invariant: the buffer is always in "get" mode
buffer.limit(0);
}
@ -38,43 +38,43 @@ public class ControlEventReader {
int head = buffer.position();
int r = input.read(rawBuffer, head, rawBuffer.length - head);
if (r == -1) {
throw new EOFException("Event controller socket closed");
throw new EOFException("Controller socket closed");
}
buffer.position(head + r);
buffer.flip();
}
public ControlEvent next() {
public ControlMessage next() {
if (!buffer.hasRemaining()) {
return null;
}
int savedPosition = buffer.position();
int type = buffer.get();
ControlEvent controlEvent;
ControlMessage controlEvent;
switch (type) {
case ControlEvent.TYPE_KEYCODE:
controlEvent = parseKeycodeControlEvent();
case ControlMessage.TYPE_INJECT_KEYCODE:
controlEvent = parseInjectKeycode();
break;
case ControlEvent.TYPE_TEXT:
controlEvent = parseTextControlEvent();
case ControlMessage.TYPE_INJECT_TEXT:
controlEvent = parseInjectText();
break;
case ControlEvent.TYPE_MOUSE:
controlEvent = parseMouseControlEvent();
case ControlMessage.TYPE_INJECT_MOUSE:
controlEvent = parseInjectMouse();
break;
case ControlEvent.TYPE_TOUCH:
controlEvent = parseMouseTouchEvent();
case ControlMessage.TYPE_INJECT_TOUCH:
controlEvent = parseInjectMouseTouch();
break;
case ControlEvent.TYPE_SCROLL:
controlEvent = parseScrollControlEvent();
case ControlMessage.TYPE_INJECT_SCROLL:
controlEvent = parseInjectScroll();
break;
case ControlEvent.TYPE_SET_CLIPBOARD:
controlEvent = parseSetClipboardEvent();
case ControlMessage.TYPE_SET_CLIPBOARD:
controlEvent = parseSetClipboard();
break;
case ControlEvent.TYPE_BACK_OR_SCREEN_ON:
case ControlEvent.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL:
case ControlEvent.TYPE_GET_CLIPBOARD:
controlEvent = ControlEvent.createSimpleControlEvent(type);
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
case ControlMessage.TYPE_GET_CLIPBOARD:
controlEvent = ControlMessage.createEmpty(type);
break;
default:
Ln.w("Unknown event type: " + type);
@ -89,14 +89,14 @@ public class ControlEventReader {
return controlEvent;
}
private ControlEvent parseKeycodeControlEvent() {
if (buffer.remaining() < KEYCODE_PAYLOAD_LENGTH) {
private ControlMessage parseInjectKeycode() {
if (buffer.remaining() < INJECT_KEYCODE_PAYLOAD_LENGTH) {
return null;
}
int action = toUnsigned(buffer.get());
int keycode = buffer.getInt();
int metaState = buffer.getInt();
return ControlEvent.createKeycodeControlEvent(action, keycode, metaState);
return ControlMessage.createInjectKeycode(action, keycode, metaState);
}
private String parseString() {
@ -111,50 +111,50 @@ public class ControlEventReader {
return new String(textBuffer, 0, len, StandardCharsets.UTF_8);
}
private ControlEvent parseTextControlEvent() {
private ControlMessage parseInjectText() {
String text = parseString();
if (text == null) {
return null;
}
return ControlEvent.createTextControlEvent(text);
return ControlMessage.createInjectText(text);
}
private ControlEvent parseMouseControlEvent() {
if (buffer.remaining() < MOUSE_PAYLOAD_LENGTH) {
private ControlMessage parseInjectMouse() {
if (buffer.remaining() < INJECT_MOUSE_PAYLOAD_LENGTH) {
return null;
}
int action = toUnsigned(buffer.get());
int buttons = buffer.getInt();
Position position = readPosition(buffer);
return ControlEvent.createMotionControlEvent(action, buttons, position);
return ControlMessage.createInjectMotion(action, buttons, position);
}
private ControlEvent parseMouseTouchEvent() {
if (buffer.remaining() < TOUCH_PAYLOAD_LENGTH) {
private ControlMessage parseInjectMouseTouch() {
if (buffer.remaining() < INJECT_TOUCH_PAYLOAD_LENGTH) {
return null;
}
int id = toUnsigned(buffer.get());
int action = toUnsigned(buffer.get());
Position position = readPosition(buffer);
return ControlEvent.createMotionTouchEvent(id, action, position);
return ControlMessage.createInjectMotionTouch(id, action, position);
}
private ControlEvent parseScrollControlEvent() {
if (buffer.remaining() < SCROLL_PAYLOAD_LENGTH) {
private ControlMessage parseInjectScroll() {
if (buffer.remaining() < INJECT_SCROLL_PAYLOAD_LENGTH) {
return null;
}
Position position = readPosition(buffer);
int hScroll = buffer.getInt();
int vScroll = buffer.getInt();
return ControlEvent.createScrollControlEvent(position, hScroll, vScroll);
return ControlMessage.createInjectScroll(position, hScroll, vScroll);
}
private ControlEvent parseSetClipboardEvent() {
private ControlMessage parseSetClipboard() {
String text = parseString();
if (text == null) {
return null;
}
return ControlEvent.createSetClipboardControlEvent(text);
return ControlMessage.createSetClipboard(text);
}
private static Position readPosition(ByteBuffer buffer) {

View file

@ -13,11 +13,11 @@ import android.view.MotionEvent;
import java.io.IOException;
import java.util.Vector;
public class EventController {
public class Controller {
private final Device device;
private final DesktopConnection connection;
private final EventSender sender;
private final DeviceMessageSender sender;
private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
@ -25,10 +25,10 @@ public class EventController {
private Vector<MotionEvent.PointerProperties> pointerProperties = new Vector<MotionEvent.PointerProperties>();
private Vector<MotionEvent.PointerCoords> pointerCoords = new Vector<MotionEvent.PointerCoords>();
public EventController(Device device, DesktopConnection connection) {
public Controller(Device device, DesktopConnection connection) {
this.device = device;
this.connection = connection;
sender = new EventSender(connection);
sender = new DeviceMessageSender(connection);
}
private int getPointer(int id) {
@ -98,7 +98,7 @@ public class EventController {
}
}
public EventSender getSender() {
public DeviceMessageSender getSender() {
return sender;
}
@ -112,38 +112,38 @@ public class EventController {
}
private void handleEvent() throws IOException {
ControlEvent controlEvent = connection.receiveControlEvent();
switch (controlEvent.getType()) {
case ControlEvent.TYPE_KEYCODE:
injectKeycode(controlEvent.getAction(), controlEvent.getKeycode(), controlEvent.getMetaState());
ControlMessage msg = connection.receiveControlMessage();
switch (msg.getType()) {
case ControlMessage.TYPE_INJECT_KEYCODE:
injectKeycode(msg.getAction(), msg.getKeycode(), msg.getMetaState());
break;
case ControlEvent.TYPE_TEXT:
injectText(controlEvent.getText());
case ControlMessage.TYPE_INJECT_TEXT:
injectText(msg.getText());
break;
case ControlEvent.TYPE_MOUSE:
injectMouse(controlEvent.getAction(), controlEvent.getButtons(), controlEvent.getPosition());
case ControlMessage.TYPE_INJECT_MOUSE:
injectMouse(msg.getAction(), msg.getButtons(), msg.getPosition());
break;
case ControlEvent.TYPE_TOUCH:
injectTouch(controlEvent.getId(), controlEvent.getAction(), controlEvent.getPosition());
case ControlMessage.TYPE_INJECT_TOUCH:
injectTouch(msg.getId(), msg.getAction(), msg.getPosition());
break;
case ControlEvent.TYPE_SCROLL:
injectScroll(controlEvent.getPosition(), controlEvent.getHScroll(), controlEvent.getVScroll());
case ControlMessage.TYPE_INJECT_SCROLL:
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll());
break;
case ControlEvent.TYPE_BACK_OR_SCREEN_ON:
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
pressBackOrTurnScreenOn();
break;
case ControlEvent.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
device.expandNotificationPanel();
break;
case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL:
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
device.collapsePanels();
break;
case ControlEvent.TYPE_GET_CLIPBOARD:
case ControlMessage.TYPE_GET_CLIPBOARD:
String clipboardText = device.getClipboardText();
sender.pushClipboardText(clipboardText);
break;
case ControlEvent.TYPE_SET_CLIPBOARD:
device.setClipboardText(controlEvent.getText());
case ControlMessage.TYPE_SET_CLIPBOARD:
device.setClipboardText(msg.getText());
break;
default:
// do nothing

View file

@ -25,8 +25,8 @@ public final class DesktopConnection implements Closeable {
private final OutputStream controlOutputStream;
private final ControlEventReader reader = new ControlEventReader();
private final DeviceEventWriter writer = new DeviceEventWriter();
private final ControlMessageReader reader = new ControlMessageReader();
private final DeviceMessageWriter writer = new DeviceMessageWriter();
private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException {
this.videoSocket = videoSocket;
@ -105,16 +105,16 @@ public final class DesktopConnection implements Closeable {
return videoFd;
}
public ControlEvent receiveControlEvent() throws IOException {
ControlEvent event = reader.next();
while (event == null) {
public ControlMessage receiveControlMessage() throws IOException {
ControlMessage msg = reader.next();
while (msg == null) {
reader.readFrom(controlInputStream);
event = reader.next();
msg = reader.next();
}
return event;
return msg;
}
public void sendDeviceEvent(DeviceEvent event) throws IOException {
writer.writeTo(event, controlOutputStream);
public void sendDeviceMessage(DeviceMessage msg) throws IOException {
writer.writeTo(msg, controlOutputStream);
}
}

View file

@ -1,27 +0,0 @@
package com.genymobile.scrcpy;
public final class DeviceEvent {
public static final int TYPE_GET_CLIPBOARD = 0;
private int type;
private String text;
private DeviceEvent() {
}
public static DeviceEvent createGetClipboardEvent(String text) {
DeviceEvent event = new DeviceEvent();
event.type = TYPE_GET_CLIPBOARD;
event.text = text;
return event;
}
public int getType() {
return type;
}
public String getText() {
return text;
}
}

View file

@ -0,0 +1,27 @@
package com.genymobile.scrcpy;
public final class DeviceMessage {
public static final int TYPE_CLIPBOARD = 0;
private int type;
private String text;
private DeviceMessage() {
}
public static DeviceMessage createClipboard(String text) {
DeviceMessage event = new DeviceMessage();
event.type = TYPE_CLIPBOARD;
event.text = text;
return event;
}
public int getType() {
return type;
}
public String getText() {
return text;
}
}

View file

@ -2,13 +2,13 @@ package com.genymobile.scrcpy;
import java.io.IOException;
public final class EventSender {
public final class DeviceMessageSender {
private final DesktopConnection connection;
private String clipboardText;
public EventSender(DesktopConnection connection) {
public DeviceMessageSender(DesktopConnection connection) {
this.connection = connection;
}
@ -27,8 +27,8 @@ public final class EventSender {
text = clipboardText;
clipboardText = null;
}
DeviceEvent event = DeviceEvent.createGetClipboardEvent(text);
connection.sendDeviceEvent(event);
DeviceMessage msg = DeviceMessage.createClipboard(text);
connection.sendDeviceMessage(msg);
}
}
}

View file

@ -5,7 +5,7 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class DeviceEventWriter {
public class DeviceMessageWriter {
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
private static final int MAX_EVENT_SIZE = CLIPBOARD_TEXT_MAX_LENGTH + 3;
@ -14,12 +14,12 @@ public class DeviceEventWriter {
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
@SuppressWarnings("checkstyle:MagicNumber")
public void writeTo(DeviceEvent event, OutputStream output) throws IOException {
public void writeTo(DeviceMessage msg, OutputStream output) throws IOException {
buffer.clear();
buffer.put((byte) DeviceEvent.TYPE_GET_CLIPBOARD);
switch (event.getType()) {
case DeviceEvent.TYPE_GET_CLIPBOARD:
String text = event.getText();
buffer.put((byte) DeviceMessage.TYPE_CLIPBOARD);
switch (msg.getType()) {
case DeviceMessage.TYPE_CLIPBOARD:
String text = msg.getText();
byte[] raw = text.getBytes(StandardCharsets.UTF_8);
int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH);
buffer.putShort((short) len);
@ -27,7 +27,7 @@ public class DeviceEventWriter {
output.write(rawBuffer, 0, buffer.position());
break;
default:
Ln.w("Unknown device event: " + event.getType());
Ln.w("Unknown device msg: " + msg.getType());
break;
}
}

View file

@ -20,11 +20,11 @@ public final class Server {
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate());
EventController controller = new EventController(device, connection);
Controller controller = new Controller(device, connection);
// asynchronous
startEventController(controller);
startEventSender(controller.getSender());
startController(controller);
startDeviceMessageSender(controller.getSender());
try {
// synchronous
@ -36,7 +36,7 @@ public final class Server {
}
}
private static void startEventController(final EventController controller) {
private static void startController(final Controller controller) {
new Thread(new Runnable() {
@Override
public void run() {
@ -44,13 +44,13 @@ public final class Server {
controller.control();
} catch (IOException e) {
// this is expected on close
Ln.d("Event controller stopped");
Ln.d("Controller stopped");
}
}
}).start();
}
private static void startEventSender(final EventSender sender) {
private static void startDeviceMessageSender(final DeviceMessageSender sender) {
new Thread(new Runnable() {
@Override
public void run() {
@ -58,7 +58,7 @@ public final class Server {
sender.loop();
} catch (IOException | InterruptedException e) {
// this is expected on close
Ln.d("Event sender stopped");
Ln.d("Devide message sender stopped");
}
}
}).start();

View file

@ -1,173 +0,0 @@
package com.genymobile.scrcpy;
import android.view.KeyEvent;
import android.view.MotionEvent;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class ControlEventReaderTest {
@Test
public void testParseKeycodeEvent() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(KeyEvent.ACTION_UP);
dos.writeInt(KeyEvent.KEYCODE_ENTER);
dos.writeInt(KeyEvent.META_CTRL_ON);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
}
@Test
public void testParseTextEvent() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_TEXT);
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeShort(text.length);
dos.write(text);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_TEXT, event.getType());
Assert.assertEquals("testé", event.getText());
}
@Test
public void testParseLongTextEvent() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_TEXT);
byte[] text = new byte[ControlEventReader.TEXT_MAX_LENGTH];
Arrays.fill(text, (byte) 'a');
dos.writeShort(text.length);
dos.write(text);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_TEXT, event.getType());
Assert.assertEquals(new String(text, StandardCharsets.US_ASCII), event.getText());
}
@Test
public void testParseMouseEvent() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(MotionEvent.ACTION_DOWN);
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
dos.writeInt(KeyEvent.META_CTRL_ON);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
}
@Test
public void testMultiEvents() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(KeyEvent.ACTION_UP);
dos.writeInt(KeyEvent.KEYCODE_ENTER);
dos.writeInt(KeyEvent.META_CTRL_ON);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(MotionEvent.ACTION_DOWN);
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
dos.writeInt(KeyEvent.META_CTRL_ON);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
}
@Test
public void testPartialEvents() throws IOException {
ControlEventReader reader = new ControlEventReader();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(KeyEvent.ACTION_UP);
dos.writeInt(KeyEvent.KEYCODE_ENTER);
dos.writeInt(KeyEvent.META_CTRL_ON);
dos.writeByte(ControlEvent.TYPE_KEYCODE);
dos.writeByte(MotionEvent.ACTION_DOWN);
byte[] packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
ControlEvent event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
event = reader.next();
Assert.assertNull(event); // the event is not complete
bos.reset();
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
dos.writeInt(KeyEvent.META_CTRL_ON);
packet = bos.toByteArray();
reader.readFrom(new ByteArrayInputStream(packet));
// the event is now complete
event = reader.next();
Assert.assertEquals(ControlEvent.TYPE_KEYCODE, event.getType());
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
}
}