diff --git a/README.md b/README.md index 3e167b06..550f1f7f 100644 --- a/README.md +++ b/README.md @@ -833,7 +833,13 @@ scrcpy --prefer-text (but this will break keyboard behavior in games) -This option has no effect on HID keyboard (all key events are sent as +On the contrary, you could force to always inject raw key events: + +```bash +scrcpy --raw-key-events +``` + +These options have no effect on HID keyboard (all key events are sent as scancodes in this mode). [textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input diff --git a/app/scrcpy.1 b/app/scrcpy.1 index f7508d5e..b99c781f 100644 --- a/app/scrcpy.1 +++ b/app/scrcpy.1 @@ -165,6 +165,10 @@ Set the target directory for pushing files to the device by drag & drop. It is p Default is "/sdcard/Download/". +.TP +.B \-\-raw\-key\-events +Inject key events for all input keys, and ignore text events. + .TP .BI "\-r, \-\-record " file Record screen to diff --git a/app/src/cli.c b/app/src/cli.c index 67a7a89f..f0b2e89c 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -51,6 +51,7 @@ #define OPT_TUNNEL_PORT 1031 #define OPT_NO_CLIPBOARD_AUTOSYNC 1032 #define OPT_TCPIP 1033 +#define OPT_RAW_KEY_EVENTS 1034 struct sc_option { char shortopt; @@ -282,6 +283,11 @@ static const struct sc_option options[] = { "drag & drop. It is passed as is to \"adb push\".\n" "Default is \"/sdcard/Download/\".", }, + { + .longopt_id = OPT_RAW_KEY_EVENTS, + .longopt = "raw-key-events", + .text = "Inject key events for all input keys, and ignore text events." + }, { .shortopt = 'r', .longopt = "record", @@ -1350,8 +1356,19 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], opts->push_target = optarg; break; case OPT_PREFER_TEXT: + if (opts->key_inject_mode != SC_KEY_INJECT_MODE_MIXED) { + LOGE("--prefer-text is incompatible with --raw-key-events"); + return false; + } opts->key_inject_mode = SC_KEY_INJECT_MODE_TEXT; break; + case OPT_RAW_KEY_EVENTS: + if (opts->key_inject_mode != SC_KEY_INJECT_MODE_MIXED) { + LOGE("--prefer-text is incompatible with --raw-key-events"); + return false; + } + opts->key_inject_mode = SC_KEY_INJECT_MODE_RAW; + break; case OPT_ROTATION: if (!parse_rotation(optarg, &opts->rotation)) { return false; diff --git a/app/src/keyboard_inject.c b/app/src/keyboard_inject.c index e6212193..5143eafc 100644 --- a/app/src/keyboard_inject.c +++ b/app/src/keyboard_inject.c @@ -101,6 +101,55 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod, {SDLK_SPACE, AKEYCODE_SPACE}, }; + // Numbers and punctuation keys. + // Used in raw mode only. + static const struct sc_intmap_entry numbers_punct_keys[] = { + {SDLK_HASH, AKEYCODE_POUND}, + {SDLK_PERCENT, AKEYCODE_PERIOD}, + {SDLK_QUOTE, AKEYCODE_APOSTROPHE}, + {SDLK_ASTERISK, AKEYCODE_STAR}, + {SDLK_PLUS, AKEYCODE_PLUS}, + {SDLK_COMMA, AKEYCODE_COMMA}, + {SDLK_MINUS, AKEYCODE_MINUS}, + {SDLK_PERIOD, AKEYCODE_PERIOD}, + {SDLK_SLASH, AKEYCODE_SLASH}, + {SDLK_0, AKEYCODE_0}, + {SDLK_1, AKEYCODE_1}, + {SDLK_2, AKEYCODE_2}, + {SDLK_3, AKEYCODE_3}, + {SDLK_4, AKEYCODE_4}, + {SDLK_5, AKEYCODE_5}, + {SDLK_6, AKEYCODE_6}, + {SDLK_7, AKEYCODE_7}, + {SDLK_8, AKEYCODE_8}, + {SDLK_9, AKEYCODE_9}, + {SDLK_SEMICOLON, AKEYCODE_SEMICOLON}, + {SDLK_EQUALS, AKEYCODE_EQUALS}, + {SDLK_AT, AKEYCODE_AT}, + {SDLK_LEFTBRACKET, AKEYCODE_LEFT_BRACKET}, + {SDLK_BACKSLASH, AKEYCODE_BACKSLASH}, + {SDLK_RIGHTBRACKET, AKEYCODE_RIGHT_BRACKET}, + {SDLK_BACKQUOTE, AKEYCODE_GRAVE}, + {SDLK_KP_1, AKEYCODE_NUMPAD_1}, + {SDLK_KP_2, AKEYCODE_NUMPAD_2}, + {SDLK_KP_3, AKEYCODE_NUMPAD_3}, + {SDLK_KP_4, AKEYCODE_NUMPAD_4}, + {SDLK_KP_5, AKEYCODE_NUMPAD_5}, + {SDLK_KP_6, AKEYCODE_NUMPAD_6}, + {SDLK_KP_7, AKEYCODE_NUMPAD_7}, + {SDLK_KP_8, AKEYCODE_NUMPAD_8}, + {SDLK_KP_9, AKEYCODE_NUMPAD_9}, + {SDLK_KP_0, AKEYCODE_NUMPAD_0}, + {SDLK_KP_DIVIDE, AKEYCODE_NUMPAD_DIVIDE}, + {SDLK_KP_MULTIPLY, AKEYCODE_NUMPAD_MULTIPLY}, + {SDLK_KP_MINUS, AKEYCODE_NUMPAD_SUBTRACT}, + {SDLK_KP_PLUS, AKEYCODE_NUMPAD_ADD}, + {SDLK_KP_PERIOD, AKEYCODE_NUMPAD_DOT}, + {SDLK_KP_EQUALS, AKEYCODE_NUMPAD_EQUALS}, + {SDLK_KP_LEFTPAREN, AKEYCODE_NUMPAD_LEFT_PAREN}, + {SDLK_KP_RIGHTPAREN, AKEYCODE_NUMPAD_RIGHT_PAREN}, + }; + const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(special_keys, from); if (entry) { @@ -134,6 +183,14 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod, return true; } + 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; + } + } + return false; } @@ -251,6 +308,11 @@ sc_key_processor_process_text(struct sc_key_processor *kp, const SDL_TextInputEvent *event) { struct sc_keyboard_inject *ki = DOWNCAST(kp); + if (ki->key_inject_mode == SC_KEY_INJECT_MODE_RAW) { + // Never inject text events + return; + } + if (ki->key_inject_mode == SC_KEY_INJECT_MODE_MIXED) { char c = event->text[0]; if (isalpha(c) || c == ' ') { diff --git a/app/src/options.h b/app/src/options.h index 84a80fbe..39703210 100644 --- a/app/src/options.h +++ b/app/src/options.h @@ -47,6 +47,9 @@ enum sc_key_inject_mode { // Inject special keys as key events. // Inject letters and space, numbers and punctuation as text events. SC_KEY_INJECT_MODE_TEXT, + + // Inject everything as key events. + SC_KEY_INJECT_MODE_RAW, }; #define SC_MAX_SHORTCUT_MODS 8