Compare commits
8 Commits
traits
...
mouse_butt
Author | SHA1 | Date | |
---|---|---|---|
75ce0b5c3f | |||
5c65f3c170 | |||
f0f96fbc3d | |||
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).
|
||||
|
||||
.TP
|
||||
.B \-v, \-\-version
|
||||
Print the version of scrcpy.
|
||||
|
||||
.TP
|
||||
.BI "\-V, \-\-verbosity " value
|
||||
Set the log level ("debug", "info", "warn" or "error").
|
||||
|
||||
Default is "info" for release builds, "debug" for debug builds.
|
||||
|
||||
.TP
|
||||
.B \-v, \-\-version
|
||||
Print the version of scrcpy.
|
||||
|
||||
.TP
|
||||
.B \-w, \-\-stay-awake
|
||||
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"
|
||||
" It only shows physical touches (not clicks from scrcpy).\n"
|
||||
"\n"
|
||||
" -v, --version\n"
|
||||
" Print the version of scrcpy.\n"
|
||||
"\n"
|
||||
" -V, --verbosity value\n"
|
||||
" Set the log level (debug, info, warn or error).\n"
|
||||
#ifndef NDEBUG
|
||||
@ -189,6 +186,9 @@ scrcpy_print_usage(const char *arg0) {
|
||||
#else
|
||||
" Default is info.\n"
|
||||
#endif
|
||||
"\n"
|
||||
" -v, --version\n"
|
||||
" Print the version of scrcpy.\n"
|
||||
"\n"
|
||||
" -w, --stay-awake\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],
|
||||
(uint32_t) msg->inject_scroll_event.vscroll);
|
||||
return 21;
|
||||
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||
buf[1] = msg->inject_keycode.action;
|
||||
return 2;
|
||||
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
||||
buf[1] = !!msg->set_clipboard.paste;
|
||||
size_t len = write_string(msg->set_clipboard.text,
|
||||
@ -77,7 +80,6 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
||||
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
||||
buf[1] = msg->set_screen_power_mode.mode;
|
||||
return 2;
|
||||
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
||||
|
@ -64,6 +64,10 @@ struct control_msg {
|
||||
int32_t hscroll;
|
||||
int32_t vscroll;
|
||||
} 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 {
|
||||
char *text; // owned, to be freed by free()
|
||||
bool paste;
|
||||
|
@ -146,13 +146,25 @@ action_cut(struct controller *controller, int actions) {
|
||||
}
|
||||
|
||||
// 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
|
||||
press_back_or_turn_screen_on(struct controller *controller) {
|
||||
press_back_or_turn_screen_on(struct controller *controller, int actions) {
|
||||
struct control_msg msg;
|
||||
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
||||
|
||||
if (!controller_push_msg(controller, &msg)) {
|
||||
LOGW("Could not request 'press back or turn screen on'");
|
||||
if (actions & ACTION_DOWN) {
|
||||
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'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -646,13 +658,15 @@ input_manager_process_mouse_button(struct input_manager *im,
|
||||
}
|
||||
|
||||
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_RIGHT) {
|
||||
press_back_or_turn_screen_on(im->controller);
|
||||
press_back_or_turn_screen_on(im->controller, action);
|
||||
return;
|
||||
}
|
||||
if (control && event->button == SDL_BUTTON_MIDDLE) {
|
||||
action_home(im->controller, ACTION_DOWN | ACTION_UP);
|
||||
action_home(im->controller, action);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -665,7 +679,9 @@ input_manager_process_mouse_button(struct input_manager *im,
|
||||
bool outside = x < r->x || x >= r->x + r->w
|
||||
|| y < r->y || y >= r->y + r->h;
|
||||
if (outside) {
|
||||
screen_resize_to_fit(im->screen);
|
||||
if (down) {
|
||||
screen_resize_to_fit(im->screen);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -128,30 +128,6 @@ sdl_init_and_configure(bool display, const char *render_driver,
|
||||
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
|
||||
is_apk(const char *file) {
|
||||
const char *ext = strrchr(file, '.');
|
||||
@ -191,7 +167,7 @@ handle_event(SDL_Event *event, const struct scrcpy_options *options) {
|
||||
action = ACTION_PUSH_FILE;
|
||||
}
|
||||
file_handler_request(&file_handler, action, file);
|
||||
break;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,11 +185,6 @@ end:
|
||||
|
||||
static bool
|
||||
event_loop(const struct scrcpy_options *options) {
|
||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||
if (options->display) {
|
||||
SDL_AddEventWatch(event_watcher, NULL);
|
||||
}
|
||||
#endif
|
||||
SDL_Event event;
|
||||
while (SDL_WaitEvent(&event)) {
|
||||
enum event_result result = handle_event(&event, options);
|
||||
@ -394,6 +365,7 @@ scrcpy(const struct scrcpy_options *options) {
|
||||
.window_borderless = options->window_borderless,
|
||||
.rotation = options->rotation,
|
||||
.mipmaps = options->mipmaps,
|
||||
.fullscreen = options->fullscreen,
|
||||
};
|
||||
|
||||
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'");
|
||||
}
|
||||
}
|
||||
|
||||
if (options->fullscreen) {
|
||||
screen_switch_fullscreen(&screen);
|
||||
}
|
||||
}
|
||||
|
||||
// now we consumed the header values, the socket receives the video stream
|
||||
|
@ -239,6 +239,29 @@ create_texture(struct screen *screen) {
|
||||
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
|
||||
screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
struct fps_counter *fps_counter,
|
||||
@ -362,10 +385,18 @@ screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
|
||||
screen_update_content_rect(screen);
|
||||
|
||||
if (params->fullscreen) {
|
||||
screen_switch_fullscreen(screen);
|
||||
}
|
||||
|
||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||
SDL_AddEventWatch(event_watcher, screen);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
screen_show_window(struct screen *screen) {
|
||||
SDL_ShowWindow(screen->window);
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ struct screen_params {
|
||||
|
||||
uint8_t rotation;
|
||||
bool mipmaps;
|
||||
|
||||
bool fullscreen;
|
||||
};
|
||||
|
||||
// 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,
|
||||
const struct screen_params *params);
|
||||
|
||||
// show the window
|
||||
void
|
||||
screen_show_window(struct screen *screen);
|
||||
|
||||
// destroy window, renderer and texture (if any)
|
||||
void
|
||||
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) {
|
||||
struct control_msg msg = {
|
||||
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||
.back_or_screen_on = {
|
||||
.action = AKEY_EVENT_ACTION_UP,
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = control_msg_serialize(&msg, buf);
|
||||
assert(size == 1);
|
||||
assert(size == 2);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||
0x01, // AKEY_EVENT_ACTION_UP
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
|
@ -71,6 +71,13 @@ public final class ControlMessage {
|
||||
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) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_SET_CLIPBOARD;
|
||||
|
@ -11,6 +11,7 @@ public class ControlMessageReader {
|
||||
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
|
||||
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
||||
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_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
|
||||
|
||||
@ -66,13 +67,15 @@ public class ControlMessageReader {
|
||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||
msg = parseInjectScrollEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
msg = parseBackOrScreenOnEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||
msg = parseSetClipboard();
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||
msg = parseSetScreenPowerMode();
|
||||
break;
|
||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||
@ -150,6 +153,14 @@ public class ControlMessageReader {
|
||||
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() {
|
||||
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
|
@ -101,7 +101,7 @@ public class Controller {
|
||||
break;
|
||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
if (device.supportsInputEvents()) {
|
||||
pressBackOrTurnScreenOn();
|
||||
pressBackOrTurnScreenOn(msg.getAction());
|
||||
}
|
||||
break;
|
||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
@ -255,12 +255,22 @@ public class Controller {
|
||||
}, 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private boolean pressBackOrTurnScreenOn() {
|
||||
int keycode = Device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER;
|
||||
if (keepPowerModeOff && keycode == KeyEvent.KEYCODE_POWER) {
|
||||
private boolean pressBackOrTurnScreenOn(int action) {
|
||||
if (Device.isScreenOn()) {
|
||||
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();
|
||||
}
|
||||
return device.injectKeycode(keycode);
|
||||
return device.injectKeycode(KeyEvent.KEYCODE_POWER);
|
||||
}
|
||||
|
||||
private boolean setClipboard(String text, boolean paste) {
|
||||
|
@ -154,6 +154,7 @@ public class ControlMessageReaderTest {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON);
|
||||
dos.writeByte(KeyEvent.ACTION_UP);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
@ -161,6 +162,7 @@ public class ControlMessageReaderTest {
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType());
|
||||
Assert.assertEquals(KeyEvent.ACTION_DOWN, event.getAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Reference in New Issue
Block a user