Add shortcut to open keyboard settings
The keyboard settings can be opened by: adb shell am start -a android.settings.HARD_KEYBOARD_SETTINGS Add a shortcut (MOD+k) for convenience if the current keyboard is HID.
This commit is contained in:
parent
8eb2ccf59f
commit
39dcaf6ce9
@ -182,10 +182,12 @@ Possible values are "disabled", "sdk" and "aoa":
|
|||||||
- "aoa" simulates a physical HID keyboard using the AOAv2 protocol. It may only work over USB.
|
- "aoa" simulates a physical HID keyboard using the AOAv2 protocol. It may only work over USB.
|
||||||
- "uhid" simulates a physical HID keyboard using the Linux HID kernel module on the device.
|
- "uhid" simulates a physical HID keyboard using the Linux HID kernel module on the device.
|
||||||
|
|
||||||
For "aoa" and "uhid", the keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly:
|
For "aoa" and "uhid", the keyboard layout must be configured (once and for all) on the device, via Settings -> System -> Languages and input -> Physical keyboard. This settings page can be started directly using the shortcut MOD+k (except in OTG mode) or by executing:
|
||||||
|
|
||||||
adb shell am start -a android.settings.HARD_KEYBOARD_SETTINGS
|
adb shell am start -a android.settings.HARD_KEYBOARD_SETTINGS
|
||||||
|
|
||||||
|
If mirroring is enabled, the shortcot MOD+k opens it.
|
||||||
|
|
||||||
This option is only available when the HID keyboard is enabled (or a physical keyboard is connected).
|
This option is only available when the HID keyboard is enabled (or a physical keyboard is connected).
|
||||||
|
|
||||||
Also see \fB\-\-mouse\fR.
|
Also see \fB\-\-mouse\fR.
|
||||||
@ -644,6 +646,10 @@ Copy computer clipboard to device, then paste (inject PASTE keycode, Android >=
|
|||||||
.B MOD+Shift+v
|
.B MOD+Shift+v
|
||||||
Inject computer clipboard text as a sequence of key events
|
Inject computer clipboard text as a sequence of key events
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B MOD+k
|
||||||
|
Open keyboard settings on the device (for HID keyboard only)
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B MOD+i
|
.B MOD+i
|
||||||
Enable/disable FPS counter (print frames/second in logs)
|
Enable/disable FPS counter (print frames/second in logs)
|
||||||
|
@ -377,8 +377,9 @@ static const struct sc_option options[] = {
|
|||||||
"For \"aoa\" and \"uhid\", the keyboard layout must be "
|
"For \"aoa\" and \"uhid\", the keyboard layout must be "
|
||||||
"configured (once and for all) on the device, via Settings -> "
|
"configured (once and for all) on the device, via Settings -> "
|
||||||
"System -> Languages and input -> Physical keyboard. This "
|
"System -> Languages and input -> Physical keyboard. This "
|
||||||
"settings page can be started directly: `adb shell am start -a "
|
"settings page can be started directly using the shortcut "
|
||||||
"android.settings.HARD_KEYBOARD_SETTINGS`.\n"
|
"MOD+k (except in OTG mode) or by executing: `adb shell am "
|
||||||
|
"start -a android.settings.HARD_KEYBOARD_SETTINGS`.\n"
|
||||||
"This option is only available when a HID keyboard is enabled "
|
"This option is only available when a HID keyboard is enabled "
|
||||||
"enabled (or a physical keyboard is connected).\n"
|
"enabled (or a physical keyboard is connected).\n"
|
||||||
"Also see --mouse.",
|
"Also see --mouse.",
|
||||||
@ -965,6 +966,10 @@ static const struct sc_shortcut shortcuts[] = {
|
|||||||
.shortcuts = { "MOD+Shift+v" },
|
.shortcuts = { "MOD+Shift+v" },
|
||||||
.text = "Inject computer clipboard text as a sequence of key events",
|
.text = "Inject computer clipboard text as a sequence of key events",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.shortcuts = { "MOD+k" },
|
||||||
|
.text = "Open keyboard settings on the device (for HID keyboard only)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.shortcuts = { "MOD+i" },
|
.shortcuts = { "MOD+i" },
|
||||||
.text = "Enable/disable FPS counter (print frames/second in logs)",
|
.text = "Enable/disable FPS counter (print frames/second in logs)",
|
||||||
|
@ -161,6 +161,7 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) {
|
|||||||
case SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
case SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
case SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
case SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS:
|
||||||
case SC_CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
case SC_CONTROL_MSG_TYPE_ROTATE_DEVICE:
|
||||||
|
case SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
|
||||||
// no additional data
|
// no additional data
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
@ -262,6 +263,9 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
|
|||||||
LOG_CMSG("UHID input (id=%" PRIu16 ", size=%" PRIu16 ")",
|
LOG_CMSG("UHID input (id=%" PRIu16 ", size=%" PRIu16 ")",
|
||||||
msg->uhid_input.id, msg->uhid_input.size);
|
msg->uhid_input.id, msg->uhid_input.size);
|
||||||
break;
|
break;
|
||||||
|
case SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
|
||||||
|
LOG_CMSG("open hard keyboard settings");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CMSG("unknown type: %u", (unsigned) msg->type);
|
LOG_CMSG("unknown type: %u", (unsigned) msg->type);
|
||||||
break;
|
break;
|
||||||
|
@ -40,6 +40,7 @@ enum sc_control_msg_type {
|
|||||||
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||||
SC_CONTROL_MSG_TYPE_UHID_CREATE,
|
SC_CONTROL_MSG_TYPE_UHID_CREATE,
|
||||||
SC_CONTROL_MSG_TYPE_UHID_INPUT,
|
SC_CONTROL_MSG_TYPE_UHID_INPUT,
|
||||||
|
SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sc_screen_power_mode {
|
enum sc_screen_power_mode {
|
||||||
|
@ -318,6 +318,18 @@ rotate_device(struct sc_input_manager *im) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
open_hard_keyboard_settings(struct sc_input_manager *im) {
|
||||||
|
assert(im->controller);
|
||||||
|
|
||||||
|
struct sc_control_msg msg;
|
||||||
|
msg.type = SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS;
|
||||||
|
|
||||||
|
if (!sc_controller_push_msg(im->controller, &msg)) {
|
||||||
|
LOGW("Could not request opening hard keyboard settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
apply_orientation_transform(struct sc_input_manager *im,
|
apply_orientation_transform(struct sc_input_manager *im,
|
||||||
enum sc_orientation transform) {
|
enum sc_orientation transform) {
|
||||||
@ -550,6 +562,13 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
|||||||
rotate_device(im);
|
rotate_device(im);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case SDLK_k:
|
||||||
|
if (control && !shift && !repeat && down
|
||||||
|
&& im->kp && im->kp->hid) {
|
||||||
|
// Only if the current keyboard is hid
|
||||||
|
open_hard_keyboard_settings(im);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -340,5 +340,6 @@ sc_keyboard_sdk_init(struct sc_keyboard_sdk *kb,
|
|||||||
|
|
||||||
// Key injection and clipboard synchronization are serialized
|
// Key injection and clipboard synchronization are serialized
|
||||||
kb->key_processor.async_paste = false;
|
kb->key_processor.async_paste = false;
|
||||||
|
kb->key_processor.hid = false;
|
||||||
kb->key_processor.ops = &ops;
|
kb->key_processor.ops = &ops;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,12 @@ struct sc_key_processor {
|
|||||||
*/
|
*/
|
||||||
bool async_paste;
|
bool async_paste;
|
||||||
|
|
||||||
|
/** Set by the implementation to indicate that the keyboard is HID. In
|
||||||
|
* practice, it is used to react on a shortcut to open the hard keyboard
|
||||||
|
* settings only if the keyboard is HID.
|
||||||
|
*/
|
||||||
|
bool hid;
|
||||||
|
|
||||||
const struct sc_key_processor_ops *ops;
|
const struct sc_key_processor_ops *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,6 +107,7 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
|
|||||||
// Clipboard synchronization is requested over the same control socket, so
|
// Clipboard synchronization is requested over the same control socket, so
|
||||||
// there is no need for a specific synchronization mechanism
|
// there is no need for a specific synchronization mechanism
|
||||||
kb->key_processor.async_paste = false;
|
kb->key_processor.async_paste = false;
|
||||||
|
kb->key_processor.hid = true;
|
||||||
kb->key_processor.ops = &ops;
|
kb->key_processor.ops = &ops;
|
||||||
|
|
||||||
static const struct sc_uhid_receiver_ops uhid_receiver_ops = {
|
static const struct sc_uhid_receiver_ops uhid_receiver_ops = {
|
||||||
|
@ -91,6 +91,7 @@ sc_keyboard_aoa_init(struct sc_keyboard_aoa *kb, struct sc_aoa *aoa) {
|
|||||||
// events are sent over AOA, so it must wait for clipboard synchronization
|
// events are sent over AOA, so it must wait for clipboard synchronization
|
||||||
// to be acknowledged by the device before injecting Ctrl+v.
|
// to be acknowledged by the device before injecting Ctrl+v.
|
||||||
kb->key_processor.async_paste = true;
|
kb->key_processor.async_paste = true;
|
||||||
|
kb->key_processor.hid = true;
|
||||||
kb->key_processor.ops = &ops;
|
kb->key_processor.ops = &ops;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -370,6 +370,21 @@ static void test_serialize_uhid_input(void) {
|
|||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_serialize_open_hard_keyboard(void) {
|
||||||
|
struct sc_control_msg msg = {
|
||||||
|
.type = SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||||
|
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||||
|
assert(size == 1);
|
||||||
|
|
||||||
|
const uint8_t expected[] = {
|
||||||
|
SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS,
|
||||||
|
};
|
||||||
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
@ -390,5 +405,6 @@ int main(int argc, char *argv[]) {
|
|||||||
test_serialize_rotate_device();
|
test_serialize_rotate_device();
|
||||||
test_serialize_uhid_create();
|
test_serialize_uhid_create();
|
||||||
test_serialize_uhid_input();
|
test_serialize_uhid_input();
|
||||||
|
test_serialize_open_hard_keyboard();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ _<kbd>[Super]</kbd> is typically the <kbd>Windows</kbd> or <kbd>Cmd</kbd> key._
|
|||||||
| Cut to clipboard⁵ | <kbd>MOD</kbd>+<kbd>x</kbd>
|
| Cut to clipboard⁵ | <kbd>MOD</kbd>+<kbd>x</kbd>
|
||||||
| Synchronize clipboards and paste⁵ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
| Synchronize clipboards and paste⁵ | <kbd>MOD</kbd>+<kbd>v</kbd>
|
||||||
| Inject computer clipboard text | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
| Inject computer clipboard text | <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>
|
||||||
|
| Open keyboard settings (HID keyboard only) | <kbd>MOD</kbd>+<kbd>k</kbd>
|
||||||
| Enable/disable FPS counter (on stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
| Enable/disable FPS counter (on stdout) | <kbd>MOD</kbd>+<kbd>i</kbd>
|
||||||
| Pinch-to-zoom/rotate | <kbd>Ctrl</kbd>+_click-and-move_
|
| Pinch-to-zoom/rotate | <kbd>Ctrl</kbd>+_click-and-move_
|
||||||
| Tilt (slide vertically with 2 fingers) | <kbd>Shift</kbd>+_click-and-move_
|
| Tilt (slide vertically with 2 fingers) | <kbd>Shift</kbd>+_click-and-move_
|
||||||
|
@ -19,6 +19,7 @@ public final class ControlMessage {
|
|||||||
public static final int TYPE_ROTATE_DEVICE = 11;
|
public static final int TYPE_ROTATE_DEVICE = 11;
|
||||||
public static final int TYPE_UHID_CREATE = 12;
|
public static final int TYPE_UHID_CREATE = 12;
|
||||||
public static final int TYPE_UHID_INPUT = 13;
|
public static final int TYPE_UHID_INPUT = 13;
|
||||||
|
public static final int TYPE_OPEN_HARD_KEYBOARD_SETTINGS = 14;
|
||||||
|
|
||||||
public static final long SEQUENCE_INVALID = 0;
|
public static final long SEQUENCE_INVALID = 0;
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ public class ControlMessageReader {
|
|||||||
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
||||||
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
||||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||||
|
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
|
||||||
msg = ControlMessage.createEmpty(type);
|
msg = ControlMessage.createEmpty(type);
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_UHID_CREATE:
|
case ControlMessage.TYPE_UHID_CREATE:
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
import com.genymobile.scrcpy.wrappers.InputManager;
|
import com.genymobile.scrcpy.wrappers.InputManager;
|
||||||
|
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
@ -200,6 +202,9 @@ public class Controller implements AsyncProcessor {
|
|||||||
case ControlMessage.TYPE_UHID_INPUT:
|
case ControlMessage.TYPE_UHID_INPUT:
|
||||||
getUhidManager().write(msg.getId(), msg.getData());
|
getUhidManager().write(msg.getId(), msg.getData());
|
||||||
break;
|
break;
|
||||||
|
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
|
||||||
|
openHardKeyboardSettings();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
@ -436,4 +441,9 @@ public class Controller implements AsyncProcessor {
|
|||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openHardKeyboardSettings() {
|
||||||
|
Intent intent = new Intent("android.settings.HARD_KEYBOARD_SETTINGS");
|
||||||
|
ServiceManager.getActivityManager().startActivityAsUserWithFeature(intent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,6 +366,22 @@ public class ControlMessageReaderTest {
|
|||||||
Assert.assertArrayEquals(data, event.getData());
|
Assert.assertArrayEquals(data, event.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseOpenHardKeyboardSettings() throws IOException {
|
||||||
|
ControlMessageReader reader = new ControlMessageReader();
|
||||||
|
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
|
dos.writeByte(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS);
|
||||||
|
|
||||||
|
byte[] packet = bos.toByteArray();
|
||||||
|
|
||||||
|
reader.readFrom(new ByteArrayInputStream(packet));
|
||||||
|
ControlMessage event = reader.next();
|
||||||
|
|
||||||
|
Assert.assertEquals(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS, event.getType());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiEvents() throws IOException {
|
public void testMultiEvents() throws IOException {
|
||||||
ControlMessageReader reader = new ControlMessageReader();
|
ControlMessageReader reader = new ControlMessageReader();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user