Compare commits
14 Commits
traits
...
settings_p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2ae5be3ea | ||
|
|
21b857959b | ||
|
|
66b6170c43 | ||
|
|
b8f3064510 | ||
|
|
f06dbd7927 | ||
|
|
b9c3f65fd8 | ||
|
|
d0739911a3 | ||
|
|
964b6d2243 | ||
|
|
8cc057c8f1 | ||
|
|
edee69d637 | ||
|
|
8ef4c044fa | ||
|
|
c23c38f99d | ||
|
|
65c4f487b3 | ||
|
|
c6d7f5ee96 |
@@ -187,16 +187,16 @@ Enable "show touches" on start, restore the initial value on exit.
|
|||||||
|
|
||||||
It only shows physical touches (not clicks from scrcpy).
|
It only shows physical touches (not clicks from scrcpy).
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-v, \-\-version
|
|
||||||
Print the version of scrcpy.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-V, \-\-verbosity " value
|
.BI "\-V, \-\-verbosity " value
|
||||||
Set the log level ("debug", "info", "warn" or "error").
|
Set the log level ("debug", "info", "warn" or "error").
|
||||||
|
|
||||||
Default is "info" for release builds, "debug" for debug builds.
|
Default is "info" for release builds, "debug" for debug builds.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-v, \-\-version
|
||||||
|
Print the version of scrcpy.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-w, \-\-stay-awake
|
.B \-w, \-\-stay-awake
|
||||||
Keep the device on while scrcpy is running, when the device is plugged in.
|
Keep the device on while scrcpy is running, when the device is plugged in.
|
||||||
|
|||||||
@@ -179,9 +179,6 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
" on exit.\n"
|
" on exit.\n"
|
||||||
" It only shows physical touches (not clicks from scrcpy).\n"
|
" It only shows physical touches (not clicks from scrcpy).\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -v, --version\n"
|
|
||||||
" Print the version of scrcpy.\n"
|
|
||||||
"\n"
|
|
||||||
" -V, --verbosity value\n"
|
" -V, --verbosity value\n"
|
||||||
" Set the log level (debug, info, warn or error).\n"
|
" Set the log level (debug, info, warn or error).\n"
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
@@ -189,6 +186,9 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
#else
|
#else
|
||||||
" Default is info.\n"
|
" Default is info.\n"
|
||||||
#endif
|
#endif
|
||||||
|
"\n"
|
||||||
|
" -v, --version\n"
|
||||||
|
" Print the version of scrcpy.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -w, --stay-awake\n"
|
" -w, --stay-awake\n"
|
||||||
" Keep the device on while scrcpy is running, when the device\n"
|
" Keep the device on while scrcpy is running, when the device\n"
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
|||||||
buffer_write32be(&buf[17],
|
buffer_write32be(&buf[17],
|
||||||
(uint32_t) msg->inject_scroll_event.vscroll);
|
(uint32_t) msg->inject_scroll_event.vscroll);
|
||||||
return 21;
|
return 21;
|
||||||
|
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||||
|
buf[1] = msg->inject_keycode.action;
|
||||||
|
return 2;
|
||||||
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
||||||
buf[1] = !!msg->set_clipboard.paste;
|
buf[1] = !!msg->set_clipboard.paste;
|
||||||
size_t len = write_string(msg->set_clipboard.text,
|
size_t len = write_string(msg->set_clipboard.text,
|
||||||
@@ -77,9 +80,9 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
|||||||
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
||||||
buf[1] = msg->set_screen_power_mode.mode;
|
buf[1] = msg->set_screen_power_mode.mode;
|
||||||
return 2;
|
return 2;
|
||||||
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
|
||||||
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
|
case CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
||||||
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
||||||
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
||||||
// no additional data
|
// no additional data
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ enum control_msg_type {
|
|||||||
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||||
CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
|
CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
@@ -64,6 +65,10 @@ struct control_msg {
|
|||||||
int32_t hscroll;
|
int32_t hscroll;
|
||||||
int32_t vscroll;
|
int32_t vscroll;
|
||||||
} inject_scroll_event;
|
} inject_scroll_event;
|
||||||
|
struct {
|
||||||
|
enum android_keyevent_action action; // action for the BACK key
|
||||||
|
// screen may only be turned on on ACTION_DOWN
|
||||||
|
} back_or_screen_on;
|
||||||
struct {
|
struct {
|
||||||
char *text; // owned, to be freed by free()
|
char *text; // owned, to be freed by free()
|
||||||
bool paste;
|
bool paste;
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ input_manager_init(struct input_manager *im,
|
|||||||
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
im->sdl_shortcut_mods.count = shortcut_mods->count;
|
||||||
|
|
||||||
im->vfinger_down = false;
|
im->vfinger_down = false;
|
||||||
|
|
||||||
|
im->last_keycode = SDLK_UNKNOWN;
|
||||||
|
im->last_mod = 0;
|
||||||
|
im->key_repeat = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -146,13 +150,25 @@ action_cut(struct controller *controller, int actions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// turn the screen on if it was off, press BACK otherwise
|
// turn the screen on if it was off, press BACK otherwise
|
||||||
|
// If the screen is off, it is turned on only on ACTION_DOWN
|
||||||
static void
|
static void
|
||||||
press_back_or_turn_screen_on(struct controller *controller) {
|
press_back_or_turn_screen_on(struct controller *controller, int actions) {
|
||||||
struct control_msg msg;
|
struct control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (actions & ACTION_DOWN) {
|
||||||
LOGW("Could not request 'press back or turn screen on'");
|
msg.back_or_screen_on.action = AKEY_EVENT_ACTION_DOWN;
|
||||||
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
|
LOGW("Could not request 'press back or turn screen on'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions & ACTION_UP) {
|
||||||
|
msg.back_or_screen_on.action = AKEY_EVENT_ACTION_UP;
|
||||||
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
|
LOGW("Could not request 'press back or turn screen on'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +183,19 @@ expand_notification_panel(struct controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
collapse_notification_panel(struct controller *controller) {
|
expand_settings_panel(struct controller *controller) {
|
||||||
struct control_msg msg;
|
struct control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL;
|
msg.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
||||||
|
|
||||||
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
|
LOGW("Could not request 'expand settings panel'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collapse_panels(struct controller *controller) {
|
||||||
|
struct control_msg msg;
|
||||||
|
msg.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
||||||
|
|
||||||
if (!controller_push_msg(controller, &msg)) {
|
if (!controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'collapse notification panel'");
|
LOGW("Could not request 'collapse notification panel'");
|
||||||
@@ -372,16 +398,27 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
// control: indicates the state of the command-line option --no-control
|
// control: indicates the state of the command-line option --no-control
|
||||||
bool control = im->control;
|
bool control = im->control;
|
||||||
|
|
||||||
bool smod = is_shortcut_mod(im, event->keysym.mod);
|
|
||||||
|
|
||||||
struct controller *controller = im->controller;
|
struct controller *controller = im->controller;
|
||||||
|
|
||||||
SDL_Keycode keycode = event->keysym.sym;
|
SDL_Keycode keycode = event->keysym.sym;
|
||||||
|
uint16_t mod = event->keysym.mod;
|
||||||
bool down = event->type == SDL_KEYDOWN;
|
bool down = event->type == SDL_KEYDOWN;
|
||||||
bool ctrl = event->keysym.mod & KMOD_CTRL;
|
bool ctrl = event->keysym.mod & KMOD_CTRL;
|
||||||
bool shift = event->keysym.mod & KMOD_SHIFT;
|
bool shift = event->keysym.mod & KMOD_SHIFT;
|
||||||
bool repeat = event->repeat;
|
bool repeat = event->repeat;
|
||||||
|
|
||||||
|
bool smod = is_shortcut_mod(im, mod);
|
||||||
|
|
||||||
|
if (down && !repeat) {
|
||||||
|
if (keycode == im->last_keycode && mod == im->last_mod) {
|
||||||
|
++im->key_repeat;
|
||||||
|
} else {
|
||||||
|
im->key_repeat = 0;
|
||||||
|
im->last_keycode = keycode;
|
||||||
|
im->last_mod = mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The shortcut modifier is pressed
|
// The shortcut modifier is pressed
|
||||||
if (smod) {
|
if (smod) {
|
||||||
int action = down ? ACTION_DOWN : ACTION_UP;
|
int action = down ? ACTION_DOWN : ACTION_UP;
|
||||||
@@ -486,9 +523,11 @@ input_manager_process_key(struct input_manager *im,
|
|||||||
case SDLK_n:
|
case SDLK_n:
|
||||||
if (control && !repeat && down) {
|
if (control && !repeat && down) {
|
||||||
if (shift) {
|
if (shift) {
|
||||||
collapse_notification_panel(controller);
|
collapse_panels(controller);
|
||||||
} else {
|
} else if (im->key_repeat == 0) {
|
||||||
expand_notification_panel(controller);
|
expand_notification_panel(controller);
|
||||||
|
} else {
|
||||||
|
expand_settings_panel(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -646,13 +685,27 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool down = event->type == SDL_MOUSEBUTTONDOWN;
|
bool down = event->type == SDL_MOUSEBUTTONDOWN;
|
||||||
if (!im->forward_all_clicks && down) {
|
if (!im->forward_all_clicks) {
|
||||||
|
int action = down ? ACTION_DOWN : ACTION_UP;
|
||||||
|
|
||||||
|
if (control && event->button == SDL_BUTTON_X1) {
|
||||||
|
action_app_switch(im->controller, action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (control && event->button == SDL_BUTTON_X2 && down) {
|
||||||
|
if (event->clicks < 2) {
|
||||||
|
expand_notification_panel(im->controller);
|
||||||
|
} else {
|
||||||
|
expand_settings_panel(im->controller);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (control && event->button == SDL_BUTTON_RIGHT) {
|
if (control && event->button == SDL_BUTTON_RIGHT) {
|
||||||
press_back_or_turn_screen_on(im->controller);
|
press_back_or_turn_screen_on(im->controller, action);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (control && event->button == SDL_BUTTON_MIDDLE) {
|
if (control && event->button == SDL_BUTTON_MIDDLE) {
|
||||||
action_home(im->controller, ACTION_DOWN | ACTION_UP);
|
action_home(im->controller, action);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +718,9 @@ input_manager_process_mouse_button(struct input_manager *im,
|
|||||||
bool outside = x < r->x || x >= r->x + r->w
|
bool outside = x < r->x || x >= r->x + r->w
|
||||||
|| y < r->y || y >= r->y + r->h;
|
|| y < r->y || y >= r->y + r->h;
|
||||||
if (outside) {
|
if (outside) {
|
||||||
screen_resize_to_fit(im->screen);
|
if (down) {
|
||||||
|
screen_resize_to_fit(im->screen);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,13 @@ struct input_manager {
|
|||||||
} sdl_shortcut_mods;
|
} sdl_shortcut_mods;
|
||||||
|
|
||||||
bool vfinger_down;
|
bool vfinger_down;
|
||||||
|
|
||||||
|
// Tracks the number of identical consecutive shortcut key down events.
|
||||||
|
// Not to be confused with event->repeat, which counts the number of
|
||||||
|
// system-generated repeated key presses.
|
||||||
|
unsigned key_repeat;
|
||||||
|
SDL_Keycode last_keycode;
|
||||||
|
uint16_t last_mod;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -128,30 +128,6 @@ sdl_init_and_configure(bool display, const char *render_driver,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__WINDOWS__)
|
|
||||||
# define CONTINUOUS_RESIZING_WORKAROUND
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
|
||||||
// On Windows and MacOS, resizing blocks the event loop, so resizing events are
|
|
||||||
// not triggered. As a workaround, handle them in an event handler.
|
|
||||||
//
|
|
||||||
// <https://bugzilla.libsdl.org/show_bug.cgi?id=2077>
|
|
||||||
// <https://stackoverflow.com/a/40693139/1987178>
|
|
||||||
static int
|
|
||||||
event_watcher(void *data, SDL_Event *event) {
|
|
||||||
(void) data;
|
|
||||||
if (event->type == SDL_WINDOWEVENT
|
|
||||||
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
|
||||||
// In practice, it seems to always be called from the same thread in
|
|
||||||
// that specific case. Anyway, it's just a workaround.
|
|
||||||
screen_render(&screen, true);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_apk(const char *file) {
|
is_apk(const char *file) {
|
||||||
const char *ext = strrchr(file, '.');
|
const char *ext = strrchr(file, '.');
|
||||||
@@ -191,7 +167,7 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
|
|||||||
action = ACTION_PUSH_FILE;
|
action = ACTION_PUSH_FILE;
|
||||||
}
|
}
|
||||||
file_handler_request(&file_handler, action, file);
|
file_handler_request(&file_handler, action, file);
|
||||||
break;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,11 +185,6 @@ end:
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
event_loop(const struct scrcpy_options *options) {
|
event_loop(const struct scrcpy_options *options) {
|
||||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
|
||||||
if (options->display) {
|
|
||||||
SDL_AddEventWatch(event_watcher, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_WaitEvent(&event)) {
|
while (SDL_WaitEvent(&event)) {
|
||||||
enum event_result result = handle_event(&event, options);
|
enum event_result result = handle_event(&event, options);
|
||||||
@@ -394,6 +365,7 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
.window_borderless = options->window_borderless,
|
.window_borderless = options->window_borderless,
|
||||||
.rotation = options->rotation,
|
.rotation = options->rotation,
|
||||||
.mipmaps = options->mipmaps,
|
.mipmaps = options->mipmaps,
|
||||||
|
.fullscreen = options->fullscreen,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!screen_init(&screen, &video_buffer, &fps_counter,
|
if (!screen_init(&screen, &video_buffer, &fps_counter,
|
||||||
@@ -411,10 +383,6 @@ scrcpy(const struct scrcpy_options *options) {
|
|||||||
LOGW("Could not request 'set screen power mode'");
|
LOGW("Could not request 'set screen power mode'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->fullscreen) {
|
|
||||||
screen_switch_fullscreen(&screen);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we consumed the header values, the socket receives the video stream
|
// now we consumed the header values, the socket receives the video stream
|
||||||
|
|||||||
@@ -239,6 +239,29 @@ create_texture(struct screen *screen) {
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__WINDOWS__)
|
||||||
|
# define CONTINUOUS_RESIZING_WORKAROUND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||||
|
// On Windows and MacOS, resizing blocks the event loop, so resizing events are
|
||||||
|
// not triggered. As a workaround, handle them in an event handler.
|
||||||
|
//
|
||||||
|
// <https://bugzilla.libsdl.org/show_bug.cgi?id=2077>
|
||||||
|
// <https://stackoverflow.com/a/40693139/1987178>
|
||||||
|
static int
|
||||||
|
event_watcher(void *data, SDL_Event *event) {
|
||||||
|
struct screen *screen = data;
|
||||||
|
if (event->type == SDL_WINDOWEVENT
|
||||||
|
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
|
// In practice, it seems to always be called from the same thread in
|
||||||
|
// that specific case. Anyway, it's just a workaround.
|
||||||
|
screen_render(screen, true);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
screen_init(struct screen *screen, struct video_buffer *vb,
|
screen_init(struct screen *screen, struct video_buffer *vb,
|
||||||
struct fps_counter *fps_counter,
|
struct fps_counter *fps_counter,
|
||||||
@@ -362,10 +385,18 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
|||||||
|
|
||||||
screen_update_content_rect(screen);
|
screen_update_content_rect(screen);
|
||||||
|
|
||||||
|
if (params->fullscreen) {
|
||||||
|
screen_switch_fullscreen(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||||
|
SDL_AddEventWatch(event_watcher, screen);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
screen_show_window(struct screen *screen) {
|
screen_show_window(struct screen *screen) {
|
||||||
SDL_ShowWindow(screen->window);
|
SDL_ShowWindow(screen->window);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ struct screen_params {
|
|||||||
|
|
||||||
uint8_t rotation;
|
uint8_t rotation;
|
||||||
bool mipmaps;
|
bool mipmaps;
|
||||||
|
|
||||||
|
bool fullscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
// initialize screen, create window, renderer and texture (window is hidden)
|
// initialize screen, create window, renderer and texture (window is hidden)
|
||||||
@@ -60,10 +62,6 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
|||||||
struct fps_counter *fps_counter,
|
struct fps_counter *fps_counter,
|
||||||
const struct screen_params *params);
|
const struct screen_params *params);
|
||||||
|
|
||||||
// show the window
|
|
||||||
void
|
|
||||||
screen_show_window(struct screen *screen);
|
|
||||||
|
|
||||||
// destroy window, renderer and texture (if any)
|
// destroy window, renderer and texture (if any)
|
||||||
void
|
void
|
||||||
screen_destroy(struct screen *screen);
|
screen_destroy(struct screen *screen);
|
||||||
|
|||||||
@@ -146,14 +146,18 @@ static void test_serialize_inject_scroll_event(void) {
|
|||||||
static void test_serialize_back_or_screen_on(void) {
|
static void test_serialize_back_or_screen_on(void) {
|
||||||
struct control_msg msg = {
|
struct control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
|
.back_or_screen_on = {
|
||||||
|
.action = AKEY_EVENT_ACTION_UP,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = control_msg_serialize(&msg, buf);
|
size_t size = control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
|
0x01, // AKEY_EVENT_ACTION_UP
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
@@ -173,9 +177,9 @@ static void test_serialize_expand_notification_panel(void) {
|
|||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_collapse_notification_panel(void) {
|
static void test_serialize_expand_settings_panel(void) {
|
||||||
struct control_msg msg = {
|
struct control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL,
|
.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
@@ -183,7 +187,22 @@ static void test_serialize_collapse_notification_panel(void) {
|
|||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
|
};
|
||||||
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_serialize_collapse_panels(void) {
|
||||||
|
struct control_msg msg = {
|
||||||
|
.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
|
size_t size = control_msg_serialize(&msg, buf);
|
||||||
|
assert(size == 1);
|
||||||
|
|
||||||
|
const unsigned char expected[] = {
|
||||||
|
CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
@@ -270,7 +289,8 @@ int main(int argc, char *argv[]) {
|
|||||||
test_serialize_inject_scroll_event();
|
test_serialize_inject_scroll_event();
|
||||||
test_serialize_back_or_screen_on();
|
test_serialize_back_or_screen_on();
|
||||||
test_serialize_expand_notification_panel();
|
test_serialize_expand_notification_panel();
|
||||||
test_serialize_collapse_notification_panel();
|
test_serialize_expand_settings_panel();
|
||||||
|
test_serialize_collapse_panels();
|
||||||
test_serialize_get_clipboard();
|
test_serialize_get_clipboard();
|
||||||
test_serialize_set_clipboard();
|
test_serialize_set_clipboard();
|
||||||
test_serialize_set_screen_power_mode();
|
test_serialize_set_screen_power_mode();
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ public final class ControlMessage {
|
|||||||
public static final int TYPE_INJECT_SCROLL_EVENT = 3;
|
public static final int TYPE_INJECT_SCROLL_EVENT = 3;
|
||||||
public static final int TYPE_BACK_OR_SCREEN_ON = 4;
|
public static final int TYPE_BACK_OR_SCREEN_ON = 4;
|
||||||
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5;
|
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5;
|
||||||
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6;
|
public static final int TYPE_EXPAND_SETTINGS_PANEL = 6;
|
||||||
public static final int TYPE_GET_CLIPBOARD = 7;
|
public static final int TYPE_COLLAPSE_PANELS = 7;
|
||||||
public static final int TYPE_SET_CLIPBOARD = 8;
|
public static final int TYPE_GET_CLIPBOARD = 8;
|
||||||
public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
|
public static final int TYPE_SET_CLIPBOARD = 9;
|
||||||
public static final int TYPE_ROTATE_DEVICE = 10;
|
public static final int TYPE_SET_SCREEN_POWER_MODE = 10;
|
||||||
|
public static final int TYPE_ROTATE_DEVICE = 11;
|
||||||
|
|
||||||
private int type;
|
private int type;
|
||||||
private String text;
|
private String text;
|
||||||
@@ -71,6 +72,13 @@ public final class ControlMessage {
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ControlMessage createBackOrScreenOn(int action) {
|
||||||
|
ControlMessage msg = new ControlMessage();
|
||||||
|
msg.type = TYPE_BACK_OR_SCREEN_ON;
|
||||||
|
msg.action = action;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
public static ControlMessage createSetClipboard(String text, boolean paste) {
|
public static ControlMessage createSetClipboard(String text, boolean paste) {
|
||||||
ControlMessage msg = new ControlMessage();
|
ControlMessage msg = new ControlMessage();
|
||||||
msg.type = TYPE_SET_CLIPBOARD;
|
msg.type = TYPE_SET_CLIPBOARD;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class ControlMessageReader {
|
|||||||
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
|
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
|
||||||
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
||||||
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
||||||
|
static final int BACK_OR_SCREEN_ON_LENGTH = 1;
|
||||||
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
||||||
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
|
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
|
||||||
|
|
||||||
@@ -66,15 +67,18 @@ public class ControlMessageReader {
|
|||||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||||
msg = parseInjectScrollEvent();
|
msg = parseInjectScrollEvent();
|
||||||
break;
|
break;
|
||||||
|
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||||
|
msg = parseBackOrScreenOnEvent();
|
||||||
|
break;
|
||||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||||
msg = parseSetClipboard();
|
msg = parseSetClipboard();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||||
msg = parseSetScreenPowerMode();
|
msg = parseSetScreenPowerMode();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
|
||||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
|
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
||||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||||
msg = ControlMessage.createEmpty(type);
|
msg = ControlMessage.createEmpty(type);
|
||||||
@@ -150,6 +154,14 @@ public class ControlMessageReader {
|
|||||||
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll);
|
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ControlMessage parseBackOrScreenOnEvent() {
|
||||||
|
if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int action = toUnsigned(buffer.get());
|
||||||
|
return ControlMessage.createBackOrScreenOn(action);
|
||||||
|
}
|
||||||
|
|
||||||
private ControlMessage parseSetClipboard() {
|
private ControlMessage parseSetClipboard() {
|
||||||
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -101,13 +101,16 @@ public class Controller {
|
|||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||||
if (device.supportsInputEvents()) {
|
if (device.supportsInputEvents()) {
|
||||||
pressBackOrTurnScreenOn();
|
pressBackOrTurnScreenOn(msg.getAction());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
Device.expandNotificationPanel();
|
Device.expandNotificationPanel();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
|
Device.expandSettingsPanel();
|
||||||
|
break;
|
||||||
|
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
||||||
Device.collapsePanels();
|
Device.collapsePanels();
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||||
@@ -255,12 +258,22 @@ public class Controller {
|
|||||||
}, 200, TimeUnit.MILLISECONDS);
|
}, 200, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean pressBackOrTurnScreenOn() {
|
private boolean pressBackOrTurnScreenOn(int action) {
|
||||||
int keycode = Device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER;
|
if (Device.isScreenOn()) {
|
||||||
if (keepPowerModeOff && keycode == KeyEvent.KEYCODE_POWER) {
|
return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Screen is off
|
||||||
|
// Only press POWER on ACTION_DOWN
|
||||||
|
if (action != KeyEvent.ACTION_DOWN) {
|
||||||
|
// do nothing,
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keepPowerModeOff) {
|
||||||
schedulePowerModeOff();
|
schedulePowerModeOff();
|
||||||
}
|
}
|
||||||
return device.injectKeycode(keycode);
|
return device.injectKeycode(KeyEvent.KEYCODE_POWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setClipboard(String text, boolean paste) {
|
private boolean setClipboard(String text, boolean paste) {
|
||||||
|
|||||||
@@ -227,6 +227,10 @@ public final class Device {
|
|||||||
SERVICE_MANAGER.getStatusBarManager().expandNotificationsPanel();
|
SERVICE_MANAGER.getStatusBarManager().expandNotificationsPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void expandSettingsPanel() {
|
||||||
|
SERVICE_MANAGER.getStatusBarManager().expandSettingsPanel();
|
||||||
|
}
|
||||||
|
|
||||||
public static void collapsePanels() {
|
public static void collapsePanels() {
|
||||||
SERVICE_MANAGER.getStatusBarManager().collapsePanels();
|
SERVICE_MANAGER.getStatusBarManager().collapsePanels();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public class StatusBarManager {
|
|||||||
|
|
||||||
private final IInterface manager;
|
private final IInterface manager;
|
||||||
private Method expandNotificationsPanelMethod;
|
private Method expandNotificationsPanelMethod;
|
||||||
|
private Method expandSettingsPanelMethod;
|
||||||
|
private boolean expandSettingsPanelMethodLegacy;
|
||||||
private Method collapsePanelsMethod;
|
private Method collapsePanelsMethod;
|
||||||
|
|
||||||
public StatusBarManager(IInterface manager) {
|
public StatusBarManager(IInterface manager) {
|
||||||
@@ -24,6 +26,20 @@ public class StatusBarManager {
|
|||||||
return expandNotificationsPanelMethod;
|
return expandNotificationsPanelMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Method getExpandSettingsPanel() throws NoSuchMethodException {
|
||||||
|
if (expandSettingsPanelMethod == null) {
|
||||||
|
try {
|
||||||
|
// Since Android 7: https://android.googlesource.com/platform/frameworks/base.git/+/a9927325eda025504d59bb6594fee8e240d95b01%5E%21/
|
||||||
|
expandSettingsPanelMethod = manager.getClass().getMethod("expandSettingsPanel", String.class);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// old version
|
||||||
|
expandSettingsPanelMethod = manager.getClass().getMethod("expandSettingsPanel");
|
||||||
|
expandSettingsPanelMethodLegacy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expandSettingsPanelMethod;
|
||||||
|
}
|
||||||
|
|
||||||
private Method getCollapsePanelsMethod() throws NoSuchMethodException {
|
private Method getCollapsePanelsMethod() throws NoSuchMethodException {
|
||||||
if (collapsePanelsMethod == null) {
|
if (collapsePanelsMethod == null) {
|
||||||
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
|
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
|
||||||
@@ -40,6 +56,21 @@ public class StatusBarManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void expandSettingsPanel() {
|
||||||
|
try {
|
||||||
|
Method method = getExpandSettingsPanel();
|
||||||
|
if (!expandSettingsPanelMethodLegacy) {
|
||||||
|
// new version
|
||||||
|
method.invoke(manager, (Object) null);
|
||||||
|
} else {
|
||||||
|
// old version
|
||||||
|
method.invoke(manager);
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
|
Ln.e("Could not invoke method", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void collapsePanels() {
|
public void collapsePanels() {
|
||||||
try {
|
try {
|
||||||
Method method = getCollapsePanelsMethod();
|
Method method = getCollapsePanelsMethod();
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ public class ControlMessageReaderTest {
|
|||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream dos = new DataOutputStream(bos);
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON);
|
dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON);
|
||||||
|
dos.writeByte(KeyEvent.ACTION_UP);
|
||||||
|
|
||||||
byte[] packet = bos.toByteArray();
|
byte[] packet = bos.toByteArray();
|
||||||
|
|
||||||
@@ -161,6 +162,7 @@ public class ControlMessageReaderTest {
|
|||||||
ControlMessage event = reader.next();
|
ControlMessage event = reader.next();
|
||||||
|
|
||||||
Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType());
|
Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType());
|
||||||
|
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -180,19 +182,35 @@ public class ControlMessageReaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCollapseNotificationPanelEvent() throws IOException {
|
public void testParseExpandSettingsPanelEvent() throws IOException {
|
||||||
ControlMessageReader reader = new ControlMessageReader();
|
ControlMessageReader reader = new ControlMessageReader();
|
||||||
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream dos = new DataOutputStream(bos);
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
dos.writeByte(ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL);
|
dos.writeByte(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL);
|
||||||
|
|
||||||
byte[] packet = bos.toByteArray();
|
byte[] packet = bos.toByteArray();
|
||||||
|
|
||||||
reader.readFrom(new ByteArrayInputStream(packet));
|
reader.readFrom(new ByteArrayInputStream(packet));
|
||||||
ControlMessage event = reader.next();
|
ControlMessage event = reader.next();
|
||||||
|
|
||||||
Assert.assertEquals(ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL, event.getType());
|
Assert.assertEquals(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL, event.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseCollapsePanelsEvent() throws IOException {
|
||||||
|
ControlMessageReader reader = new ControlMessageReader();
|
||||||
|
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
|
dos.writeByte(ControlMessage.TYPE_COLLAPSE_PANELS);
|
||||||
|
|
||||||
|
byte[] packet = bos.toByteArray();
|
||||||
|
|
||||||
|
reader.readFrom(new ByteArrayInputStream(packet));
|
||||||
|
ControlMessage event = reader.next();
|
||||||
|
|
||||||
|
Assert.assertEquals(ControlMessage.TYPE_COLLAPSE_PANELS, event.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user