Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93ac6a347e |
@@ -248,15 +248,8 @@ Caused by: java.lang.IllegalArgumentException: displayToken must not be null
|
|||||||
|
|
||||||
## Command line on Windows
|
## Command line on Windows
|
||||||
|
|
||||||
Since v1.22, a "shortcut" has been added to directly open a terminal in the
|
Some Windows users are not familiar with the command line. Here is how to open a
|
||||||
scrcpy directory. Double-click on `open_a_terminal_here.bat`, then type your
|
terminal and run `scrcpy` with arguments:
|
||||||
command. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
scrcpy --record file.mkv
|
|
||||||
```
|
|
||||||
|
|
||||||
You could also open a terminal and go to the scrcpy folder manually:
|
|
||||||
|
|
||||||
1. Press <kbd>Windows</kbd>+<kbd>r</kbd>, this opens a dialog box.
|
1. Press <kbd>Windows</kbd>+<kbd>r</kbd>, this opens a dialog box.
|
||||||
2. Type `cmd` and press <kbd>Enter</kbd>, this opens a terminal.
|
2. Type `cmd` and press <kbd>Enter</kbd>, this opens a terminal.
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
<img src="data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
<img src="data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||||
|
|
||||||
_pronounced "**scr**een **c**o**py**"_
|
|
||||||
|
|
||||||
[Read in another language](#translations)
|
[Read in another language](#translations)
|
||||||
|
|
||||||
This application provides display and control of Android devices connected via
|
This application provides display and control of Android devices connected via
|
||||||
@@ -35,7 +33,6 @@ Its features include:
|
|||||||
(Linux-only)
|
(Linux-only)
|
||||||
- [physical mouse simulation (HID)](#physical-mouse-simulation-hid)
|
- [physical mouse simulation (HID)](#physical-mouse-simulation-hid)
|
||||||
(Linux-only)
|
(Linux-only)
|
||||||
- [OTG mode](#otg) (Linux-only)
|
|
||||||
- and more…
|
- and more…
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
@@ -850,36 +847,6 @@ Special capture keys, either <kbd>Alt</kbd> or <kbd>Super</kbd>, toggle
|
|||||||
the mouse back to the computer.
|
the mouse back to the computer.
|
||||||
|
|
||||||
|
|
||||||
#### OTG
|
|
||||||
|
|
||||||
It is possible to run _scrcpy_ with only physical keyboard and mouse simulation
|
|
||||||
(HID), as if the computer keyboard and mouse were plugged directly to the device
|
|
||||||
via an OTG cable.
|
|
||||||
|
|
||||||
In this mode, _adb_ (USB debugging) is not necessary, and mirroring is disabled.
|
|
||||||
|
|
||||||
To enable OTG mode:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --otg
|
|
||||||
# Pass the serial if several USB devices are available
|
|
||||||
scrcpy --otg -s 0123456789abcdef
|
|
||||||
```
|
|
||||||
|
|
||||||
It is possible to enable only HID keyboard or HID mouse:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scrcpy --otg --hid-keyboard # keyboard only
|
|
||||||
scrcpy --otg --hid-mouse # mouse only
|
|
||||||
scrcpy --otg --hid-keyboard --hid-mouse # keyboard and mouse
|
|
||||||
# for convenience, enable both by default
|
|
||||||
scrcpy --otg # keyboard and mouse
|
|
||||||
```
|
|
||||||
|
|
||||||
Like `--hid-keyboard` and `--hid-mouse`, it only works if the device is
|
|
||||||
connected by USB, and is currently only supported on Linux.
|
|
||||||
|
|
||||||
|
|
||||||
#### Text injection preference
|
#### Text injection preference
|
||||||
|
|
||||||
There are two kinds of [events][textevents] generated when typing text:
|
There are two kinds of [events][textevents] generated when typing text:
|
||||||
|
|||||||
+7
-10
@@ -72,15 +72,12 @@ if v4l2_support
|
|||||||
src += [ 'src/v4l2_sink.c' ]
|
src += [ 'src/v4l2_sink.c' ]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
usb_support = host_machine.system() == 'linux'
|
aoa_hid_support = host_machine.system() == 'linux'
|
||||||
if usb_support
|
if aoa_hid_support
|
||||||
src += [
|
src += [
|
||||||
'src/usb/aoa_hid.c',
|
'src/aoa_hid.c',
|
||||||
'src/usb/hid_keyboard.c',
|
'src/hid_keyboard.c',
|
||||||
'src/usb/hid_mouse.c',
|
'src/hid_mouse.c',
|
||||||
'src/usb/scrcpy_otg.c',
|
|
||||||
'src/usb/screen_otg.c',
|
|
||||||
'src/usb/usb.c',
|
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -102,7 +99,7 @@ if not crossbuild_windows
|
|||||||
dependencies += dependency('libavdevice')
|
dependencies += dependency('libavdevice')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if usb_support
|
if aoa_hid_support
|
||||||
dependencies += dependency('libusb-1.0')
|
dependencies += dependency('libusb-1.0')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -196,7 +193,7 @@ conf.set('SERVER_DEBUGGER_METHOD_NEW', get_option('server_debugger_method') == '
|
|||||||
conf.set('HAVE_V4L2', v4l2_support)
|
conf.set('HAVE_V4L2', v4l2_support)
|
||||||
|
|
||||||
# enable HID over AOA support (linux only)
|
# enable HID over AOA support (linux only)
|
||||||
conf.set('HAVE_USB', usb_support)
|
conf.set('HAVE_AOA_HID', aoa_hid_support)
|
||||||
|
|
||||||
configure_file(configuration: conf, output: 'config.h')
|
configure_file(configuration: conf, output: 'config.h')
|
||||||
|
|
||||||
|
|||||||
@@ -162,20 +162,6 @@ Do not forward repeated key events when a key is held down.
|
|||||||
.B \-\-no\-mipmaps
|
.B \-\-no\-mipmaps
|
||||||
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.
|
If the renderer is OpenGL 3.0+ or OpenGL ES 2.0+, then mipmaps are automatically generated to improve downscaling quality. This option disables the generation of mipmaps.
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-otg
|
|
||||||
Run in OTG mode: simulate physical keyboard and mouse, as if the computer keyboard and mouse were plugged directly to the device via an OTG cable.
|
|
||||||
|
|
||||||
In this mode, adb (USB debugging) is not necessary, and mirroring is disabled.
|
|
||||||
|
|
||||||
LAlt, LSuper or RSuper toggle the mouse capture mode, to give control of the mouse back to the computer.
|
|
||||||
|
|
||||||
If any of \fB\-\-hid\-keyboard\fR or \fB\-\-hid\-mouse\fR is set, only enable keyboard or mouse respectively, otherwise enable both.
|
|
||||||
|
|
||||||
It may only work over USB, and is currently only supported on Linux.
|
|
||||||
|
|
||||||
See \fB\-\-hid\-keyboard\fR and \fB\-\-hid\-mouse\fR.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-p, \-\-port " port[:port]
|
.BI "\-p, \-\-port " port[:port]
|
||||||
Set the TCP port (range) used by the client to listen.
|
Set the TCP port (range) used by the client to listen.
|
||||||
|
|||||||
+2
-2
@@ -425,7 +425,7 @@ adb_get_serialno(struct sc_intr *intr, unsigned flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_str_truncate(buf, r, " \r\n");
|
sc_str_truncate(buf, r, " \r\n");
|
||||||
@@ -455,7 +455,7 @@ adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((size_t) r <= sizeof(buf));
|
assert((size_t) r <= sizeof(buf));
|
||||||
|
|||||||
@@ -50,9 +50,79 @@ log_libusb_error(enum libusb_error errcode) {
|
|||||||
LOGW("libusb error: %s", libusb_strerror(errcode));
|
LOGW("libusb error: %s", libusb_strerror(errcode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
accept_device(libusb_device *device, const char *serial) {
|
||||||
|
// do not log any USB error in this function, it is expected that many USB
|
||||||
|
// devices available on the computer have permission restrictions
|
||||||
|
|
||||||
|
struct libusb_device_descriptor desc;
|
||||||
|
int result = libusb_get_device_descriptor(device, &desc);
|
||||||
|
if (result < 0 || !desc.iSerialNumber) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device_handle *handle;
|
||||||
|
result = libusb_open(device, &handle);
|
||||||
|
if (result < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[128];
|
||||||
|
result = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
|
||||||
|
(unsigned char *) buffer,
|
||||||
|
sizeof(buffer));
|
||||||
|
libusb_close(handle);
|
||||||
|
if (result < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0'; // just in case
|
||||||
|
|
||||||
|
// accept the device if its serial matches
|
||||||
|
return !strcmp(buffer, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
static libusb_device *
|
||||||
|
sc_aoa_find_usb_device(const char *serial) {
|
||||||
|
if (!serial) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device **list;
|
||||||
|
libusb_device *result = NULL;
|
||||||
|
ssize_t count = libusb_get_device_list(NULL, &list);
|
||||||
|
if (count < 0) {
|
||||||
|
log_libusb_error((enum libusb_error) count);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (size_t) count; ++i) {
|
||||||
|
libusb_device *device = list[i];
|
||||||
|
|
||||||
|
if (accept_device(device, serial)) {
|
||||||
|
result = libusb_ref_device(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_device_list(list, 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sc_aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle) {
|
||||||
|
int result = libusb_open(device, handle);
|
||||||
|
if (result < 0) {
|
||||||
|
log_libusb_error((enum libusb_error) result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_aoa_init(struct sc_aoa *aoa, struct sc_usb *usb,
|
sc_aoa_init(struct sc_aoa *aoa, const char *serial,
|
||||||
struct sc_acksync *acksync) {
|
struct sc_acksync *acksync) {
|
||||||
|
assert(acksync);
|
||||||
|
|
||||||
cbuf_init(&aoa->queue);
|
cbuf_init(&aoa->queue);
|
||||||
|
|
||||||
if (!sc_mutex_init(&aoa->mutex)) {
|
if (!sc_mutex_init(&aoa->mutex)) {
|
||||||
@@ -60,15 +130,39 @@ sc_aoa_init(struct sc_aoa *aoa, struct sc_usb *usb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!sc_cond_init(&aoa->event_cond)) {
|
if (!sc_cond_init(&aoa->event_cond)) {
|
||||||
sc_mutex_destroy(&aoa->mutex);
|
goto error_destroy_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (libusb_init(&aoa->usb_context) != LIBUSB_SUCCESS) {
|
||||||
|
goto error_destroy_cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
aoa->usb_device = sc_aoa_find_usb_device(serial);
|
||||||
|
if (!aoa->usb_device) {
|
||||||
|
LOGW("USB device of serial %s not found", serial);
|
||||||
|
goto error_exit_libusb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc_aoa_open_usb_handle(aoa->usb_device, &aoa->usb_handle) < 0) {
|
||||||
|
LOGW("Open USB handle failed");
|
||||||
|
goto error_unref_device;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
aoa->stopped = false;
|
aoa->stopped = false;
|
||||||
aoa->acksync = acksync;
|
aoa->acksync = acksync;
|
||||||
aoa->usb = usb;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error_unref_device:
|
||||||
|
libusb_unref_device(aoa->usb_device);
|
||||||
|
error_exit_libusb:
|
||||||
|
libusb_exit(aoa->usb_context);
|
||||||
|
error_destroy_cond:
|
||||||
|
sc_cond_destroy(&aoa->event_cond);
|
||||||
|
error_destroy_mutex:
|
||||||
|
sc_mutex_destroy(&aoa->mutex);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -79,6 +173,9 @@ sc_aoa_destroy(struct sc_aoa *aoa) {
|
|||||||
sc_hid_event_destroy(&event);
|
sc_hid_event_destroy(&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libusb_close(aoa->usb_handle);
|
||||||
|
libusb_unref_device(aoa->usb_device);
|
||||||
|
libusb_exit(aoa->usb_context);
|
||||||
sc_cond_destroy(&aoa->event_cond);
|
sc_cond_destroy(&aoa->event_cond);
|
||||||
sc_mutex_destroy(&aoa->mutex);
|
sc_mutex_destroy(&aoa->mutex);
|
||||||
}
|
}
|
||||||
@@ -95,8 +192,8 @@ sc_aoa_register_hid(struct sc_aoa *aoa, uint16_t accessory_id,
|
|||||||
uint16_t index = report_desc_size;
|
uint16_t index = report_desc_size;
|
||||||
unsigned char *buffer = NULL;
|
unsigned char *buffer = NULL;
|
||||||
uint16_t length = 0;
|
uint16_t length = 0;
|
||||||
int result = libusb_control_transfer(aoa->usb->handle, request_type,
|
int result = libusb_control_transfer(aoa->usb_handle, request_type, request,
|
||||||
request, value, index, buffer, length,
|
value, index, buffer, length,
|
||||||
DEFAULT_TIMEOUT);
|
DEFAULT_TIMEOUT);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
log_libusb_error((enum libusb_error) result);
|
log_libusb_error((enum libusb_error) result);
|
||||||
@@ -131,8 +228,8 @@ sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
|
|||||||
// libusb_control_transfer expects a pointer to non-const
|
// libusb_control_transfer expects a pointer to non-const
|
||||||
unsigned char *buffer = (unsigned char *) report_desc;
|
unsigned char *buffer = (unsigned char *) report_desc;
|
||||||
uint16_t length = report_desc_size;
|
uint16_t length = report_desc_size;
|
||||||
int result = libusb_control_transfer(aoa->usb->handle, request_type,
|
int result = libusb_control_transfer(aoa->usb_handle, request_type, request,
|
||||||
request, value, index, buffer, length,
|
value, index, buffer, length,
|
||||||
DEFAULT_TIMEOUT);
|
DEFAULT_TIMEOUT);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
log_libusb_error((enum libusb_error) result);
|
log_libusb_error((enum libusb_error) result);
|
||||||
@@ -173,8 +270,8 @@ sc_aoa_send_hid_event(struct sc_aoa *aoa, const struct sc_hid_event *event) {
|
|||||||
uint16_t index = 0;
|
uint16_t index = 0;
|
||||||
unsigned char *buffer = event->buffer;
|
unsigned char *buffer = event->buffer;
|
||||||
uint16_t length = event->size;
|
uint16_t length = event->size;
|
||||||
int result = libusb_control_transfer(aoa->usb->handle, request_type,
|
int result = libusb_control_transfer(aoa->usb_handle, request_type, request,
|
||||||
request, value, index, buffer, length,
|
value, index, buffer, length,
|
||||||
DEFAULT_TIMEOUT);
|
DEFAULT_TIMEOUT);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
log_libusb_error((enum libusb_error) result);
|
log_libusb_error((enum libusb_error) result);
|
||||||
@@ -195,8 +292,8 @@ sc_aoa_unregister_hid(struct sc_aoa *aoa, const uint16_t accessory_id) {
|
|||||||
uint16_t index = 0;
|
uint16_t index = 0;
|
||||||
unsigned char *buffer = NULL;
|
unsigned char *buffer = NULL;
|
||||||
uint16_t length = 0;
|
uint16_t length = 0;
|
||||||
int result = libusb_control_transfer(aoa->usb->handle, request_type,
|
int result = libusb_control_transfer(aoa->usb_handle, request_type, request,
|
||||||
request, value, index, buffer, length,
|
value, index, buffer, length,
|
||||||
DEFAULT_TIMEOUT);
|
DEFAULT_TIMEOUT);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
log_libusb_error((enum libusb_error) result);
|
log_libusb_error((enum libusb_error) result);
|
||||||
@@ -246,11 +343,6 @@ run_aoa_thread(void *data) {
|
|||||||
|
|
||||||
if (ack_to_wait != SC_SEQUENCE_INVALID) {
|
if (ack_to_wait != SC_SEQUENCE_INVALID) {
|
||||||
LOGD("Waiting ack from server sequence=%" PRIu64_, ack_to_wait);
|
LOGD("Waiting ack from server sequence=%" PRIu64_, ack_to_wait);
|
||||||
|
|
||||||
// If some events have ack_to_wait set, then sc_aoa must have been
|
|
||||||
// initialized with a non NULL acksync
|
|
||||||
assert(aoa->acksync);
|
|
||||||
|
|
||||||
// Do not block the loop indefinitely if the ack never comes (it
|
// Do not block the loop indefinitely if the ack never comes (it
|
||||||
// should never happen)
|
// should never happen)
|
||||||
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_MS(500);
|
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_MS(500);
|
||||||
@@ -297,9 +389,7 @@ sc_aoa_stop(struct sc_aoa *aoa) {
|
|||||||
sc_cond_signal(&aoa->event_cond);
|
sc_cond_signal(&aoa->event_cond);
|
||||||
sc_mutex_unlock(&aoa->mutex);
|
sc_mutex_unlock(&aoa->mutex);
|
||||||
|
|
||||||
if (aoa->acksync) {
|
sc_acksync_interrupt(aoa->acksync);
|
||||||
sc_acksync_interrupt(aoa->acksync);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include <libusb-1.0/libusb.h>
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
#include "usb.h"
|
|
||||||
#include "util/acksync.h"
|
#include "util/acksync.h"
|
||||||
#include "util/cbuf.h"
|
#include "util/cbuf.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
@@ -30,7 +29,9 @@ sc_hid_event_destroy(struct sc_hid_event *hid_event);
|
|||||||
struct sc_hid_event_queue CBUF(struct sc_hid_event, 64);
|
struct sc_hid_event_queue CBUF(struct sc_hid_event, 64);
|
||||||
|
|
||||||
struct sc_aoa {
|
struct sc_aoa {
|
||||||
struct sc_usb *usb;
|
libusb_context *usb_context;
|
||||||
|
libusb_device *usb_device;
|
||||||
|
libusb_device_handle *usb_handle;
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
sc_mutex mutex;
|
sc_mutex mutex;
|
||||||
sc_cond event_cond;
|
sc_cond event_cond;
|
||||||
@@ -41,7 +42,7 @@ struct sc_aoa {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_aoa_init(struct sc_aoa *aoa, struct sc_usb *usb, struct sc_acksync *acksync);
|
sc_aoa_init(struct sc_aoa *aoa, const char *serial, struct sc_acksync *acksync);
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_aoa_destroy(struct sc_aoa *aoa);
|
sc_aoa_destroy(struct sc_aoa *aoa);
|
||||||
+2
-65
@@ -53,7 +53,6 @@
|
|||||||
#define OPT_TCPIP 1033
|
#define OPT_TCPIP 1033
|
||||||
#define OPT_RAW_KEY_EVENTS 1034
|
#define OPT_RAW_KEY_EVENTS 1034
|
||||||
#define OPT_NO_DOWNSIZE_ON_ERROR 1035
|
#define OPT_NO_DOWNSIZE_ON_ERROR 1035
|
||||||
#define OPT_OTG 1036
|
|
||||||
|
|
||||||
struct sc_option {
|
struct sc_option {
|
||||||
char shortopt;
|
char shortopt;
|
||||||
@@ -277,22 +276,6 @@ static const struct sc_option options[] = {
|
|||||||
"mipmaps are automatically generated to improve downscaling "
|
"mipmaps are automatically generated to improve downscaling "
|
||||||
"quality. This option disables the generation of mipmaps.",
|
"quality. This option disables the generation of mipmaps.",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.longopt_id = OPT_OTG,
|
|
||||||
.longopt = "otg",
|
|
||||||
.text = "Run in OTG mode: simulate physical keyboard and mouse, "
|
|
||||||
"as if the computer keyboard and mouse were plugged directly "
|
|
||||||
"to the device via an OTG cable.\n"
|
|
||||||
"In this mode, adb (USB debugging) is not necessary, and "
|
|
||||||
"mirroring is disabled.\n"
|
|
||||||
"LAlt, LSuper or RSuper toggle the mouse capture mode, to give "
|
|
||||||
"control of the mouse back to the computer.\n"
|
|
||||||
"If any of --hid-keyboard or --hid-mouse is set, only enable "
|
|
||||||
"keyboard or mouse respectively, otherwise enable both."
|
|
||||||
"It may only work over USB, and is currently only supported "
|
|
||||||
"on Linux.\n"
|
|
||||||
"See --hid-keyboard and --hid-mouse.",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.shortopt = 'p',
|
.shortopt = 'p',
|
||||||
.longopt = "port",
|
.longopt = "port",
|
||||||
@@ -1335,7 +1318,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
args->help = true;
|
args->help = true;
|
||||||
break;
|
break;
|
||||||
case 'K':
|
case 'K':
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID;
|
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
@@ -1354,7 +1337,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID;
|
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
@@ -1517,15 +1500,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
case OPT_NO_DOWNSIZE_ON_ERROR:
|
case OPT_NO_DOWNSIZE_ON_ERROR:
|
||||||
opts->downsize_on_error = false;
|
opts->downsize_on_error = false;
|
||||||
break;
|
break;
|
||||||
case OPT_OTG:
|
|
||||||
#ifdef HAVE_USB
|
|
||||||
opts->otg = true;
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
LOGE("OTG mode (--otg) is not supported on this platform. It "
|
|
||||||
"is only available on Linux.");
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
case OPT_V4L2_SINK:
|
case OPT_V4L2_SINK:
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
opts->v4l2_device = optarg;
|
opts->v4l2_device = optarg;
|
||||||
@@ -1636,43 +1610,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_USB
|
|
||||||
if (opts->otg) {
|
|
||||||
// OTG mode is compatible with only very few options.
|
|
||||||
// Only report obvious errors.
|
|
||||||
if (opts->record_filename) {
|
|
||||||
LOGE("OTG mode: could not record");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (opts->turn_screen_off) {
|
|
||||||
LOGE("OTG mode: could not turn screen off");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (opts->stay_awake) {
|
|
||||||
LOGE("OTG mode: could not stay awake");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (opts->show_touches) {
|
|
||||||
LOGE("OTG mode: could not request to show touches");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (opts->power_off_on_close) {
|
|
||||||
LOGE("OTG mode: could not request power off on close");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (opts->display_id) {
|
|
||||||
LOGE("OTG mode: could not select display");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_V4L2
|
|
||||||
if (opts->v4l2_device) {
|
|
||||||
LOGE("OTG mode: could not sink to V4L2 device");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-28
@@ -92,19 +92,19 @@ size_t
|
|||||||
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
||||||
buf[0] = msg->type;
|
buf[0] = msg->type;
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
||||||
buf[1] = msg->inject_keycode.action;
|
buf[1] = msg->inject_keycode.action;
|
||||||
buffer_write32be(&buf[2], msg->inject_keycode.keycode);
|
buffer_write32be(&buf[2], msg->inject_keycode.keycode);
|
||||||
buffer_write32be(&buf[6], msg->inject_keycode.repeat);
|
buffer_write32be(&buf[6], msg->inject_keycode.repeat);
|
||||||
buffer_write32be(&buf[10], msg->inject_keycode.metastate);
|
buffer_write32be(&buf[10], msg->inject_keycode.metastate);
|
||||||
return 14;
|
return 14;
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_TEXT: {
|
case CONTROL_MSG_TYPE_INJECT_TEXT: {
|
||||||
size_t len =
|
size_t len =
|
||||||
write_string(msg->inject_text.text,
|
write_string(msg->inject_text.text,
|
||||||
SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH, &buf[1]);
|
CONTROL_MSG_INJECT_TEXT_MAX_LENGTH, &buf[1]);
|
||||||
return 1 + len;
|
return 1 + len;
|
||||||
}
|
}
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:
|
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:
|
||||||
buf[1] = msg->inject_touch_event.action;
|
buf[1] = msg->inject_touch_event.action;
|
||||||
buffer_write64be(&buf[2], msg->inject_touch_event.pointer_id);
|
buffer_write64be(&buf[2], msg->inject_touch_event.pointer_id);
|
||||||
write_position(&buf[10], &msg->inject_touch_event.position);
|
write_position(&buf[10], &msg->inject_touch_event.position);
|
||||||
@@ -113,7 +113,7 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
|||||||
buffer_write16be(&buf[22], pressure);
|
buffer_write16be(&buf[22], pressure);
|
||||||
buffer_write32be(&buf[24], msg->inject_touch_event.buttons);
|
buffer_write32be(&buf[24], msg->inject_touch_event.buttons);
|
||||||
return 28;
|
return 28;
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
||||||
write_position(&buf[1], &msg->inject_scroll_event.position);
|
write_position(&buf[1], &msg->inject_scroll_event.position);
|
||||||
buffer_write32be(&buf[13],
|
buffer_write32be(&buf[13],
|
||||||
(uint32_t) msg->inject_scroll_event.hscroll);
|
(uint32_t) msg->inject_scroll_event.hscroll);
|
||||||
@@ -121,26 +121,27 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
|||||||
(uint32_t) msg->inject_scroll_event.vscroll);
|
(uint32_t) msg->inject_scroll_event.vscroll);
|
||||||
buffer_write32be(&buf[21], msg->inject_scroll_event.buttons);
|
buffer_write32be(&buf[21], msg->inject_scroll_event.buttons);
|
||||||
return 25;
|
return 25;
|
||||||
case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||||
buf[1] = msg->inject_keycode.action;
|
buf[1] = msg->inject_keycode.action;
|
||||||
return 2;
|
return 2;
|
||||||
case SC_CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
||||||
buf[1] = msg->get_clipboard.copy_key;
|
buf[1] = msg->get_clipboard.copy_key;
|
||||||
return 2;
|
return 2;
|
||||||
case SC_CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
||||||
buffer_write64be(&buf[1], msg->set_clipboard.sequence);
|
buffer_write64be(&buf[1], msg->set_clipboard.sequence);
|
||||||
buf[9] = !!msg->set_clipboard.paste;
|
buf[9] = !!msg->set_clipboard.paste;
|
||||||
size_t len = write_string(msg->set_clipboard.text,
|
size_t len = write_string(msg->set_clipboard.text,
|
||||||
SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
|
||||||
&buf[10]);
|
&buf[10]);
|
||||||
return 10 + len;
|
return 10 + len;
|
||||||
case SC_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 SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
case SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
case SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
case CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
||||||
case SC_CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
||||||
// no additional data
|
// no additional data
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
@@ -153,17 +154,17 @@ void
|
|||||||
sc_control_msg_log(const struct sc_control_msg *msg) {
|
sc_control_msg_log(const struct sc_control_msg *msg) {
|
||||||
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
|
#define LOG_CMSG(fmt, ...) LOGV("input: " fmt, ## __VA_ARGS__)
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
case CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
||||||
LOG_CMSG("key %-4s code=%d repeat=%" PRIu32 " meta=%06lx",
|
LOG_CMSG("key %-4s code=%d repeat=%" PRIu32 " meta=%06lx",
|
||||||
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action),
|
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action),
|
||||||
(int) msg->inject_keycode.keycode,
|
(int) msg->inject_keycode.keycode,
|
||||||
msg->inject_keycode.repeat,
|
msg->inject_keycode.repeat,
|
||||||
(long) msg->inject_keycode.metastate);
|
(long) msg->inject_keycode.metastate);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_TEXT:
|
case CONTROL_MSG_TYPE_INJECT_TEXT:
|
||||||
LOG_CMSG("text \"%s\"", msg->inject_text.text);
|
LOG_CMSG("text \"%s\"", msg->inject_text.text);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: {
|
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT: {
|
||||||
int action = msg->inject_touch_event.action
|
int action = msg->inject_touch_event.action
|
||||||
& AMOTION_EVENT_ACTION_MASK;
|
& AMOTION_EVENT_ACTION_MASK;
|
||||||
uint64_t id = msg->inject_touch_event.pointer_id;
|
uint64_t id = msg->inject_touch_event.pointer_id;
|
||||||
@@ -190,7 +191,7 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
||||||
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
|
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
|
||||||
" vscroll=%" PRIi32 " buttons=%06lx",
|
" vscroll=%" PRIi32 " buttons=%06lx",
|
||||||
msg->inject_scroll_event.position.point.x,
|
msg->inject_scroll_event.position.point.x,
|
||||||
@@ -199,34 +200,34 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
|
|||||||
msg->inject_scroll_event.vscroll,
|
msg->inject_scroll_event.vscroll,
|
||||||
(long) msg->inject_scroll_event.buttons);
|
(long) msg->inject_scroll_event.buttons);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||||
LOG_CMSG("back-or-screen-on %s",
|
LOG_CMSG("back-or-screen-on %s",
|
||||||
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
|
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_GET_CLIPBOARD:
|
||||||
LOG_CMSG("get clipboard copy_key=%s",
|
LOG_CMSG("get clipboard copy_key=%s",
|
||||||
copy_key_labels[msg->get_clipboard.copy_key]);
|
copy_key_labels[msg->get_clipboard.copy_key]);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
||||||
LOG_CMSG("clipboard %" PRIu64_ " %s \"%s\"",
|
LOG_CMSG("clipboard %" PRIu64_ " %s \"%s\"",
|
||||||
msg->set_clipboard.sequence,
|
msg->set_clipboard.sequence,
|
||||||
msg->set_clipboard.paste ? "paste" : "nopaste",
|
msg->set_clipboard.paste ? "paste" : "nopaste",
|
||||||
msg->set_clipboard.text);
|
msg->set_clipboard.text);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
||||||
LOG_CMSG("power mode %s",
|
LOG_CMSG("power mode %s",
|
||||||
SCREEN_POWER_MODE_LABEL(msg->set_screen_power_mode.mode));
|
SCREEN_POWER_MODE_LABEL(msg->set_screen_power_mode.mode));
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||||
LOG_CMSG("expand notification panel");
|
LOG_CMSG("expand notification panel");
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
case CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
LOG_CMSG("expand settings panel");
|
LOG_CMSG("expand settings panel");
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
case CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
||||||
LOG_CMSG("collapse panels");
|
LOG_CMSG("collapse panels");
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
case CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
||||||
LOG_CMSG("rotate device");
|
LOG_CMSG("rotate device");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -238,10 +239,10 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
|
|||||||
void
|
void
|
||||||
sc_control_msg_destroy(struct sc_control_msg *msg) {
|
sc_control_msg_destroy(struct sc_control_msg *msg) {
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case SC_CONTROL_MSG_TYPE_INJECT_TEXT:
|
case CONTROL_MSG_TYPE_INJECT_TEXT:
|
||||||
free(msg->inject_text.text);
|
free(msg->inject_text.text);
|
||||||
break;
|
break;
|
||||||
case SC_CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
||||||
free(msg->set_clipboard.text);
|
free(msg->set_clipboard.text);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+24
-24
@@ -11,40 +11,40 @@
|
|||||||
#include "android/keycodes.h"
|
#include "android/keycodes.h"
|
||||||
#include "coords.h"
|
#include "coords.h"
|
||||||
|
|
||||||
#define SC_CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
|
#define CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
|
||||||
|
|
||||||
#define SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
|
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
|
||||||
// type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes
|
// type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes
|
||||||
#define SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (SC_CONTROL_MSG_MAX_SIZE - 14)
|
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 14)
|
||||||
|
|
||||||
#define POINTER_ID_MOUSE UINT64_C(-1)
|
#define POINTER_ID_MOUSE UINT64_C(-1)
|
||||||
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
||||||
|
|
||||||
enum sc_control_msg_type {
|
enum sc_control_msg_type {
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_TEXT,
|
CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||||
SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
SC_CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sc_screen_power_mode {
|
enum screen_power_mode {
|
||||||
// see <https://android.googlesource.com/platform/frameworks/base.git/+/pie-release-2/core/java/android/view/SurfaceControl.java#305>
|
// see <https://android.googlesource.com/platform/frameworks/base.git/+/pie-release-2/core/java/android/view/SurfaceControl.java#305>
|
||||||
SC_SCREEN_POWER_MODE_OFF = 0,
|
SCREEN_POWER_MODE_OFF = 0,
|
||||||
SC_SCREEN_POWER_MODE_NORMAL = 2,
|
SCREEN_POWER_MODE_NORMAL = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sc_copy_key {
|
enum get_clipboard_copy_key {
|
||||||
SC_COPY_KEY_NONE,
|
GET_CLIPBOARD_COPY_KEY_NONE,
|
||||||
SC_COPY_KEY_COPY,
|
GET_CLIPBOARD_COPY_KEY_COPY,
|
||||||
SC_COPY_KEY_CUT,
|
GET_CLIPBOARD_COPY_KEY_CUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_control_msg {
|
struct sc_control_msg {
|
||||||
@@ -77,7 +77,7 @@ struct sc_control_msg {
|
|||||||
// screen may only be turned on on ACTION_DOWN
|
// screen may only be turned on on ACTION_DOWN
|
||||||
} back_or_screen_on;
|
} back_or_screen_on;
|
||||||
struct {
|
struct {
|
||||||
enum sc_copy_key copy_key;
|
enum get_clipboard_copy_key copy_key;
|
||||||
} get_clipboard;
|
} get_clipboard;
|
||||||
struct {
|
struct {
|
||||||
uint64_t sequence;
|
uint64_t sequence;
|
||||||
@@ -85,7 +85,7 @@ struct sc_control_msg {
|
|||||||
bool paste;
|
bool paste;
|
||||||
} set_clipboard;
|
} set_clipboard;
|
||||||
struct {
|
struct {
|
||||||
enum sc_screen_power_mode mode;
|
enum screen_power_mode mode;
|
||||||
} set_screen_power_mode;
|
} set_screen_power_mode;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ sc_controller_push_msg(struct sc_controller *controller,
|
|||||||
static bool
|
static bool
|
||||||
process_msg(struct sc_controller *controller,
|
process_msg(struct sc_controller *controller,
|
||||||
const struct sc_control_msg *msg) {
|
const struct sc_control_msg *msg) {
|
||||||
static unsigned char serialized_msg[SC_CONTROL_MSG_MAX_SIZE];
|
static unsigned char serialized_msg[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t length = sc_control_msg_serialize(msg, serialized_msg);
|
size_t length = sc_control_msg_serialize(msg, serialized_msg);
|
||||||
if (!length) {
|
if (!length) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -2,4 +2,3 @@
|
|||||||
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 1)
|
#define EVENT_STREAM_STOPPED (SDL_USEREVENT + 1)
|
||||||
#define EVENT_SERVER_CONNECTION_FAILED (SDL_USEREVENT + 2)
|
#define EVENT_SERVER_CONNECTION_FAILED (SDL_USEREVENT + 2)
|
||||||
#define EVENT_SERVER_CONNECTED (SDL_USEREVENT + 3)
|
#define EVENT_SERVER_CONNECTED (SDL_USEREVENT + 3)
|
||||||
#define EVENT_USB_DEVICE_DISCONNECTED (SDL_USEREVENT + 4)
|
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ swap_frames(AVFrame **lhs, AVFrame **rhs) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
|
sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
|
||||||
bool *previous_frame_skipped) {
|
bool *previous_frame_skipped) {
|
||||||
|
sc_mutex_lock(&fb->mutex);
|
||||||
|
|
||||||
// Use a temporary frame to preserve pending_frame in case of error.
|
// Use a temporary frame to preserve pending_frame in case of error.
|
||||||
// tmp_frame is an empty frame, no need to call av_frame_unref() beforehand.
|
// tmp_frame is an empty frame, no need to call av_frame_unref() beforehand.
|
||||||
int r = av_frame_ref(fb->tmp_frame, frame);
|
int r = av_frame_ref(fb->tmp_frame, frame);
|
||||||
@@ -59,8 +61,6 @@ sc_frame_buffer_push(struct sc_frame_buffer *fb, const AVFrame *frame,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_mutex_lock(&fb->mutex);
|
|
||||||
|
|
||||||
// Now that av_frame_ref() succeeded, we can replace the previous
|
// Now that av_frame_ref() succeeded, we can replace the previous
|
||||||
// pending_frame
|
// pending_frame
|
||||||
swap_frames(&fb->pending_frame, &fb->tmp_frame);
|
swap_frames(&fb->pending_frame, &fb->tmp_frame);
|
||||||
|
|||||||
@@ -377,76 +377,4 @@ struct sc_touch_event {
|
|||||||
float pressure;
|
float pressure;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint16_t
|
|
||||||
sc_mods_state_from_sdl(uint16_t mods_state) {
|
|
||||||
return mods_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_keycode
|
|
||||||
sc_keycode_from_sdl(SDL_Keycode keycode) {
|
|
||||||
return (enum sc_keycode) keycode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_scancode
|
|
||||||
sc_scancode_from_sdl(SDL_Scancode scancode) {
|
|
||||||
return (enum sc_scancode) scancode;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_action
|
|
||||||
sc_action_from_sdl_keyboard_type(uint32_t type) {
|
|
||||||
assert(type == SDL_KEYDOWN || type == SDL_KEYUP);
|
|
||||||
if (type == SDL_KEYDOWN) {
|
|
||||||
return SC_ACTION_DOWN;
|
|
||||||
}
|
|
||||||
return SC_ACTION_UP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_action
|
|
||||||
sc_action_from_sdl_mousebutton_type(uint32_t type) {
|
|
||||||
assert(type == SDL_MOUSEBUTTONDOWN || type == SDL_MOUSEBUTTONUP);
|
|
||||||
if (type == SDL_MOUSEBUTTONDOWN) {
|
|
||||||
return SC_ACTION_DOWN;
|
|
||||||
}
|
|
||||||
return SC_ACTION_UP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_touch_action
|
|
||||||
sc_touch_action_from_sdl(uint32_t type) {
|
|
||||||
assert(type == SDL_FINGERMOTION || type == SDL_FINGERDOWN ||
|
|
||||||
type == SDL_FINGERUP);
|
|
||||||
if (type == SDL_FINGERMOTION) {
|
|
||||||
return SC_TOUCH_ACTION_MOVE;
|
|
||||||
}
|
|
||||||
if (type == SDL_FINGERDOWN) {
|
|
||||||
return SC_TOUCH_ACTION_DOWN;
|
|
||||||
}
|
|
||||||
return SC_TOUCH_ACTION_UP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline enum sc_mouse_button
|
|
||||||
sc_mouse_button_from_sdl(uint8_t button) {
|
|
||||||
if (button >= SDL_BUTTON_LEFT && button <= SDL_BUTTON_X2) {
|
|
||||||
// SC_MOUSE_BUTTON_* constants are initialized from SDL_BUTTON(index)
|
|
||||||
return SDL_BUTTON(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SC_MOUSE_BUTTON_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t
|
|
||||||
sc_mouse_buttons_state_from_sdl(uint32_t buttons_state,
|
|
||||||
bool forward_all_clicks) {
|
|
||||||
assert(buttons_state < 0x100); // fits in uint8_t
|
|
||||||
|
|
||||||
uint8_t mask = SC_MOUSE_BUTTON_LEFT;
|
|
||||||
if (forward_all_clicks) {
|
|
||||||
mask |= SC_MOUSE_BUTTON_RIGHT
|
|
||||||
| SC_MOUSE_BUTTON_MIDDLE
|
|
||||||
| SC_MOUSE_BUTTON_X1
|
|
||||||
| SC_MOUSE_BUTTON_X2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons_state & mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+92
-18
@@ -7,6 +7,78 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
|
static inline uint16_t
|
||||||
|
sc_mods_state_from_sdl(uint16_t mods_state) {
|
||||||
|
return mods_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_keycode
|
||||||
|
sc_keycode_from_sdl(SDL_Keycode keycode) {
|
||||||
|
return (enum sc_keycode) keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_scancode
|
||||||
|
sc_scancode_from_sdl(SDL_Scancode scancode) {
|
||||||
|
return (enum sc_scancode) scancode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_action
|
||||||
|
sc_action_from_sdl_keyboard_type(uint32_t type) {
|
||||||
|
assert(type == SDL_KEYDOWN || type == SDL_KEYUP);
|
||||||
|
if (type == SDL_KEYDOWN) {
|
||||||
|
return SC_ACTION_DOWN;
|
||||||
|
}
|
||||||
|
return SC_ACTION_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_action
|
||||||
|
sc_action_from_sdl_mousebutton_type(uint32_t type) {
|
||||||
|
assert(type == SDL_MOUSEBUTTONDOWN || type == SDL_MOUSEBUTTONUP);
|
||||||
|
if (type == SDL_MOUSEBUTTONDOWN) {
|
||||||
|
return SC_ACTION_DOWN;
|
||||||
|
}
|
||||||
|
return SC_ACTION_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_touch_action
|
||||||
|
sc_touch_action_from_sdl(uint32_t type) {
|
||||||
|
assert(type == SDL_FINGERMOTION || type == SDL_FINGERDOWN ||
|
||||||
|
type == SDL_FINGERUP);
|
||||||
|
if (type == SDL_FINGERMOTION) {
|
||||||
|
return SC_TOUCH_ACTION_MOVE;
|
||||||
|
}
|
||||||
|
if (type == SDL_FINGERDOWN) {
|
||||||
|
return SC_TOUCH_ACTION_DOWN;
|
||||||
|
}
|
||||||
|
return SC_TOUCH_ACTION_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum sc_mouse_button
|
||||||
|
sc_mouse_button_from_sdl(uint8_t button) {
|
||||||
|
if (button >= SDL_BUTTON_LEFT && button <= SDL_BUTTON_X2) {
|
||||||
|
// SC_MOUSE_BUTTON_* constants are initialized from SDL_BUTTON(index)
|
||||||
|
return SDL_BUTTON(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_MOUSE_BUTTON_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
sc_mouse_buttons_state_from_sdl(uint32_t buttons_state,
|
||||||
|
bool forward_all_clicks) {
|
||||||
|
assert(buttons_state < 0x100); // fits in uint8_t
|
||||||
|
|
||||||
|
uint8_t mask = SC_MOUSE_BUTTON_LEFT;
|
||||||
|
if (forward_all_clicks) {
|
||||||
|
mask |= SC_MOUSE_BUTTON_RIGHT
|
||||||
|
| SC_MOUSE_BUTTON_MIDDLE
|
||||||
|
| SC_MOUSE_BUTTON_X1
|
||||||
|
| SC_MOUSE_BUTTON_X2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttons_state & mask;
|
||||||
|
}
|
||||||
|
|
||||||
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
|
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
|
||||||
|
|
||||||
static inline uint16_t
|
static inline uint16_t
|
||||||
@@ -89,7 +161,7 @@ send_keycode(struct sc_controller *controller, enum android_keycode keycode,
|
|||||||
enum sc_action action, const char *name) {
|
enum sc_action action, const char *name) {
|
||||||
// send DOWN event
|
// send DOWN event
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
msg.type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
||||||
msg.inject_keycode.action = action == SC_ACTION_DOWN
|
msg.inject_keycode.action = action == SC_ACTION_DOWN
|
||||||
? AKEY_EVENT_ACTION_DOWN
|
? AKEY_EVENT_ACTION_DOWN
|
||||||
: AKEY_EVENT_ACTION_UP;
|
: AKEY_EVENT_ACTION_UP;
|
||||||
@@ -143,7 +215,7 @@ static void
|
|||||||
press_back_or_turn_screen_on(struct sc_controller *controller,
|
press_back_or_turn_screen_on(struct sc_controller *controller,
|
||||||
enum sc_action action) {
|
enum sc_action action) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
|
||||||
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
|
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
|
||||||
? AKEY_EVENT_ACTION_DOWN
|
? AKEY_EVENT_ACTION_DOWN
|
||||||
: AKEY_EVENT_ACTION_UP;
|
: AKEY_EVENT_ACTION_UP;
|
||||||
@@ -156,7 +228,7 @@ press_back_or_turn_screen_on(struct sc_controller *controller,
|
|||||||
static void
|
static void
|
||||||
expand_notification_panel(struct sc_controller *controller) {
|
expand_notification_panel(struct sc_controller *controller) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL;
|
msg.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'expand notification panel'");
|
LOGW("Could not request 'expand notification panel'");
|
||||||
@@ -166,7 +238,7 @@ expand_notification_panel(struct sc_controller *controller) {
|
|||||||
static void
|
static void
|
||||||
expand_settings_panel(struct sc_controller *controller) {
|
expand_settings_panel(struct sc_controller *controller) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
msg.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'expand settings panel'");
|
LOGW("Could not request 'expand settings panel'");
|
||||||
@@ -176,7 +248,7 @@ expand_settings_panel(struct sc_controller *controller) {
|
|||||||
static void
|
static void
|
||||||
collapse_panels(struct sc_controller *controller) {
|
collapse_panels(struct sc_controller *controller) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
msg.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request 'collapse notification panel'");
|
LOGW("Could not request 'collapse notification panel'");
|
||||||
@@ -185,9 +257,9 @@ collapse_panels(struct sc_controller *controller) {
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
get_device_clipboard(struct sc_controller *controller,
|
get_device_clipboard(struct sc_controller *controller,
|
||||||
enum sc_copy_key copy_key) {
|
enum get_clipboard_copy_key copy_key) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
msg.type = CONTROL_MSG_TYPE_GET_CLIPBOARD;
|
||||||
msg.get_clipboard.copy_key = copy_key;
|
msg.get_clipboard.copy_key = copy_key;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
@@ -215,7 +287,7 @@ set_device_clipboard(struct sc_controller *controller, bool paste,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
||||||
msg.set_clipboard.sequence = sequence;
|
msg.set_clipboard.sequence = sequence;
|
||||||
msg.set_clipboard.text = text_dup;
|
msg.set_clipboard.text = text_dup;
|
||||||
msg.set_clipboard.paste = paste;
|
msg.set_clipboard.paste = paste;
|
||||||
@@ -231,9 +303,9 @@ set_device_clipboard(struct sc_controller *controller, bool paste,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
set_screen_power_mode(struct sc_controller *controller,
|
set_screen_power_mode(struct sc_controller *controller,
|
||||||
enum sc_screen_power_mode mode) {
|
enum screen_power_mode mode) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
||||||
msg.set_screen_power_mode.mode = mode;
|
msg.set_screen_power_mode.mode = mode;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
@@ -278,7 +350,7 @@ clipboard_paste(struct sc_controller *controller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
msg.inject_text.text = text_dup;
|
msg.inject_text.text = text_dup;
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
free(text_dup);
|
free(text_dup);
|
||||||
@@ -289,7 +361,7 @@ clipboard_paste(struct sc_controller *controller) {
|
|||||||
static void
|
static void
|
||||||
rotate_device(struct sc_controller *controller) {
|
rotate_device(struct sc_controller *controller) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE;
|
msg.type = CONTROL_MSG_TYPE_ROTATE_DEVICE;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(controller, &msg)) {
|
if (!sc_controller_push_msg(controller, &msg)) {
|
||||||
LOGW("Could not request device rotation");
|
LOGW("Could not request device rotation");
|
||||||
@@ -335,7 +407,7 @@ simulate_virtual_finger(struct sc_input_manager *im,
|
|||||||
bool up = action == AMOTION_EVENT_ACTION_UP;
|
bool up = action == AMOTION_EVENT_ACTION_UP;
|
||||||
|
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
||||||
msg.inject_touch_event.action = action;
|
msg.inject_touch_event.action = action;
|
||||||
msg.inject_touch_event.position.screen_size = im->screen->frame_size;
|
msg.inject_touch_event.position.screen_size = im->screen->frame_size;
|
||||||
msg.inject_touch_event.position.point = point;
|
msg.inject_touch_event.position.point = point;
|
||||||
@@ -415,9 +487,9 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
|||||||
return;
|
return;
|
||||||
case SDLK_o:
|
case SDLK_o:
|
||||||
if (controller && !repeat && down) {
|
if (controller && !repeat && down) {
|
||||||
enum sc_screen_power_mode mode = shift
|
enum screen_power_mode mode = shift
|
||||||
? SC_SCREEN_POWER_MODE_NORMAL
|
? SCREEN_POWER_MODE_NORMAL
|
||||||
: SC_SCREEN_POWER_MODE_OFF;
|
: SCREEN_POWER_MODE_OFF;
|
||||||
set_screen_power_mode(controller, mode);
|
set_screen_power_mode(controller, mode);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -445,12 +517,14 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
|||||||
return;
|
return;
|
||||||
case SDLK_c:
|
case SDLK_c:
|
||||||
if (controller && !shift && !repeat && down) {
|
if (controller && !shift && !repeat && down) {
|
||||||
get_device_clipboard(controller, SC_COPY_KEY_COPY);
|
get_device_clipboard(controller,
|
||||||
|
GET_CLIPBOARD_COPY_KEY_COPY);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_x:
|
case SDLK_x:
|
||||||
if (controller && !shift && !repeat && down) {
|
if (controller && !shift && !repeat && down) {
|
||||||
get_device_clipboard(controller, SC_COPY_KEY_CUT);
|
get_device_clipboard(controller,
|
||||||
|
GET_CLIPBOARD_COPY_KEY_CUT);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_v:
|
case SDLK_v:
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ convert_meta_state(uint16_t mod) {
|
|||||||
static bool
|
static bool
|
||||||
convert_input_key(const struct sc_key_event *event, struct sc_control_msg *msg,
|
convert_input_key(const struct sc_key_event *event, struct sc_control_msg *msg,
|
||||||
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
|
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
|
||||||
msg->type = SC_CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
msg->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
|
||||||
|
|
||||||
if (!convert_keycode(event->keycode, &msg->inject_keycode.keycode,
|
if (!convert_keycode(event->keycode, &msg->inject_keycode.keycode,
|
||||||
event->mods_state, key_inject_mode)) {
|
event->mods_state, key_inject_mode)) {
|
||||||
@@ -310,7 +310,7 @@ sc_key_processor_process_text(struct sc_key_processor *kp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
msg.inject_text.text = strdup(event->text);
|
msg.inject_text.text = strdup(event->text);
|
||||||
if (!msg.inject_text.text) {
|
if (!msg.inject_text.text) {
|
||||||
LOGW("Could not strdup input text");
|
LOGW("Could not strdup input text");
|
||||||
|
|||||||
+19
-23
@@ -13,27 +13,28 @@
|
|||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "scrcpy.h"
|
#include "scrcpy.h"
|
||||||
#include "usb/scrcpy_otg.h"
|
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_version(void) {
|
print_version(void) {
|
||||||
printf("\ndependencies:\n");
|
fprintf(stderr, "scrcpy %s\n\n", SCRCPY_VERSION);
|
||||||
printf(" - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION,
|
|
||||||
SDL_PATCHLEVEL);
|
fprintf(stderr, "dependencies:\n");
|
||||||
printf(" - libavcodec %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR,
|
fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION,
|
||||||
LIBAVCODEC_VERSION_MINOR,
|
SDL_PATCHLEVEL);
|
||||||
LIBAVCODEC_VERSION_MICRO);
|
fprintf(stderr, " - libavcodec %d.%d.%d\n", LIBAVCODEC_VERSION_MAJOR,
|
||||||
printf(" - libavformat %d.%d.%d\n", LIBAVFORMAT_VERSION_MAJOR,
|
LIBAVCODEC_VERSION_MINOR,
|
||||||
LIBAVFORMAT_VERSION_MINOR,
|
LIBAVCODEC_VERSION_MICRO);
|
||||||
LIBAVFORMAT_VERSION_MICRO);
|
fprintf(stderr, " - libavformat %d.%d.%d\n", LIBAVFORMAT_VERSION_MAJOR,
|
||||||
printf(" - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR,
|
LIBAVFORMAT_VERSION_MINOR,
|
||||||
LIBAVUTIL_VERSION_MINOR,
|
LIBAVFORMAT_VERSION_MICRO);
|
||||||
LIBAVUTIL_VERSION_MICRO);
|
fprintf(stderr, " - libavutil %d.%d.%d\n", LIBAVUTIL_VERSION_MAJOR,
|
||||||
|
LIBAVUTIL_VERSION_MINOR,
|
||||||
|
LIBAVUTIL_VERSION_MICRO);
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
printf(" - libavdevice %d.%d.%d\n", LIBAVDEVICE_VERSION_MAJOR,
|
fprintf(stderr, " - libavdevice %d.%d.%d\n", LIBAVDEVICE_VERSION_MAJOR,
|
||||||
LIBAVDEVICE_VERSION_MINOR,
|
LIBAVDEVICE_VERSION_MINOR,
|
||||||
LIBAVDEVICE_VERSION_MICRO);
|
LIBAVDEVICE_VERSION_MICRO);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,14 +90,9 @@ main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_USB
|
int res = scrcpy(&args.opts) ? 0 : 1;
|
||||||
bool ok = args.opts.otg ? scrcpy_otg(&args.opts)
|
|
||||||
: scrcpy(&args.opts);
|
|
||||||
#else
|
|
||||||
bool ok = scrcpy(&args.opts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
avformat_network_deinit(); // ignore failure
|
avformat_network_deinit(); // ignore failure
|
||||||
|
|
||||||
return ok ? 0 : 1;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
|
|||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = AMOTION_EVENT_ACTION_MOVE,
|
.action = AMOTION_EVENT_ACTION_MOVE,
|
||||||
.pointer_id = POINTER_ID_MOUSE,
|
.pointer_id = POINTER_ID_MOUSE,
|
||||||
@@ -87,7 +87,7 @@ sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
|
|||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = convert_mouse_action(event->action),
|
.action = convert_mouse_action(event->action),
|
||||||
.pointer_id = POINTER_ID_MOUSE,
|
.pointer_id = POINTER_ID_MOUSE,
|
||||||
@@ -108,7 +108,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
|
|||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
.inject_scroll_event = {
|
.inject_scroll_event = {
|
||||||
.position = event->position,
|
.position = event->position,
|
||||||
.hscroll = event->hscroll,
|
.hscroll = event->hscroll,
|
||||||
@@ -128,7 +128,7 @@ sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
|
|||||||
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
struct sc_mouse_inject *mi = DOWNCAST(mp);
|
||||||
|
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = convert_touch_action(event->action),
|
.action = convert_touch_action(event->action),
|
||||||
.pointer_id = event->pointer_id,
|
.pointer_id = event->pointer_id,
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||||||
.display_id = 0,
|
.display_id = 0,
|
||||||
.display_buffer = 0,
|
.display_buffer = 0,
|
||||||
.v4l2_buffer = 0,
|
.v4l2_buffer = 0,
|
||||||
#ifdef HAVE_USB
|
|
||||||
.otg = false,
|
|
||||||
#endif
|
|
||||||
.show_touches = false,
|
.show_touches = false,
|
||||||
.fullscreen = false,
|
.fullscreen = false,
|
||||||
.always_on_top = false,
|
.always_on_top = false,
|
||||||
|
|||||||
@@ -112,9 +112,6 @@ struct scrcpy_options {
|
|||||||
uint32_t display_id;
|
uint32_t display_id;
|
||||||
sc_tick display_buffer;
|
sc_tick display_buffer;
|
||||||
sc_tick v4l2_buffer;
|
sc_tick v4l2_buffer;
|
||||||
#ifdef HAVE_USB
|
|
||||||
bool otg;
|
|
||||||
#endif
|
|
||||||
bool show_touches;
|
bool show_touches;
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool always_on_top;
|
bool always_on_top;
|
||||||
|
|||||||
+14
-66
@@ -17,18 +17,16 @@
|
|||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "file_pusher.h"
|
#include "file_pusher.h"
|
||||||
|
#ifdef HAVE_AOA_HID
|
||||||
|
# include "hid_keyboard.h"
|
||||||
|
# include "hid_mouse.h"
|
||||||
|
#endif
|
||||||
#include "keyboard_inject.h"
|
#include "keyboard_inject.h"
|
||||||
#include "mouse_inject.h"
|
#include "mouse_inject.h"
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#ifdef HAVE_USB
|
|
||||||
# include "usb/aoa_hid.h"
|
|
||||||
# include "usb/hid_keyboard.h"
|
|
||||||
# include "usb/hid_mouse.h"
|
|
||||||
# include "usb/usb.h"
|
|
||||||
#endif
|
|
||||||
#include "util/acksync.h"
|
#include "util/acksync.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
@@ -47,21 +45,20 @@ struct scrcpy {
|
|||||||
#endif
|
#endif
|
||||||
struct sc_controller controller;
|
struct sc_controller controller;
|
||||||
struct sc_file_pusher file_pusher;
|
struct sc_file_pusher file_pusher;
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
struct sc_usb usb;
|
|
||||||
struct sc_aoa aoa;
|
struct sc_aoa aoa;
|
||||||
// sequence/ack helper to synchronize clipboard and Ctrl+v via HID
|
// sequence/ack helper to synchronize clipboard and Ctrl+v via HID
|
||||||
struct sc_acksync acksync;
|
struct sc_acksync acksync;
|
||||||
#endif
|
#endif
|
||||||
union {
|
union {
|
||||||
struct sc_keyboard_inject keyboard_inject;
|
struct sc_keyboard_inject keyboard_inject;
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
struct sc_hid_keyboard keyboard_hid;
|
struct sc_hid_keyboard keyboard_hid;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
struct sc_mouse_inject mouse_inject;
|
struct sc_mouse_inject mouse_inject;
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
struct sc_hid_mouse mouse_hid;
|
struct sc_hid_mouse mouse_hid;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -286,7 +283,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
bool v4l2_sink_initialized = false;
|
bool v4l2_sink_initialized = false;
|
||||||
#endif
|
#endif
|
||||||
bool stream_started = false;
|
bool stream_started = false;
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
bool aoa_hid_initialized = false;
|
bool aoa_hid_initialized = false;
|
||||||
bool hid_keyboard_initialized = false;
|
bool hid_keyboard_initialized = false;
|
||||||
bool hid_mouse_initialized = false;
|
bool hid_mouse_initialized = false;
|
||||||
@@ -413,7 +410,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
struct sc_mouse_processor *mp = NULL;
|
struct sc_mouse_processor *mp = NULL;
|
||||||
|
|
||||||
if (options->control) {
|
if (options->control) {
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
bool use_hid_keyboard =
|
bool use_hid_keyboard =
|
||||||
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID;
|
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID;
|
||||||
bool use_hid_mouse =
|
bool use_hid_mouse =
|
||||||
@@ -424,52 +421,9 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = sc_usb_init(&s->usb);
|
ok = sc_aoa_init(&s->aoa, serial, &s->acksync);
|
||||||
if (!ok) {
|
|
||||||
LOGE("Failed to initialize USB");
|
|
||||||
sc_acksync_destroy(&s->acksync);
|
|
||||||
goto aoa_hid_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(serial);
|
|
||||||
struct sc_usb_device usb_devices[16];
|
|
||||||
ssize_t count = sc_usb_find_devices(&s->usb, serial, usb_devices,
|
|
||||||
ARRAY_LEN(usb_devices));
|
|
||||||
if (count <= 0) {
|
|
||||||
LOGE("Could not find USB device %s", serial);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
sc_acksync_destroy(&s->acksync);
|
|
||||||
goto aoa_hid_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 1) {
|
|
||||||
LOGE("Multiple (%d) devices with serial %s", (int) count, serial);
|
|
||||||
sc_usb_device_destroy_all(usb_devices, count);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
sc_acksync_destroy(&s->acksync);
|
|
||||||
goto aoa_hid_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sc_usb_device *usb_device = &usb_devices[0];
|
|
||||||
|
|
||||||
LOGI("USB device: %s (%04" PRIx16 ":%04" PRIx16 ") %s %s",
|
|
||||||
usb_device->serial, usb_device->vid, usb_device->pid,
|
|
||||||
usb_device->manufacturer, usb_device->product);
|
|
||||||
|
|
||||||
ok = sc_usb_connect(&s->usb, usb_device->device, NULL, NULL);
|
|
||||||
sc_usb_device_destroy(usb_device);
|
|
||||||
if (!ok) {
|
|
||||||
LOGE("Failed to connect to USB device %s", serial);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
sc_acksync_destroy(&s->acksync);
|
|
||||||
goto aoa_hid_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = sc_aoa_init(&s->aoa, &s->usb, &s->acksync);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Failed to enable HID over AOA");
|
LOGE("Failed to enable HID over AOA");
|
||||||
sc_usb_disconnect(&s->usb);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
sc_acksync_destroy(&s->acksync);
|
sc_acksync_destroy(&s->acksync);
|
||||||
goto aoa_hid_end;
|
goto aoa_hid_end;
|
||||||
}
|
}
|
||||||
@@ -496,8 +450,6 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
|
|
||||||
if (!need_aoa || !sc_aoa_start(&s->aoa)) {
|
if (!need_aoa || !sc_aoa_start(&s->aoa)) {
|
||||||
sc_acksync_destroy(&s->acksync);
|
sc_acksync_destroy(&s->acksync);
|
||||||
sc_usb_disconnect(&s->usb);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
sc_aoa_destroy(&s->aoa);
|
sc_aoa_destroy(&s->aoa);
|
||||||
goto aoa_hid_end;
|
goto aoa_hid_end;
|
||||||
}
|
}
|
||||||
@@ -563,8 +515,8 @@ aoa_hid_end:
|
|||||||
|
|
||||||
if (options->turn_screen_off) {
|
if (options->turn_screen_off) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;
|
||||||
msg.set_screen_power_mode.mode = SC_SCREEN_POWER_MODE_OFF;
|
msg.set_screen_power_mode.mode = SCREEN_POWER_MODE_OFF;
|
||||||
|
|
||||||
if (!sc_controller_push_msg(&s->controller, &msg)) {
|
if (!sc_controller_push_msg(&s->controller, &msg)) {
|
||||||
LOGW("Could not request 'set screen power mode'");
|
LOGW("Could not request 'set screen power mode'");
|
||||||
@@ -641,7 +593,7 @@ aoa_hid_end:
|
|||||||
end:
|
end:
|
||||||
// The stream is not stopped explicitly, because it will stop by itself on
|
// The stream is not stopped explicitly, because it will stop by itself on
|
||||||
// end-of-stream
|
// end-of-stream
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
if (aoa_hid_initialized) {
|
if (aoa_hid_initialized) {
|
||||||
if (hid_keyboard_initialized) {
|
if (hid_keyboard_initialized) {
|
||||||
sc_hid_keyboard_destroy(&s->keyboard_hid);
|
sc_hid_keyboard_destroy(&s->keyboard_hid);
|
||||||
@@ -650,7 +602,6 @@ end:
|
|||||||
sc_hid_mouse_destroy(&s->mouse_hid);
|
sc_hid_mouse_destroy(&s->mouse_hid);
|
||||||
}
|
}
|
||||||
sc_aoa_stop(&s->aoa);
|
sc_aoa_stop(&s->aoa);
|
||||||
sc_usb_stop(&s->usb);
|
|
||||||
}
|
}
|
||||||
if (acksync) {
|
if (acksync) {
|
||||||
sc_acksync_destroy(acksync);
|
sc_acksync_destroy(acksync);
|
||||||
@@ -683,13 +634,10 @@ end:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_USB
|
#ifdef HAVE_AOA_HID
|
||||||
if (aoa_hid_initialized) {
|
if (aoa_hid_initialized) {
|
||||||
sc_aoa_join(&s->aoa);
|
sc_aoa_join(&s->aoa);
|
||||||
sc_aoa_destroy(&s->aoa);
|
sc_aoa_destroy(&s->aoa);
|
||||||
sc_usb_join(&s->usb);
|
|
||||||
sc_usb_disconnect(&s->usb);
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+2
-7
@@ -769,10 +769,12 @@ run_server(void *data) {
|
|||||||
// Interrupt sockets to wake up socket blocking calls on the server
|
// Interrupt sockets to wake up socket blocking calls on the server
|
||||||
assert(server->video_socket != SC_SOCKET_NONE);
|
assert(server->video_socket != SC_SOCKET_NONE);
|
||||||
net_interrupt(server->video_socket);
|
net_interrupt(server->video_socket);
|
||||||
|
net_close(server->video_socket);
|
||||||
|
|
||||||
if (server->control_socket != SC_SOCKET_NONE) {
|
if (server->control_socket != SC_SOCKET_NONE) {
|
||||||
// There is no control_socket if --no-control is set
|
// There is no control_socket if --no-control is set
|
||||||
net_interrupt(server->control_socket);
|
net_interrupt(server->control_socket);
|
||||||
|
net_close(server->control_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give some delay for the server to terminate properly
|
// Give some delay for the server to terminate properly
|
||||||
@@ -828,13 +830,6 @@ sc_server_stop(struct sc_server *server) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
sc_server_destroy(struct sc_server *server) {
|
sc_server_destroy(struct sc_server *server) {
|
||||||
if (server->video_socket != SC_SOCKET_NONE) {
|
|
||||||
net_close(server->video_socket);
|
|
||||||
}
|
|
||||||
if (server->control_socket != SC_SOCKET_NONE) {
|
|
||||||
net_close(server->control_socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
sc_server_params_destroy(&server->params);
|
sc_server_params_destroy(&server->params);
|
||||||
sc_intr_destroy(&server->intr);
|
sc_intr_destroy(&server->intr);
|
||||||
sc_cond_destroy(&server->cond_stopped);
|
sc_cond_destroy(&server->cond_stopped);
|
||||||
|
|||||||
@@ -1,232 +0,0 @@
|
|||||||
#include "scrcpy_otg.h"
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#include "events.h"
|
|
||||||
#include "screen_otg.h"
|
|
||||||
#include "util/log.h"
|
|
||||||
|
|
||||||
struct scrcpy_otg {
|
|
||||||
struct sc_usb usb;
|
|
||||||
struct sc_aoa aoa;
|
|
||||||
struct sc_hid_keyboard keyboard;
|
|
||||||
struct sc_hid_mouse mouse;
|
|
||||||
|
|
||||||
struct sc_screen_otg screen_otg;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_usb_on_disconnected(struct sc_usb *usb, void *userdata) {
|
|
||||||
(void) usb;
|
|
||||||
(void) userdata;
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
event.type = EVENT_USB_DEVICE_DISCONNECTED;
|
|
||||||
int ret = SDL_PushEvent(&event);
|
|
||||||
if (ret < 0) {
|
|
||||||
LOGE("Could not post USB disconnection event: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
event_loop(struct scrcpy_otg *s) {
|
|
||||||
SDL_Event event;
|
|
||||||
while (SDL_WaitEvent(&event)) {
|
|
||||||
switch (event.type) {
|
|
||||||
case EVENT_USB_DEVICE_DISCONNECTED:
|
|
||||||
LOGW("Device disconnected");
|
|
||||||
return false;
|
|
||||||
case SDL_QUIT:
|
|
||||||
LOGD("User requested to quit");
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
sc_screen_otg_handle_event(&s->screen_otg, &event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
scrcpy_otg(struct scrcpy_options *options) {
|
|
||||||
static struct scrcpy_otg scrcpy_otg;
|
|
||||||
struct scrcpy_otg *s = &scrcpy_otg;
|
|
||||||
|
|
||||||
const char *serial = options->serial;
|
|
||||||
|
|
||||||
// Minimal SDL initialization
|
|
||||||
if (SDL_Init(SDL_INIT_EVENTS)) {
|
|
||||||
LOGC("Could not initialize SDL: %s", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
atexit(SDL_Quit);
|
|
||||||
|
|
||||||
if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) {
|
|
||||||
LOGW("Could not enable mouse focus clickthrough");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
struct sc_hid_keyboard *keyboard = NULL;
|
|
||||||
struct sc_hid_mouse *mouse = NULL;
|
|
||||||
bool usb_device_initialized = false;
|
|
||||||
bool usb_connected = false;
|
|
||||||
bool aoa_started = false;
|
|
||||||
bool aoa_initialized = false;
|
|
||||||
|
|
||||||
static const struct sc_usb_callbacks cbs = {
|
|
||||||
.on_disconnected = sc_usb_on_disconnected,
|
|
||||||
};
|
|
||||||
bool ok = sc_usb_init(&s->usb);
|
|
||||||
if (!ok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sc_usb_device usb_devices[16];
|
|
||||||
ssize_t count = sc_usb_find_devices(&s->usb, serial, usb_devices,
|
|
||||||
ARRAY_LEN(usb_devices));
|
|
||||||
if (count < 0) {
|
|
||||||
LOGE("Could not list USB devices");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
if (serial) {
|
|
||||||
LOGE("Could not find USB device %s", serial);
|
|
||||||
} else {
|
|
||||||
LOGE("Could not find any USB device");
|
|
||||||
}
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 1) {
|
|
||||||
if (serial) {
|
|
||||||
LOGE("Multiple (%d) USB devices with serial %s:", (int) count,
|
|
||||||
serial);
|
|
||||||
} else {
|
|
||||||
LOGE("Multiple (%d) USB devices:", (int) count);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < (size_t) count; ++i) {
|
|
||||||
struct sc_usb_device *d = &usb_devices[i];
|
|
||||||
LOGE(" %-18s (%04" PRIx16 ":%04" PRIx16 ") %s %s",
|
|
||||||
d->serial, d->vid, d->pid, d->manufacturer, d->product);
|
|
||||||
}
|
|
||||||
if (!serial) {
|
|
||||||
LOGE("Specify the device via -s or --serial");
|
|
||||||
}
|
|
||||||
sc_usb_device_destroy_all(usb_devices, count);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
usb_device_initialized = true;
|
|
||||||
|
|
||||||
struct sc_usb_device *usb_device = &usb_devices[0];
|
|
||||||
|
|
||||||
LOGI("USB device: %s (%04" PRIx16 ":%04" PRIx16 ") %s %s",
|
|
||||||
usb_device->serial, usb_device->vid, usb_device->pid,
|
|
||||||
usb_device->manufacturer, usb_device->product);
|
|
||||||
|
|
||||||
ok = sc_usb_connect(&s->usb, usb_device->device, &cbs, NULL);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
usb_connected = true;
|
|
||||||
|
|
||||||
ok = sc_aoa_init(&s->aoa, &s->usb, NULL);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
aoa_initialized = true;
|
|
||||||
|
|
||||||
bool enable_keyboard =
|
|
||||||
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID;
|
|
||||||
bool enable_mouse =
|
|
||||||
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID;
|
|
||||||
|
|
||||||
// If neither --hid-keyboard or --hid-mouse is passed, enable both
|
|
||||||
if (!enable_keyboard && !enable_mouse) {
|
|
||||||
enable_keyboard = true;
|
|
||||||
enable_mouse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable_keyboard) {
|
|
||||||
ok = sc_hid_keyboard_init(&s->keyboard, &s->aoa);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
keyboard = &s->keyboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable_mouse) {
|
|
||||||
ok = sc_hid_mouse_init(&s->mouse, &s->aoa);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
mouse = &s->mouse;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = sc_aoa_start(&s->aoa);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
aoa_started = true;
|
|
||||||
|
|
||||||
const char *window_title = options->window_title;
|
|
||||||
if (!window_title) {
|
|
||||||
window_title = usb_device->product ? usb_device->product : "scrcpy";
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sc_screen_otg_params params = {
|
|
||||||
.keyboard = keyboard,
|
|
||||||
.mouse = mouse,
|
|
||||||
.window_title = window_title,
|
|
||||||
.always_on_top = options->always_on_top,
|
|
||||||
.window_x = options->window_x,
|
|
||||||
.window_y = options->window_y,
|
|
||||||
.window_borderless = options->window_borderless,
|
|
||||||
};
|
|
||||||
|
|
||||||
ok = sc_screen_otg_init(&s->screen_otg, ¶ms);
|
|
||||||
if (!ok) {
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
// usb_device not needed anymore
|
|
||||||
sc_usb_device_destroy(usb_device);
|
|
||||||
usb_device_initialized = false;
|
|
||||||
|
|
||||||
ret = event_loop(s);
|
|
||||||
LOGD("quit...");
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (aoa_started) {
|
|
||||||
sc_aoa_stop(&s->aoa);
|
|
||||||
}
|
|
||||||
sc_usb_stop(&s->usb);
|
|
||||||
|
|
||||||
if (mouse) {
|
|
||||||
sc_hid_mouse_destroy(&s->mouse);
|
|
||||||
}
|
|
||||||
if (keyboard) {
|
|
||||||
sc_hid_keyboard_destroy(&s->keyboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aoa_initialized) {
|
|
||||||
sc_aoa_join(&s->aoa);
|
|
||||||
sc_aoa_destroy(&s->aoa);
|
|
||||||
}
|
|
||||||
|
|
||||||
sc_usb_join(&s->usb);
|
|
||||||
|
|
||||||
if (usb_connected) {
|
|
||||||
sc_usb_disconnect(&s->usb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usb_device_initialized) {
|
|
||||||
sc_usb_device_destroy(usb_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
sc_usb_destroy(&s->usb);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef SCRCPY_OTG_H
|
|
||||||
#define SCRCPY_OTG_H
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
bool
|
|
||||||
scrcpy_otg(struct scrcpy_options *options);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
#include "screen_otg.h"
|
|
||||||
|
|
||||||
#include "icon.h"
|
|
||||||
#include "options.h"
|
|
||||||
#include "util/log.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_screen_otg_capture_mouse(struct sc_screen_otg *screen, bool capture) {
|
|
||||||
assert(screen->mouse);
|
|
||||||
if (SDL_SetRelativeMouseMode(capture)) {
|
|
||||||
LOGE("Could not set relative mouse mode to %s: %s",
|
|
||||||
capture ? "true" : "false", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->mouse_captured = capture;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_screen_otg_render(struct sc_screen_otg *screen) {
|
|
||||||
SDL_RenderClear(screen->renderer);
|
|
||||||
if (screen->texture) {
|
|
||||||
SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
|
|
||||||
}
|
|
||||||
SDL_RenderPresent(screen->renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_screen_otg_init(struct sc_screen_otg *screen,
|
|
||||||
const struct sc_screen_otg_params *params) {
|
|
||||||
screen->keyboard = params->keyboard;
|
|
||||||
screen->mouse = params->mouse;
|
|
||||||
|
|
||||||
screen->mouse_captured = false;
|
|
||||||
screen->mouse_capture_key_pressed = 0;
|
|
||||||
|
|
||||||
const char *title = params->window_title;
|
|
||||||
assert(title);
|
|
||||||
|
|
||||||
int x = params->window_x != SC_WINDOW_POSITION_UNDEFINED
|
|
||||||
? params->window_x : (int) SDL_WINDOWPOS_UNDEFINED;
|
|
||||||
int y = params->window_y != SC_WINDOW_POSITION_UNDEFINED
|
|
||||||
? params->window_y : (int) SDL_WINDOWPOS_UNDEFINED;
|
|
||||||
int width = 256;
|
|
||||||
int height = 256;
|
|
||||||
|
|
||||||
uint32_t window_flags = 0;
|
|
||||||
if (params->always_on_top) {
|
|
||||||
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
|
||||||
}
|
|
||||||
if (params->window_borderless) {
|
|
||||||
window_flags |= SDL_WINDOW_BORDERLESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->window = SDL_CreateWindow(title, x, y, width, height, window_flags);
|
|
||||||
if (!screen->window) {
|
|
||||||
LOGE("Could not create window: %s", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->renderer = SDL_CreateRenderer(screen->window, -1, 0);
|
|
||||||
if (!screen->renderer) {
|
|
||||||
LOGE("Could not create renderer: %s", SDL_GetError());
|
|
||||||
goto error_destroy_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Surface *icon = scrcpy_icon_load();
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
SDL_SetWindowIcon(screen->window, icon);
|
|
||||||
|
|
||||||
screen->texture = SDL_CreateTextureFromSurface(screen->renderer, icon);
|
|
||||||
scrcpy_icon_destroy(icon);
|
|
||||||
if (!screen->texture) {
|
|
||||||
goto error_destroy_renderer;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
screen->texture = NULL;
|
|
||||||
LOGW("Could not load icon");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen->mouse) {
|
|
||||||
// Capture mouse on start
|
|
||||||
sc_screen_otg_capture_mouse(screen, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
error_destroy_window:
|
|
||||||
SDL_DestroyWindow(screen->window);
|
|
||||||
error_destroy_renderer:
|
|
||||||
SDL_DestroyRenderer(screen->renderer);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_screen_otg_destroy(struct sc_screen_otg *screen) {
|
|
||||||
if (screen->texture) {
|
|
||||||
SDL_DestroyTexture(screen->texture);
|
|
||||||
}
|
|
||||||
SDL_DestroyRenderer(screen->renderer);
|
|
||||||
SDL_DestroyWindow(screen->window);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
sc_screen_otg_is_mouse_capture_key(SDL_Keycode key) {
|
|
||||||
return key == SDLK_LALT || key == SDLK_LGUI || key == SDLK_RGUI;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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),
|
|
||||||
.repeat = event->repeat,
|
|
||||||
.mods_state = sc_mods_state_from_sdl(event->keysym.mod),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(kp->ops->process_key);
|
|
||||||
kp->ops->process_key(kp, &evt, SC_SEQUENCE_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_screen_otg_process_mouse_motion(struct sc_screen_otg *screen,
|
|
||||||
const SDL_MouseMotionEvent *event) {
|
|
||||||
assert(screen->mouse);
|
|
||||||
struct sc_mouse_processor *mp = &screen->mouse->mouse_processor;
|
|
||||||
|
|
||||||
struct sc_mouse_motion_event evt = {
|
|
||||||
// .position not used for HID events
|
|
||||||
.xrel = event->xrel,
|
|
||||||
.yrel = event->yrel,
|
|
||||||
.buttons_state = sc_mouse_buttons_state_from_sdl(event->state, true),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(mp->ops->process_mouse_motion);
|
|
||||||
mp->ops->process_mouse_motion(mp, &evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_screen_otg_process_mouse_button(struct sc_screen_otg *screen,
|
|
||||||
const SDL_MouseButtonEvent *event) {
|
|
||||||
assert(screen->mouse);
|
|
||||||
struct sc_mouse_processor *mp = &screen->mouse->mouse_processor;
|
|
||||||
|
|
||||||
uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL);
|
|
||||||
|
|
||||||
struct sc_mouse_click_event evt = {
|
|
||||||
// .position not used for HID events
|
|
||||||
.action = sc_action_from_sdl_mousebutton_type(event->type),
|
|
||||||
.button = sc_mouse_button_from_sdl(event->button),
|
|
||||||
.buttons_state =
|
|
||||||
sc_mouse_buttons_state_from_sdl(sdl_buttons_state, true),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(mp->ops->process_mouse_click);
|
|
||||||
mp->ops->process_mouse_click(mp, &evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen,
|
|
||||||
const SDL_MouseWheelEvent *event) {
|
|
||||||
assert(screen->mouse);
|
|
||||||
struct sc_mouse_processor *mp = &screen->mouse->mouse_processor;
|
|
||||||
|
|
||||||
uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL);
|
|
||||||
|
|
||||||
struct sc_mouse_scroll_event evt = {
|
|
||||||
// .position not used for HID events
|
|
||||||
.hscroll = event->x,
|
|
||||||
.vscroll = event->y,
|
|
||||||
.buttons_state =
|
|
||||||
sc_mouse_buttons_state_from_sdl(sdl_buttons_state, true),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert(mp->ops->process_mouse_scroll);
|
|
||||||
mp->ops->process_mouse_scroll(mp, &evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) {
|
|
||||||
switch (event->type) {
|
|
||||||
case SDL_WINDOWEVENT:
|
|
||||||
switch (event->window.event) {
|
|
||||||
case SDL_WINDOWEVENT_EXPOSED:
|
|
||||||
sc_screen_otg_render(screen);
|
|
||||||
break;
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
||||||
if (screen->mouse) {
|
|
||||||
sc_screen_otg_capture_mouse(screen, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case SDL_KEYDOWN:
|
|
||||||
if (screen->mouse) {
|
|
||||||
SDL_Keycode key = event->key.keysym.sym;
|
|
||||||
if (sc_screen_otg_is_mouse_capture_key(key)) {
|
|
||||||
if (!screen->mouse_capture_key_pressed) {
|
|
||||||
screen->mouse_capture_key_pressed = key;
|
|
||||||
} else {
|
|
||||||
// Another mouse capture key has been pressed, cancel
|
|
||||||
// mouse (un)capture
|
|
||||||
screen->mouse_capture_key_pressed = 0;
|
|
||||||
}
|
|
||||||
// Mouse capture keys are never forwarded to the device
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen->keyboard) {
|
|
||||||
sc_screen_otg_process_key(screen, &event->key);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_KEYUP:
|
|
||||||
if (screen->mouse) {
|
|
||||||
SDL_Keycode key = event->key.keysym.sym;
|
|
||||||
SDL_Keycode cap = screen->mouse_capture_key_pressed;
|
|
||||||
screen->mouse_capture_key_pressed = 0;
|
|
||||||
if (sc_screen_otg_is_mouse_capture_key(key)) {
|
|
||||||
if (key == cap) {
|
|
||||||
// A mouse capture key has been pressed then released:
|
|
||||||
// toggle the capture mouse mode
|
|
||||||
sc_screen_otg_capture_mouse(screen,
|
|
||||||
!screen->mouse_captured);
|
|
||||||
}
|
|
||||||
// Mouse capture keys are never forwarded to the device
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen->keyboard) {
|
|
||||||
sc_screen_otg_process_key(screen, &event->key);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_MOUSEMOTION:
|
|
||||||
if (screen->mouse && screen->mouse_captured) {
|
|
||||||
sc_screen_otg_process_mouse_motion(screen, &event->motion);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
|
||||||
if (screen->mouse && screen->mouse_captured) {
|
|
||||||
sc_screen_otg_process_mouse_button(screen, &event->button);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_MOUSEBUTTONUP:
|
|
||||||
if (screen->mouse) {
|
|
||||||
if (screen->mouse_captured) {
|
|
||||||
sc_screen_otg_process_mouse_button(screen, &event->button);
|
|
||||||
} else {
|
|
||||||
sc_screen_otg_capture_mouse(screen, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_MOUSEWHEEL:
|
|
||||||
if (screen->mouse && screen->mouse_captured) {
|
|
||||||
sc_screen_otg_process_mouse_wheel(screen, &event->wheel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#ifndef SC_SCREEN_OTG_H
|
|
||||||
#define SC_SCREEN_OTG_H
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#include "hid_keyboard.h"
|
|
||||||
#include "hid_mouse.h"
|
|
||||||
|
|
||||||
struct sc_screen_otg {
|
|
||||||
struct sc_hid_keyboard *keyboard;
|
|
||||||
struct sc_hid_mouse *mouse;
|
|
||||||
|
|
||||||
SDL_Window *window;
|
|
||||||
SDL_Renderer *renderer;
|
|
||||||
SDL_Texture *texture;
|
|
||||||
|
|
||||||
// See equivalent mechanism in screen.h
|
|
||||||
bool mouse_captured;
|
|
||||||
SDL_Keycode mouse_capture_key_pressed;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sc_screen_otg_params {
|
|
||||||
struct sc_hid_keyboard *keyboard;
|
|
||||||
struct sc_hid_mouse *mouse;
|
|
||||||
|
|
||||||
const char *window_title;
|
|
||||||
bool always_on_top;
|
|
||||||
int16_t window_x; // accepts SC_WINDOW_POSITION_UNDEFINED
|
|
||||||
int16_t window_y; // accepts SC_WINDOW_POSITION_UNDEFINED
|
|
||||||
bool window_borderless;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_screen_otg_init(struct sc_screen_otg *screen,
|
|
||||||
const struct sc_screen_otg_params *params);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_screen_otg_destroy(struct sc_screen_otg *screen);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
#include "usb.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "util/log.h"
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
log_libusb_error(enum libusb_error errcode) {
|
|
||||||
LOGW("libusb error: %s", libusb_strerror(errcode));
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
read_string(libusb_device_handle *handle, uint8_t desc_index) {
|
|
||||||
char buffer[128];
|
|
||||||
int result =
|
|
||||||
libusb_get_string_descriptor_ascii(handle, desc_index,
|
|
||||||
(unsigned char *) buffer,
|
|
||||||
sizeof(buffer));
|
|
||||||
if (result < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert((size_t) result <= sizeof(buffer));
|
|
||||||
|
|
||||||
// When non-negative, 'result' contains the number of bytes written
|
|
||||||
char *s = malloc(result + 1);
|
|
||||||
memcpy(s, buffer, result);
|
|
||||||
s[result] = '\0';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
accept_device(libusb_device *device, const char *serial,
|
|
||||||
struct sc_usb_device *out) {
|
|
||||||
// Do not log any USB error in this function, it is expected that many USB
|
|
||||||
// devices available on the computer have permission restrictions
|
|
||||||
|
|
||||||
struct libusb_device_descriptor desc;
|
|
||||||
int result = libusb_get_device_descriptor(device, &desc);
|
|
||||||
if (result < 0 || !desc.iSerialNumber) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_device_handle *handle;
|
|
||||||
result = libusb_open(device, &handle);
|
|
||||||
if (result < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *device_serial = read_string(handle, desc.iSerialNumber);
|
|
||||||
if (!device_serial) {
|
|
||||||
libusb_close(handle);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serial) {
|
|
||||||
// Filter by serial
|
|
||||||
bool matches = !strcmp(serial, device_serial);
|
|
||||||
if (!matches) {
|
|
||||||
free(device_serial);
|
|
||||||
libusb_close(handle);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out->device = libusb_ref_device(device);
|
|
||||||
out->serial = device_serial;
|
|
||||||
out->vid = desc.idVendor;
|
|
||||||
out->pid = desc.idProduct;
|
|
||||||
out->manufacturer = read_string(handle, desc.iManufacturer);
|
|
||||||
out->product = read_string(handle, desc.iProduct);
|
|
||||||
|
|
||||||
libusb_close(handle);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_device_destroy(struct sc_usb_device *usb_device) {
|
|
||||||
libusb_unref_device(usb_device->device);
|
|
||||||
free(usb_device->serial);
|
|
||||||
free(usb_device->manufacturer);
|
|
||||||
free(usb_device->product);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_device_destroy_all(struct sc_usb_device *usb_devices, size_t count) {
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
sc_usb_device_destroy(&usb_devices[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
sc_usb_find_devices(struct sc_usb *usb, const char *serial,
|
|
||||||
struct sc_usb_device *devices, size_t len) {
|
|
||||||
libusb_device **list;
|
|
||||||
ssize_t count = libusb_get_device_list(usb->context, &list);
|
|
||||||
if (count < 0) {
|
|
||||||
log_libusb_error((enum libusb_error) count);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = 0;
|
|
||||||
for (size_t i = 0; i < (size_t) count && idx < len; ++i) {
|
|
||||||
libusb_device *device = list[i];
|
|
||||||
|
|
||||||
if (accept_device(device, serial, &devices[idx])) {
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_free_device_list(list, 1);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static libusb_device_handle *
|
|
||||||
sc_usb_open_handle(libusb_device *device) {
|
|
||||||
libusb_device_handle *handle;
|
|
||||||
int result = libusb_open(device, &handle);
|
|
||||||
if (result < 0) {
|
|
||||||
log_libusb_error((enum libusb_error) result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_usb_init(struct sc_usb *usb) {
|
|
||||||
usb->handle = NULL;
|
|
||||||
return libusb_init(&usb->context) == LIBUSB_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_destroy(struct sc_usb *usb) {
|
|
||||||
libusb_exit(usb->context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device,
|
|
||||||
libusb_hotplug_event event, void *userdata) {
|
|
||||||
(void) ctx;
|
|
||||||
(void) device;
|
|
||||||
(void) event;
|
|
||||||
|
|
||||||
struct sc_usb *usb = userdata;
|
|
||||||
|
|
||||||
libusb_device *dev = libusb_get_device(usb->handle);
|
|
||||||
assert(dev);
|
|
||||||
if (dev != device) {
|
|
||||||
// Not the connected device
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(usb->cbs && usb->cbs->on_disconnected);
|
|
||||||
usb->cbs->on_disconnected(usb, usb->cbs_userdata);
|
|
||||||
|
|
||||||
// Do not automatically deregister the callback by returning 1. Instead,
|
|
||||||
// manually deregister to interrupt libusb_handle_events() from the libusb
|
|
||||||
// event thread: <https://stackoverflow.com/a/60119225/1987178>
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
run_libusb_event_handler(void *data) {
|
|
||||||
struct sc_usb *usb = data;
|
|
||||||
while (!atomic_load(&usb->stopped)) {
|
|
||||||
// Interrupted by events or by libusb_hotplug_deregister_callback()
|
|
||||||
libusb_handle_events(usb->context);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
sc_usb_register_callback(struct sc_usb *usb) {
|
|
||||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
|
|
||||||
LOGW("libusb does not have hotplug capability");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_device *device = libusb_get_device(usb->handle);
|
|
||||||
assert(device);
|
|
||||||
|
|
||||||
struct libusb_device_descriptor desc;
|
|
||||||
int result = libusb_get_device_descriptor(device, &desc);
|
|
||||||
if (result < 0) {
|
|
||||||
log_libusb_error((enum libusb_error) result);
|
|
||||||
LOGW("Could not read USB device descriptor");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int events = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
|
|
||||||
int flags = LIBUSB_HOTPLUG_NO_FLAGS;
|
|
||||||
int vendor_id = desc.idVendor;
|
|
||||||
int product_id = desc.idProduct;
|
|
||||||
int dev_class = LIBUSB_HOTPLUG_MATCH_ANY;
|
|
||||||
result = libusb_hotplug_register_callback(usb->context, events, flags,
|
|
||||||
vendor_id, product_id, dev_class,
|
|
||||||
sc_usb_libusb_callback, usb,
|
|
||||||
&usb->callback_handle);
|
|
||||||
if (result < 0) {
|
|
||||||
log_libusb_error((enum libusb_error) result);
|
|
||||||
LOGW("Could not register USB callback");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb->has_callback_handle = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_usb_connect(struct sc_usb *usb, libusb_device *device,
|
|
||||||
const struct sc_usb_callbacks *cbs, void *cbs_userdata) {
|
|
||||||
usb->handle = sc_usb_open_handle(device);
|
|
||||||
if (!usb->handle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb->has_callback_handle = false;
|
|
||||||
usb->has_libusb_event_thread = false;
|
|
||||||
|
|
||||||
// If cbs is set, then cbs->on_disconnected must be set
|
|
||||||
assert(!cbs || cbs->on_disconnected);
|
|
||||||
usb->cbs = cbs;
|
|
||||||
usb->cbs_userdata = cbs_userdata;
|
|
||||||
|
|
||||||
if (cbs) {
|
|
||||||
atomic_init(&usb->stopped, false);
|
|
||||||
if (sc_usb_register_callback(usb)) {
|
|
||||||
// Create a thread to process libusb events, so that device
|
|
||||||
// disconnection could be detected immediately
|
|
||||||
usb->has_libusb_event_thread =
|
|
||||||
sc_thread_create(&usb->libusb_event_thread,
|
|
||||||
run_libusb_event_handler, "scrcpy-usbev", usb);
|
|
||||||
if (!usb->has_libusb_event_thread) {
|
|
||||||
LOGW("Libusb event thread handler could not be created, USB "
|
|
||||||
"device disconnection might not be detected immediately");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGW("Could not register USB device disconnection callback");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_disconnect(struct sc_usb *usb) {
|
|
||||||
libusb_close(usb->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_stop(struct sc_usb *usb) {
|
|
||||||
if (usb->has_callback_handle) {
|
|
||||||
atomic_store(&usb->stopped, true);
|
|
||||||
libusb_hotplug_deregister_callback(usb->context, usb->callback_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_join(struct sc_usb *usb) {
|
|
||||||
if (usb->has_libusb_event_thread) {
|
|
||||||
sc_thread_join(&usb->libusb_event_thread, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#ifndef SC_USB_H
|
|
||||||
#define SC_USB_H
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
|
|
||||||
#include "util/thread.h"
|
|
||||||
|
|
||||||
struct sc_usb {
|
|
||||||
libusb_context *context;
|
|
||||||
libusb_device_handle *handle;
|
|
||||||
|
|
||||||
const struct sc_usb_callbacks *cbs;
|
|
||||||
void *cbs_userdata;
|
|
||||||
|
|
||||||
bool has_callback_handle;
|
|
||||||
libusb_hotplug_callback_handle callback_handle;
|
|
||||||
|
|
||||||
bool has_libusb_event_thread;
|
|
||||||
sc_thread libusb_event_thread;
|
|
||||||
|
|
||||||
atomic_bool stopped; // only used if cbs != NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sc_usb_callbacks {
|
|
||||||
void (*on_disconnected)(struct sc_usb *usb, void *userdata);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sc_usb_device {
|
|
||||||
libusb_device *device;
|
|
||||||
char *serial;
|
|
||||||
char *manufacturer;
|
|
||||||
char *product;
|
|
||||||
uint16_t vid;
|
|
||||||
uint16_t pid;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_device_destroy(struct sc_usb_device *usb_device);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_device_destroy_all(struct sc_usb_device *usb_devices, size_t count);
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_usb_init(struct sc_usb *usb);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_destroy(struct sc_usb *usb);
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
sc_usb_find_devices(struct sc_usb *usb, const char *serial,
|
|
||||||
struct sc_usb_device *devices, size_t len);
|
|
||||||
|
|
||||||
bool
|
|
||||||
sc_usb_connect(struct sc_usb *usb, libusb_device *device,
|
|
||||||
const struct sc_usb_callbacks *cbs, void *cbs_userdata);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_disconnect(struct sc_usb *usb);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_stop(struct sc_usb *usb);
|
|
||||||
|
|
||||||
void
|
|
||||||
sc_usb_join(struct sc_usb *usb);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
static void test_serialize_inject_keycode(void) {
|
static void test_serialize_inject_keycode(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
.type = CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||||
.inject_keycode = {
|
.inject_keycode = {
|
||||||
.action = AKEY_EVENT_ACTION_UP,
|
.action = AKEY_EVENT_ACTION_UP,
|
||||||
.keycode = AKEYCODE_ENTER,
|
.keycode = AKEYCODE_ENTER,
|
||||||
@@ -16,12 +16,12 @@ static void test_serialize_inject_keycode(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 14);
|
assert(size == 14);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||||
0x01, // AKEY_EVENT_ACTION_UP
|
0x01, // AKEY_EVENT_ACTION_UP
|
||||||
0x00, 0x00, 0x00, 0x42, // AKEYCODE_ENTER
|
0x00, 0x00, 0x00, 0x42, // AKEYCODE_ENTER
|
||||||
0x00, 0x00, 0x00, 0X05, // repeat
|
0x00, 0x00, 0x00, 0X05, // repeat
|
||||||
@@ -32,18 +32,18 @@ static void test_serialize_inject_keycode(void) {
|
|||||||
|
|
||||||
static void test_serialize_inject_text(void) {
|
static void test_serialize_inject_text(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_TEXT,
|
.type = CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||||
.inject_text = {
|
.inject_text = {
|
||||||
.text = "hello, world!",
|
.text = "hello, world!",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 18);
|
assert(size == 18);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_TEXT,
|
CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||||
0x00, 0x00, 0x00, 0x0d, // text length
|
0x00, 0x00, 0x00, 0x0d, // text length
|
||||||
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
|
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
|
||||||
};
|
};
|
||||||
@@ -52,30 +52,30 @@ static void test_serialize_inject_text(void) {
|
|||||||
|
|
||||||
static void test_serialize_inject_text_long(void) {
|
static void test_serialize_inject_text_long(void) {
|
||||||
struct sc_control_msg msg;
|
struct sc_control_msg msg;
|
||||||
msg.type = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
char text[SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
||||||
memset(text, 'a', SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
memset(text, 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
text[SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
|
text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
|
||||||
msg.inject_text.text = text;
|
msg.inject_text.text = text;
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
assert(size == 5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
|
|
||||||
unsigned char expected[5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
unsigned char expected[5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
||||||
expected[0] = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
expected[0] = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
expected[1] = 0x00;
|
expected[1] = 0x00;
|
||||||
expected[2] = 0x00;
|
expected[2] = 0x00;
|
||||||
expected[3] = 0x01;
|
expected[3] = 0x01;
|
||||||
expected[4] = 0x2c; // text length (32 bits)
|
expected[4] = 0x2c; // text length (32 bits)
|
||||||
memset(&expected[5], 'a', SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
memset(&expected[5], 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
|
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_inject_touch_event(void) {
|
static void test_serialize_inject_touch_event(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
.inject_touch_event = {
|
.inject_touch_event = {
|
||||||
.action = AMOTION_EVENT_ACTION_DOWN,
|
.action = AMOTION_EVENT_ACTION_DOWN,
|
||||||
.pointer_id = UINT64_C(0x1234567887654321),
|
.pointer_id = UINT64_C(0x1234567887654321),
|
||||||
@@ -94,12 +94,12 @@ static void test_serialize_inject_touch_event(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 28);
|
assert(size == 28);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||||
0x00, // AKEY_EVENT_ACTION_DOWN
|
0x00, // AKEY_EVENT_ACTION_DOWN
|
||||||
0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, // pointer id
|
0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, // pointer id
|
||||||
0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xc8, // 100 200
|
0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xc8, // 100 200
|
||||||
@@ -112,7 +112,7 @@ static void test_serialize_inject_touch_event(void) {
|
|||||||
|
|
||||||
static void test_serialize_inject_scroll_event(void) {
|
static void test_serialize_inject_scroll_event(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
.inject_scroll_event = {
|
.inject_scroll_event = {
|
||||||
.position = {
|
.position = {
|
||||||
.point = {
|
.point = {
|
||||||
@@ -130,12 +130,12 @@ static void test_serialize_inject_scroll_event(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 25);
|
assert(size == 25);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||||
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
|
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
|
||||||
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
||||||
0x00, 0x00, 0x00, 0x01, // 1
|
0x00, 0x00, 0x00, 0x01, // 1
|
||||||
@@ -147,18 +147,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 sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
.back_or_screen_on = {
|
.back_or_screen_on = {
|
||||||
.action = AKEY_EVENT_ACTION_UP,
|
.action = AKEY_EVENT_ACTION_UP,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||||
0x01, // AKEY_EVENT_ACTION_UP
|
0x01, // AKEY_EVENT_ACTION_UP
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
@@ -166,71 +166,71 @@ static void test_serialize_back_or_screen_on(void) {
|
|||||||
|
|
||||||
static void test_serialize_expand_notification_panel(void) {
|
static void test_serialize_expand_notification_panel(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_expand_settings_panel(void) {
|
static void test_serialize_expand_settings_panel(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
.type = CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_collapse_panels(void) {
|
static void test_serialize_collapse_panels(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
.type = CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_get_clipboard(void) {
|
static void test_serialize_get_clipboard(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
.get_clipboard = {
|
.get_clipboard = {
|
||||||
.copy_key = SC_COPY_KEY_COPY,
|
.copy_key = GET_CLIPBOARD_COPY_KEY_COPY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||||
SC_COPY_KEY_COPY,
|
GET_CLIPBOARD_COPY_KEY_COPY,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_set_clipboard(void) {
|
static void test_serialize_set_clipboard(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
.set_clipboard = {
|
.set_clipboard = {
|
||||||
.sequence = UINT64_C(0x0102030405060708),
|
.sequence = UINT64_C(0x0102030405060708),
|
||||||
.paste = true,
|
.paste = true,
|
||||||
@@ -238,12 +238,12 @@ static void test_serialize_set_clipboard(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 27);
|
assert(size == 27);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||||
1, // paste
|
1, // paste
|
||||||
0x00, 0x00, 0x00, 0x0d, // text length
|
0x00, 0x00, 0x00, 0x0d, // text length
|
||||||
@@ -254,7 +254,7 @@ static void test_serialize_set_clipboard(void) {
|
|||||||
|
|
||||||
static void test_serialize_set_clipboard_long(void) {
|
static void test_serialize_set_clipboard_long(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
.set_clipboard = {
|
.set_clipboard = {
|
||||||
.sequence = UINT64_C(0x0102030405060708),
|
.sequence = UINT64_C(0x0102030405060708),
|
||||||
.paste = true,
|
.paste = true,
|
||||||
@@ -262,60 +262,60 @@ static void test_serialize_set_clipboard_long(void) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
char text[SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH + 1];
|
char text[CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH + 1];
|
||||||
memset(text, 'a', SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
memset(text, 'a', CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
||||||
text[SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH] = '\0';
|
text[CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH] = '\0';
|
||||||
msg.set_clipboard.text = text;
|
msg.set_clipboard.text = text;
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == SC_CONTROL_MSG_MAX_SIZE);
|
assert(size == CONTROL_MSG_MAX_SIZE);
|
||||||
|
|
||||||
unsigned char expected[SC_CONTROL_MSG_MAX_SIZE] = {
|
unsigned char expected[CONTROL_MSG_MAX_SIZE] = {
|
||||||
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||||
1, // paste
|
1, // paste
|
||||||
// text length
|
// text length
|
||||||
SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 24,
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 24,
|
||||||
(SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 16) & 0xff,
|
(CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 16) & 0xff,
|
||||||
(SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 8) & 0xff,
|
(CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 8) & 0xff,
|
||||||
SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH & 0xff,
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH & 0xff,
|
||||||
};
|
};
|
||||||
memset(expected + 14, 'a', SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
memset(expected + 14, 'a', CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
||||||
|
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_set_screen_power_mode(void) {
|
static void test_serialize_set_screen_power_mode(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
.set_screen_power_mode = {
|
.set_screen_power_mode = {
|
||||||
.mode = SC_SCREEN_POWER_MODE_NORMAL,
|
.mode = SCREEN_POWER_MODE_NORMAL,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 2);
|
assert(size == 2);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
0x02, // SC_SCREEN_POWER_MODE_NORMAL
|
0x02, // SCREEN_POWER_MODE_NORMAL
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_serialize_rotate_device(void) {
|
static void test_serialize_rotate_device(void) {
|
||||||
struct sc_control_msg msg = {
|
struct sc_control_msg msg = {
|
||||||
.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
.type = CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
assert(size == 1);
|
assert(size == 1);
|
||||||
|
|
||||||
const unsigned char expected[] = {
|
const unsigned char expected[] = {
|
||||||
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||||
};
|
};
|
||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -20,4 +20,4 @@ ffmpeg_avcodec = 'avcodec-58'
|
|||||||
ffmpeg_avformat = 'avformat-58'
|
ffmpeg_avformat = 'avformat-58'
|
||||||
ffmpeg_avutil = 'avutil-56'
|
ffmpeg_avutil = 'avutil-56'
|
||||||
prebuilt_ffmpeg = 'ffmpeg-4.3.1-win32-shared'
|
prebuilt_ffmpeg = 'ffmpeg-4.3.1-win32-shared'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.20/i686-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.18/i686-w64-mingw32'
|
||||||
|
|||||||
+1
-1
@@ -20,4 +20,4 @@ ffmpeg_avcodec = 'avcodec-59'
|
|||||||
ffmpeg_avformat = 'avformat-59'
|
ffmpeg_avformat = 'avformat-59'
|
||||||
ffmpeg_avutil = 'avutil-57'
|
ffmpeg_avutil = 'avutil-57'
|
||||||
prebuilt_ffmpeg = 'ffmpeg-5.0-full_build-shared'
|
prebuilt_ffmpeg = 'ffmpeg-5.0-full_build-shared'
|
||||||
prebuilt_sdl2 = 'SDL2-2.0.20/x86_64-w64-mingw32'
|
prebuilt_sdl2 = 'SDL2-2.0.18/x86_64-w64-mingw32'
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
@cmd
|
|
||||||
@@ -23,11 +23,11 @@ prepare-ffmpeg-win64:
|
|||||||
ffmpeg-5.0-full_build-shared
|
ffmpeg-5.0-full_build-shared
|
||||||
|
|
||||||
prepare-sdl2:
|
prepare-sdl2:
|
||||||
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.20-mingw.tar.gz \
|
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.18-mingw.tar.gz \
|
||||||
38094d82a857d6c62352e5c5cdec74948c5b4d25c59cbd298d6d233568976bd1 \
|
bbad7c6947f6ca3e05292f065852ed8b62f319fc5533047e7708769c4dbae394 \
|
||||||
SDL2-2.0.20
|
SDL2-2.0.18
|
||||||
|
|
||||||
prepare-adb:
|
prepare-adb:
|
||||||
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r32.0.0-windows.zip \
|
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r31.0.3-windows.zip \
|
||||||
41f4c7512b32cbb3f8c624c20b56326abb692a6f169b03b4b63b6c5a6fdbb08c \
|
0f4b8fdd26af2c3733539d6eebb3c2ed499ea1d4bb1f4e0ecc2d6016961a6e24 \
|
||||||
platform-tools
|
platform-tools
|
||||||
|
|||||||
+2
-4
@@ -93,7 +93,6 @@ dist-win32: build-server build-win32
|
|||||||
cp data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp data/scrcpy-console.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)"
|
cp data/icon.png "$(DIST)/$(WIN32_TARGET_DIR)"
|
||||||
cp data/open_a_terminal_here.bat "$(DIST)/$(WIN32_TARGET_DIR)"
|
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avutil-56.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avcodec-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-4.3.1-win32-shared/bin/avformat-58.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
@@ -102,7 +101,7 @@ dist-win32: build-server build-win32
|
|||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.20/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.18/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
|
||||||
|
|
||||||
dist-win64: build-server build-win64
|
dist-win64: build-server build-win64
|
||||||
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
@@ -111,7 +110,6 @@ dist-win64: build-server build-win64
|
|||||||
cp data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/scrcpy-console.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/scrcpy-noconsole.vbs "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
cp data/icon.png "$(DIST)/$(WIN64_TARGET_DIR)"
|
||||||
cp data/open_a_terminal_here.bat "$(DIST)/$(WIN64_TARGET_DIR)"
|
|
||||||
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avutil-57.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avutil-57.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avcodec-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avcodec-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avformat-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/ffmpeg-5.0-full_build-shared/bin/avformat-59.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
@@ -120,7 +118,7 @@ dist-win64: build-server build-win64
|
|||||||
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
cp prebuilt-deps/SDL2-2.0.20/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
cp prebuilt-deps/SDL2-2.0.18/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
|
||||||
|
|
||||||
zip-win32: dist-win32
|
zip-win32: dist-win32
|
||||||
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public final class Server {
|
|||||||
private static void initAndCleanUp(Options options) {
|
private static void initAndCleanUp(Options options) {
|
||||||
boolean mustDisableShowTouchesOnCleanUp = false;
|
boolean mustDisableShowTouchesOnCleanUp = false;
|
||||||
int restoreStayOn = -1;
|
int restoreStayOn = -1;
|
||||||
boolean restoreNormalPowerMode = options.getControl(); // only restore power mode if control is enabled
|
|
||||||
if (options.getShowTouches() || options.getStayAwake()) {
|
if (options.getShowTouches() || options.getStayAwake()) {
|
||||||
Settings settings = Device.getSettings();
|
Settings settings = Device.getSettings();
|
||||||
if (options.getShowTouches()) {
|
if (options.getShowTouches()) {
|
||||||
@@ -52,8 +51,7 @@ public final class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CleanUp.configure(options.getDisplayId(), restoreStayOn, mustDisableShowTouchesOnCleanUp, restoreNormalPowerMode,
|
CleanUp.configure(options.getDisplayId(), restoreStayOn, mustDisableShowTouchesOnCleanUp, true, options.getPowerOffScreenOnClose());
|
||||||
options.getPowerOffScreenOnClose());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Ln.e("Could not configure cleanup", e);
|
Ln.e("Could not configure cleanup", e);
|
||||||
}
|
}
|
||||||
@@ -262,7 +260,6 @@ public final class Server {
|
|||||||
options.setSendFrameMeta(false);
|
options.setSendFrameMeta(false);
|
||||||
options.setSendDummyByte(false);
|
options.setSendDummyByte(false);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
Ln.w("Unknown server option: " + key);
|
Ln.w("Unknown server option: " + key);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user