# Remote control

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

The remote control feature allows someone to take control of another user's screen in a session when given permission. A user can either request remote control of another user's screen or the other user can give it to them. Once given permission, a user can control the other user's mouse and keyboard, and even copy text from their screen.

> **Note:** Since this enables remote control of a user's screen, it is your responsibility as the developer to inform the user of the permission they're giving to the person who can remote control their screen. This includes all notices, consents, and a well-defined user experience.

## Prerequisites

-   Set up [screen sharing](/docs/video-sdk/macos/share/). You must configure screen sharing in order for remote control to work.
-   Turn on remote control on the web portal. Go to **Account Settings**, **In Session (Basic)**, and toggle the **Remote control** option on. Optionally select the **Allow remote controlling user to share clipboard** option.
-   Before starting, check whether controllers can request (`canRequestControl`) and users can start remote control.

## Remote Control Flow

1. On the requester side, identify the remote user (`ZMVideoSDKUser`) to have remote control over, check for request access, and request for access.

    ```swift
    let user: ZMVideoSDKUser; // Get the user you want to remote control of
    let shareActionList = user.getShareActionList()

    // The shareActionList can contain 0 to multiple shares coming from the selected user
    if let shareActionList = shareActionList, shareActionList.count > 0 {
        // Get the share you want - Example the first share
        let shareAction = shareActionList[0]

        if shareAction.getRemoteControlHelper().canRequestControl() {
            shareAction.getRemoteControlHelper().requestRemoteControl()
        }
    }
    ```

    ```objectivec
    ZMVideoSDKUser* user; // Get the user you want to remote control of
    NSArray* shareActionList = [user getShareActionList];

    // The shareActionList can contain 0 to multiple share coming from the selected user
    if (shareActionList.count > 0) {
        // Get the share you want - Example the first share
        ZMVideoSDKShareAction* shareAction = [shareActionList objectAtIndex:0];

        if ([[shareAction getRemoteControlHelper] canRequestControl]) {
            [[shareAction getRemoteControlHelper] requestRemoteControl];
        }
    }
    ```

2. The requester will then get the `onRemoteControlRequestReceived` callback within the `ZMVideoSDKDelegate` class. From this callback, the approver will get the user requesting for remote control access and also the `ZMVideoSDKRemoteControlRequestHandler`, which the SDK will use to either approve or deny the request. If the approver denied the request, the requester can request again.

    > **Note**: For macOS, the approver must give their application access in the **Accessibility** tab in the **Privacy and Security** preferences of their Mac.

    ```swift
    func onRemoteControlRequestReceived(user: ZMVideoSDKUser, handler: ZMVideoSDKRemoteControlRequestHandler) {
        handler.approve() // OR
        handler.deny()
    }
    ```

    ```objectivec
    - (void)onRemoteControlRequestReceived:(ZMVideoSDKUser *)user shareAction:(ZMVideoSDKShareAction *)shareAction handler:(ZMVideoSDKRemoteControlRequestHandler *)handler
    {
        [handler approve]; // OR
        [handler deny];
    }
    ```

3. Both the requestor and approver will receive an `onRemoteControlStatus` callback under the `ZMVideoSDKDelegate` class on the request status. With a `CanRequestControl` callback status on the requestor side, check if `canRemoteControl` is `true` and `isRemoteControlling` is `false` before starting remote control.

    ```swift
    let remoteControlHelper = shareAction.getRemoteControlHelper()
    if remoteControlHelper.canRemoteControl() && !remoteControlHelper.isRemoteControlling() {
        remoteControlHelper.enterRemoteControl()
    }
    ```

    ```objectivec
    ZMVideoSDKRemoteControlHelper* remoteControlHelper = [shareAction getRemoteControlHelper];
    if ([remoteControlHelper canRemoteControl] && ![remoteControlHelper isRemoteControlling]) {
        [remoteControlHelper enterRemoteControl];
    }
    ```

4. After entering remote control status, the requestor can choose to temporarily pause remote control using `leaveRemoteControl` and enter again later on with `enterRemoteControl`, or to end it with `endRemoteControl`. Whereas the approver can also choose to get the list of approved users using `getRemoteControlApprovedUserList` or to revoke all the approved user using `revokeRemoteControl`.

    ```swift
    // Requestor
    remoteControlHelper.leaveRemoteControl()
    remoteControlHelper.endRemoteControl()

    // Approver - These methods are only available for the local user themselves.
    shareAction.getRemoteControlApprovedUserList()
    shareAction.revokeRemoteControl()
    ```

    ```objectivec
    // Requestor
    [remoteControlHelper leaveRemoteControl];
    [remoteControlHelper endRemoteControl];

    // Approver - These methods are only available for the local user themselves.
    [shareAction getRemoteControlApprovedUserList]
    [shareAction revokeRemoteControl];
    ```

## Callbacks

There are 2 callbacks related to remote control access under the `ZMVideoSDKDelegate` class.

1. `onRemoteControlRequestReceived`: Triggered when a remote user requests to remote control the local user.

    ```swift
    func onRemoteControlRequestReceived(user: ZMVideoSDKUser, shareAction: ZMVideoSDKShareAction, handler: ZMVideoSDKRemoteControlRequestHandler) {
        handler.approve() // OR
        handler.deny()
    }
    ```

    ```objectivec
    - (void)onRemoteControlRequestReceived:(ZMVideoSDKUser *)user handler:(ZMVideoSDKRemoteControlRequestHandler *)handler
    {
        [handler approve]; // OR
        [handler deny];
    }
    ```

2. `onRemoteControlStatus`: Triggered when the remote control status changes. This applies to the local user either requesting remote control, controlling the remote user, or is being controlled by a remote user.

    **`ZMVideoSDKRemoteControlStatus Enum`**

    ```objectivec
    None // For initialization
    CanRequestControl // Local user can enable the remote control
    RequestDenied // Local user have received a refused of remote control
    GotControl // Local user got control when remote control begins
    LostControl // Local user lost control when remote control ends
    ControlStart // Local user start controlling remotely another user
    ControlStop // Local user stop controlling remotely another user
    GiveControlTo // Local user gave remote control access to an user
    ControlRevoked // Local user revoked remote control access to an user
    ControlledBy // Local user is being remotely controlled by an user
    NotControlled // Local user is not remotely controlled by an user
    ```

    ```swift
    func onRemoteControlStatus(status: ZMVideoSDKRemoteControlStatus, user: ZMVideoSDKUser, shareAction: ZMVideoSDKShareAction) {}
    ```

    ```objectivec
    - (void)onRemoteControlStatus:(ZMVideoSDKRemoteControlStatus)status user:(ZMVideoSDKUser *)user shareAction:(ZMVideoSDKShareAction *)shareAction
    ```
