From 44791d6b4033394f5ca081f0b2a1918af6722cd6 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Wed, 6 Nov 2019 21:48:36 +0100 Subject: [PATCH] Add --prefer-text-events option Expose an option to configure how key/text events are forwarded to the Android device. Fixes --- app/scrcpy.1 | 10 +++++++++ app/src/event_converter.c | 13 ++++++++++- app/src/event_converter.h | 5 ++++- app/src/input_manager.c | 24 +++++++++++++++------ app/src/input_manager.h | 7 ++++++ app/src/main.c | 45 +++++++++++++++++++++++++++++++++++++++ app/src/scrcpy.c | 3 +++ app/src/scrcpy.h | 3 +++ 8 files changed, 101 insertions(+), 9 deletions(-) diff --git a/app/scrcpy.1 b/app/scrcpy.1 index 1dafbc6a69..0091c60ff0 100644 --- a/app/scrcpy.1 +++ b/app/scrcpy.1 @@ -61,6 +61,16 @@ Set the TCP port the client listens on. Default is 27183. +.TP +.BI \-\-prefer\-text\-events " mode +Configure how key/text events are forwarded to the Android device. + +Possible \fImode\fRs are "always" (every text is sent as text), "non-alpha" +(only letters are sent as a sequence of key events, other characters are sent +as text) and "never" (every text is sent as a sequence of key events). + +Default is "non-alpha". + .TP .BI "\-\-push\-target " path Set the target directory for pushing files to the device by drag & drop. It is passed as\-is to "adb push". diff --git a/app/src/event_converter.c b/app/src/event_converter.c index 00e989f736..25d972b367 100644 --- a/app/src/event_converter.c +++ b/app/src/event_converter.c @@ -75,7 +75,8 @@ convert_meta_state(SDL_Keymod mod) { } bool -convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) { +convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod, + enum text_events_pref pref) { switch (from) { MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER); @@ -92,6 +93,16 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) { MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN); MAP(SDLK_UP, AKEYCODE_DPAD_UP); } + + if (pref == PREFER_TEXT_EVENTS_ALWAYS) { + // never forward key events + return false; + } + + // forward all supported key events + SDL_assert(pref == PREFER_TEXT_EVENTS_NEVER || + pref == PREFER_TEXT_EVENTS_NON_ALPHA); + if (mod & (KMOD_LALT | KMOD_RALT | KMOD_LGUI | KMOD_RGUI)) { return false; } diff --git a/app/src/event_converter.h b/app/src/event_converter.h index 8bad7358e7..cad036bcee 100644 --- a/app/src/event_converter.h +++ b/app/src/event_converter.h @@ -2,10 +2,12 @@ #define CONVERT_H #include +#include #include #include "config.h" #include "control_msg.h" +#include "input_manager.h" bool convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to); @@ -14,7 +16,8 @@ enum android_metastate convert_meta_state(SDL_Keymod mod); bool -convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod); +convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod, + enum text_events_pref pref); enum android_motionevent_buttons convert_mouse_buttons(uint32_t state); diff --git a/app/src/input_manager.c b/app/src/input_manager.c index fe8919900d..aea2e5d30a 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -214,12 +214,20 @@ clipboard_paste(struct controller *controller) { void input_manager_process_text_input(struct input_manager *im, const SDL_TextInputEvent *event) { - char c = event->text[0]; - if (isalpha(c) || c == ' ') { - SDL_assert(event->text[1] == '\0'); - // letters and space are handled as raw key event + if (im->text_events_pref == PREFER_TEXT_EVENTS_NEVER) { + // ignore all text events (key events will be injected instead) return; } + + if (im->text_events_pref == PREFER_TEXT_EVENTS_NON_ALPHA) { + char c = event->text[0]; + if (isalpha(c) || c == ' ') { + SDL_assert(event->text[1] == '\0'); + // letters and space are handled as raw key event + return; + } + } + struct control_msg msg; msg.type = CONTROL_MSG_TYPE_INJECT_TEXT; msg.inject_text.text = SDL_strdup(event->text); @@ -234,7 +242,8 @@ input_manager_process_text_input(struct input_manager *im, } static bool -convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) { +convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to, + enum text_events_pref pref) { to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE; if (!convert_keycode_action(from->type, &to->inject_keycode.action)) { @@ -242,7 +251,8 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) { } uint16_t mod = from->keysym.mod; - if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod)) { + if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod, + pref)) { return false; } @@ -393,7 +403,7 @@ input_manager_process_key(struct input_manager *im, } struct control_msg msg; - if (convert_input_key(event, &msg)) { + if (convert_input_key(event, &msg, im->text_events_pref)) { if (!controller_push_msg(controller, &msg)) { LOGW("Could not request 'inject keycode'"); } diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 934c529e65..725455ffe6 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -10,10 +10,17 @@ #include "video_buffer.h" #include "screen.h" +enum text_events_pref { + PREFER_TEXT_EVENTS_ALWAYS, + PREFER_TEXT_EVENTS_NON_ALPHA, + PREFER_TEXT_EVENTS_NEVER, +}; + struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; + enum text_events_pref text_events_pref; }; void diff --git a/app/src/main.c b/app/src/main.c index d2a1323780..accd9ab97b 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -11,6 +11,7 @@ #include "config.h" #include "compat.h" #include "log.h" +#include "input_manager.h" #include "recorder.h" struct args { @@ -67,6 +68,18 @@ static void usage(const char *arg0) { " Set the TCP port the client listens on.\n" " Default is %d.\n" "\n" + " --prefer-text-events mode\n" + " Configure how key/text events are forwarded to the Android\n" + " device.\n" + " Possible values are:\n" + " always:\n" + " Every text is sent as text.\n" + " non-alpha:\n" + " Only letters are sent as a sequence of key events, other\n" + " characters are sent as text. (default)\n" + " never:\n" + " Every text is sent as a sequence of key events.\n" + "\n" " --push-target path\n" " Set the target directory for pushing files to the device by\n" " drag & drop. It is passed as-is to \"adb push\".\n" @@ -294,9 +307,33 @@ guess_record_format(const char *filename) { return 0; } +static bool +parse_prefer_text_events(const char *optarg, + enum text_events_pref *pref) { + if (!strcmp(optarg, "always")) { + *pref = PREFER_TEXT_EVENTS_ALWAYS; + return true; + } + + if (!strcmp(optarg, "non-alpha")) { + *pref = PREFER_TEXT_EVENTS_NON_ALPHA; + return true; + } + + if (!strcmp(optarg, "never")) { + *pref = PREFER_TEXT_EVENTS_NEVER; + return true; + } + + LOGE("Unsupported text events preference: %s" + "(expected 'always', 'non-alpha' or 'never')", optarg); + return false; +} + #define OPT_RENDER_EXPIRED_FRAMES 1000 #define OPT_WINDOW_TITLE 1001 #define OPT_PUSH_TARGET 1002 +#define OPT_PREFER_TEXT_EVENTS 1003 static bool parse_args(struct args *args, int argc, char *argv[]) { @@ -319,6 +356,8 @@ parse_args(struct args *args, int argc, char *argv[]) { {"serial", required_argument, NULL, 's'}, {"show-touches", no_argument, NULL, 't'}, {"turn-screen-off", no_argument, NULL, 'S'}, + {"prefer-text-events", required_argument, NULL, + OPT_PREFER_TEXT_EVENTS}, {"version", no_argument, NULL, 'v'}, {"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, @@ -393,6 +432,12 @@ parse_args(struct args *args, int argc, char *argv[]) { case OPT_PUSH_TARGET: opts->push_target = optarg; break; + case OPT_PREFER_TEXT_EVENTS: + if (!parse_prefer_text_events(optarg, + &opts->text_events_pref)) { + return false; + } + break; default: // getopt prints the error message on stderr return false; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index c219c9e5a4..10cb785d22 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -42,6 +42,7 @@ static struct input_manager input_manager = { .controller = &controller, .video_buffer = &video_buffer, .screen = &screen, + .text_events_pref = 0, // initialized later }; // init SDL and set appropriate hints @@ -414,6 +415,8 @@ scrcpy(const struct scrcpy_options *options) { show_touches_waited = true; } + input_manager.text_events_pref = options->text_events_pref; + ret = event_loop(options->display, options->control); LOGD("quit..."); diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 4bc24742c5..4c78968e6e 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -5,6 +5,7 @@ #include #include "config.h" +#include "input_manager.h" #include "recorder.h" struct scrcpy_options { @@ -14,6 +15,7 @@ struct scrcpy_options { const char *window_title; const char *push_target; enum recorder_format record_format; + enum text_events_pref text_events_pref; uint16_t port; uint16_t max_size; uint32_t bit_rate; @@ -33,6 +35,7 @@ struct scrcpy_options { .window_title = NULL, \ .push_target = NULL, \ .record_format = RECORDER_FORMAT_AUTO, \ + .text_events_pref = PREFER_TEXT_EVENTS_NON_ALPHA, \ .port = DEFAULT_LOCAL_PORT, \ .max_size = DEFAULT_LOCAL_PORT, \ .bit_rate = DEFAULT_BIT_RATE, \