diff --git a/app/src/cli.c b/app/src/cli.c index b2e3e30a..06592aa0 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -2928,7 +2928,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], } #endif - if (opts->control) { + if (opts->control && opts->video_source == SC_VIDEO_SOURCE_DISPLAY) { if (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AUTO) { opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA : SC_KEYBOARD_INPUT_MODE_SDK; @@ -3106,8 +3106,10 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], } if (opts->control) { - LOGI("Camera video source: control disabled"); - opts->control = false; + // Disable all inputs for camera + opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_DISABLED; + opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_DISABLED; + opts->gamepad_input_mode = SC_GAMEPAD_INPUT_MODE_DISABLED; } } else if (opts->camera_id || opts->camera_ar diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 6804b7ab..f941101d 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -29,6 +29,7 @@ sc_input_manager_init(struct sc_input_manager *im, im->kp = params->kp; im->mp = params->mp; im->gp = params->gp; + im->camera = params->camera; im->mouse_bindings = params->mouse_bindings; im->legacy_paste = params->legacy_paste; @@ -52,7 +53,7 @@ sc_input_manager_init(struct sc_input_manager *im, static void send_keycode(struct sc_input_manager *im, enum android_keycode keycode, enum sc_action action, const char *name) { - assert(im->controller && im->kp); + assert(im->controller && im->kp && !im->camera); // send DOWN event struct sc_control_msg msg; @@ -109,7 +110,7 @@ action_menu(struct sc_input_manager *im, enum sc_action action) { static void press_back_or_turn_screen_on(struct sc_input_manager *im, enum sc_action action) { - assert(im->controller && im->kp); + assert(im->controller && im->kp && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON; @@ -124,7 +125,7 @@ press_back_or_turn_screen_on(struct sc_input_manager *im, static void expand_notification_panel(struct sc_input_manager *im) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL; @@ -136,7 +137,7 @@ expand_notification_panel(struct sc_input_manager *im) { static void expand_settings_panel(struct sc_input_manager *im) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL; @@ -148,7 +149,7 @@ expand_settings_panel(struct sc_input_manager *im) { static void collapse_panels(struct sc_input_manager *im) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS; @@ -160,7 +161,7 @@ collapse_panels(struct sc_input_manager *im) { static bool get_device_clipboard(struct sc_input_manager *im, enum sc_copy_key copy_key) { - assert(im->controller && im->kp); + assert(im->controller && im->kp && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_GET_CLIPBOARD; @@ -177,7 +178,7 @@ get_device_clipboard(struct sc_input_manager *im, enum sc_copy_key copy_key) { static bool set_device_clipboard(struct sc_input_manager *im, bool paste, uint64_t sequence) { - assert(im->controller && im->kp); + assert(im->controller && im->kp && !im->camera); char *text = SDL_GetClipboardText(); if (!text) { @@ -209,7 +210,7 @@ set_device_clipboard(struct sc_input_manager *im, bool paste, static void set_display_power(struct sc_input_manager *im, bool on) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_SET_DISPLAY_POWER; @@ -236,7 +237,7 @@ switch_fps_counter_state(struct sc_input_manager *im) { static void clipboard_paste(struct sc_input_manager *im) { - assert(im->controller && im->kp); + assert(im->controller && im->kp && !im->camera); char *text = SDL_GetClipboardText(); if (!text) { @@ -267,7 +268,7 @@ clipboard_paste(struct sc_input_manager *im) { static void rotate_device(struct sc_input_manager *im) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE; @@ -279,7 +280,7 @@ rotate_device(struct sc_input_manager *im) { static void open_hard_keyboard_settings(struct sc_input_manager *im) { - assert(im->controller); + assert(im->controller && !im->camera); struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS; @@ -313,7 +314,7 @@ apply_orientation_transform(struct sc_input_manager *im, static void sc_input_manager_process_text_input(struct sc_input_manager *im, const SDL_TextInputEvent *event) { - if (!im->kp || im->screen->paused) { + if (im->camera || !im->kp || im->screen->paused) { return; } @@ -464,7 +465,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, } return; } - if (control) { + if (control && !im->camera) { switch (sdl_keycode) { case SDLK_H: if (im->kp && !shift && !repeat && !paused) { @@ -569,6 +570,8 @@ sc_input_manager_process_key(struct sc_input_manager *im, return; } + assert(!im->camera); + uint64_t ack_to_wait = SC_SEQUENCE_INVALID; bool is_ctrl_v = ctrl && !shift && sdl_keycode == SDLK_V && down && !repeat; if (im->clipboard_autosync && is_ctrl_v) { @@ -640,7 +643,7 @@ sc_input_manager_get_position(struct sc_input_manager *im, int32_t x, static void sc_input_manager_process_mouse_motion(struct sc_input_manager *im, const SDL_MouseMotionEvent *event) { - if (!im->mp || im->screen->paused) { + if (im->camera || !im->mp || im->screen->paused) { return; } @@ -679,7 +682,7 @@ sc_input_manager_process_mouse_motion(struct sc_input_manager *im, static void sc_input_manager_process_touch(struct sc_input_manager *im, const SDL_TouchFingerEvent *event) { - if (!im->mp || im->screen->paused) { + if (im->camera || !im->mp || im->screen->paused) { return; } @@ -734,6 +737,10 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im, // some mouse events do not interact with the device, so process the event // even if control is disabled + if (im->camera) { + return; + } + if (event->which == SDL_TOUCH_MOUSEID) { // simulated from touch events, so it's a duplicate return; @@ -901,7 +908,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im, static void sc_input_manager_process_mouse_wheel(struct sc_input_manager *im, const SDL_MouseWheelEvent *event) { - if (!im->kp || im->screen->paused) { + if (im->camera || !im->kp || im->screen->paused) { return; } @@ -931,7 +938,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im, const SDL_GamepadDeviceEvent *event) { // Handle device added or removed even if paused - if (!im->gp) { + if (im->camera || !im->gp) { return; } @@ -976,7 +983,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im, static void sc_input_manager_process_gamepad_axis(struct sc_input_manager *im, const SDL_GamepadAxisEvent *event) { - if (!im->gp || im->screen->paused) { + if (im->camera || !im->gp || im->screen->paused) { return; } @@ -996,7 +1003,7 @@ sc_input_manager_process_gamepad_axis(struct sc_input_manager *im, static void sc_input_manager_process_gamepad_button(struct sc_input_manager *im, const SDL_GamepadButtonEvent *event) { - if (!im->gp || im->screen->paused) { + if (im->camera || !im->gp || im->screen->paused) { return; } @@ -1022,7 +1029,7 @@ is_apk(const char *file) { static void sc_input_manager_process_file(struct sc_input_manager *im, const SDL_DropEvent *event) { - if (!im->controller) { + if (im->camera || !im->controller) { return; } diff --git a/app/src/input_manager.h b/app/src/input_manager.h index 6f4af8f7..ed96a3dd 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -24,6 +24,8 @@ struct sc_input_manager { struct sc_mouse_processor *mp; struct sc_gamepad_processor *gp; + bool camera; + struct sc_mouse_bindings mouse_bindings; bool legacy_paste; bool clipboard_autosync; @@ -53,6 +55,7 @@ struct sc_input_manager_params { struct sc_key_processor *kp; struct sc_mouse_processor *mp; struct sc_gamepad_processor *gp; + bool camera; struct sc_mouse_bindings mouse_bindings; bool legacy_paste; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 97ba8617..01730ce7 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -802,6 +802,7 @@ aoa_complete: struct sc_screen_params screen_params = { .video = options->video_playback, + .camera = options->video_source == SC_VIDEO_SOURCE_CAMERA, .controller = controller, .fp = fp, .kp = kp, diff --git a/app/src/screen.c b/app/src/screen.c index 7e07ff5c..535288db 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -302,6 +302,7 @@ sc_screen_init(struct sc_screen *screen, screen->orientation = SC_ORIENTATION_0; screen->video = params->video; + screen->camera = params->camera; screen->req.x = params->window_x; screen->req.y = params->window_y; @@ -412,6 +413,7 @@ sc_screen_init(struct sc_screen *screen, .kp = params->kp, .mp = params->mp, .gp = params->gp, + .camera = params->camera, .mouse_bindings = params->mouse_bindings, .legacy_paste = params->legacy_paste, .clipboard_autosync = params->clipboard_autosync, diff --git a/app/src/screen.h b/app/src/screen.h index 0b992292..94403825 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -30,6 +30,7 @@ struct sc_screen { #endif bool video; + bool camera; struct sc_display display; struct sc_input_manager im; @@ -74,6 +75,7 @@ struct sc_screen { struct sc_screen_params { bool video; + bool camera; struct sc_controller *controller; struct sc_file_pusher *fp; diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index 8119539f..cc230b1d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -13,6 +13,7 @@ import com.genymobile.scrcpy.device.Size; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.util.LogUtils; import com.genymobile.scrcpy.video.SurfaceCapture; +import com.genymobile.scrcpy.video.VideoSource; import com.genymobile.scrcpy.video.VirtualDisplayListener; import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.InputManager; @@ -75,6 +76,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { private UhidManager uhidManager; + private final boolean camera; private final int displayId; private final boolean supportsInputEvents; private final ControlChannel controlChannel; @@ -101,9 +103,22 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { private SurfaceCapture surfaceCapture; public Controller(ControlChannel controlChannel, CleanUp cleanUp, Options options) { - this.displayId = options.getDisplayId(); + this.camera = options.getVideoSource() == VideoSource.CAMERA; this.controlChannel = controlChannel; this.cleanUp = cleanUp; + + if (this.camera) { + // Unused for camera + this.displayId = Device.DISPLAY_ID_NONE; + this.supportsInputEvents = false; + this.sender = null; + this.clipboardAutosync = false; + this.powerOn = false; + return; + } + + this.displayId = options.getDisplayId(); + this.clipboardAutosync = options.getClipboardAutosync(); this.powerOn = options.getPowerOn(); initPointers(); @@ -201,7 +216,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { private void control() throws IOException { // on start, power on the device - if (powerOn && displayId == 0 && !Device.isScreenOn(displayId)) { + if (!camera && powerOn && displayId == 0 && !Device.isScreenOn(displayId)) { Device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId, Device.INJECT_MODE_ASYNC); // dirty hack @@ -236,7 +251,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { } }, "control-recv"); thread.start(); - sender.start(); + if (sender != null) { + sender.start(); + } } @Override @@ -244,7 +261,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { if (thread != null) { thread.interrupt(); } - sender.stop(); + if (sender != null) { + sender.stop(); + } } @Override @@ -252,7 +271,9 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { if (thread != null) { thread.join(); } - sender.join(); + if (sender != null) { + sender.join(); + } } private boolean handleEvent() throws IOException { @@ -266,75 +287,78 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener { int type = msg.getType(); - switch (type) { - case ControlMessage.TYPE_INJECT_KEYCODE: - if (supportsInputEvents) { - injectKeycode(msg.getAction(), msg.getKeycode(), msg.getRepeat(), msg.getMetaState()); - } - return true; - case ControlMessage.TYPE_INJECT_TEXT: - if (supportsInputEvents) { - injectText(msg.getText()); - } - return true; - case ControlMessage.TYPE_INJECT_TOUCH_EVENT: - if (supportsInputEvents) { - injectTouch(msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure(), msg.getActionButton(), msg.getButtons()); - } - return true; - case ControlMessage.TYPE_INJECT_SCROLL_EVENT: - if (supportsInputEvents) { - injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll(), msg.getButtons()); - } - return true; - case ControlMessage.TYPE_BACK_OR_SCREEN_ON: - if (supportsInputEvents) { - pressBackOrTurnScreenOn(msg.getAction()); - } - return true; - case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: - Device.expandNotificationPanel(); - return true; - case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL: - Device.expandSettingsPanel(); - return true; - case ControlMessage.TYPE_COLLAPSE_PANELS: - Device.collapsePanels(); - return true; - case ControlMessage.TYPE_GET_CLIPBOARD: - getClipboard(msg.getCopyKey()); - return true; - case ControlMessage.TYPE_SET_CLIPBOARD: - setClipboard(msg.getText(), msg.getPaste(), msg.getSequence()); - return true; - case ControlMessage.TYPE_SET_DISPLAY_POWER: - if (supportsInputEvents) { - setDisplayPower(msg.getOn()); - } - return true; - case ControlMessage.TYPE_ROTATE_DEVICE: - Device.rotateDevice(getActionDisplayId()); - return true; - case ControlMessage.TYPE_UHID_CREATE: - getUhidManager().open(msg.getId(), msg.getVendorId(), msg.getProductId(), msg.getText(), msg.getData()); - return true; - case ControlMessage.TYPE_UHID_INPUT: - getUhidManager().writeInput(msg.getId(), msg.getData()); - return true; - case ControlMessage.TYPE_UHID_DESTROY: - getUhidManager().close(msg.getId()); - return true; - case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS: - openHardKeyboardSettings(); - return true; - case ControlMessage.TYPE_START_APP: - startAppAsync(msg.getText()); - return true; - case ControlMessage.TYPE_RESET_VIDEO: - resetVideo(); - return true; - default: - // fall through + if (!camera) { + switch (type) { + case ControlMessage.TYPE_INJECT_KEYCODE: + if (supportsInputEvents) { + injectKeycode(msg.getAction(), msg.getKeycode(), msg.getRepeat(), msg.getMetaState()); + } + return true; + case ControlMessage.TYPE_INJECT_TEXT: + if (supportsInputEvents) { + injectText(msg.getText()); + } + return true; + case ControlMessage.TYPE_INJECT_TOUCH_EVENT: + if (supportsInputEvents) { + injectTouch( + msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure(), msg.getActionButton(), msg.getButtons()); + } + return true; + case ControlMessage.TYPE_INJECT_SCROLL_EVENT: + if (supportsInputEvents) { + injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll(), msg.getButtons()); + } + return true; + case ControlMessage.TYPE_BACK_OR_SCREEN_ON: + if (supportsInputEvents) { + pressBackOrTurnScreenOn(msg.getAction()); + } + return true; + case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: + Device.expandNotificationPanel(); + return true; + case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL: + Device.expandSettingsPanel(); + return true; + case ControlMessage.TYPE_COLLAPSE_PANELS: + Device.collapsePanels(); + return true; + case ControlMessage.TYPE_GET_CLIPBOARD: + getClipboard(msg.getCopyKey()); + return true; + case ControlMessage.TYPE_SET_CLIPBOARD: + setClipboard(msg.getText(), msg.getPaste(), msg.getSequence()); + return true; + case ControlMessage.TYPE_SET_DISPLAY_POWER: + if (supportsInputEvents) { + setDisplayPower(msg.getOn()); + } + return true; + case ControlMessage.TYPE_ROTATE_DEVICE: + Device.rotateDevice(getActionDisplayId()); + return true; + case ControlMessage.TYPE_UHID_CREATE: + getUhidManager().open(msg.getId(), msg.getVendorId(), msg.getProductId(), msg.getText(), msg.getData()); + return true; + case ControlMessage.TYPE_UHID_INPUT: + getUhidManager().writeInput(msg.getId(), msg.getData()); + return true; + case ControlMessage.TYPE_UHID_DESTROY: + getUhidManager().close(msg.getId()); + return true; + case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS: + openHardKeyboardSettings(); + return true; + case ControlMessage.TYPE_START_APP: + startAppAsync(msg.getText()); + return true; + case ControlMessage.TYPE_RESET_VIDEO: + resetVideo(); + return true; + default: + // fall through + } } throw new AssertionError("Unexpected message type: " + type);