Skip to content

Commit 9de332b

Browse files
committed
Add "raw key events" mode
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>
1 parent 3b5e542 commit 9de332b

8 files changed

+135
-14
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,19 @@ To show physical touches while scrcpy is running:
312312
scrcpy -t
313313
```
314314

315+
For playing games, it may be useful to enable "raw key events" (see [#87] and
316+
[#127]):
317+
318+
```bash
319+
scrcpy -k
320+
```
321+
322+
Note that in this mode, text inputs may not work as expected. As a workaround,
323+
it is still possible to send text using copy-paste.
324+
325+
[#87]: https://github.com/Genymobile/scrcpy/issues/87
326+
[#127]: https://github.com/Genymobile/scrcpy/issues/127
327+
315328
To run without installing:
316329

317330
```bash

app/src/convert.c

+83-2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,83 @@ static enum android_metastate convert_meta_state(SDL_Keymod mod) {
7070
return autocomplete_metastate(metastate);
7171
}
7272

73+
// only used if raw_key_events is enabled
74+
static SDL_bool convert_text_keycode(SDL_Keycode from, enum android_keycode *to) {
75+
switch (from) {
76+
MAP(SDLK_SPACE, AKEYCODE_SPACE);
77+
MAP(SDLK_HASH, AKEYCODE_POUND);
78+
MAP(SDLK_QUOTE, AKEYCODE_APOSTROPHE);
79+
MAP(SDLK_ASTERISK, AKEYCODE_STAR);
80+
MAP(SDLK_COMMA, AKEYCODE_COMMA);
81+
MAP(SDLK_MINUS, AKEYCODE_MINUS);
82+
MAP(SDLK_PERIOD, AKEYCODE_PERIOD);
83+
MAP(SDLK_SLASH, AKEYCODE_SLASH);
84+
MAP(SDLK_0, AKEYCODE_0);
85+
MAP(SDLK_1, AKEYCODE_1);
86+
MAP(SDLK_2, AKEYCODE_2);
87+
MAP(SDLK_3, AKEYCODE_3);
88+
MAP(SDLK_4, AKEYCODE_4);
89+
MAP(SDLK_5, AKEYCODE_5);
90+
MAP(SDLK_6, AKEYCODE_6);
91+
MAP(SDLK_7, AKEYCODE_7);
92+
MAP(SDLK_8, AKEYCODE_8);
93+
MAP(SDLK_9, AKEYCODE_9);
94+
MAP(SDLK_SEMICOLON, AKEYCODE_SEMICOLON);
95+
MAP(SDLK_EQUALS, AKEYCODE_EQUALS);
96+
MAP(SDLK_AT, AKEYCODE_AT);
97+
MAP(SDLK_LEFTBRACKET, AKEYCODE_LEFT_BRACKET);
98+
MAP(SDLK_BACKSLASH, AKEYCODE_BACKSLASH);
99+
MAP(SDLK_RIGHTBRACKET, AKEYCODE_RIGHT_BRACKET);
100+
MAP(SDLK_BACKQUOTE, AKEYCODE_GRAVE);
101+
MAP(SDLK_a, AKEYCODE_A);
102+
MAP(SDLK_b, AKEYCODE_B);
103+
MAP(SDLK_c, AKEYCODE_C);
104+
MAP(SDLK_d, AKEYCODE_D);
105+
MAP(SDLK_e, AKEYCODE_E);
106+
MAP(SDLK_f, AKEYCODE_F);
107+
MAP(SDLK_g, AKEYCODE_G);
108+
MAP(SDLK_h, AKEYCODE_H);
109+
MAP(SDLK_i, AKEYCODE_I);
110+
MAP(SDLK_j, AKEYCODE_J);
111+
MAP(SDLK_k, AKEYCODE_K);
112+
MAP(SDLK_l, AKEYCODE_L);
113+
MAP(SDLK_m, AKEYCODE_M);
114+
MAP(SDLK_n, AKEYCODE_N);
115+
MAP(SDLK_o, AKEYCODE_O);
116+
MAP(SDLK_p, AKEYCODE_P);
117+
MAP(SDLK_q, AKEYCODE_Q);
118+
MAP(SDLK_r, AKEYCODE_R);
119+
MAP(SDLK_s, AKEYCODE_S);
120+
MAP(SDLK_t, AKEYCODE_T);
121+
MAP(SDLK_u, AKEYCODE_U);
122+
MAP(SDLK_v, AKEYCODE_V);
123+
MAP(SDLK_w, AKEYCODE_W);
124+
MAP(SDLK_x, AKEYCODE_X);
125+
MAP(SDLK_y, AKEYCODE_Y);
126+
MAP(SDLK_z, AKEYCODE_Z);
127+
MAP(SDLK_KP_ENTER, AKEYCODE_NUMPAD_ENTER);
128+
MAP(SDLK_KP_1, AKEYCODE_NUMPAD_1);
129+
MAP(SDLK_KP_2, AKEYCODE_NUMPAD_2);
130+
MAP(SDLK_KP_3, AKEYCODE_NUMPAD_3);
131+
MAP(SDLK_KP_4, AKEYCODE_NUMPAD_4);
132+
MAP(SDLK_KP_5, AKEYCODE_NUMPAD_5);
133+
MAP(SDLK_KP_6, AKEYCODE_NUMPAD_6);
134+
MAP(SDLK_KP_7, AKEYCODE_NUMPAD_7);
135+
MAP(SDLK_KP_8, AKEYCODE_NUMPAD_8);
136+
MAP(SDLK_KP_9, AKEYCODE_NUMPAD_9);
137+
MAP(SDLK_KP_0, AKEYCODE_NUMPAD_0);
138+
MAP(SDLK_KP_DIVIDE, AKEYCODE_NUMPAD_DIVIDE);
139+
MAP(SDLK_KP_MULTIPLY, AKEYCODE_NUMPAD_MULTIPLY);
140+
MAP(SDLK_KP_MINUS, AKEYCODE_NUMPAD_SUBTRACT);
141+
MAP(SDLK_KP_PLUS, AKEYCODE_NUMPAD_ADD);
142+
MAP(SDLK_KP_PERIOD, AKEYCODE_NUMPAD_DOT);
143+
MAP(SDLK_KP_EQUALS, AKEYCODE_NUMPAD_EQUALS);
144+
MAP(SDLK_KP_LEFTPAREN, AKEYCODE_NUMPAD_LEFT_PAREN);
145+
MAP(SDLK_KP_RIGHTPAREN, AKEYCODE_NUMPAD_RIGHT_PAREN);
146+
FAIL;
147+
}
148+
}
149+
73150
static SDL_bool convert_keycode(SDL_Keycode from, enum android_keycode *to) {
74151
switch (from) {
75152
MAP(SDLK_RETURN, AKEYCODE_ENTER);
@@ -119,15 +196,19 @@ static enum android_motionevent_buttons convert_mouse_buttons(Uint32 state) {
119196
}
120197

121198
SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from,
122-
struct control_event *to) {
199+
struct control_event *to,
200+
SDL_bool raw_key_events) {
123201
to->type = CONTROL_EVENT_TYPE_KEYCODE;
124202

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

129207
if (!convert_keycode(from->keysym.sym, &to->keycode_event.keycode)) {
130-
return SDL_FALSE;
208+
if (!raw_key_events ||
209+
!convert_text_keycode(from->keysym.sym, &to->keycode_event.keycode)) {
210+
return SDL_FALSE;
211+
}
131212
}
132213

133214
to->keycode_event.metastate = convert_meta_state(from->keysym.mod);

app/src/convert.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ struct complete_mouse_wheel_event {
1616
};
1717

1818
SDL_bool input_key_from_sdl_to_android(const SDL_KeyboardEvent *from,
19-
struct control_event *to);
19+
struct control_event *to,
20+
SDL_bool raw_key_events);
21+
2022
SDL_bool mouse_button_from_sdl_to_android(const SDL_MouseButtonEvent *from,
2123
struct size screen_size,
2224
struct control_event *to);

app/src/input_manager.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ static void clipboard_paste(struct controller *controller) {
129129

130130
void input_manager_process_text_input(struct input_manager *input_manager,
131131
const SDL_TextInputEvent *event) {
132+
if (input_manager->raw_key_events) {
133+
// we will forward the raw key events instead
134+
return;
135+
}
132136
struct control_event control_event;
133137
control_event.type = CONTROL_EVENT_TYPE_TEXT;
134138
control_event.text_event.text = SDL_strdup(event->text);
@@ -222,7 +226,8 @@ void input_manager_process_key(struct input_manager *input_manager,
222226
}
223227

224228
struct control_event control_event;
225-
if (input_key_from_sdl_to_android(event, &control_event)) {
229+
SDL_bool raw_key_events = input_manager->raw_key_events;
230+
if (input_key_from_sdl_to_android(event, &control_event, raw_key_events)) {
226231
if (!controller_push_event(input_manager->controller, &control_event)) {
227232
LOGW("Cannot send control event");
228233
}

app/src/input_manager.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct input_manager {
1111
struct controller *controller;
1212
struct frames *frames;
1313
struct screen *screen;
14+
SDL_bool raw_key_events;
1415
};
1516

1617
void input_manager_process_text_input(struct input_manager *input_manager,

app/src/main.c

+22-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct args {
1414
SDL_bool help;
1515
SDL_bool version;
1616
SDL_bool show_touches;
17+
SDL_bool raw_key_events;
1718
Uint16 port;
1819
Uint16 max_size;
1920
Uint32 bit_rate;
@@ -36,6 +37,11 @@ static void usage(const char *arg0) {
3637
" (typically, portrait for a phone, landscape for a tablet).\n"
3738
" Any --max-size value is computed on the cropped size.\n"
3839
"\n"
40+
" -k, --raw-key-events\n"
41+
" Send key events even for text keys, and ignore text input\n"
42+
" events. This is useful when text keys are not used for\n"
43+
" typing text, for example in video games.\n"
44+
"\n"
3945
" -h, --help\n"
4046
" Print this help.\n"
4147
"\n"
@@ -198,18 +204,19 @@ static SDL_bool parse_port(char *optarg, Uint16 *port) {
198204

199205
static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
200206
static const struct option long_options[] = {
201-
{"bit-rate", required_argument, NULL, 'b'},
202-
{"crop", required_argument, NULL, 'c'},
203-
{"help", no_argument, NULL, 'h'},
204-
{"max-size", required_argument, NULL, 'm'},
205-
{"port", required_argument, NULL, 'p'},
206-
{"serial", required_argument, NULL, 's'},
207-
{"show-touches", no_argument, NULL, 't'},
208-
{"version", no_argument, NULL, 'v'},
209-
{NULL, 0, NULL, 0 },
207+
{"bit-rate", required_argument, NULL, 'b'},
208+
{"crop", required_argument, NULL, 'c'},
209+
{"raw-key-events", no_argument, NULL, 'k'},
210+
{"help", no_argument, NULL, 'h'},
211+
{"max-size", required_argument, NULL, 'm'},
212+
{"port", required_argument, NULL, 'p'},
213+
{"serial", required_argument, NULL, 's'},
214+
{"show-touches", no_argument, NULL, 't'},
215+
{"version", no_argument, NULL, 'v'},
216+
{NULL, 0, NULL, 0 },
210217
};
211218
int c;
212-
while ((c = getopt_long(argc, argv, "b:c:hm:p:s:tv", long_options, NULL)) != -1) {
219+
while ((c = getopt_long(argc, argv, "b:c:khm:p:s:tv", long_options, NULL)) != -1) {
213220
switch (c) {
214221
case 'b':
215222
if (!parse_bit_rate(optarg, &args->bit_rate)) {
@@ -219,6 +226,9 @@ static SDL_bool parse_args(struct args *args, int argc, char *argv[]) {
219226
case 'c':
220227
args->crop = optarg;
221228
break;
229+
case 'k':
230+
args->raw_key_events = SDL_TRUE;
231+
break;
222232
case 'h':
223233
args->help = SDL_TRUE;
224234
break;
@@ -268,6 +278,7 @@ int main(int argc, char *argv[]) {
268278
.help = SDL_FALSE,
269279
.version = SDL_FALSE,
270280
.show_touches = SDL_FALSE,
281+
.raw_key_events = SDL_FALSE,
271282
.port = DEFAULT_LOCAL_PORT,
272283
.max_size = DEFAULT_MAX_SIZE,
273284
.bit_rate = DEFAULT_BIT_RATE,
@@ -305,6 +316,7 @@ int main(int argc, char *argv[]) {
305316
.max_size = args.max_size,
306317
.bit_rate = args.bit_rate,
307318
.show_touches = args.show_touches,
319+
.raw_key_events = args.raw_key_events,
308320
};
309321
int res = scrcpy(&options) ? 0 : 1;
310322

app/src/scrcpy.c

+6
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ SDL_bool scrcpy(const struct scrcpy_options *options) {
223223
show_touches_waited = SDL_TRUE;
224224
}
225225

226+
// configure the "raw key events" flag on the input manager
227+
input_manager.raw_key_events = options->raw_key_events;
228+
if (options->raw_key_events) {
229+
LOGI("Raw key events mode enabled");
230+
}
231+
226232
ret = event_loop();
227233
LOGD("quit...");
228234

app/src/scrcpy.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ struct scrcpy_options {
1010
Uint16 max_size;
1111
Uint32 bit_rate;
1212
SDL_bool show_touches;
13+
SDL_bool raw_key_events; // ignore text input, forward key events instead
1314
};
1415

1516
SDL_bool scrcpy(const struct scrcpy_options *options);

0 commit comments

Comments
 (0)