Compare commits

..

2 Commits

Author SHA1 Message Date
d613b10efc Add a new method for text injection
On Android >= 7, inject text using the clipboard.

This is faster and allows to inject UTF-8.
2020-05-25 03:28:33 +02:00
cc4e1e20de Add more convenience methods for injection
Expose methods to inject key events and key codes with an additional
parameter to specify the "mode" (async, wait for finish, wait for
result).
2020-05-25 03:28:33 +02:00
19 changed files with 129 additions and 160 deletions

View File

@ -249,10 +249,10 @@ You can then [run](README.md#run) _scrcpy_.
## Prebuilt server
- [`scrcpy-server-v1.14`][direct-scrcpy-server]
_(SHA-256: 1d1b18a2b80e956771fd63b99b414d2d028713a8f12ddfa5a369709ad4295620)_
- [`scrcpy-server-v1.13`][direct-scrcpy-server]
_(SHA-256: 5fee64ca1ccdc2f38550f31f5353c66de3de30c2e929a964e30fa2d005d5f885)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.14/scrcpy-server-v1.14
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-server-v1.13
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:

View File

@ -1,4 +1,4 @@
# scrcpy (v1.14)
# scrcpy (v1.13)
This application provides display and control of Android devices connected on
USB (or [over TCP/IP][article-tcpip]). It does not require any _root_ access.
@ -69,10 +69,10 @@ hard).
For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available:
- [`scrcpy-win64-v1.14.zip`][direct-win64]
_(SHA-256: 2be9139e46e29cf2f5f695848bb2b75a543b8f38be1133257dc5068252abc25f)_
- [`scrcpy-win64-v1.13.zip`][direct-win64]
_(SHA-256: 806aafc00d4db01513193addaa24f47858893ba5efe75770bfef6ae1ea987d27)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.14/scrcpy-win64-v1.14.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-win64-v1.13.zip
It is also available in [Chocolatey]:
@ -417,7 +417,7 @@ The secondary display may only be controlled if the device runs at least Android
#### Stay awake
To prevent the device to sleep after some delay when the device is plugged in:
To prevent the device to sleep after some delay:
```bash
scrcpy --stay-awake
@ -439,7 +439,7 @@ scrcpy -S
Or by pressing `Ctrl`+`o` at any time.
To turn it back on, press `Ctrl`+`Shift`+`o` (or `POWER`, `Ctrl`+`p`).
To turn it back on, press `POWER` (or `Ctrl`+`p`).
It can be useful to also prevent the device to sleep:
@ -494,8 +494,7 @@ It is possible to synchronize clipboards between the computer and the device, in
both directions:
- `Ctrl`+`c` copies the device clipboard to the computer clipboard;
- `Ctrl`+`Shift`+`v` copies the computer clipboard to the device clipboard (and
pastes if the device runs Android >= 7);
- `Ctrl`+`Shift`+`v` copies the computer clipboard to the device clipboard;
- `Ctrl`+`v` _pastes_ the computer clipboard as a sequence of text events (but
breaks non-ASCII characters).
@ -560,33 +559,29 @@ Also see [issue #14].
## Shortcuts
`LCtrl` is the left `Ctrl` key (the right `Ctrl` key is forwarded to the
device).
| Action | Shortcut | Shortcut (macOS)
| ------------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `LCtrl`+`f` | `Cmd`+`f`
| Rotate display left | `LCtrl`+`` _(left)_ | `Cmd`+`` _(left)_
| Rotate display right | `LCtrl`+`` _(right)_ | `Cmd`+`` _(right)_
| Resize window to 1:1 (pixel-perfect) | `LCtrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `LCtrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `LCtrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `LCtrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `LCtrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `LCtrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `LCtrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
| Click on `VOLUME_DOWN` | `LCtrl`+`` _(down)_ | `Cmd`+`` _(down)_
| Click on `POWER` | `LCtrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring) | `LCtrl`+`o` | `Cmd`+`o`
| Turn device screen on | `LCtrl`+`Shift`+`o` | `Cmd`+`Shift`+`o`
| Rotate device screen | `LCtrl`+`r` | `Cmd`+`r`
| Expand notification panel | `LCtrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `LCtrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `LCtrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `LCtrl`+`v` | `Cmd`+`v`
| Copy computer clipboard to device and paste | `LCtrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
| Enable/disable FPS counter (on stdout) | `LCtrl`+`i` | `Cmd`+`i`
| Action | Shortcut | Shortcut (macOS)
| -------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f`
| Rotate display left | `Ctrl`+`←` _(left)_ | `Cmd`+`←` _(left)_
| Rotate display right | `Ctrl`+`→` _(right)_ | `Cmd`+`→` _(right)_
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `Ctrl`+`` _(up)_ | `Cmd`+`` _(up)_
| Click on `VOLUME_DOWN` | `Ctrl`+`` _(down)_ | `Cmd`+`` _(down)_
| Click on `POWER` | `Ctrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring)| `Ctrl`+`o` | `Cmd`+`o`
| Rotate device screen | `Ctrl`+`r` | `Cmd`+`r`
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v`
| Copy computer clipboard to device | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
| Enable/disable FPS counter (on stdout) | `Ctrl`+`i` | `Cmd`+`i`
_¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._

View File

@ -129,7 +129,6 @@ Force recording format (either mp4 or mkv).
Request SDL to use the given render driver (this is just a hint).
Supported names are currently "direct3d", "opengl", "opengles2", "opengles", "metal" and "software".
.UR https://wiki.libsdl.org/SDL_HINT_RENDER_DRIVER
.UE
@ -167,7 +166,7 @@ Default is "info" for release builds, "debug" for debug builds.
.TP
.B \-w, \-\-stay-awake
Keep the device on while scrcpy is running, when the device is plugged in.
Keep the device on while scrcpy is running.
.TP
.B \-\-window\-borderless
@ -203,54 +202,52 @@ Default is 0 (automatic).\n
.SH SHORTCUTS
\fBLCtrl\fR is the left Ctrl key (the right Ctrl key is forwarded to the device).
.TP
.B LCtrl+f
.B Ctrl+f
Switch fullscreen mode
.TP
.B LCtrl+Left
.B Ctrl+Left
Rotate display left
.TP
.B LCtrl+Right
.B Ctrl+Right
Rotate display right
.TP
.B LCtrl+g
.B Ctrl+g
Resize window to 1:1 (pixel\-perfect)
.TP
.B LCtrl+x, Double\-click on black borders
.B Ctrl+x, Double\-click on black borders
Resize window to remove black borders
.TP
.B LCtrl+h, Home, Middle\-click
.B Ctrl+h, Home, Middle\-click
Click on HOME
.TP
.B LCtrl+b, Ctrl+Backspace, Right\-click (when screen is on)
.B Ctrl+b, Ctrl+Backspace, Right\-click (when screen is on)
Click on BACK
.TP
.B LCtrl+s
.B Ctrl+s
Click on APP_SWITCH
.TP
.B LCtrl+m
.B Ctrl+m
Click on MENU
.TP
.B LCtrl+Up
.B Ctrl+Up
Click on VOLUME_UP
.TP
.B LCtrl+Down
.B Ctrl+Down
Click on VOLUME_DOWN
.TP
.B LCtrl+p
.B Ctrl+p
Click on POWER (turn screen on/off)
.TP
@ -258,39 +255,35 @@ Click on POWER (turn screen on/off)
Turn screen on
.TP
.B LCtrl+o
.B Ctrl+o
Turn device screen off (keep mirroring)
.TP
.B LCtrl+Shift+o
Turn device screen on
.TP
.B LCtrl+r
.B Ctrl+r
Rotate device screen
.TP
.B LCtrl+n
.B Ctrl+n
Expand notification panel
.TP
.B LCtrl+Shift+n
.B Ctrl+Shift+n
Collapse notification panel
.TP
.B LCtrl+c
.B Ctrl+c
Copy device clipboard to computer
.TP
.B LCtrl+v
.B Ctrl+v
Paste computer clipboard to device
.TP
.B LCtrl+Shift+v
Copy computer clipboard to device (and paste if the device runs Android >= 7)
.B Ctrl+Shift+v
Copy computer clipboard to device
.TP
.B LCtrl+i
.B Ctrl+i
Enable/disable FPS counter (print frames/second in logs)
.TP

View File

@ -15,7 +15,7 @@ scrcpy_print_usage(const char *arg0) {
#ifdef __APPLE__
# define CTRL_OR_CMD "Cmd"
#else
# define CTRL_OR_CMD "LCtrl"
# define CTRL_OR_CMD "Ctrl"
#endif
fprintf(stderr,
"Usage: %s [options]\n"
@ -159,8 +159,7 @@ scrcpy_print_usage(const char *arg0) {
#endif
"\n"
" -w, --stay-awake\n"
" Keep the device on while scrcpy is running, when the device\n"
" is plugged in.\n"
" Keep the device on while scrcpy is running.\n"
"\n"
" --window-borderless\n"
" Disable window decorations (display borderless window).\n"
@ -186,9 +185,6 @@ scrcpy_print_usage(const char *arg0) {
"\n"
"Shortcuts:\n"
"\n"
" LCtrl is the left Ctrl key (the right Ctrl key is forwarded to\n"
" the device).\n"
"\n"
" " CTRL_OR_CMD "+f\n"
" Switch fullscreen mode\n"
"\n"
@ -205,7 +201,7 @@ scrcpy_print_usage(const char *arg0) {
" Double-click on black borders\n"
" Resize window to remove black borders\n"
"\n"
" LCtrl+h\n"
" Ctrl+h\n"
" Middle-click\n"
" Click on HOME\n"
"\n"
@ -217,7 +213,7 @@ scrcpy_print_usage(const char *arg0) {
" " CTRL_OR_CMD "+s\n"
" Click on APP_SWITCH\n"
"\n"
" LCtrl+m\n"
" Ctrl+m\n"
" Click on MENU\n"
"\n"
" " CTRL_OR_CMD "+Up\n"
@ -235,9 +231,6 @@ scrcpy_print_usage(const char *arg0) {
" " CTRL_OR_CMD "+o\n"
" Turn device screen off (keep mirroring)\n"
"\n"
" " CTRL_OR_CMD "+Shift+o\n"
" Turn device screen on\n"
"\n"
" " CTRL_OR_CMD "+r\n"
" Rotate device screen\n"
"\n"
@ -254,8 +247,7 @@ scrcpy_print_usage(const char *arg0) {
" Paste computer clipboard to device\n"
"\n"
" " CTRL_OR_CMD "+Shift+v\n"
" Copy computer clipboard to device (and paste if the device\n"
" runs Android >= 7)\n"
" Copy computer clipboard to device\n"
"\n"
" " CTRL_OR_CMD "+i\n"
" Enable/disable FPS counter (print frames/second in logs)\n"

View File

@ -67,11 +67,10 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
(uint32_t) msg->inject_scroll_event.vscroll);
return 21;
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
buf[1] = !!msg->set_clipboard.paste;
size_t len = write_string(msg->set_clipboard.text,
size_t len = write_string(msg->inject_text.text,
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
&buf[2]);
return 2 + len;
&buf[1]);
return 1 + len;
}
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
buf[1] = msg->set_screen_power_mode.mode;

View File

@ -11,9 +11,9 @@
#include "common.h"
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4092
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4093
#define CONTROL_MSG_SERIALIZED_MAX_SIZE \
(4 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH)
(3 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH)
#define POINTER_ID_MOUSE UINT64_C(-1);
@ -62,7 +62,6 @@ struct control_msg {
} inject_scroll_event;
struct {
char *text; // owned, to be freed by SDL_free()
bool paste;
} set_clipboard;
struct {
enum screen_power_mode mode;

View File

@ -92,7 +92,6 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod,
MAP(SDLK_LEFT, AKEYCODE_DPAD_LEFT);
MAP(SDLK_DOWN, AKEYCODE_DPAD_DOWN);
MAP(SDLK_UP, AKEYCODE_DPAD_UP);
MAP(SDLK_RCTRL, AKEYCODE_CTRL_RIGHT);
}
if (!(mod & (KMOD_NUM | KMOD_SHIFT))) {

View File

@ -112,7 +112,7 @@ request_device_clipboard(struct controller *controller) {
}
static void
set_device_clipboard(struct controller *controller, bool paste) {
set_device_clipboard(struct controller *controller) {
char *text = SDL_GetClipboardText();
if (!text) {
LOGW("Could not get clipboard text: %s", SDL_GetError());
@ -127,7 +127,6 @@ set_device_clipboard(struct controller *controller, bool paste) {
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
msg.set_clipboard.text = text;
msg.set_clipboard.paste = paste;
if (!controller_push_msg(controller, &msg)) {
SDL_free(text);
@ -259,8 +258,7 @@ input_manager_process_key(struct input_manager *im,
// control: indicates the state of the command-line option --no-control
// ctrl: the Ctrl key
// Only capture Left-Ctrl, Right-Ctrl is forwarded to the device
bool ctrl = event->keysym.mod & KMOD_LCTRL;
bool ctrl = event->keysym.mod & (KMOD_LCTRL | KMOD_RCTRL);
bool alt = event->keysym.mod & (KMOD_LALT | KMOD_RALT);
bool meta = event->keysym.mod & (KMOD_LGUI | KMOD_RGUI);
@ -322,11 +320,8 @@ input_manager_process_key(struct input_manager *im,
}
return;
case SDLK_o:
if (control && cmd && down) {
enum screen_power_mode mode = shift
? SCREEN_POWER_MODE_NORMAL
: SCREEN_POWER_MODE_OFF;
set_screen_power_mode(controller, mode);
if (control && cmd && !shift && down) {
set_screen_power_mode(controller, SCREEN_POWER_MODE_OFF);
}
return;
case SDLK_DOWN:
@ -359,8 +354,8 @@ input_manager_process_key(struct input_manager *im,
case SDLK_v:
if (control && cmd && !repeat && down) {
if (shift) {
// store the text in the device clipboard and paste
set_device_clipboard(controller, true);
// store the text in the device clipboard
set_device_clipboard(controller);
} else {
// inject the text as input events
clipboard_paste(controller);

View File

@ -200,19 +200,17 @@ static void test_serialize_get_clipboard(void) {
static void test_serialize_set_clipboard(void) {
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
.set_clipboard = {
.paste = true,
.inject_text = {
.text = "hello, world!",
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 17);
assert(size == 16);
const unsigned char expected[] = {
CONTROL_MSG_TYPE_SET_CLIPBOARD,
1, // paste
0x00, 0x0d, // text length
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
};

View File

@ -1,5 +1,5 @@
project('scrcpy', 'c',
version: '1.14',
version: '1.13',
meson_version: '>= 0.48',
default_options: [
'c_std=c11',

View File

@ -35,6 +35,6 @@ prepare-sdl2:
SDL2-2.0.12
prepare-adb:
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.0-windows.zip \
854305f9a702f5ea2c3de73edde402bd26afa0ee944c9b0c4380420f5a862e0d \
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r29.0.5-windows.zip \
2df06160056ec9a84c7334af2a1e42740befbb1a2e34370e7af544a2cc78152c \
platform-tools

View File

@ -6,8 +6,8 @@ android {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 29
versionCode 16
versionName "1.14"
versionCode 15
versionName "1.13"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {

View File

@ -12,7 +12,7 @@
set -e
SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=1.14
SCRCPY_VERSION_NAME=1.13
PLATFORM=${ANDROID_PLATFORM:-29}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-29.0.2}

View File

@ -17,8 +17,6 @@ public final class ControlMessage {
public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
public static final int TYPE_ROTATE_DEVICE = 10;
public static final int FLAGS_PASTE = 1;
private int type;
private String text;
private int metaState; // KeyEvent.META_*
@ -30,7 +28,6 @@ public final class ControlMessage {
private Position position;
private int hScroll;
private int vScroll;
private int flags;
private ControlMessage() {
}
@ -71,13 +68,10 @@ public final class ControlMessage {
return msg;
}
public static ControlMessage createSetClipboard(String text, boolean paste) {
public static ControlMessage createSetClipboard(String text) {
ControlMessage msg = new ControlMessage();
msg.type = TYPE_SET_CLIPBOARD;
msg.text = text;
if (paste) {
msg.flags = FLAGS_PASTE;
}
return msg;
}
@ -140,8 +134,4 @@ public final class ControlMessage {
public int getVScroll() {
return vScroll;
}
public int getFlags() {
return flags;
}
}

View File

@ -12,9 +12,8 @@ public class ControlMessageReader {
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4092; // 4096 - 1 (type) - 1 (parse flag) - 2 (length)
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
public static final int INJECT_TEXT_MAX_LENGTH = 300;
private static final int RAW_BUFFER_SIZE = 4096;
@ -149,15 +148,11 @@ public class ControlMessageReader {
}
private ControlMessage parseSetClipboard() {
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
return null;
}
boolean parse = buffer.get() != 0;
String text = parseString();
if (text == null) {
return null;
}
return ControlMessage.createSetClipboard(text, parse);
return ControlMessage.createSetClipboard(text);
}
private ControlMessage parseSetScreenPowerMode() {

View File

@ -1,6 +1,5 @@
package com.genymobile.scrcpy;
import android.os.Build;
import android.os.SystemClock;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@ -105,13 +104,13 @@ public class Controller {
break;
case ControlMessage.TYPE_GET_CLIPBOARD:
String clipboardText = device.getClipboardText();
if (clipboardText != null) {
sender.pushClipboardText(clipboardText);
}
sender.pushClipboardText(clipboardText);
break;
case ControlMessage.TYPE_SET_CLIPBOARD:
boolean paste = (msg.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
setClipboard(msg.getText(), paste);
boolean setClipboardOk = device.setClipboardText(msg.getText());
if (setClipboardOk) {
Ln.i("Device clipboard set");
}
break;
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
if (device.supportsInputEvents()) {
@ -150,6 +149,10 @@ public class Controller {
}
private int injectText(String text) {
if (device.injectTextPaste(text)) {
// The best method (fastest and UTF-8) worked!
return text.length();
}
int successCount = 0;
for (char c : text.toCharArray()) {
if (!injectChar(c)) {
@ -228,18 +231,4 @@ public class Controller {
int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER;
return device.injectKeycode(keycode);
}
private boolean setClipboard(String text, boolean paste) {
boolean ok = device.setClipboardText(text);
if (ok) {
Ln.i("Device clipboard set");
}
// On Android >= 7, also press the PASTE key if requested
if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) {
device.injectKeycode(KeyEvent.KEYCODE_PASTE);
}
return ok;
}
}

View File

@ -167,15 +167,44 @@ public final class Device {
return injectEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) {
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int mode) {
long now = SystemClock.uptimeMillis();
KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0,
InputDevice.SOURCE_KEYBOARD);
return injectEvent(event);
return injectEvent(event, mode);
}
public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) {
return injectKeyEvent(action, keyCode, repeat, metaState, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectKeycode(int keyCode, int mode) {
return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, mode);
}
public boolean injectKeycode(int keyCode) {
return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0);
return injectKeycode(keyCode, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
public boolean injectTextPaste(String text) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return false;
}
// On Android >= 7, we can inject UTF-8 text as follow:
// - set the clipboard
// - inject the PASTE key event
// - restore the clipboard
String clipboardBackup = getClipboardText();
isSettingClipboard.set(true);
rawSetClipboardText(text);
boolean ok = injectKeycode(KeyEvent.KEYCODE_PASTE, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT);
rawSetClipboardText(clipboardBackup);
isSettingClipboard.set(false);
return ok;
}
public boolean isScreenOn() {
@ -206,9 +235,13 @@ public final class Device {
return s.toString();
}
private boolean rawSetClipboardText(String text) {
return serviceManager.getClipboardManager().setText(text);
}
public boolean setClipboardText(String text) {
isSettingClipboard.set(true);
boolean ok = serviceManager.getClipboardManager().setText(text);
boolean ok = rawSetClipboardText(text);
isSettingClipboard.set(false);
return ok;
}

View File

@ -15,7 +15,7 @@ public final class Ln {
DEBUG, INFO, WARN, ERROR
}
private static Level threshold = Level.INFO;
private static Level threshold;
private Ln() {
// not instantiable

View File

@ -216,7 +216,6 @@ public class ControlMessageReaderTest {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
dos.writeByte(1); // paste
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeShort(text.length);
dos.write(text);
@ -228,9 +227,6 @@ public class ControlMessageReaderTest {
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals("testé", event.getText());
boolean parse = (event.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
Assert.assertTrue(parse);
}
@Test
@ -242,7 +238,6 @@ public class ControlMessageReaderTest {
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
byte[] rawText = new byte[ControlMessageReader.CLIPBOARD_TEXT_MAX_LENGTH];
dos.writeByte(1); // paste
Arrays.fill(rawText, (byte) 'a');
String text = new String(rawText, 0, rawText.length);
@ -256,9 +251,6 @@ public class ControlMessageReaderTest {
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals(text, event.getText());
boolean parse = (event.getFlags() & ControlMessage.FLAGS_PASTE) != 0;
Assert.assertTrue(parse);
}
@Test