All Products
Search
Document Center

Cloud Phone:Paste text in the Safari browser using the Web SDK

Last Updated:Jan 15, 2026

Due to Safari's security restrictions, accessing clipboard content programmatically triggers a native paste confirmation pop-up. This disrupts the user experience when trying to synchronize the local client's clipboard with the Cloud Phone's clipboard. This topic explains how to implement a custom solution using the Web SDK to seamlessly paste locally copied text into a Cloud Phone session running in Safari.

Solution overview

  1. Add a custom clipboard button to your local client's UI. Clicking this button opens a pop-up input box.

  2. The user pastes the content they want to send to the Cloud Phone into this pop-up input box.

  3. Clicking a "Paste Now" button within the pop-up synchronizes the content to both the Cloud Phone's clipboard and its active input field.

Implementation steps

Cloud Phone SDK parameter configuration

  • Set readClipboardDataByUser to true: Enable this parameter to prevent the SDK from attempting to read the clipboard automatically, giving you control over the process.

  • Set useCustomIme to true: Enable the local Input Method Editor (IME). This is required to programmatically insert the content into the Cloud Phone's active input field.

// Check if the browser is Safari
function isSafari() {
    return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
}
// Main control configuration. Disable automatic clipboard reading by the SDK and enable the local IME.
connConfig = {..., readClipboardDataByUser:isSafari(), useCustomIme:true}; 
var appInfo = {
  ...,
  connConfig: connConfig,
  ...
};
var sessionParam = {
  ...,
  appInfo: appInfo,
  ....
};
var wuyingSdk = Wuying.WebSDK;
session = wuyingSdk.createSession('appstream', sessionParam);
// Thumbnail configuration. Enable the local IME.
this.thumbnail = new window.Wuying.ThumbnailSDK({
  ...,
  connectionConfig: {
    useCustomIme: true,
  },
},
{
  onConnected: (data) => {
    this.thumbnail.session.getLocalConfig().setClipboardEnabled(true);
  },
  onDisConnected: (data) => {},
  onThumbnailData: (url) => {},
}
);

Create the pop-up input box

In your client application, create a clipboard button that, when clicked, displays a dialog box designed to handle clipboard interaction. You can refer to the following code sample:

function showInput() {
  showCustomDialog();
  // Click the modal overlay to close the dialog box
  document.querySelector('.modal-overlay').addEventListener('click', function (e) {
      if (e.target === this) {
          closeModal();
      }
  });

  // Press the ESC key to close the dialog box
  document.addEventListener('keydown', function (e) {
      if (e.key === 'Escape') {
          closeModal();
      }
  });
}

function closeModal() {
  console.log('closeModal');
  const overlay = document.querySelector('.modal-overlay');
  if (overlay) {
      overlay.style.display = 'none';
      overlay.remove();
  }
}

function submitContent() {
  const content = document.querySelector('.input-field').value.trim();
  if (!content) {
      alert('Please enter content');
      return;
  }
  // Sync content to the cloud phone
  sendMsgToCloudPhoneOperation(content);
  closeModal();
}

function showCustomDialog() {
  // Create the modal background
  const overlay = document.createElement('div');
  overlay.className = 'modal-overlay';
  // Ensure the modal captures all events and is displayed at the highest level
  overlay.style.pointerEvents = 'all';
  overlay.style.zIndex = '9999';
  
  // Prevent events from propagating to underlying layers
  const stopPropagation = function(e) {
      e.stopPropagation();
  };
  
  overlay.addEventListener('contextmenu', stopPropagation, true);
  
  // Add event listeners to intercept all keyboard events
  overlay.addEventListener('keydown', stopPropagation, true);
  overlay.addEventListener('keyup', stopPropagation, true);
  overlay.addEventListener('keypress', stopPropagation, true);
  
  overlay.innerHTML = `
      <div class="modal">
          <div class="modal-header">
              <h2 class="modal-title">Clipboard</h2>
              <button class="close-btn" onclick="closeModal()">×</button>
          </div>
          
          <div class="input-container">
              <textarea 
                  class="input-field" 
                  placeholder="Enter content"
                  maxlength="500"
              ></textarea>
          </div>
          
          <button class="submit-btn" onclick="submitContent()">
              Paste Now
          </button>
      </div>
  `;

  document.body.appendChild(overlay);
  
  // Focus the textarea when the modal opens to ensure keyboard events are captured
  setTimeout(() => {
      const textarea = overlay.querySelector('.input-field');
      if (textarea) {
          textarea.focus();
      }
  }, 100);
}

Send the copied text to the cloud phone

Trigger the sync task

function submitContent() {
  const content = document.querySelector('.input-field').value.trim();
  if (!content) {
      alert('Please enter content');
      return;
  }
  // Sync content to the cloud phone
  sendMsgToCloudPhoneOperation(content);
  closeModal();
}

Sync the content to the cloud phone

function sendMsgToCloudPhoneOperation(msg) {
  // Main control
  if (session) {
    session.setClipboardModule('sendClipboardDataToRemote', msg) 
  }
  // Thumbnail
  for (const [key, value] of thumbnailSDKMap) {
      console.log('thumbnail sendMsgToCloudPhoneOperation ', key, msg);
      value.thumbnail.session.getClipboardModule().sendClipboardDataToRemote(msg);
  }
}

Usage notes

The newly created dialog box must take full control of all keyboard events to prevent them from being captured by other UI elements on the page. Otherwise, standard key presses (like typing) will not be correctly handled within the dialog. Refer to the following configuration example:

overlay.addEventListener('contextmenu', stopPropagation, true);

// Add event listeners to intercept all keyboard events
overlay.addEventListener('keydown', stopPropagation, true);
overlay.addEventListener('keyup', stopPropagation, true);
overlay.addEventListener('keypress', stopPropagation, true);