Skip to content

Commit

Permalink
Add shortcut to open keyboard settings
Browse files Browse the repository at this point in the history
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.

PR #4473 <#4473>
  • Loading branch information
rom1v committed Feb 29, 2024
1 parent 54dede3 commit 151a622
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 3 deletions.
6 changes: 5 additions & 1 deletion app/scrcpy.1
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ Possible values are "disabled", "sdk", "uhid" and "aoa":
- "uhid" simulates a physical HID keyboard using the Linux HID kernel module on the device.
- "aoa" simulates a physical HID keyboard using the AOAv2 protocol. It may only work over USB.

For "uhid" and "aoa", 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 "uhid" and "aoa", 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

Expand Down Expand Up @@ -644,6 +644,10 @@ Copy computer clipboard to device, then paste (inject PASTE keycode, Android >=
.B MOD+Shift+v
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
.B MOD+i
Enable/disable FPS counter (print frames/second in logs)
Expand Down
9 changes: 7 additions & 2 deletions app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,9 @@ static const struct sc_option options[] = {
"For \"uhid\" and \"aoa\", 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: `adb shell am start -a "
"android.settings.HARD_KEYBOARD_SETTINGS`.\n"
"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`.\n"
"This option is only available when a HID keyboard is enabled "
"(or a physical keyboard is connected).\n"
"Also see --mouse.",
Expand Down Expand Up @@ -965,6 +966,10 @@ static const struct sc_shortcut shortcuts[] = {
.shortcuts = { "MOD+Shift+v" },
.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" },
.text = "Enable/disable FPS counter (print frames/second in logs)",
Expand Down
4 changes: 4 additions & 0 deletions app/src/control_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_COLLAPSE_PANELS:
case SC_CONTROL_MSG_TYPE_ROTATE_DEVICE:
case SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
// no additional data
return 1;
default:
Expand Down Expand Up @@ -270,6 +271,9 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
}
break;
}
case SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
LOG_CMSG("open hard keyboard settings");
break;
default:
LOG_CMSG("unknown type: %u", (unsigned) msg->type);
break;
Expand Down
1 change: 1 addition & 0 deletions app/src/control_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum sc_control_msg_type {
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
SC_CONTROL_MSG_TYPE_UHID_CREATE,
SC_CONTROL_MSG_TYPE_UHID_INPUT,
SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS,
};

enum sc_screen_power_mode {
Expand Down
19 changes: 19 additions & 0 deletions app/src/input_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
apply_orientation_transform(struct sc_input_manager *im,
enum sc_orientation transform) {
Expand Down Expand Up @@ -550,6 +562,13 @@ sc_input_manager_process_key(struct sc_input_manager *im,
rotate_device(im);
}
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;
Expand Down
1 change: 1 addition & 0 deletions app/src/keyboard_sdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,6 @@ sc_keyboard_sdk_init(struct sc_keyboard_sdk *kb,

// Key injection and clipboard synchronization are serialized
kb->key_processor.async_paste = false;
kb->key_processor.hid = false;
kb->key_processor.ops = &ops;
}
7 changes: 7 additions & 0 deletions app/src/trait/key_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ struct sc_key_processor {
*/
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;
};

Expand Down
1 change: 1 addition & 0 deletions app/src/uhid/keyboard_uhid.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
// Clipboard synchronization is requested over the same control socket, so
// there is no need for a specific synchronization mechanism
kb->key_processor.async_paste = false;
kb->key_processor.hid = true;
kb->key_processor.ops = &ops;

static const struct sc_uhid_receiver_ops uhid_receiver_ops = {
Expand Down
1 change: 1 addition & 0 deletions app/src/usb/keyboard_aoa.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,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
// to be acknowledged by the device before injecting Ctrl+v.
kb->key_processor.async_paste = true;
kb->key_processor.hid = true;
kb->key_processor.ops = &ops;

return true;
Expand Down
16 changes: 16 additions & 0 deletions app/tests/test_control_msg_serialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,21 @@ static void test_serialize_uhid_input(void) {
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[]) {
(void) argc;
(void) argv;
Expand All @@ -390,5 +405,6 @@ int main(int argc, char *argv[]) {
test_serialize_rotate_device();
test_serialize_uhid_create();
test_serialize_uhid_input();
test_serialize_open_hard_keyboard();
return 0;
}
1 change: 1 addition & 0 deletions doc/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
| Synchronize clipboards and paste⁵ | <kbd>MOD</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>
| Pinch-to-zoom/rotate | <kbd>Ctrl</kbd>+_click-and-move_
| Tilt (slide vertically with 2 fingers) | <kbd>Shift</kbd>+_click-and-move_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class ControlMessage {
public static final int TYPE_ROTATE_DEVICE = 11;
public static final int TYPE_UHID_CREATE = 12;
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public ControlMessage next() {
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
case ControlMessage.TYPE_COLLAPSE_PANELS:
case ControlMessage.TYPE_ROTATE_DEVICE:
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
msg = ControlMessage.createEmpty(type);
break;
case ControlMessage.TYPE_UHID_CREATE:
Expand Down
10 changes: 10 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Controller.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.genymobile.scrcpy;

import com.genymobile.scrcpy.wrappers.InputManager;
import com.genymobile.scrcpy.wrappers.ServiceManager;

import android.content.Intent;
import android.os.Build;
import android.os.SystemClock;
import android.view.InputDevice;
Expand Down Expand Up @@ -208,6 +210,9 @@ private boolean handleEvent() throws IOException {
case ControlMessage.TYPE_UHID_INPUT:
getUhidManager().writeInput(msg.getId(), msg.getData());
break;
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
openHardKeyboardSettings();
break;
default:
// do nothing
}
Expand Down Expand Up @@ -446,4 +451,9 @@ private boolean setClipboard(String text, boolean paste, long sequence) {

return ok;
}

private void openHardKeyboardSettings() {
Intent intent = new Intent("android.settings.HARD_KEYBOARD_SETTINGS");
ServiceManager.getActivityManager().startActivity(intent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,22 @@ public void testParseUhidInput() throws IOException {
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
public void testMultiEvents() throws IOException {
ControlMessageReader reader = new ControlMessageReader();
Expand Down

0 comments on commit 151a622

Please sign in to comment.