2021-10-03 23:11:20 +08:00
|
|
|
#include "keyboard_inject.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "android/input.h"
|
|
|
|
#include "control_msg.h"
|
|
|
|
#include "controller.h"
|
2021-12-29 23:14:34 +08:00
|
|
|
#include "input_events.h"
|
2021-11-27 04:58:56 +08:00
|
|
|
#include "util/intmap.h"
|
2021-10-03 23:11:20 +08:00
|
|
|
#include "util/log.h"
|
|
|
|
|
|
|
|
/** Downcast key processor to sc_keyboard_inject */
|
2021-11-27 04:57:06 +08:00
|
|
|
#define DOWNCAST(KP) container_of(KP, struct sc_keyboard_inject, key_processor)
|
2021-10-03 23:11:20 +08:00
|
|
|
|
2021-12-29 23:55:01 +08:00
|
|
|
static enum android_keyevent_action
|
|
|
|
convert_keycode_action(enum sc_action action) {
|
|
|
|
if (action == SC_ACTION_DOWN) {
|
|
|
|
return AKEY_EVENT_ACTION_DOWN;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
2021-12-29 23:55:01 +08:00
|
|
|
assert(action == SC_ACTION_UP);
|
|
|
|
return AKEY_EVENT_ACTION_UP;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-12-29 23:14:34 +08:00
|
|
|
convert_keycode(enum sc_keycode from, enum android_keycode *to, uint16_t mod,
|
2021-11-27 05:05:28 +08:00
|
|
|
enum sc_key_inject_mode key_inject_mode) {
|
2021-11-27 04:58:56 +08:00
|
|
|
// Navigation keys and ENTER.
|
|
|
|
// Used in all modes.
|
|
|
|
static const struct sc_intmap_entry special_keys[] = {
|
2021-12-29 23:14:34 +08:00
|
|
|
{SC_KEYCODE_RETURN, AKEYCODE_ENTER},
|
|
|
|
{SC_KEYCODE_KP_ENTER, AKEYCODE_NUMPAD_ENTER},
|
|
|
|
{SC_KEYCODE_ESCAPE, AKEYCODE_ESCAPE},
|
|
|
|
{SC_KEYCODE_BACKSPACE, AKEYCODE_DEL},
|
|
|
|
{SC_KEYCODE_TAB, AKEYCODE_TAB},
|
|
|
|
{SC_KEYCODE_PAGEUP, AKEYCODE_PAGE_UP},
|
|
|
|
{SC_KEYCODE_DELETE, AKEYCODE_FORWARD_DEL},
|
|
|
|
{SC_KEYCODE_HOME, AKEYCODE_MOVE_HOME},
|
|
|
|
{SC_KEYCODE_END, AKEYCODE_MOVE_END},
|
|
|
|
{SC_KEYCODE_PAGEDOWN, AKEYCODE_PAGE_DOWN},
|
|
|
|
{SC_KEYCODE_RIGHT, AKEYCODE_DPAD_RIGHT},
|
|
|
|
{SC_KEYCODE_LEFT, AKEYCODE_DPAD_LEFT},
|
|
|
|
{SC_KEYCODE_DOWN, AKEYCODE_DPAD_DOWN},
|
|
|
|
{SC_KEYCODE_UP, AKEYCODE_DPAD_UP},
|
|
|
|
{SC_KEYCODE_LCTRL, AKEYCODE_CTRL_LEFT},
|
|
|
|
{SC_KEYCODE_RCTRL, AKEYCODE_CTRL_RIGHT},
|
|
|
|
{SC_KEYCODE_LSHIFT, AKEYCODE_SHIFT_LEFT},
|
|
|
|
{SC_KEYCODE_RSHIFT, AKEYCODE_SHIFT_RIGHT},
|
2021-11-27 04:58:56 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Numpad navigation keys.
|
|
|
|
// Used in all modes, when NumLock and Shift are disabled.
|
|
|
|
static const struct sc_intmap_entry kp_nav_keys[] = {
|
2021-12-29 23:14:34 +08:00
|
|
|
{SC_KEYCODE_KP_0, AKEYCODE_INSERT},
|
|
|
|
{SC_KEYCODE_KP_1, AKEYCODE_MOVE_END},
|
|
|
|
{SC_KEYCODE_KP_2, AKEYCODE_DPAD_DOWN},
|
|
|
|
{SC_KEYCODE_KP_3, AKEYCODE_PAGE_DOWN},
|
|
|
|
{SC_KEYCODE_KP_4, AKEYCODE_DPAD_LEFT},
|
|
|
|
{SC_KEYCODE_KP_6, AKEYCODE_DPAD_RIGHT},
|
|
|
|
{SC_KEYCODE_KP_7, AKEYCODE_MOVE_HOME},
|
|
|
|
{SC_KEYCODE_KP_8, AKEYCODE_DPAD_UP},
|
|
|
|
{SC_KEYCODE_KP_9, AKEYCODE_PAGE_UP},
|
|
|
|
{SC_KEYCODE_KP_PERIOD, AKEYCODE_FORWARD_DEL},
|
2021-11-27 04:58:56 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Letters and space.
|
|
|
|
// Used in non-text mode.
|
|
|
|
static const struct sc_intmap_entry alphaspace_keys[] = {
|
2021-12-29 23:14:34 +08:00
|
|
|
{SC_KEYCODE_a, AKEYCODE_A},
|
|
|
|
{SC_KEYCODE_b, AKEYCODE_B},
|
|
|
|
{SC_KEYCODE_c, AKEYCODE_C},
|
|
|
|
{SC_KEYCODE_d, AKEYCODE_D},
|
|
|
|
{SC_KEYCODE_e, AKEYCODE_E},
|
|
|
|
{SC_KEYCODE_f, AKEYCODE_F},
|
|
|
|
{SC_KEYCODE_g, AKEYCODE_G},
|
|
|
|
{SC_KEYCODE_h, AKEYCODE_H},
|
|
|
|
{SC_KEYCODE_i, AKEYCODE_I},
|
|
|
|
{SC_KEYCODE_j, AKEYCODE_J},
|
|
|
|
{SC_KEYCODE_k, AKEYCODE_K},
|
|
|
|
{SC_KEYCODE_l, AKEYCODE_L},
|
|
|
|
{SC_KEYCODE_m, AKEYCODE_M},
|
|
|
|
{SC_KEYCODE_n, AKEYCODE_N},
|
|
|
|
{SC_KEYCODE_o, AKEYCODE_O},
|
|
|
|
{SC_KEYCODE_p, AKEYCODE_P},
|
|
|
|
{SC_KEYCODE_q, AKEYCODE_Q},
|
|
|
|
{SC_KEYCODE_r, AKEYCODE_R},
|
|
|
|
{SC_KEYCODE_s, AKEYCODE_S},
|
|
|
|
{SC_KEYCODE_t, AKEYCODE_T},
|
|
|
|
{SC_KEYCODE_u, AKEYCODE_U},
|
|
|
|
{SC_KEYCODE_v, AKEYCODE_V},
|
|
|
|
{SC_KEYCODE_w, AKEYCODE_W},
|
|
|
|
{SC_KEYCODE_x, AKEYCODE_X},
|
|
|
|
{SC_KEYCODE_y, AKEYCODE_Y},
|
|
|
|
{SC_KEYCODE_z, AKEYCODE_Z},
|
|
|
|
{SC_KEYCODE_SPACE, AKEYCODE_SPACE},
|
2021-11-27 04:58:56 +08:00
|
|
|
};
|
|
|
|
|
2021-11-27 05:15:44 +08:00
|
|
|
// Numbers and punctuation keys.
|
|
|
|
// Used in raw mode only.
|
|
|
|
static const struct sc_intmap_entry numbers_punct_keys[] = {
|
2021-12-29 23:14:34 +08:00
|
|
|
{SC_KEYCODE_HASH, AKEYCODE_POUND},
|
|
|
|
{SC_KEYCODE_PERCENT, AKEYCODE_PERIOD},
|
|
|
|
{SC_KEYCODE_QUOTE, AKEYCODE_APOSTROPHE},
|
|
|
|
{SC_KEYCODE_ASTERISK, AKEYCODE_STAR},
|
|
|
|
{SC_KEYCODE_PLUS, AKEYCODE_PLUS},
|
|
|
|
{SC_KEYCODE_COMMA, AKEYCODE_COMMA},
|
|
|
|
{SC_KEYCODE_MINUS, AKEYCODE_MINUS},
|
|
|
|
{SC_KEYCODE_PERIOD, AKEYCODE_PERIOD},
|
|
|
|
{SC_KEYCODE_SLASH, AKEYCODE_SLASH},
|
|
|
|
{SC_KEYCODE_0, AKEYCODE_0},
|
|
|
|
{SC_KEYCODE_1, AKEYCODE_1},
|
|
|
|
{SC_KEYCODE_2, AKEYCODE_2},
|
|
|
|
{SC_KEYCODE_3, AKEYCODE_3},
|
|
|
|
{SC_KEYCODE_4, AKEYCODE_4},
|
|
|
|
{SC_KEYCODE_5, AKEYCODE_5},
|
|
|
|
{SC_KEYCODE_6, AKEYCODE_6},
|
|
|
|
{SC_KEYCODE_7, AKEYCODE_7},
|
|
|
|
{SC_KEYCODE_8, AKEYCODE_8},
|
|
|
|
{SC_KEYCODE_9, AKEYCODE_9},
|
|
|
|
{SC_KEYCODE_SEMICOLON, AKEYCODE_SEMICOLON},
|
|
|
|
{SC_KEYCODE_EQUALS, AKEYCODE_EQUALS},
|
|
|
|
{SC_KEYCODE_AT, AKEYCODE_AT},
|
|
|
|
{SC_KEYCODE_LEFTBRACKET, AKEYCODE_LEFT_BRACKET},
|
|
|
|
{SC_KEYCODE_BACKSLASH, AKEYCODE_BACKSLASH},
|
|
|
|
{SC_KEYCODE_RIGHTBRACKET, AKEYCODE_RIGHT_BRACKET},
|
|
|
|
{SC_KEYCODE_BACKQUOTE, AKEYCODE_GRAVE},
|
|
|
|
{SC_KEYCODE_KP_1, AKEYCODE_NUMPAD_1},
|
|
|
|
{SC_KEYCODE_KP_2, AKEYCODE_NUMPAD_2},
|
|
|
|
{SC_KEYCODE_KP_3, AKEYCODE_NUMPAD_3},
|
|
|
|
{SC_KEYCODE_KP_4, AKEYCODE_NUMPAD_4},
|
|
|
|
{SC_KEYCODE_KP_5, AKEYCODE_NUMPAD_5},
|
|
|
|
{SC_KEYCODE_KP_6, AKEYCODE_NUMPAD_6},
|
|
|
|
{SC_KEYCODE_KP_7, AKEYCODE_NUMPAD_7},
|
|
|
|
{SC_KEYCODE_KP_8, AKEYCODE_NUMPAD_8},
|
|
|
|
{SC_KEYCODE_KP_9, AKEYCODE_NUMPAD_9},
|
|
|
|
{SC_KEYCODE_KP_0, AKEYCODE_NUMPAD_0},
|
|
|
|
{SC_KEYCODE_KP_DIVIDE, AKEYCODE_NUMPAD_DIVIDE},
|
|
|
|
{SC_KEYCODE_KP_MULTIPLY, AKEYCODE_NUMPAD_MULTIPLY},
|
|
|
|
{SC_KEYCODE_KP_MINUS, AKEYCODE_NUMPAD_SUBTRACT},
|
|
|
|
{SC_KEYCODE_KP_PLUS, AKEYCODE_NUMPAD_ADD},
|
|
|
|
{SC_KEYCODE_KP_PERIOD, AKEYCODE_NUMPAD_DOT},
|
|
|
|
{SC_KEYCODE_KP_EQUALS, AKEYCODE_NUMPAD_EQUALS},
|
|
|
|
{SC_KEYCODE_KP_LEFTPAREN, AKEYCODE_NUMPAD_LEFT_PAREN},
|
|
|
|
{SC_KEYCODE_KP_RIGHTPAREN, AKEYCODE_NUMPAD_RIGHT_PAREN},
|
2021-11-27 05:15:44 +08:00
|
|
|
};
|
|
|
|
|
2021-11-27 04:58:56 +08:00
|
|
|
const struct sc_intmap_entry *entry =
|
|
|
|
SC_INTMAP_FIND_ENTRY(special_keys, from);
|
|
|
|
if (entry) {
|
|
|
|
*to = entry->value;
|
|
|
|
return true;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
|
|
|
|
2021-12-29 23:14:34 +08:00
|
|
|
if (!(mod & (SC_MOD_NUM | SC_MOD_LSHIFT | SC_MOD_RSHIFT))) {
|
2021-10-03 23:11:20 +08:00
|
|
|
// Handle Numpad events when Num Lock is disabled
|
|
|
|
// If SHIFT is pressed, a text event will be sent instead
|
2021-11-27 04:58:56 +08:00
|
|
|
entry = SC_INTMAP_FIND_ENTRY(kp_nav_keys, from);
|
|
|
|
if (entry) {
|
|
|
|
*to = entry->value;
|
|
|
|
return true;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-29 23:14:34 +08:00
|
|
|
if (key_inject_mode == SC_KEY_INJECT_MODE_TEXT &&
|
|
|
|
!(mod & (SC_MOD_LCTRL | SC_MOD_RCTRL))) {
|
2021-10-03 23:11:20 +08:00
|
|
|
// do not forward alpha and space key events (unless Ctrl is pressed)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & (SC_MOD_LALT | SC_MOD_RALT | SC_MOD_LGUI | SC_MOD_RGUI)) {
|
2021-10-03 23:11:20 +08:00
|
|
|
return false;
|
|
|
|
}
|
2021-11-27 04:58:56 +08:00
|
|
|
|
2021-10-03 23:11:20 +08:00
|
|
|
// if ALT and META are not pressed, also handle letters and space
|
2021-11-27 04:58:56 +08:00
|
|
|
entry = SC_INTMAP_FIND_ENTRY(alphaspace_keys, from);
|
|
|
|
if (entry) {
|
|
|
|
*to = entry->value;
|
|
|
|
return true;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
2021-11-27 04:58:56 +08:00
|
|
|
|
2021-11-27 05:15:44 +08:00
|
|
|
if (key_inject_mode == SC_KEY_INJECT_MODE_RAW) {
|
|
|
|
entry = SC_INTMAP_FIND_ENTRY(numbers_punct_keys, from);
|
|
|
|
if (entry) {
|
|
|
|
*to = entry->value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-27 04:58:56 +08:00
|
|
|
return false;
|
2021-10-03 23:11:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static enum android_metastate
|
|
|
|
autocomplete_metastate(enum android_metastate metastate) {
|
|
|
|
// fill dependent flags
|
|
|
|
if (metastate & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
|
|
|
|
metastate |= AMETA_SHIFT_ON;
|
|
|
|
}
|
|
|
|
if (metastate & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
|
|
|
|
metastate |= AMETA_CTRL_ON;
|
|
|
|
}
|
|
|
|
if (metastate & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
|
|
|
|
metastate |= AMETA_ALT_ON;
|
|
|
|
}
|
|
|
|
if (metastate & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
|
|
|
|
metastate |= AMETA_META_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
return metastate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum android_metastate
|
2021-12-29 23:14:34 +08:00
|
|
|
convert_meta_state(uint16_t mod) {
|
2021-10-03 23:11:20 +08:00
|
|
|
enum android_metastate metastate = 0;
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_LSHIFT) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_SHIFT_LEFT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_RSHIFT) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_SHIFT_RIGHT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_LCTRL) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_CTRL_LEFT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_RCTRL) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_CTRL_RIGHT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_LALT) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_ALT_LEFT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_RALT) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_ALT_RIGHT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_LGUI) { // Windows key
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_META_LEFT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_RGUI) { // Windows key
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_META_RIGHT_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_NUM) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_NUM_LOCK_ON;
|
|
|
|
}
|
2021-12-29 23:14:34 +08:00
|
|
|
if (mod & SC_MOD_CAPS) {
|
2021-10-03 23:11:20 +08:00
|
|
|
metastate |= AMETA_CAPS_LOCK_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fill the dependent fields
|
|
|
|
return autocomplete_metastate(metastate);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-12-29 23:14:34 +08:00
|
|
|
convert_input_key(const struct sc_key_event *event, struct control_msg *msg,
|
2021-11-27 05:05:28 +08:00
|
|
|
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
|
2021-12-29 23:14:34 +08:00
|
|
|
msg->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
2021-10-03 23:11:20 +08:00
|
|
|
|
2021-12-29 23:14:34 +08:00
|
|
|
if (!convert_keycode(event->keycode, &msg->inject_keycode.keycode,
|
|
|
|
event->mods_state, key_inject_mode)) {
|
2021-10-03 23:11:20 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-12-29 23:55:01 +08:00
|
|
|
msg->inject_keycode.action = convert_keycode_action(event->action);
|
2021-12-29 23:14:34 +08:00
|
|
|
msg->inject_keycode.repeat = repeat;
|
|
|
|
msg->inject_keycode.metastate = convert_meta_state(event->mods_state);
|
2021-10-03 23:11:20 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sc_key_processor_process_key(struct sc_key_processor *kp,
|
2021-12-29 23:14:34 +08:00
|
|
|
const struct sc_key_event *event,
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
uint64_t ack_to_wait) {
|
2021-11-22 00:24:34 +08:00
|
|
|
// The device clipboard synchronization and the key event messages are
|
|
|
|
// serialized, there is nothing special to do to ensure that the clipboard
|
|
|
|
// is set before injecting Ctrl+v.
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
(void) ack_to_wait;
|
2021-11-22 00:24:34 +08:00
|
|
|
|
2021-10-03 23:11:20 +08:00
|
|
|
struct sc_keyboard_inject *ki = DOWNCAST(kp);
|
|
|
|
|
|
|
|
if (event->repeat) {
|
|
|
|
if (!ki->forward_key_repeat) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
++ki->repeat;
|
|
|
|
} else {
|
|
|
|
ki->repeat = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct control_msg msg;
|
2021-11-27 05:05:28 +08:00
|
|
|
if (convert_input_key(event, &msg, ki->key_inject_mode, ki->repeat)) {
|
2021-10-03 23:11:20 +08:00
|
|
|
if (!controller_push_msg(ki->controller, &msg)) {
|
|
|
|
LOGW("Could not request 'inject keycode'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sc_key_processor_process_text(struct sc_key_processor *kp,
|
2021-12-29 23:14:34 +08:00
|
|
|
const struct sc_text_event *event) {
|
2021-10-03 23:11:20 +08:00
|
|
|
struct sc_keyboard_inject *ki = DOWNCAST(kp);
|
|
|
|
|
2021-11-27 05:15:44 +08:00
|
|
|
if (ki->key_inject_mode == SC_KEY_INJECT_MODE_RAW) {
|
|
|
|
// Never inject text events
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-27 05:05:28 +08:00
|
|
|
if (ki->key_inject_mode == SC_KEY_INJECT_MODE_MIXED) {
|
2021-10-03 23:11:20 +08:00
|
|
|
char c = event->text[0];
|
|
|
|
if (isalpha(c) || c == ' ') {
|
|
|
|
assert(event->text[1] == '\0');
|
2021-11-27 05:05:28 +08:00
|
|
|
// Letters and space are handled as raw key events
|
2021-10-03 23:11:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct control_msg msg;
|
|
|
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
|
|
|
msg.inject_text.text = strdup(event->text);
|
|
|
|
if (!msg.inject_text.text) {
|
|
|
|
LOGW("Could not strdup input text");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!controller_push_msg(ki->controller, &msg)) {
|
|
|
|
free(msg.inject_text.text);
|
|
|
|
LOGW("Could not request 'inject text'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
|
|
|
struct controller *controller,
|
|
|
|
const struct scrcpy_options *options) {
|
|
|
|
ki->controller = controller;
|
2021-11-27 05:05:28 +08:00
|
|
|
ki->key_inject_mode = options->key_inject_mode;
|
2021-10-03 23:11:20 +08:00
|
|
|
ki->forward_key_repeat = options->forward_key_repeat;
|
|
|
|
|
|
|
|
ki->repeat = 0;
|
|
|
|
|
|
|
|
static const struct sc_key_processor_ops ops = {
|
|
|
|
.process_key = sc_key_processor_process_key,
|
|
|
|
.process_text = sc_key_processor_process_text,
|
|
|
|
};
|
|
|
|
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
// Key injection and clipboard synchronization are serialized
|
|
|
|
ki->key_processor.async_paste = false;
|
2021-10-03 23:11:20 +08:00
|
|
|
ki->key_processor.ops = &ops;
|
|
|
|
}
|