diff --git a/app/src/control_msg.c b/app/src/control_msg.c index 436a886142..69e750140a 100644 --- a/app/src/control_msg.c +++ b/app/src/control_msg.c @@ -67,6 +67,9 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) { buffer_write32be(&buf[17], (uint32_t) msg->inject_scroll_event.vscroll); return 21; + case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON: + buf[1] = msg->inject_keycode.action; + return 2; case CONTROL_MSG_TYPE_SET_CLIPBOARD: { buf[1] = !!msg->set_clipboard.paste; size_t len = write_string(msg->set_clipboard.text, @@ -77,7 +80,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) { case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE: buf[1] = msg->set_screen_power_mode.mode; return 2; - case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON: case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL: case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL: case CONTROL_MSG_TYPE_GET_CLIPBOARD: diff --git a/app/src/control_msg.h b/app/src/control_msg.h index 1b25591de1..8d9ab7d42d 100644 --- a/app/src/control_msg.h +++ b/app/src/control_msg.h @@ -64,6 +64,10 @@ struct control_msg { int32_t hscroll; int32_t vscroll; } inject_scroll_event; + struct { + enum android_keyevent_action action; // action for the BACK key + // screen may only be turned on on ACTION_DOWN + } back_or_screen_on; struct { char *text; // owned, to be freed by free() bool paste; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 10af6e8b4e..c10e53af5d 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -146,13 +146,25 @@ action_cut(struct controller *controller, int actions) { } // turn the screen on if it was off, press BACK otherwise +// If the screen is off, it is turned on only on ACTION_DOWN static void -press_back_or_turn_screen_on(struct controller *controller) { +press_back_or_turn_screen_on(struct controller *controller, int actions) { struct control_msg msg; 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'"); + if (actions & ACTION_DOWN) { + msg.back_or_screen_on.action = AKEY_EVENT_ACTION_DOWN; + if (!controller_push_msg(controller, &msg)) { + LOGW("Could not request 'press back or turn screen on'"); + return; + } + } + + if (actions & ACTION_UP) { + msg.back_or_screen_on.action = AKEY_EVENT_ACTION_UP; + if (!controller_push_msg(controller, &msg)) { + LOGW("Could not request 'press back or turn screen on'"); + } } } @@ -650,9 +662,7 @@ input_manager_process_mouse_button(struct input_manager *im, int action = down ? ACTION_DOWN : ACTION_UP; if (control && event->button == SDL_BUTTON_RIGHT) { - if (down) { - press_back_or_turn_screen_on(im->controller); - } + press_back_or_turn_screen_on(im->controller, action); return; } if (control && event->button == SDL_BUTTON_MIDDLE) { diff --git a/app/tests/test_control_msg_serialize.c b/app/tests/test_control_msg_serialize.c index dc6e082109..4771ce1fe5 100644 --- a/app/tests/test_control_msg_serialize.c +++ b/app/tests/test_control_msg_serialize.c @@ -146,14 +146,18 @@ static void test_serialize_inject_scroll_event(void) { static void test_serialize_back_or_screen_on(void) { struct control_msg msg = { .type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON, + .back_or_screen_on = { + .action = AKEY_EVENT_ACTION_UP, + }, }; unsigned char buf[CONTROL_MSG_MAX_SIZE]; size_t size = control_msg_serialize(&msg, buf); - assert(size == 1); + assert(size == 2); const unsigned char expected[] = { CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON, + 0x01, // AKEY_EVENT_ACTION_UP }; assert(!memcmp(buf, expected, sizeof(expected))); } diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java index 736acf80b9..44cb1b599f 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java @@ -71,6 +71,13 @@ public static ControlMessage createInjectScrollEvent(Position position, int hScr return msg; } + public static ControlMessage createBackOrScreenOn(int action) { + ControlMessage msg = new ControlMessage(); + msg.type = TYPE_BACK_OR_SCREEN_ON; + msg.action = action; + return msg; + } + public static ControlMessage createSetClipboard(String text, boolean paste) { ControlMessage msg = new ControlMessage(); msg.type = TYPE_SET_CLIPBOARD; diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java index ce18510318..7ebecf76ac 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java @@ -11,6 +11,7 @@ public class ControlMessageReader { static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13; static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27; static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20; + static final int BACK_OR_SCREEN_ON_LENGTH = 1; static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1; static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1; @@ -66,13 +67,15 @@ public ControlMessage next() { case ControlMessage.TYPE_INJECT_SCROLL_EVENT: msg = parseInjectScrollEvent(); break; + case ControlMessage.TYPE_BACK_OR_SCREEN_ON: + msg = parseBackOrScreenOnEvent(); + break; case ControlMessage.TYPE_SET_CLIPBOARD: msg = parseSetClipboard(); break; case ControlMessage.TYPE_SET_SCREEN_POWER_MODE: msg = parseSetScreenPowerMode(); break; - case ControlMessage.TYPE_BACK_OR_SCREEN_ON: case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL: case ControlMessage.TYPE_GET_CLIPBOARD: @@ -150,6 +153,14 @@ private ControlMessage parseInjectScrollEvent() { return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll); } + private ControlMessage parseBackOrScreenOnEvent() { + if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) { + return null; + } + int action = toUnsigned(buffer.get()); + return ControlMessage.createBackOrScreenOn(action); + } + private ControlMessage parseSetClipboard() { if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) { return null; diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index 8f262ab6de..6af5ddf649 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -101,7 +101,7 @@ private void handleEvent() throws IOException { break; case ControlMessage.TYPE_BACK_OR_SCREEN_ON: if (device.supportsInputEvents()) { - pressBackOrTurnScreenOn(); + pressBackOrTurnScreenOn(msg.getAction()); } break; case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: @@ -255,12 +255,22 @@ public void run() { }, 200, TimeUnit.MILLISECONDS); } - private boolean pressBackOrTurnScreenOn() { - int keycode = Device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER; - if (keepPowerModeOff && keycode == KeyEvent.KEYCODE_POWER) { + private boolean pressBackOrTurnScreenOn(int action) { + if (Device.isScreenOn()) { + return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0); + } + + // Screen is off + // Only press POWER on ACTION_DOWN + if (action != KeyEvent.ACTION_DOWN) { + // do nothing, + return true; + } + + if (keepPowerModeOff) { schedulePowerModeOff(); } - return device.injectKeycode(keycode); + return device.injectKeycode(KeyEvent.KEYCODE_POWER); } private boolean setClipboard(String text, boolean paste) { diff --git a/server/src/test/java/com/genymobile/scrcpy/ControlMessageReaderTest.java b/server/src/test/java/com/genymobile/scrcpy/ControlMessageReaderTest.java index 5eb52760fe..8dfaa5aa1b 100644 --- a/server/src/test/java/com/genymobile/scrcpy/ControlMessageReaderTest.java +++ b/server/src/test/java/com/genymobile/scrcpy/ControlMessageReaderTest.java @@ -154,6 +154,7 @@ public void testParseBackOrScreenOnEvent() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON); + dos.writeByte(KeyEvent.ACTION_UP); byte[] packet = bos.toByteArray(); @@ -161,6 +162,7 @@ public void testParseBackOrScreenOnEvent() throws IOException { ControlMessage event = reader.next(); Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType()); + Assert.assertEquals(KeyEvent.ACTION_DOWN, event.getAction()); } @Test