mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Add flag to emulate QWERTY in OTG mode
Add the flag `--otg-emulate-qwerty` to allow for behaving as though the controlled QWERTY-expecting device had the local keymap.
This commit is contained in:
parent
3fcc177da5
commit
9a3d5b3798
9 changed files with 123 additions and 6 deletions
|
|
@ -61,6 +61,7 @@ enum {
|
|||
OPT_RAW_KEY_EVENTS,
|
||||
OPT_NO_DOWNSIZE_ON_ERROR,
|
||||
OPT_OTG,
|
||||
OPT_OTG_EMULATE_QWERTY,
|
||||
OPT_NO_CLEANUP,
|
||||
OPT_PRINT_FPS,
|
||||
OPT_NO_POWER_ON,
|
||||
|
|
@ -745,6 +746,14 @@ static const struct sc_option options[] = {
|
|||
"It may only work over USB.\n"
|
||||
"See --keyboard, --mouse and --gamepad.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_OTG_EMULATE_QWERTY,
|
||||
.longopt = "otg-emulate-qwerty",
|
||||
.text = "When running in OTG mode, send the keypress corresponding to "
|
||||
"the logical layout rather than the physical layout.\n"
|
||||
"Useful when using an AZERTY, Dvorak or Colemak layout to "
|
||||
"control a device configured to use QWERTY.",
|
||||
},
|
||||
{
|
||||
.shortopt = 'p',
|
||||
.longopt = "port",
|
||||
|
|
@ -2685,6 +2694,14 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
#else
|
||||
LOGE("OTG mode (--otg) is disabled.");
|
||||
return false;
|
||||
#endif
|
||||
case OPT_OTG_EMULATE_QWERTY:
|
||||
#ifdef HAVE_USB
|
||||
opts->otg_emulate_qwerty = true;
|
||||
break;
|
||||
#else
|
||||
LOGE("OTG mode (--otg) is disabled.");
|
||||
return false;
|
||||
#endif
|
||||
case OPT_V4L2_SINK:
|
||||
#ifdef HAVE_V4L2
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
#endif
|
||||
#ifdef HAVE_USB
|
||||
.otg = false,
|
||||
.otg_emulate_qwerty = false,
|
||||
#endif
|
||||
.show_touches = false,
|
||||
.fullscreen = false,
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ struct scrcpy_options {
|
|||
#endif
|
||||
#ifdef HAVE_USB
|
||||
bool otg;
|
||||
bool otg_emulate_qwerty;
|
||||
#endif
|
||||
bool show_touches;
|
||||
bool fullscreen;
|
||||
|
|
|
|||
|
|
@ -702,7 +702,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||
|
||||
bool aoa_fail = false;
|
||||
if (use_keyboard_aoa) {
|
||||
if (sc_keyboard_aoa_init(&s->keyboard_aoa, &s->aoa)) {
|
||||
if (sc_keyboard_aoa_init(&s->keyboard_aoa, &s->aoa, false)) {
|
||||
keyboard_aoa_initialized = true;
|
||||
kp = &s->keyboard_aoa.key_processor;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,14 @@ struct sc_key_processor {
|
|||
*/
|
||||
bool hid;
|
||||
|
||||
/**
|
||||
* Set by the implementation to indicate that scancodes should be falsified
|
||||
* such that keystrokes are sent as though the logical keymap were the
|
||||
* physical keymap. Useful when using an AZERTY, Dvorak or Colemak layout
|
||||
* to control a device configured to use QWERTY.
|
||||
*/
|
||||
bool use_logical_scancodes;
|
||||
|
||||
const struct sc_key_processor_ops *ops;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
|
|||
}
|
||||
|
||||
bool
|
||||
sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
|
||||
sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb,
|
||||
struct sc_aoa *aoa,
|
||||
bool use_logical_scancodes) {
|
||||
kb->aoa = aoa;
|
||||
|
||||
struct sc_hid_open hid_open;
|
||||
|
|
@ -91,6 +93,7 @@ sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
|
|||
// to be acknowledged by the device before injecting Ctrl+v.
|
||||
kb->key_processor.async_paste = true;
|
||||
kb->key_processor.hid = true;
|
||||
kb->key_processor.use_logical_scancodes = use_logical_scancodes;
|
||||
kb->key_processor.ops = &ops;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ struct sc_keyboard_aoa {
|
|||
};
|
||||
|
||||
bool
|
||||
sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa);
|
||||
sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb,
|
||||
struct sc_aoa *aoa,
|
||||
bool use_logical_scancodes);
|
||||
|
||||
void
|
||||
sc_keyboard_aoa_destroy(struct sc_keyboard_aoa *kb);
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||
options->gamepad_input_mode == SC_GAMEPAD_INPUT_MODE_AOA;
|
||||
|
||||
if (enable_keyboard) {
|
||||
ok = sc_keyboard_aoa_init(&s->keyboard, &s->aoa);
|
||||
ok = sc_keyboard_aoa_init(&s->keyboard, &s->aoa, options->otg_emulate_qwerty);
|
||||
if (!ok) {
|
||||
goto end;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,16 +100,101 @@ sc_screen_otg_destroy(struct sc_screen_otg *screen) {
|
|||
SDL_DestroyWindow(screen->window);
|
||||
}
|
||||
|
||||
static const enum sc_scancode keycode_to_scancode[] = {
|
||||
/* SDL2 has SDL_GetScancodeFromKey, but that uses the current keymap */
|
||||
|
||||
[SC_KEYCODE_RETURN] = SC_SCANCODE_RETURN,
|
||||
[SC_KEYCODE_ESCAPE] = SC_SCANCODE_ESCAPE,
|
||||
[SC_KEYCODE_BACKSPACE] = SC_SCANCODE_BACKSPACE,
|
||||
[SC_KEYCODE_TAB] = SC_SCANCODE_TAB,
|
||||
[SC_KEYCODE_SPACE] = SC_SCANCODE_SPACE,
|
||||
[SC_KEYCODE_EXCLAIM] = SC_SCANCODE_1,
|
||||
[SC_KEYCODE_QUOTEDBL] = SC_SCANCODE_APOSTROPHE,
|
||||
[SC_KEYCODE_HASH] = SC_SCANCODE_3,
|
||||
[SC_KEYCODE_PERCENT] = SC_SCANCODE_5,
|
||||
[SC_KEYCODE_DOLLAR] = SC_SCANCODE_4,
|
||||
[SC_KEYCODE_AMPERSAND] = SC_SCANCODE_7,
|
||||
[SC_KEYCODE_QUOTE] = SC_SCANCODE_APOSTROPHE,
|
||||
[SC_KEYCODE_LEFTPAREN] = SC_SCANCODE_9,
|
||||
[SC_KEYCODE_RIGHTPAREN] = SC_SCANCODE_0,
|
||||
[SC_KEYCODE_ASTERISK] = SC_SCANCODE_8,
|
||||
[SC_KEYCODE_PLUS] = SC_SCANCODE_EQUALS,
|
||||
[SC_KEYCODE_COMMA] = SC_SCANCODE_COMMA,
|
||||
[SC_KEYCODE_MINUS] = SC_SCANCODE_MINUS,
|
||||
[SC_KEYCODE_PERIOD] = SC_SCANCODE_PERIOD,
|
||||
[SC_KEYCODE_SLASH] = SC_SCANCODE_SLASH,
|
||||
[SC_KEYCODE_0] = SC_SCANCODE_0,
|
||||
[SC_KEYCODE_1] = SC_SCANCODE_1,
|
||||
[SC_KEYCODE_2] = SC_SCANCODE_2,
|
||||
[SC_KEYCODE_3] = SC_SCANCODE_3,
|
||||
[SC_KEYCODE_4] = SC_SCANCODE_4,
|
||||
[SC_KEYCODE_5] = SC_SCANCODE_5,
|
||||
[SC_KEYCODE_6] = SC_SCANCODE_6,
|
||||
[SC_KEYCODE_7] = SC_SCANCODE_7,
|
||||
[SC_KEYCODE_8] = SC_SCANCODE_8,
|
||||
[SC_KEYCODE_9] = SC_SCANCODE_9,
|
||||
[SC_KEYCODE_COLON] = SC_SCANCODE_SEMICOLON,
|
||||
[SC_KEYCODE_SEMICOLON] = SC_SCANCODE_SEMICOLON,
|
||||
[SC_KEYCODE_LESS] = SC_SCANCODE_COMMA,
|
||||
[SC_KEYCODE_EQUALS] = SC_SCANCODE_EQUALS,
|
||||
[SC_KEYCODE_GREATER] = SC_SCANCODE_PERIOD,
|
||||
[SC_KEYCODE_QUESTION] = SC_SCANCODE_SLASH,
|
||||
[SC_KEYCODE_AT] = SC_SCANCODE_2,
|
||||
|
||||
[SC_KEYCODE_LEFTBRACKET] = SC_SCANCODE_LEFTBRACKET,
|
||||
[SC_KEYCODE_BACKSLASH] = SC_SCANCODE_BACKSLASH,
|
||||
[SC_KEYCODE_RIGHTBRACKET] = SC_SCANCODE_RIGHTBRACKET,
|
||||
[SC_KEYCODE_CARET] = SC_SCANCODE_6,
|
||||
[SC_KEYCODE_UNDERSCORE] = SC_SCANCODE_MINUS,
|
||||
[SC_KEYCODE_BACKQUOTE] = SC_SCANCODE_GRAVE,
|
||||
[SC_KEYCODE_a] = SC_SCANCODE_A,
|
||||
[SC_KEYCODE_b] = SC_SCANCODE_B,
|
||||
[SC_KEYCODE_c] = SC_SCANCODE_C,
|
||||
[SC_KEYCODE_d] = SC_SCANCODE_D,
|
||||
[SC_KEYCODE_e] = SC_SCANCODE_E,
|
||||
[SC_KEYCODE_f] = SC_SCANCODE_F,
|
||||
[SC_KEYCODE_g] = SC_SCANCODE_G,
|
||||
[SC_KEYCODE_h] = SC_SCANCODE_H,
|
||||
[SC_KEYCODE_i] = SC_SCANCODE_I,
|
||||
[SC_KEYCODE_j] = SC_SCANCODE_J,
|
||||
[SC_KEYCODE_k] = SC_SCANCODE_K,
|
||||
[SC_KEYCODE_l] = SC_SCANCODE_L,
|
||||
[SC_KEYCODE_m] = SC_SCANCODE_M,
|
||||
[SC_KEYCODE_n] = SC_SCANCODE_N,
|
||||
[SC_KEYCODE_o] = SC_SCANCODE_O,
|
||||
[SC_KEYCODE_p] = SC_SCANCODE_P,
|
||||
[SC_KEYCODE_q] = SC_SCANCODE_Q,
|
||||
[SC_KEYCODE_r] = SC_SCANCODE_R,
|
||||
[SC_KEYCODE_s] = SC_SCANCODE_S,
|
||||
[SC_KEYCODE_t] = SC_SCANCODE_T,
|
||||
[SC_KEYCODE_u] = SC_SCANCODE_U,
|
||||
[SC_KEYCODE_v] = SC_SCANCODE_V,
|
||||
[SC_KEYCODE_w] = SC_SCANCODE_W,
|
||||
[SC_KEYCODE_x] = SC_SCANCODE_X,
|
||||
[SC_KEYCODE_y] = SC_SCANCODE_Y,
|
||||
[SC_KEYCODE_z] = SC_SCANCODE_Z,
|
||||
};
|
||||
|
||||
static void
|
||||
sc_screen_otg_process_key(struct sc_screen_otg *screen,
|
||||
const SDL_KeyboardEvent *event) {
|
||||
assert(screen->keyboard);
|
||||
struct sc_key_processor *kp = &screen->keyboard->key_processor;
|
||||
|
||||
enum sc_keycode keycode = sc_keycode_from_sdl(event->keysym.sym);
|
||||
enum sc_scancode scancode = sc_scancode_from_sdl(event->keysym.scancode);
|
||||
|
||||
if (kp->use_logical_scancodes && keycode < ARRAY_LEN(keycode_to_scancode)) {
|
||||
enum sc_scancode logical_scancode = keycode_to_scancode[keycode];
|
||||
if (logical_scancode != 0) {
|
||||
scancode = logical_scancode;
|
||||
}
|
||||
}
|
||||
|
||||
struct sc_key_event evt = {
|
||||
.action = sc_action_from_sdl_keyboard_type(event->type),
|
||||
.keycode = sc_keycode_from_sdl(event->keysym.sym),
|
||||
.scancode = sc_scancode_from_sdl(event->keysym.scancode),
|
||||
.keycode = keycode,
|
||||
.scancode = scancode,
|
||||
.repeat = event->repeat,
|
||||
.mods_state = sc_mods_state_from_sdl(event->keysym.mod),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue