Copy, Paste & Select All Hotkeys not working in Browser Source Interact & Docks (macOS) #365

Open
opened 2022-06-16 20:34:18 -05:00 by dustindmiller · 10 comments
dustindmiller commented 2022-06-16 20:34:18 -05:00 (Migrated from github.com)

Operating System Info

macOS 11

Other OS

No response

OBS Studio Version

27.2.4

OBS Studio Version (Other)

No response

OBS Studio Log URL

All

OBS Studio Crash Log URL

No response

Expected Behavior

Using CMD+C, CMD+V & CMD+A should copy, paste and select all respectively.

Current Behavior

Using mouse and contextual menu is the only way to currently do this.

Steps to Reproduce

  1. Place cursor in browser source interact or dock.
  2. Try hotkey (example CMD+A)
  3. Does not function (does not select all)
  4. Same for all other aforementioned commands.

Anything else we should know?

No response

### Operating System Info macOS 11 ### Other OS _No response_ ### OBS Studio Version 27.2.4 ### OBS Studio Version (Other) _No response_ ### OBS Studio Log URL All ### OBS Studio Crash Log URL _No response_ ### Expected Behavior Using CMD+C, CMD+V & CMD+A should copy, paste and select all respectively. ### Current Behavior Using mouse and contextual menu is the only way to currently do this. ### Steps to Reproduce 1. Place cursor in browser source interact or dock. 2. Try hotkey (example CMD+A) 3. Does not function (does not select all) 4. Same for all other aforementioned commands. ### Anything else we should know? _No response_
WizardCM commented 2022-06-16 20:41:58 -05:00 (Migrated from github.com)

Note: this was split from #238.

Honestly, this is pretty much expected behaviour. The way hotkeys work on macOS as an operating system is that whatever is in the menu bar takes priority.

To properly fix this, we'd have to ensure OBS knows what context the user is in, and modify the Edit menu to replace the actions of copy/paste/select all with their CEF counterparts.

Unfortunately, I don't know how viable/possible this is. I know CEF in general is very bad at notifying the parent application (in this case OBS) whether it's focused.

The good(?) news is the API to perform the actions themselves does exist as part of CefFrame(), including

  • Copy
  • Paste
  • Undo
  • Redo
  • Select All
Note: this was split from #238. Honestly, this is pretty much expected behaviour. The way hotkeys work on macOS as an operating system is that whatever is in the menu bar takes priority. To properly fix this, we'd have to ensure OBS knows what context the user is in, and modify the Edit menu to replace the actions of copy/paste/select all with their CEF counterparts. Unfortunately, I don't know how viable/possible this is. I know **CEF in general is very bad at notifying the parent application** (in this case OBS) whether it's focused. The good(?) news is the API to perform the actions themselves does exist as part of [CefFrame()](https://magpcss.org/ceforum/apidocs3/projects/(default)/CefFrame.html), including * Copy * Paste * Undo * Redo * Select All
Doodle-Med commented 2023-04-25 03:32:27 -05:00 (Migrated from github.com)
  1. Set up OBS Studio and OBS Browser Source on macOS:

  2. Modify the OBS Browser Source plugin:

    • Navigate to the obs-browser plugin directory.
    • Open the obs-browser-source.cpp file in a text editor or IDE.
  3. Define the custom Edit menu:

    • Inside the obs-browser-source.cpp file, locate the browser_source_create function.
    • In this function, create a new instance of CefMenuModel to represent the custom Edit menu:
      CefRefPtr<CefMenuModel> edit_menu = CefMenuModel::CreateMenuModel();
      
    • Add custom items to the menu using the AddItem method. For example:
      edit_menu->AddItem(1, "Copy");
      edit_menu->AddItem(2, "Paste");
      edit_menu->AddItem(3, "Select All");
      
    • Set the new edit_menu as a submenu for the browser source's context menu:
      browser_source->context_menu()->AddSubMenu(4, "Edit", edit_menu);
      
  4. Handle user input for the new menu item:

    • Create a new class that inherits from CefMenuModelDelegate and override the ExecuteCommand method to handle the custom menu commands:
      class EditMenuDelegate : public CefMenuModelDelegate {
      public:
        virtual void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
                                    int command_id,
                                    CefEventHandle event) OVERRIDE {
          // Handle the custom menu commands here.
        }
      
        IMPLEMENT_REFCOUNTING(EditMenuDelegate);
      };
      
    • In the browser_source_create function, create a new instance of the EditMenuDelegate class and set it as the delegate for the edit_menu:
      CefRefPtr<EditMenuDelegate> edit_menu_delegate = new EditMenuDelegate();
      edit_menu->SetDelegate(edit_menu_delegate.get());
      
  5. Trigger the corresponding CEF actions:

    • In the ExecuteCommand method of the EditMenuDelegate class, use the command_id parameter to determine which action to perform. For example:
      void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
                          int command_id,
                          CefEventHandle event) OVERRIDE {
        CefRefPtr<CefBrowser> browser = ...; // Get the CEF browser instance from the OBS browser source.
      
        switch (command_id) {
          case 1: // Copy
            browser->GetFocusedFrame()->Copy();
            break;
          case 2: // Paste
            browser->GetFocusedFrame()->Paste();
            break;
          case 3: // Select All
            browser->GetFocusedFrame()->SelectAll();
            break;
          default:
            break;
        }
      }
      
  6. Compile and test:

    • Rebuild the OBS Browser Source plugin with your changes.
    • Test the new custom Edit menu in OBS Studio, ensuring that the custom copy, paste, and select all commands work as expected.
1. Set up OBS Studio and OBS Browser Source on macOS: - Download and install OBS Studio: https://obsproject.com/download - Download and compile the OBS Browser Source plugin: https://github.com/obsproject/obs-browser - Ensure the plugin is installed and working correctly with OBS Studio. 2. Modify the OBS Browser Source plugin: - Navigate to the obs-browser plugin directory. - Open the `obs-browser-source.cpp` file in a text editor or IDE. 3. Define the custom Edit menu: - Inside the `obs-browser-source.cpp` file, locate the `browser_source_create` function. - In this function, create a new instance of `CefMenuModel` to represent the custom Edit menu: ```cpp CefRefPtr<CefMenuModel> edit_menu = CefMenuModel::CreateMenuModel(); ``` - Add custom items to the menu using the `AddItem` method. For example: ```cpp edit_menu->AddItem(1, "Copy"); edit_menu->AddItem(2, "Paste"); edit_menu->AddItem(3, "Select All"); ``` - Set the new `edit_menu` as a submenu for the browser source's context menu: ```cpp browser_source->context_menu()->AddSubMenu(4, "Edit", edit_menu); ``` 4. Handle user input for the new menu item: - Create a new class that inherits from `CefMenuModelDelegate` and override the `ExecuteCommand` method to handle the custom menu commands: ```cpp class EditMenuDelegate : public CefMenuModelDelegate { public: virtual void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model, int command_id, CefEventHandle event) OVERRIDE { // Handle the custom menu commands here. } IMPLEMENT_REFCOUNTING(EditMenuDelegate); }; ``` - In the `browser_source_create` function, create a new instance of the `EditMenuDelegate` class and set it as the delegate for the `edit_menu`: ```cpp CefRefPtr<EditMenuDelegate> edit_menu_delegate = new EditMenuDelegate(); edit_menu->SetDelegate(edit_menu_delegate.get()); ``` 5. Trigger the corresponding CEF actions: - In the `ExecuteCommand` method of the `EditMenuDelegate` class, use the `command_id` parameter to determine which action to perform. For example: ```cpp void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model, int command_id, CefEventHandle event) OVERRIDE { CefRefPtr<CefBrowser> browser = ...; // Get the CEF browser instance from the OBS browser source. switch (command_id) { case 1: // Copy browser->GetFocusedFrame()->Copy(); break; case 2: // Paste browser->GetFocusedFrame()->Paste(); break; case 3: // Select All browser->GetFocusedFrame()->SelectAll(); break; default: break; } } ``` 6. Compile and test: - Rebuild the OBS Browser Source plugin with your changes. - Test the new custom Edit menu in OBS Studio, ensuring that the custom copy, paste, and select all commands work as expected.
Doodle-Med commented 2023-04-25 03:39:07 -05:00 (Migrated from github.com)

The OBS Browser plugin uses CEF internally, but it doesn't expose the source code for the CEF part in a .cpp file. Instead, you'll have to modify the JavaScript code that communicates with the plugin to create a custom context menu with the desired functionality.

To create a custom Edit menu for the OBS Browser Source, follow these steps:

Set up a new local HTML file that will be used as the Browser Source:

Create a new HTML file with the following basic structure:
php
Copy code

<html> <head> </head> </html> Save the file locally, e.g., as custom_edit_menu.html. Add an event listener for the context menu to the JavaScript code in the HTML file:

javascript
Copy code
window.addEventListener('contextmenu', (event) => {
event.preventDefault();
// Code to create and display the custom context menu will go here.
});
Create the custom Edit menu using JavaScript:

Inside the event listener, create an HTML element for the custom context menu:
javascript
Copy code
const contextMenu = document.createElement('div');
contextMenu.style.position = 'fixed';
contextMenu.style.left = ${event.clientX}px;
contextMenu.style.top = ${event.clientY}px;
contextMenu.style.backgroundColor = '#f8f8f8';
contextMenu.style.border = '1px solid #ccc';
contextMenu.style.padding = '8px';
contextMenu.style.zIndex = 9999;
Create menu items for copy, paste, and select all, and add them to the context menu:
javascript
Copy code
const copyItem = document.createElement('button');
copyItem.textContent = 'Copy';
copyItem.onclick = () => {
document.execCommand('copy');
document.body.removeChild(contextMenu);
};
contextMenu.appendChild(copyItem);

const pasteItem = document.createElement('button');
pasteItem.textContent = 'Paste';
pasteItem.onclick = () => {
document.execCommand('paste');
document.body.removeChild(contextMenu);
};
contextMenu.appendChild(pasteItem);

const selectAllItem = document.createElement('button');
selectAllItem.textContent = 'Select All';
selectAllItem.onclick = () => {
document.execCommand('selectAll');
document.body.removeChild(contextMenu);
};
contextMenu.appendChild(selectAllItem);
Display the custom context menu and handle hiding it:

Add the context menu to the document body:
javascript
Copy code
document.body.appendChild(contextMenu);
Add an event listener to hide the context menu when clicking outside of it:
javascript
Copy code
window.addEventListener('click', () => {
if (document.body.contains(contextMenu)) {
document.body.removeChild(contextMenu);
}
});
Set up OBS Studio and the Browser Source:

Open OBS Studio.
Create a new Browser Source.
In the Browser Source properties, set the local file as the source, e.g., custom_edit_menu.html.
With these modifications, you should have a custom context menu with copy, paste, and select all commands in the OBS Browser Source. Note that this approach uses JavaScript's execCommand function, which is now deprecated. You may need to use the Clipboard API.

The OBS Browser plugin uses CEF internally, but it doesn't expose the source code for the CEF part in a .cpp file. Instead, you'll have to modify the JavaScript code that communicates with the plugin to create a custom context menu with the desired functionality. To create a custom Edit menu for the OBS Browser Source, follow these steps: Set up a new local HTML file that will be used as the Browser Source: Create a new HTML file with the following basic structure: php Copy code <!DOCTYPE html> <html> <head> <title>Custom Edit Menu</title> <style> /* Add any required CSS here */ </style> </head> <body> <!-- Add your page content here --> <script> // Add JavaScript code here </script> </body> </html> Save the file locally, e.g., as custom_edit_menu.html. Add an event listener for the context menu to the JavaScript code in the HTML file: javascript Copy code window.addEventListener('contextmenu', (event) => { event.preventDefault(); // Code to create and display the custom context menu will go here. }); Create the custom Edit menu using JavaScript: Inside the event listener, create an HTML element for the custom context menu: javascript Copy code const contextMenu = document.createElement('div'); contextMenu.style.position = 'fixed'; contextMenu.style.left = `${event.clientX}px`; contextMenu.style.top = `${event.clientY}px`; contextMenu.style.backgroundColor = '#f8f8f8'; contextMenu.style.border = '1px solid #ccc'; contextMenu.style.padding = '8px'; contextMenu.style.zIndex = 9999; Create menu items for copy, paste, and select all, and add them to the context menu: javascript Copy code const copyItem = document.createElement('button'); copyItem.textContent = 'Copy'; copyItem.onclick = () => { document.execCommand('copy'); document.body.removeChild(contextMenu); }; contextMenu.appendChild(copyItem); const pasteItem = document.createElement('button'); pasteItem.textContent = 'Paste'; pasteItem.onclick = () => { document.execCommand('paste'); document.body.removeChild(contextMenu); }; contextMenu.appendChild(pasteItem); const selectAllItem = document.createElement('button'); selectAllItem.textContent = 'Select All'; selectAllItem.onclick = () => { document.execCommand('selectAll'); document.body.removeChild(contextMenu); }; contextMenu.appendChild(selectAllItem); Display the custom context menu and handle hiding it: Add the context menu to the document body: javascript Copy code document.body.appendChild(contextMenu); Add an event listener to hide the context menu when clicking outside of it: javascript Copy code window.addEventListener('click', () => { if (document.body.contains(contextMenu)) { document.body.removeChild(contextMenu); } }); Set up OBS Studio and the Browser Source: Open OBS Studio. Create a new Browser Source. In the Browser Source properties, set the local file as the source, e.g., custom_edit_menu.html. With these modifications, you should have a custom context menu with copy, paste, and select all commands in the OBS Browser Source. Note that this approach uses JavaScript's execCommand function, which is now deprecated. You may need to use the Clipboard API.
Doodle-Med commented 2023-04-25 03:43:40 -05:00 (Migrated from github.com)
  1. Set up a new local HTML file that will be used as the Browser Source:

    • Create a new HTML file with the following basic structure:
      <!DOCTYPE html>
      <html>
      <head>
        <title>Custom Edit Menu</title>
        <style>
          /* Add any required CSS here */
        </style>
      </head>
      <body>
        <!-- Add your page content here -->
        <script>
          // Add JavaScript code here
        </script>
      </body>
      </html>
      
    • Save the file locally, e.g., as custom_edit_menu.html.
  2. Add an event listener for the context menu to the JavaScript code in the HTML file:
    window.addEventListener('contextmenu', (event) => {
    event.preventDefault();
    // Code to create and display the custom context menu will go here.
    });

  3. Create the custom Edit menu using JavaScript:

  • Inside the event listener, create an HTML element for the custom context menu:
    const contextMenu = document.createElement('div');
    contextMenu.style.position = 'fixed';
    contextMenu.style.left = `${event.clientX}px`;
    contextMenu.style.top = `${event.clientY}px`;
    contextMenu.style.backgroundColor = '#f8f8f8';
    contextMenu.style.border = '1px solid #ccc';
    contextMenu.style.padding = '8px';
    contextMenu.style.zIndex = 9999;
    
  • Create menu items for copy, paste, and select all, and add them to the context menu using the Clipboard API:
    const copyItem = document.createElement('button');
    copyItem.textContent = 'Copy';
    copyItem.onclick = async () => {
      try {
        const selectedText = window.getSelection().toString();
        await navigator.clipboard.writeText(selectedText);
      } catch (err) {
        console.error('Failed to copy text:', err);
      }
      document.body.removeChild(contextMenu);
    };
    contextMenu.appendChild(copyItem);
    
    const pasteItem = document.createElement('button');
    pasteItem.textContent = 'Paste';
    pasteItem.onclick = async () => {
      try {
        const clipboardText = await navigator.clipboard.readText();
        // Handle pasting the text as needed.
      } catch (err) {
        console.error('Failed to paste text:', err);
      }
      document.body.removeChild(contextMenu);
    };
    contextMenu.appendChild(pasteItem);
    
    const selectAllItem = document.createElement('button');
    selectAllItem.textContent = 'Select All';
    selectAllItem.onclick = () => {
      document.execCommand('selectAll');
      document.body.removeChild(contextMenu);
    };
    contextMenu.appendChild(selectAllItem);
    
  1. Display the custom context menu and handle hiding it:
  • Add the context menu to the document body:
    document.body.appendChild(contextMenu);
    
  • Add an event listener to hide the context menu when clicking outside of it:
    window.addEventListener('click', () => {
      if (document.body.contains(contextMenu)) {
        document.body.removeChild(contextMenu);
      }
    });
    
  1. Set up OBS Studio and the Browser Source:
  • Open OBS Studio.
  • Create a new Browser Source.
  • In the Browser Source properties, set the local file as the source, e.g., custom_edit_menu.html.
1. Set up a new local HTML file that will be used as the Browser Source: - Create a new HTML file with the following basic structure: ``` <!DOCTYPE html> <html> <head> <title>Custom Edit Menu</title> <style> /* Add any required CSS here */ </style> </head> <body> <!-- Add your page content here --> <script> // Add JavaScript code here </script> </body> </html> ``` - Save the file locally, e.g., as `custom_edit_menu.html`. 2. Add an event listener for the context menu to the JavaScript code in the HTML file: window.addEventListener('contextmenu', (event) => { event.preventDefault(); // Code to create and display the custom context menu will go here. }); 3. Create the custom Edit menu using JavaScript: - Inside the event listener, create an HTML element for the custom context menu: ``` const contextMenu = document.createElement('div'); contextMenu.style.position = 'fixed'; contextMenu.style.left = `${event.clientX}px`; contextMenu.style.top = `${event.clientY}px`; contextMenu.style.backgroundColor = '#f8f8f8'; contextMenu.style.border = '1px solid #ccc'; contextMenu.style.padding = '8px'; contextMenu.style.zIndex = 9999; ``` - Create menu items for copy, paste, and select all, and add them to the context menu using the Clipboard API: ``` const copyItem = document.createElement('button'); copyItem.textContent = 'Copy'; copyItem.onclick = async () => { try { const selectedText = window.getSelection().toString(); await navigator.clipboard.writeText(selectedText); } catch (err) { console.error('Failed to copy text:', err); } document.body.removeChild(contextMenu); }; contextMenu.appendChild(copyItem); const pasteItem = document.createElement('button'); pasteItem.textContent = 'Paste'; pasteItem.onclick = async () => { try { const clipboardText = await navigator.clipboard.readText(); // Handle pasting the text as needed. } catch (err) { console.error('Failed to paste text:', err); } document.body.removeChild(contextMenu); }; contextMenu.appendChild(pasteItem); const selectAllItem = document.createElement('button'); selectAllItem.textContent = 'Select All'; selectAllItem.onclick = () => { document.execCommand('selectAll'); document.body.removeChild(contextMenu); }; contextMenu.appendChild(selectAllItem); ``` 4. Display the custom context menu and handle hiding it: - Add the context menu to the document body: ``` document.body.appendChild(contextMenu); ``` - Add an event listener to hide the context menu when clicking outside of it: ``` window.addEventListener('click', () => { if (document.body.contains(contextMenu)) { document.body.removeChild(contextMenu); } }); ``` 5. Set up OBS Studio and the Browser Source: - Open OBS Studio. - Create a new Browser Source. - In the Browser Source properties, set the local file as the source, e.g., `custom_edit_menu.html`.
Blackn0va commented 2023-07-24 08:27:48 -05:00 (Migrated from github.com)

is there a possibility that the copy paste is also installed with the hotkey in a next update? The function has otherwise no use for me.

is there a possibility that the copy paste is also installed with the hotkey in a next update? The function has otherwise no use for me.
hyperiris commented 2024-01-04 05:00:54 -06:00 (Migrated from github.com)

This is a CEF related bug.

please try https://glitch.com/edit/#!/async-clipboard-text in web browser and cef demo such as cefclient, you can find that.

This is a CEF related bug. please try https://glitch.com/edit/#!/async-clipboard-text in web browser and cef demo such as cefclient, you can find that.
gitwittidbit commented 2024-10-29 13:09:36 -05:00 (Migrated from github.com)

Any update on this (that works for non-dev users)?

Any update on this (that works for non-dev users)?
LooneyH commented 2025-06-12 04:17:29 -05:00 (Migrated from github.com)

Bumping this as this issue still has not been fixed as of the latest stable or beta release, and it seems to be a problem that if resolved would allow for easy replication among other OBS panels and display elements on macOS

Bumping this as this issue still has not been fixed as of the latest stable or beta release, and it seems to be a problem that if resolved would allow for easy replication among other OBS panels and display elements on macOS
DC4JG commented 2025-06-17 17:25:27 -05:00 (Migrated from github.com)

Happy to see that there is a workaround but would've never guessed that compiling (parts of) OBS to fix copy&paste will land on my todo list.

If possible I'd suggest documenting this lack of feature parity between different OS versions somewhere easier to find, especially for normal users. It took me way too long to discover why I'm failing to edit the Twitch stream information on my Macbook.


OBS 31.0.3 (64 bit), macOS Sequoia 15.5 (24F74)

Happy to see that there is a workaround but would've never guessed that compiling (parts of) OBS to fix copy&paste will land on my todo list. If possible I'd suggest documenting this lack of feature parity between different OS versions somewhere easier to find, especially for normal users. It took me way too long to discover why I'm failing to edit the Twitch stream information on my Macbook. --- OBS 31.0.3 (64 bit), macOS Sequoia 15.5 (24F74)
yllekz commented 2025-09-07 09:47:19 -05:00 (Migrated from github.com)

Is this fixed? I ran into this days ago. Not sure how it blocks system level keyboard shortcuts on macOS but accessibility-wise it's not great.

Is this fixed? I ran into this days ago. Not sure how it blocks system level keyboard shortcuts on macOS but accessibility-wise it's not great.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-obsproject/obs-browser#365
No description provided.