The shortcut "back on screen on" is a bit special: the control is requested by the client, but the actual event injection (POWER or BACK) is determined on the device. To properly inject DOWN and UP events for BACK, transmit the action as a control parameter. If the screen is off: - on DOWN, inject POWER (DOWN and UP) (wake up the device immediately) - on UP, do nothing If the screen is on: - on DOWN, inject BACK DOWN - on UP, inject BACK UP A corner case is when the screen turns off between the DOWN and UP event. In that case, a BACK UP event will be injected, so it's harmless. As a consequence of this change, the BACK button is now handled by Android on mouse released. This is consistent with the keyboard shortcut (Mod+b) behavior. PR #2259 <https://github.com/Genymobile/scrcpy/pull/2259> Refs #2258 <https://github.com/Genymobile/scrcpy/pull/2258>
109 lines
3.7 KiB
C
109 lines
3.7 KiB
C
#include "control_msg.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "util/buffer_util.h"
|
|
#include "util/log.h"
|
|
#include "util/str_util.h"
|
|
|
|
static void
|
|
write_position(uint8_t *buf, const struct position *position) {
|
|
buffer_write32be(&buf[0], position->point.x);
|
|
buffer_write32be(&buf[4], position->point.y);
|
|
buffer_write16be(&buf[8], position->screen_size.width);
|
|
buffer_write16be(&buf[10], position->screen_size.height);
|
|
}
|
|
|
|
// write length (2 bytes) + string (non nul-terminated)
|
|
static size_t
|
|
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
|
|
size_t len = utf8_truncation_index(utf8, max_len);
|
|
buffer_write32be(buf, len);
|
|
memcpy(&buf[4], utf8, len);
|
|
return 4 + len;
|
|
}
|
|
|
|
static uint16_t
|
|
to_fixed_point_16(float f) {
|
|
assert(f >= 0.0f && f <= 1.0f);
|
|
uint32_t u = f * 0x1p16f; // 2^16
|
|
if (u >= 0xffff) {
|
|
u = 0xffff;
|
|
}
|
|
return (uint16_t) u;
|
|
}
|
|
|
|
size_t
|
|
control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
|
buf[0] = msg->type;
|
|
switch (msg->type) {
|
|
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
|
buf[1] = msg->inject_keycode.action;
|
|
buffer_write32be(&buf[2], msg->inject_keycode.keycode);
|
|
buffer_write32be(&buf[6], msg->inject_keycode.repeat);
|
|
buffer_write32be(&buf[10], msg->inject_keycode.metastate);
|
|
return 14;
|
|
case CONTROL_MSG_TYPE_INJECT_TEXT: {
|
|
size_t len =
|
|
write_string(msg->inject_text.text,
|
|
CONTROL_MSG_INJECT_TEXT_MAX_LENGTH, &buf[1]);
|
|
return 1 + len;
|
|
}
|
|
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:
|
|
buf[1] = msg->inject_touch_event.action;
|
|
buffer_write64be(&buf[2], msg->inject_touch_event.pointer_id);
|
|
write_position(&buf[10], &msg->inject_touch_event.position);
|
|
uint16_t pressure =
|
|
to_fixed_point_16(msg->inject_touch_event.pressure);
|
|
buffer_write16be(&buf[22], pressure);
|
|
buffer_write32be(&buf[24], msg->inject_touch_event.buttons);
|
|
return 28;
|
|
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
|
write_position(&buf[1], &msg->inject_scroll_event.position);
|
|
buffer_write32be(&buf[13],
|
|
(uint32_t) msg->inject_scroll_event.hscroll);
|
|
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,
|
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
|
|
&buf[2]);
|
|
return 2 + len;
|
|
}
|
|
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
|
buf[1] = msg->set_screen_power_mode.mode;
|
|
return 2;
|
|
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
|
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
|
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
|
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
|
// no additional data
|
|
return 1;
|
|
default:
|
|
LOGW("Unknown message type: %u", (unsigned) msg->type);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
control_msg_destroy(struct control_msg *msg) {
|
|
switch (msg->type) {
|
|
case CONTROL_MSG_TYPE_INJECT_TEXT:
|
|
free(msg->inject_text.text);
|
|
break;
|
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
|
free(msg->set_clipboard.text);
|
|
break;
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
}
|