From c916af0984f72a60301d13fa8ef9a85112f54202 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 7 Nov 2019 19:01:35 +0100 Subject: [PATCH] Add --prefer-text option Expose an option to configure how key/text events are forwarded to the Android device. Enabling the option avoids issues when combining multiple keys to enter special characters, but breaks the expected behavior of alpha keys in games (typically WASD). Fixes --- app/scrcpy.1 | 7 +++++++ app/src/event_converter.c | 9 ++++++++- app/src/event_converter.h | 3 ++- app/src/input_manager.c | 21 +++++++++++++-------- app/src/input_manager.h | 1 + app/src/main.c | 12 ++++++++++++ app/src/scrcpy.c | 3 +++ app/src/scrcpy.h | 3 +++ 8 files changed, 49 insertions(+), 10 deletions(-) diff --git a/app/scrcpy.1 b/app/scrcpy.1 index 1dafbc6a..203395a4 100644 --- a/app/scrcpy.1 +++ b/app/scrcpy.1 @@ -61,6 +61,13 @@ Set the TCP port the client listens on. Default is 27183. +.TP +.B \-\-prefer\-text +Inject alpha characters and space as text events instead of key events. + +This avoids issues when combining multiple keys to enter special characters, +but breaks the expected behavior of alpha keys in games (typically WASD). + .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 00e989f7..80ead615 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, + bool prefer_text) { switch (from) { MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER); @@ -92,6 +93,12 @@ 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 (prefer_text) { + // do not forward alpha and space key events + return false; + } + 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 8bad7358..c41887e1 100644 --- a/app/src/event_converter.h +++ b/app/src/event_converter.h @@ -14,7 +14,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, + bool prefer_text); 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 fe891990..7d333c1b 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -214,12 +214,15 @@ 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 - return; + if (!im->prefer_text) { + 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 +237,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, + bool prefer_text) { to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE; if (!convert_keycode_action(from->type, &to->inject_keycode.action)) { @@ -242,7 +246,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, + prefer_text)) { return false; } @@ -393,7 +398,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->prefer_text)) { 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 934c529e..43fc0eeb 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -14,6 +14,7 @@ struct input_manager { struct controller *controller; struct video_buffer *video_buffer; struct screen *screen; + bool prefer_text; }; void diff --git a/app/src/main.c b/app/src/main.c index 1d5beb64..12c65ed4 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -67,6 +67,13 @@ static void usage(const char *arg0) { " Set the TCP port the client listens on.\n" " Default is %d.\n" "\n" + " --prefer-text\n" + " Inject alpha characters and space as text events instead of\n" + " key events.\n" + " This avoids issues when combining multiple keys to enter a\n" + " special character, but breaks the expected behavior of alpha\n" + " keys in games (typically WASD).\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" @@ -300,6 +307,7 @@ guess_record_format(const char *filename) { #define OPT_ALWAYS_ON_TOP 1003 #define OPT_CROP 1004 #define OPT_RECORD_FORMAT 1005 +#define OPT_PREFER_TEXT 1006 static bool parse_args(struct args *args, int argc, char *argv[]) { @@ -321,6 +329,7 @@ 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", no_argument, NULL, OPT_PREFER_TEXT}, {"version", no_argument, NULL, 'v'}, {"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, @@ -404,6 +413,9 @@ parse_args(struct args *args, int argc, char *argv[]) { case OPT_PUSH_TARGET: opts->push_target = optarg; break; + case OPT_PREFER_TEXT: + opts->prefer_text = true; + break; default: // getopt prints the error message on stderr return false; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index c219c9e5..16f1b4f7 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, + .prefer_text = false, // initialized later }; // init SDL and set appropriate hints @@ -414,6 +415,8 @@ scrcpy(const struct scrcpy_options *options) { show_touches_waited = true; } + input_manager.prefer_text = options->prefer_text; + ret = event_loop(options->display, options->control); LOGD("quit..."); diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 4bc24742..70a41ec1 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 { @@ -24,6 +25,7 @@ struct scrcpy_options { bool display; bool turn_screen_off; bool render_expired_frames; + bool prefer_text; }; #define SCRCPY_OPTIONS_DEFAULT { \ @@ -43,6 +45,7 @@ struct scrcpy_options { .display = true, \ .turn_screen_off = false, \ .render_expired_frames = false, \ + .prefer_text = false, \ } bool