Add shortcut to expand/collapse notification panel
Use Ctrl+n to expand, Ctrl+Shift+n to collapse. Fixes <https://github.com/Genymobile/scrcpy/issues/392>
This commit is contained in:
parent
1c1fe5ec53
commit
7d10ec2b5a
9 changed files with 129 additions and 22 deletions
|
@ -267,6 +267,8 @@ you are interested, see [issue 14].
|
||||||
| click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ (`Cmd`+`↓` on MacOS) |
|
| click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ (`Cmd`+`↓` on MacOS) |
|
||||||
| click on `POWER` | `Ctrl`+`p` |
|
| click on `POWER` | `Ctrl`+`p` |
|
||||||
| turn screen on | _Right-click²_ |
|
| turn screen on | _Right-click²_ |
|
||||||
|
| expand notification panel | `Ctrl`+`n` |
|
||||||
|
| collapse notification panel | `Ctrl`+`Shift`+`n` |
|
||||||
| paste computer clipboard to device | `Ctrl`+`v` |
|
| paste computer clipboard to device | `Ctrl`+`v` |
|
||||||
| enable/disable FPS counter (on stdout) | `Ctrl`+`i` |
|
| enable/disable FPS counter (on stdout) | `Ctrl`+`i` |
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,11 @@ enum control_event_type {
|
||||||
CONTROL_EVENT_TYPE_COMMAND,
|
CONTROL_EVENT_TYPE_COMMAND,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON 0
|
enum control_event_command {
|
||||||
|
CONTROL_EVENT_COMMAND_BACK_OR_SCREEN_ON,
|
||||||
|
CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL,
|
||||||
|
CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL,
|
||||||
|
};
|
||||||
|
|
||||||
struct control_event {
|
struct control_event {
|
||||||
enum control_event_type type;
|
enum control_event_type type;
|
||||||
|
@ -44,7 +48,7 @@ struct control_event {
|
||||||
Sint32 vscroll;
|
Sint32 vscroll;
|
||||||
} scroll_event;
|
} scroll_event;
|
||||||
struct {
|
struct {
|
||||||
int action;
|
enum control_event_command action;
|
||||||
} command_event;
|
} command_event;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,6 +94,26 @@ static void press_back_or_turn_screen_on(struct controller *controller) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void expand_notification_panel(struct controller *controller) {
|
||||||
|
struct control_event control_event;
|
||||||
|
control_event.type = CONTROL_EVENT_TYPE_COMMAND;
|
||||||
|
control_event.command_event.action = CONTROL_EVENT_COMMAND_EXPAND_NOTIFICATION_PANEL;
|
||||||
|
|
||||||
|
if (!controller_push_event(controller, &control_event)) {
|
||||||
|
LOGW("Cannot expand notification panel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collapse_notification_panel(struct controller *controller) {
|
||||||
|
struct control_event control_event;
|
||||||
|
control_event.type = CONTROL_EVENT_TYPE_COMMAND;
|
||||||
|
control_event.command_event.action = CONTROL_EVENT_COMMAND_COLLAPSE_NOTIFICATION_PANEL;
|
||||||
|
|
||||||
|
if (!controller_push_event(controller, &control_event)) {
|
||||||
|
LOGW("Cannot collapse notification panel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void switch_fps_counter_state(struct frames *frames) {
|
static void switch_fps_counter_state(struct frames *frames) {
|
||||||
mutex_lock(frames->mutex);
|
mutex_lock(frames->mutex);
|
||||||
if (frames->fps_counter.started) {
|
if (frames->fps_counter.started) {
|
||||||
|
@ -162,47 +182,42 @@ void input_manager_process_key(struct input_manager *input_manager,
|
||||||
|
|
||||||
// capture all Ctrl events
|
// capture all Ctrl events
|
||||||
if (ctrl | meta) {
|
if (ctrl | meta) {
|
||||||
SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
|
|
||||||
if (shift) {
|
|
||||||
// currently, there is no shortcut involving SHIFT
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Keycode keycode = event->keysym.sym;
|
SDL_Keycode keycode = event->keysym.sym;
|
||||||
int action = event->type == SDL_KEYDOWN ? ACTION_DOWN : ACTION_UP;
|
int action = event->type == SDL_KEYDOWN ? ACTION_DOWN : ACTION_UP;
|
||||||
SDL_bool repeat = event->repeat;
|
SDL_bool repeat = event->repeat;
|
||||||
|
SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
case SDLK_h:
|
case SDLK_h:
|
||||||
if (ctrl && !meta && !repeat) {
|
if (ctrl && !meta && !shift && !repeat) {
|
||||||
action_home(input_manager->controller, action);
|
action_home(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_b: // fall-through
|
case SDLK_b: // fall-through
|
||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
if (ctrl && !meta && !repeat) {
|
if (ctrl && !meta && !shift && !repeat) {
|
||||||
action_back(input_manager->controller, action);
|
action_back(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_s:
|
case SDLK_s:
|
||||||
if (ctrl && !meta && !repeat) {
|
if (ctrl && !meta && !shift && !repeat) {
|
||||||
action_app_switch(input_manager->controller, action);
|
action_app_switch(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_m:
|
case SDLK_m:
|
||||||
if (ctrl && !meta && !repeat) {
|
if (ctrl && !meta && !shift && !repeat) {
|
||||||
action_menu(input_manager->controller, action);
|
action_menu(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_p:
|
case SDLK_p:
|
||||||
if (ctrl && !meta && !repeat) {
|
if (ctrl && !meta && !shift && !repeat) {
|
||||||
action_power(input_manager->controller, action);
|
action_power(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (!ctrl && meta) {
|
if (!ctrl && meta && !shift) {
|
||||||
#else
|
#else
|
||||||
if (ctrl && !meta) {
|
if (ctrl && !meta && !shift) {
|
||||||
#endif
|
#endif
|
||||||
// forward repeated events
|
// forward repeated events
|
||||||
action_volume_down(input_manager->controller, action);
|
action_volume_down(input_manager->controller, action);
|
||||||
|
@ -210,39 +225,53 @@ void input_manager_process_key(struct input_manager *input_manager,
|
||||||
return;
|
return;
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (!ctrl && meta) {
|
if (!ctrl && meta && !shift) {
|
||||||
#else
|
#else
|
||||||
if (ctrl && !meta) {
|
if (ctrl && !meta && !shift) {
|
||||||
#endif
|
#endif
|
||||||
// forward repeated events
|
// forward repeated events
|
||||||
action_volume_up(input_manager->controller, action);
|
action_volume_up(input_manager->controller, action);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_v:
|
case SDLK_v:
|
||||||
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
if (ctrl && !meta && !shift && !repeat
|
||||||
|
&& event->type == SDL_KEYDOWN) {
|
||||||
clipboard_paste(input_manager->controller);
|
clipboard_paste(input_manager->controller);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_f:
|
case SDLK_f:
|
||||||
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
if (ctrl && !meta && !shift && !repeat
|
||||||
|
&& event->type == SDL_KEYDOWN) {
|
||||||
screen_switch_fullscreen(input_manager->screen);
|
screen_switch_fullscreen(input_manager->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_x:
|
case SDLK_x:
|
||||||
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
if (ctrl && !meta && !shift && !repeat
|
||||||
|
&& event->type == SDL_KEYDOWN) {
|
||||||
screen_resize_to_fit(input_manager->screen);
|
screen_resize_to_fit(input_manager->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_g:
|
case SDLK_g:
|
||||||
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
if (ctrl && !meta && !shift && !repeat
|
||||||
|
&& event->type == SDL_KEYDOWN) {
|
||||||
screen_resize_to_pixel_perfect(input_manager->screen);
|
screen_resize_to_pixel_perfect(input_manager->screen);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case SDLK_i:
|
case SDLK_i:
|
||||||
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
if (ctrl && !meta && !shift && !repeat
|
||||||
|
&& event->type == SDL_KEYDOWN) {
|
||||||
switch_fps_counter_state(input_manager->frames);
|
switch_fps_counter_state(input_manager->frames);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case SDLK_n:
|
||||||
|
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
|
||||||
|
if (shift) {
|
||||||
|
collapse_notification_panel(input_manager->controller);
|
||||||
|
} else {
|
||||||
|
expand_notification_panel(input_manager->controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -120,6 +120,12 @@ static void usage(const char *arg0) {
|
||||||
" Right-click (when screen is off)\n"
|
" Right-click (when screen is off)\n"
|
||||||
" turn screen on\n"
|
" turn screen on\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" Ctrl+n\n"
|
||||||
|
" expand notification panel\n"
|
||||||
|
"\n"
|
||||||
|
" Ctrl+Shift+n\n"
|
||||||
|
" collapse notification panel\n"
|
||||||
|
"\n"
|
||||||
" Ctrl+v\n"
|
" Ctrl+v\n"
|
||||||
" paste computer clipboard to device\n"
|
" paste computer clipboard to device\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
@ -12,6 +12,8 @@ public final class ControlEvent {
|
||||||
public static final int TYPE_COMMAND = 4;
|
public static final int TYPE_COMMAND = 4;
|
||||||
|
|
||||||
public static final int COMMAND_BACK_OR_SCREEN_ON = 0;
|
public static final int COMMAND_BACK_OR_SCREEN_ON = 0;
|
||||||
|
public static final int COMMAND_EXPAND_NOTIFICATION_PANEL = 1;
|
||||||
|
public static final int COMMAND_COLLAPSE_NOTIFICATION_PANEL = 2;
|
||||||
|
|
||||||
private int type;
|
private int type;
|
||||||
private String text;
|
private String text;
|
||||||
|
|
|
@ -132,6 +132,14 @@ public final class Device {
|
||||||
this.rotationListener = rotationListener;
|
this.rotationListener = rotationListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void expandNotificationPanel() {
|
||||||
|
serviceManager.getStatusBarManager().expandNotificationsPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapsePanels() {
|
||||||
|
serviceManager.getStatusBarManager().collapsePanels();
|
||||||
|
}
|
||||||
|
|
||||||
static Rect flipRect(Rect crop) {
|
static Rect flipRect(Rect crop) {
|
||||||
return new Rect(crop.top, crop.left, crop.bottom, crop.right);
|
return new Rect(crop.top, crop.left, crop.bottom, crop.right);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
@ -172,6 +173,12 @@ public class EventController {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ControlEvent.COMMAND_BACK_OR_SCREEN_ON:
|
case ControlEvent.COMMAND_BACK_OR_SCREEN_ON:
|
||||||
return pressBackOrTurnScreenOn();
|
return pressBackOrTurnScreenOn();
|
||||||
|
case ControlEvent.COMMAND_EXPAND_NOTIFICATION_PANEL:
|
||||||
|
device.expandNotificationPanel();
|
||||||
|
return true;
|
||||||
|
case ControlEvent.COMMAND_COLLAPSE_NOTIFICATION_PANEL:
|
||||||
|
device.collapsePanels();
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Ln.w("Unsupported command: " + action);
|
Ln.w("Unsupported command: " + action);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ public final class ServiceManager {
|
||||||
private DisplayManager displayManager;
|
private DisplayManager displayManager;
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
private PowerManager powerManager;
|
private PowerManager powerManager;
|
||||||
|
private StatusBarManager statusBarManager;
|
||||||
|
|
||||||
public ServiceManager() {
|
public ServiceManager() {
|
||||||
try {
|
try {
|
||||||
|
@ -60,4 +61,11 @@ public final class ServiceManager {
|
||||||
}
|
}
|
||||||
return powerManager;
|
return powerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StatusBarManager getStatusBarManager() {
|
||||||
|
if (statusBarManager == null) {
|
||||||
|
statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService"));
|
||||||
|
}
|
||||||
|
return statusBarManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.genymobile.scrcpy.wrappers;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.os.IInterface;
|
||||||
|
import android.view.InputEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class StatusBarManager {
|
||||||
|
|
||||||
|
private final IInterface manager;
|
||||||
|
private final Method expandNotificationsPanelMethod;
|
||||||
|
private final Method collapsePanelsMethod;
|
||||||
|
|
||||||
|
public StatusBarManager(IInterface manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
try {
|
||||||
|
expandNotificationsPanelMethod = manager.getClass().getMethod("expandNotificationsPanel");
|
||||||
|
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expandNotificationsPanel() {
|
||||||
|
try {
|
||||||
|
expandNotificationsPanelMethod.invoke(manager);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapsePanels() {
|
||||||
|
try {
|
||||||
|
collapsePanelsMethod.invoke(manager);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue