-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automagical copy paste #1174
Automagical copy paste #1174
Changes from all commits
709193d
f77cf27
aff1207
16858a5
d1c6c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ const UI = { | |
isSafari: false, | ||
lastKeyboardinput: null, | ||
defaultKeyboardinputLen: 100, | ||
needToCheckClipboardChange: false, | ||
|
||
inhibit_reconnect: true, | ||
reconnect_callback: null, | ||
|
@@ -936,24 +937,180 @@ const UI = { | |
} | ||
}, | ||
|
||
readClipboard(callback) { | ||
var readfuture = navigator.clipboard.readText(); | ||
readfuture | ||
.then(text => callback(text)) | ||
.catch(() => | ||
Log.Debug("Failed to read system clipboard") | ||
); | ||
}, | ||
|
||
// Copy text from NoVNC desktop to local computer | ||
clipboardReceive(e) { | ||
Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); | ||
document.getElementById('noVNC_clipboard_text').value = e.detail.text; | ||
Log.Debug("<< UI.clipboardReceive"); | ||
var curvalue = document.getElementById('noVNC_clipboard_text').value; | ||
if (curvalue != e.detail.text) { | ||
Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); | ||
document.getElementById('noVNC_clipboard_text').value = e.detail.text; | ||
Log.Debug("<< UI.clipboardReceive"); | ||
|
||
var writefuture = navigator.clipboard.writeText(e.detail.text); | ||
writefuture | ||
.then(function() { | ||
/* clipboard successfully set */ | ||
UI.popupMessage("Selection Copied"); | ||
}, function() { | ||
console.error("Failed to write system clipboard (trying to copy from NoVNC clipboard)") | ||
}); | ||
} | ||
}, | ||
|
||
popupMessage(msg) { | ||
// Quick popup to give feedback that selection was copied | ||
setTimeout(UI.showOverlay.bind(this, msg, 500), 200); | ||
}, | ||
|
||
// Enter and focus events come when we return to NoVNC. | ||
// In both cases, check the local clipboard to see if it changed. | ||
focusVNC() { | ||
UI.copyFromLocalClipboard(); | ||
}, | ||
enterVNC() { | ||
UI.copyFromLocalClipboard(); | ||
}, | ||
copyFromLocalClipboard() { | ||
UI.readClipboard(text => { | ||
var clipVal = document.getElementById('noVNC_clipboard_text').value; | ||
if ( clipVal != text ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is essential, otherwise we have no mechanism that avoids just blindly overwriting the server clipboard whenever focus changes. However this is still a hack, so I think we should reference the |
||
document.getElementById('noVNC_clipboard_text').value = text; | ||
UI.popupMessage("Copied from Local Clipboard"); | ||
UI.rfb.clipboardPasteFrom(text); | ||
} | ||
// Reset flag to prevent checking too often | ||
UI.needToCheckClipboardChange = false; | ||
}) | ||
}, | ||
|
||
// These 3 events indicate the focus has gone outside the NoVNC. | ||
// When outside the NoVNC, the system clipboard could change. | ||
leaveVNC() { | ||
UI.needToCheckClipboardChange = true; | ||
}, | ||
blurVNC() { | ||
UI.needToCheckClipboardChange = true; | ||
}, | ||
focusoutVNC() { | ||
UI.needToCheckClipboardChange = true; | ||
}, | ||
|
||
// On these 2 events, check if we need to look at clipboard. | ||
mouseMoveVNC() { | ||
if ( UI.needToCheckClipboardChange ) { | ||
UI.copyFromLocalClipboard(); | ||
} | ||
}, | ||
mouseDownVNC() { | ||
if ( UI.needToCheckClipboardChange ) { | ||
UI.copyFromLocalClipboard(); | ||
} | ||
}, | ||
|
||
clipboardClear() { | ||
document.getElementById('noVNC_clipboard_text').value = ""; | ||
UI.popupMessage("Clipboard Cleared"); | ||
// TODO: Should this also clear the local clipboard? | ||
UI.rfb.clipboardPasteFrom(""); | ||
}, | ||
|
||
// Send clipboard from HTML clipboard element to NoVNC desktop | ||
clipboardSend() { | ||
const text = document.getElementById('noVNC_clipboard_text').value; | ||
Log.Debug(">> UI.clipboardSend: " + text.substr(0, 40) + "..."); | ||
UI.rfb.clipboardPasteFrom(text); | ||
Log.Debug("<< UI.clipboardSend"); | ||
}, | ||
|
||
/** | ||
* Show the terminal overlay for a given amount of time. | ||
* | ||
* The terminal overlay appears in inverse video in a large font, centered | ||
* over the terminal. You should probably keep the overlay message brief, | ||
* since it's in a large font and you probably aren't going to check the size | ||
* of the terminal first. | ||
* | ||
* @param {string} msg The text (not HTML) message to display in the overlay. | ||
* @param {number} opt_timeout The amount of time to wait before fading out | ||
* the overlay. Defaults to 1.5 seconds. Pass null to have the overlay | ||
* stay up forever (or until the next overlay). | ||
*/ | ||
showOverlay(msg, opt_timeout) { | ||
if (!UI.overlayNode) { | ||
UI.overlayNode = document.createElement('div'); | ||
UI.overlayNode.style.cssText = ( | ||
'border-radius: 15px;' + | ||
'font-size: xx-large;' + | ||
'opacity: 0.90;' + | ||
'padding: 0.2em 0.5em 0.2em 0.5em;' + | ||
'position: absolute;' + | ||
'-webkit-user-select: none;' + | ||
'-webkit-transition: opacity 180ms ease-in;' + | ||
'-moz-user-select: none;' + | ||
'-moz-transition: opacity 180ms ease-in;'); | ||
UI.overlayNode.style.color = 'rgb(16,16,16)'; | ||
UI.overlayNode.style.backgroundColor = 'rgb(240,240,240)'; | ||
UI.overlayNode.style.fontFamily = '"DejaVu Sans Mono", "Noto Sans Mono", "Everson Mono", FreeMono, Menlo, Terminal, monospace"'; | ||
UI.overlayNode.style.opacity = '0.90'; | ||
|
||
//UI.overlayNode.addEventListener('mousedown', function(e) { | ||
// e.preventDefault(); | ||
// e.stopPropagation(); | ||
// }, true); | ||
} | ||
|
||
UI.overlayNode.textContent = msg; | ||
|
||
if (!UI.overlayNode.parentNode_) { | ||
UI.overlayNode.parentNode_ = document.getElementById('noVNC_container'); | ||
} | ||
UI.overlayNode.parentNode_.appendChild(UI.overlayNode); | ||
|
||
var divWidth = UI.overlayNode.parentNode_.offsetWidth; | ||
var divHeight = UI.overlayNode.parentNode_.offsetHeight; | ||
var overlayWidth = UI.overlayNode.offsetWidth; | ||
var overlayHeight = UI.overlayNode.offsetHeight; | ||
|
||
UI.overlayNode.style.top = | ||
(divHeight - overlayHeight) / 2 + 'px'; | ||
UI.overlayNode.style.left = | ||
(divWidth - overlayWidth) / 2 + 'px'; | ||
|
||
if (UI.overlayTimeout) | ||
clearTimeout(UI.overlayTimeout); | ||
|
||
if (opt_timeout === null) | ||
opt_timeout = 500; | ||
|
||
UI.overlayTimeout = setTimeout(() => { | ||
UI.overlayNode.style.opacity = '0'; | ||
UI.overlayTimeout = setTimeout(() => UI.hideOverlay(), 200); | ||
}, opt_timeout || 1500); | ||
}, | ||
|
||
/** | ||
* Hide the terminal overlay immediately. | ||
* | ||
* Useful when we show an overlay for an event with an unknown end time. | ||
*/ | ||
hideOverlay() { | ||
if (UI.overlayTimeout) | ||
clearTimeout(UI.overlayTimeout); | ||
UI.overlayTimeout = null; | ||
|
||
if (UI.overlayNode.parentNode_) | ||
UI.overlayNode.parentNode_.removeChild(UI.overlayNode); | ||
UI.overlayNode.style.opacity = '0.90'; | ||
}, | ||
|
||
/* ------^------- | ||
* /CLIPBOARD | ||
* ============== | ||
|
@@ -1024,6 +1181,15 @@ const UI = { | |
UI.rfb.addEventListener("securityfailure", UI.securityFailed); | ||
UI.rfb.addEventListener("capabilities", UI.updatePowerButton); | ||
UI.rfb.addEventListener("clipboard", UI.clipboardReceive); | ||
|
||
document.addEventListener('mouseenter', UI.enterVNC); | ||
document.addEventListener('mouseleave', UI.leaveVNC); | ||
document.addEventListener('blur', UI.blurVNC); | ||
document.addEventListener('focus', UI.focusVNC); | ||
document.addEventListener('focusout', UI.focusoutVNC); | ||
document.addEventListener('mousemove', UI.mouseMoveVNC); | ||
document.addEventListener('mousedown', UI.mouseDownVNC); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need all of these events? Isn't it sufficient with just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I discovered while implementing the clipboard feature that the Chrome API clipboard.readText() is still buggy. It fails sometimes (not-deterministic why) with undefined error. When using all these events here to try to read it, it mostly works. I reported the bug to the Chrome community and suggest not implement this feature until it doesn't work properly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's disappointing. Do you have a link? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes of course, follow this: https://bugs.chromium.org/p/chromium/issues/detail?id=949926&q=clipboard&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified There I described how to reproduce the bug. |
||
|
||
UI.rfb.addEventListener("bell", UI.bell); | ||
UI.rfb.addEventListener("desktopname", UI.updateDesktopName); | ||
UI.rfb.clipViewport = UI.getSetting('view_clip'); | ||
|
@@ -1373,6 +1539,10 @@ const UI = { | |
keepVirtualKeyboard(event) { | ||
const input = document.getElementById('noVNC_keyboardinput'); | ||
|
||
if ( UI.needToCheckClipboardChange ) { | ||
UI.copyFromLocalClipboard(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't hijack existing (and unrelated) event handlers. |
||
|
||
// Only prevent focus change if the virtual keyboard is active | ||
if (document.activeElement != input) { | ||
return; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👎
We should always update the local clipboard on a proper event.