UTM icon indicating copy to clipboard operation
UTM copied to clipboard

Cannot copy text in terminal/console-only display mode

Open tie opened this issue 4 years ago • 10 comments

When selecting text in a non-GUI VM (i.e. “Console Only” under “Display” settings), both “Edit → Copy” under menu bar menu and Command+C shortcut do nothing. It’s possible to drag-and-drop selected text though.

Configuration

  • UTM Version: v2.1.2, v2.2.4
  • macOS Version: 11.6
  • Intel or Apple Silicon? Intel

tie avatar Sep 15 '21 12:09 tie

This is a limitation of the javascript terminal. I think if you right click, it will copy.

osy avatar Oct 04 '21 00:10 osy

@tie You can try this patch: hterm_all.js.patch.txt

Steps to apply:

  1. Download the patch
  2. Rename it to hterm_all.js.patch
  3. Open Terminal.app
  4. Type cd /Applications/UTM.app/Contents/Resources and press enter
  5. Type patch <, then drag the patch file over the terminal and drop it, which will autofill the path, then press enter.
  6. Open UTM and test if it's fixed.

@osy can you please confirm, it seems that changing files in Contents/Resources doesn't invalidate the code signature?

ktprograms avatar Oct 04 '21 06:10 ktprograms

It definitely will.

osy avatar Oct 04 '21 07:10 osy

Not sure why but it still runs for me?

Edit: So it seems that changing files in Contents/Resources invalidates the signature but the app can still be used?

ktprograms avatar Oct 04 '21 07:10 ktprograms

Thanks, runs for me too 🙂 I ended up enabling default window copy behavior. It’d be also nice to have GUI for hterm settings.

tie avatar Oct 06 '21 13:10 tie

I ended up enabling default window copy behavior.

@tie how did you do this? Just wondering.

ktprograms avatar Oct 06 '21 14:10 ktprograms

Uh, I just hardcoded the preferences.

Also, use-default-window-copy doesn’t work that well with line wrapping, so I’m actually not using it now.

For some reason Cmd+C didn’t work out of the box even with patched hterm.copySelectionToClipboard, but adding copySelectionToClipboard call in onMetaC_ fixed that for me.

hterm_all.js diff
--- a/UTM.app/Contents/Resources/hterm_all.js
+++ b/UTM.app/Contents/Resources/hterm_all.js
@@ -5471,106 +5471,7 @@
  * @return {!Promise<void>}
  */
 hterm.copySelectionToClipboard = function(document, str) {
-  // Request permission if need be.
-  const requestPermission = () => {
-    // Use the Permissions API if available.
-    if (navigator.permissions && navigator.permissions.query) {
-      return navigator.permissions.query({name: 'clipboard-write'})
-        .then((status) => {
-          const checkState = (resolve, reject) => {
-            switch (status.state) {
-              case 'granted':
-                return resolve();
-              case 'denied':
-                return reject();
-              default:
-                // Wait for the user to approve/disprove.
-                return new Promise((resolve, reject) => {
-                  status.onchange = () => checkState(resolve, reject);
-                });
-            }
-          };
-
-          return new Promise(checkState);
-        })
-        // If the platform doesn't support "clipboard-write", or is denied,
-        // we move on to the copying step anyways.
-        .catch(() => Promise.resolve());
-    } else {
-      // No permissions API, so resolve right away.
-      return Promise.resolve();
-    }
-  };
-
-  // Write to the clipboard.
-  const writeClipboard = () => {
-    // Use the Clipboard API if available.
-    if (navigator.clipboard && navigator.clipboard.writeText) {
-      // If this fails (perhaps due to focus changing windows), fallback to the
-      // legacy copy method.
-      return navigator.clipboard.writeText(str)
-        .catch(execCommand);
-    } else {
-      // No Clipboard API, so use the old execCommand style.
-      return execCommand();
-    }
-  };
-
-  // Write to the clipboard using the legacy execCommand method.
-  // TODO: Once we can rely on the Clipboard API everywhere, we can simplify
-  // this a lot by deleting the custom selection logic.
-  const execCommand = () => {
-    const copySource = document.createElement('pre');
-    copySource.id = 'hterm:copy-to-clipboard-source';
-    copySource.textContent = str;
-    copySource.style.cssText = (
-        '-webkit-user-select: text;' +
-        '-moz-user-select: text;' +
-        'position: absolute;' +
-        'top: -99px');
-
-    document.body.appendChild(copySource);
-
-    const selection = document.getSelection();
-    const anchorNode = selection.anchorNode;
-    const anchorOffset = selection.anchorOffset;
-    const focusNode = selection.focusNode;
-    const focusOffset = selection.focusOffset;
-
-    // FF sometimes throws NS_ERROR_FAILURE exceptions when we make this call.
-    // Catch it because a failure here leaks the copySource node.
-    // https://bugzilla.mozilla.org/show_bug.cgi?id=1178676
-    try {
-      selection.selectAllChildren(copySource);
-    } catch (ex) {}
-
-    try {
-      document.execCommand('copy');
-    } catch (firefoxException) {
-      // Ignore this. FF throws an exception if there was an error, even
-      // though the spec says just return false.
-    }
-
-    // IE doesn't support selection.extend.  This means that the selection won't
-    // return on IE.
-    if (selection.extend) {
-      // When running in the test harness, we won't have any related nodes.
-      if (anchorNode) {
-        selection.collapse(anchorNode, anchorOffset);
-      }
-      if (focusNode) {
-        selection.extend(focusNode, focusOffset);
-      }
-    }
-
-    copySource.parentNode.removeChild(copySource);
-
-    // Since execCommand is synchronous, resolve right away.
-    return Promise.resolve();
-  };
-
-  // Kick it all off!
-  return requestPermission().then(writeClipboard);
+  return navigator.clipboard.writeText(str);
 };
 
 /**
@@ -8245,6 +8146,7 @@
   if (this.keyboard.terminal.clearSelectionAfterCopy) {
     setTimeout(function() { document.getSelection().collapseToEnd(); }, 50);
   }
+  this.keyboard.terminal.copySelectionToClipboard();
   return hterm.Keyboard.KeyActions.PASS;
 };
 
@@ -9438,7 +9340,7 @@
   'copy-on-select': hterm.PreferenceManager.definePref_(
       'Automatically copy selected content',
       hterm.PreferenceManager.Categories.CopyPaste,
-      true, 'bool',
+      false, 'bool',
       `Automatically copy mouse selection to the clipboard.`
   ),
 
@@ -9459,7 +9361,7 @@
   'clear-selection-after-copy': hterm.PreferenceManager.definePref_(
       'Automatically clear text selection',
       hterm.PreferenceManager.Categories.CopyPaste,
-      true, 'bool',
+      false, 'bool',
       `Whether to clear the selection after copying.`
   ),
 

tie avatar Oct 07 '21 04:10 tie

I think I am encountering that too

nrolland avatar Nov 13 '22 12:11 nrolland

@tie You can try this patch: hterm_all.js.patch.txt

Steps to apply:

1. Download the patch

2. Rename it to `hterm_all.js.patch`

3. Open `Terminal.app`

4. Type `cd /Applications/UTM.app/Contents/Resources` and press enter

5. Type `patch <`, then drag the patch file over the terminal and drop it, which will autofill the path, then press enter.

6. Open UTM and test if it's fixed.

@osy can you please confirm, it seems that changing files in Contents/Resources doesn't invalidate the code signature? Can I still use this patch in UTM 4.2.5 ?

It is indeed very annoying that I can't copy / paste from / to the console window. I mean the console window of a non-GUI OS which is not (yet) reachable via SSH.

freebrowser1 avatar May 09 '23 10:05 freebrowser1

Does not work.

mac:/Applications/UTM.app/Contents/Resources % patch < /Users/klaas/Downloads/hterm_all.js.patch.txt 
File to patch: /Users/klaas/Downloads/hterm_all.js.patch.txt 
patching file '/Users/klaas/Downloads/hterm_all.js.patch.txt'
patching file '/Users/klaas/Downloads/hterm_all.js.patch.txt'
No such line 16251 in input file, ignoring
1 out of 1 hunks failed--saving rejects to '/Users/klaas/Downloads/hterm_all.js.patch.txt.rej'

freebrowser1 avatar Aug 02 '24 07:08 freebrowser1