Skip to content

Commit

Permalink
Add "raw key events" mode
Browse files Browse the repository at this point in the history
Add a command-line option to enable "raw key events" mode
(-k,--raw-key-events).

This disable text inputs and forwards "text" key events (which are
not forwarded by default).

This is helpful for gaming:
<#87>
<#127>
  • Loading branch information
rom1v committed Aug 15, 2018
1 parent 3b5e542 commit 9de332b
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 14 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,19 @@ To show physical touches while scrcpy is running:
scrcpy -t
```

For playing games, it may be useful to enable "raw key events" (see [#87] and
[#127]):

```bash
scrcpy -k
```

Note that in this mode, text inputs may not work as expected. As a workaround,
it is still possible to send text using copy-paste.

[#87]: https://github.com/Genymobile/scrcpy/issues/87
[#127]: https://github.com/Genymobile/scrcpy/issues/127

To run without installing:

```bash
Expand Down
85 changes: 83 additions & 2 deletions app/src/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,83 @@ static enum android_metastate convert_meta_state(SDL_Keymod mod) {
return autocomplete_metastate(metastate);
}

// only used if raw_key_events is enabled
static SDL_bool convert_text_keycode(SDL_Keycode from, enum android_keycode *to) {
switch (from) {
MAP(SDLK_SPACE, AKEYCODE_SPACE);
MAP(SDLK_HASH, AKEYCODE_POUND);
MAP(SDLK_QUOTE, AKEYCODE_APOSTROPHE);
MAP(SDLK_ASTERISK, AKEYCODE_STAR);
MAP(SDLK_COMMA, AKEYCODE_COMMA);
MAP(SDLK_MINUS, AKEYCODE_MINUS);
MAP(SDLK_PERIOD, AKEYCODE_PERIOD);
MAP(SDLK_SLASH, AKEYCODE_SLASH);
MAP(SDLK_0, AKEYCODE_0);
MAP(SDLK_1, AKEYCODE_1);
MAP(SDLK_2, AKEYCODE_2);
MAP(SDLK_3, AKEYCODE_3);
MAP(SDLK_4, AKEYCODE_4);
MAP(SDLK_5, AKEYCODE_5);
MAP(SDLK_6, AKEYCODE_6);
MAP(SDLK_7, AKEYCODE_7);
MAP(SDLK_8, AKEYCODE_8);
MAP(SDLK_9, AKEYCODE_9);
MAP(SDLK_SEMICOLON, AKEYCODE_SEMICOLON);
MAP(SDLK_EQUALS, AKEYCODE_EQUALS);
MAP(SDLK_AT, AKEYCODE_AT);
MAP(SDLK_LEFTBRACKET, AKEYCODE_LEFT_BRACKET);
MAP(SDLK_BACKSLASH, AKEYCODE_BACKSLASH);
MAP(SDLK_RIGHTBRACKET, AKEYCODE_RIGHT_BRACKET);
MAP(SDLK_BACKQUOTE, AKEYCODE_GRAVE);
MAP(SDLK_a, AKEYCODE_A);
MAP(SDLK_b, AKEYCODE_B);
MAP(SDLK_c, AKEYCODE_C);
MAP(SDLK_d, AKEYCODE_D);
MAP(SDLK_e, AKEYCODE_E);
MAP(SDLK_f, AKEYCODE_F);
MAP(SDLK_g, AKEYCODE_G);
MAP(SDLK_h, AKEYCODE_H);
MAP(SDLK_i, AKEYCODE_I);
MAP(SDLK_j, AKEYCODE_J);
MAP(SDLK_k, AKEYCODE_K);
MAP(SDLK_l, AKEYCODE_L);
MAP(SDLK_m, AKEYCODE_M);
MAP(SDLK_n, AKEYCODE_N);
MAP(SDLK_o, AKEYCODE_O);
MAP(SDLK_p, AKEYCODE_P);
MAP(SDLK_q, AKEYCODE_Q);
MAP(SDLK_r, AKEYCODE_R);
MAP(SDLK_s, AKEYCODE_S);
MAP(SDLK_t, AKEYCODE_T);
MAP(SDLK_u, AKEYCODE_U);
MAP(SDLK_v, AKEYCODE_V);
MAP(SDLK_w, AKEYCODE_W);
MAP(SDLK_x, AKEYCODE_X);
MAP(SDLK_y, AKEYCODE_Y);
MAP(SDLK_z, AKEYCODE_Z);
MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER);
MAP(SDLK_KP_1, AKEYCODE_NUMPAD_1);
MAP(SDLK_KP_2, AKEYCODE_NUMPAD_2);
MAP(SDLK_KP_3, AKEYCODE_NUMPAD_3);
MAP(SDLK_KP_4, AKEYCODE_NUMPAD_4);
MAP(SDLK_KP_5, AKEYCODE_NUMPAD_5);
MAP(SDLK_KP_6, AKEYCODE_NUMPAD_6);
MAP(SDLK_KP_7, AKEYCODE_NUMPAD_7);
MAP(SDLK_KP_8, AKEYCODE_NUMPAD_8);
MAP(SDLK_KP_9, AKEYCODE_NUMPAD_9);
MAP(SDLK_KP_0, AKEYCODE_NUMPAD_0);
MAP(SDLK_KP_DIVIDE, AKEYCODE_NUMPAD_DIVIDE);
MAP(SDLK_KP_MULTIPLY, AKEYCODE_NUMPAD_MULTIPLY);
MAP(SDLK_KP_MINUS, AKEYCODE_NUMPAD_SUBTRACT);
MAP(SDLK_KP_PLUS, AKEYCODE_NUMPAD_ADD);
MAP(SDLK_KP_PERIOD, AKEYCODE_NUMPAD_DOT);
MAP(SDLK_KP_EQUALS, AKEYCODE_NUMPAD_EQUALS);
MAP(SDLK_KP_LEFTPAREN, AKEYCODE_NUMPAD_LEFT_PAREN);
MAP(SDLK_KP_RIGHTPAREN, AKEYCODE_NUMPAD_RIGHT_PAREN);
FAIL;
}
}

static SDL_bool convert_keycode(SDL_Keycode from, enum android_keycode *to) {
switch (from) {
MAP(SDLK_RETURN, AKEYCODE_ENTER);
Expand Down Expand Up @@ -119,15 +196,19 @@ static enum android_motionevent_buttons convert_mouse_buttons(Uint32 state) {
}

SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from,
struct control_event *to) {
struct control_event *to,
SDL_bool raw_key_events) {
to->type = CONTROL_EVENT_TYPE_KEYCODE;

if (!convert_keycode_action(from->type, &to->keycode_event.action)) {
return SDL_FALSE;
}

if (!convert_keycode(from->keysym.sym, &to->keycode_event.keycode)) {
return SDL_FALSE;
if (!raw_key_events ||
!convert_text_keycode(from->keysym.sym, &to->keycode_event.keycode)) {
return SDL_FALSE;
}
}

to->keycode_event.metastate = convert_meta_state(from->keysym.mod);
Expand Down
4 changes: 3 additions & 1 deletion app/src/convert.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct complete_mouse_wheel_event {
};

SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from,
struct control_event *to);
struct control_event *to,
SDL_bool raw_key_events);

SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from,
struct size screen_size,
struct control_event *to);
Expand Down
7 changes: 6 additions & 1 deletion app/src/input_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ static void clipboard_paste(struct controller *controller) {

void input_manager_process_text_input(struct input_manager *input_manager,
const SDL_TextInputEvent *event) {
if (input_manager->raw_key_events) {
// we will forward the raw key events instead
return;
}
struct control_event control_event;
control_event.type = CONTROL_EVENT_TYPE_TEXT;
control_event.text_event.text = SDL_strdup(event->text);
Expand Down Expand Up @@ -222,7 +226,8 @@ void input_manager_process_key(struct input_manager *input_manager,
}

struct control_event control_event;
if (input_key_from_sdl_to_android(event, &control_event)) {
SDL_bool raw_key_events = input_manager->raw_key_events;
if (input_key_from_sdl_to_android(event, &control_event, raw_key_events)) {
if (!controller_push_event(input_manager->controller, &control_event)) {
LOGW("Cannot send control event");
}
Expand Down
1 change: 1 addition & 0 deletions app/src/input_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct input_manager {
struct controller *controller;
struct frames *frames;
struct screen *screen;
SDL_bool raw_key_events;
};

void input_manager_process_text_input(struct input_manager *input_manager,
Expand Down
32 changes: 22 additions & 10 deletions app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct args {
SDL_bool help;
SDL_bool version;
SDL_bool show_touches;
SDL_bool raw_key_events;
Uint16 port;
Uint16 max_size;
Uint32 bit_rate;
Expand All @@ -36,6 +37,11 @@ static void usage(const char *arg0) {
" (typically, portrait for a phone, landscape for a tablet).\n"
" Any --max-size value is computed on the cropped size.\n"
"\n"
" -k, --raw-key-events\n"
" Send key events even for text keys, and ignore text input\n"
" events. This is useful when text keys are not used for\n"
" typing text, for example in video games.\n"
"\n"
" -h, --help\n"
" Print this help.\n"
"\n"
Expand Down Expand Up @@ -198,18 +204,19 @@ static SDL_bool parse_port(char *optarg, Uint16 *port) {

static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
static const struct option long_options[] = {
{"bit-rate", required_argument, NULL, 'b'},
{"crop", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0 },
{"bit-rate", required_argument, NULL, 'b'},
{"crop", required_argument, NULL, 'c'},
{"raw-key-events", no_argument, NULL, 'k'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"port", required_argument, NULL, 'p'},
{"serial", required_argument, NULL, 's'},
{"show-touches", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0 },
};
int c;
while ((c = getopt_long(argc, argv, "b:c:hm:p:s:tv", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "b:c:khm:p:s:tv", long_options, NULL)) != -1) {
switch (c) {
case 'b':
if (!parse_bit_rate(optarg, &args->bit_rate)) {
Expand All @@ -219,6 +226,9 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
case 'c':
args->crop = optarg;
break;
case 'k':
args->raw_key_events = SDL_TRUE;
break;
case 'h':
args->help = SDL_TRUE;
break;
Expand Down Expand Up @@ -268,6 +278,7 @@ int main(int argc, char *argv[]) {
.help = SDL_FALSE,
.version = SDL_FALSE,
.show_touches = SDL_FALSE,
.raw_key_events = SDL_FALSE,
.port = DEFAULT_LOCAL_PORT,
.max_size = DEFAULT_MAX_SIZE,
.bit_rate = DEFAULT_BIT_RATE,
Expand Down Expand Up @@ -305,6 +316,7 @@ int main(int argc, char *argv[]) {
.max_size = args.max_size,
.bit_rate = args.bit_rate,
.show_touches = args.show_touches,
.raw_key_events = args.raw_key_events,
};
int res = scrcpy(&options) ? 0 : 1;

Expand Down
6 changes: 6 additions & 0 deletions app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ SDL_bool scrcpy(const struct scrcpy_options *options) {
show_touches_waited = SDL_TRUE;
}

// configure the "raw key events" flag on the input manager
input_manager.raw_key_events = options->raw_key_events;
if (options->raw_key_events) {
LOGI("Raw key events mode enabled");
}

ret = event_loop();
LOGD("quit...");

Expand Down
1 change: 1 addition & 0 deletions app/src/scrcpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ struct scrcpy_options {
Uint16 max_size;
Uint32 bit_rate;
SDL_bool show_touches;
SDL_bool raw_key_events; // ignore text input, forward key events instead
};

SDL_bool scrcpy(const struct scrcpy_options *options);
Expand Down

0 comments on commit 9de332b

Please sign in to comment.