Skip to content

Commit 7543d73

Browse files
committed
GUACAMOLE-2237: Multiline paste and text input client fixes.
1 parent a301739 commit 7543d73

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

guacamole-common-js/src/main/webapp/modules/Keyboard.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ Guacamole.Keyboard = function Keyboard(element) {
407407
var keycodeKeysyms = {
408408
8: [0xFF08], // backspace
409409
9: [0xFF09], // tab
410+
// 10 (LF) intentionally absent: no physical key generates a linefeed.
410411
12: [0xFF0B, 0xFF0B, 0xFF0B, 0xFFB5], // clear / KP 5
411412
13: [0xFF0D], // enter
412413
16: [0xFFE1, 0xFFE1, 0xFFE2], // shift
@@ -1060,7 +1061,31 @@ Guacamole.Keyboard = function Keyboard(element) {
10601061
if (str.charCodeAt(i) !== codepoint) {
10611062
i++;
10621063
}
1063-
var keysym = keysym_from_charcode(codepoint);
1064+
1065+
// CR and LF are handled explicitly; all other codepoints go through
1066+
// keysym_from_charcode().
1067+
var keysym;
1068+
1069+
if (codepoint === 0x0D) {
1070+
keysym = 0xFF0D;
1071+
1072+
// CRLF pairs are collapsed to produce a single Return.
1073+
var nextCodepoint = (i + 1 < str.length)
1074+
? (str.codePointAt ? str.codePointAt(i + 1) : str.charCodeAt(i + 1))
1075+
: 0;
1076+
1077+
if (nextCodepoint === 0x0A)
1078+
i++;
1079+
}
1080+
else if (codepoint === 0x0A) {
1081+
// keysym_from_charcode(0x0A) would return 0xFF0A which is not
1082+
// a keyboard character and is ignored by protocol input
1083+
// handlers.
1084+
keysym = 0xFF0D;
1085+
}
1086+
else {
1087+
keysym = keysym_from_charcode(codepoint);
1088+
}
10641089

10651090
// Press and release key for current character
10661091
guac_keyboard.press(keysym);

guacamole/src/main/frontend/src/app/textInput/directives/guacTextInput.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,35 @@ angular.module('textInput').directive('guacTextInput', [function guacTextInput()
286286

287287
};
288288

289+
// Handle paste separately from normal input.
290+
target.addEventListener("paste", function targetPaste(e) {
291+
292+
if (!e.clipboardData)
293+
return;
294+
295+
// Take over paste handling before the browser inserts anything.
296+
e.preventDefault();
297+
e.stopPropagation();
298+
299+
var content = e.clipboardData.getData('text/plain');
300+
301+
// Normalize line endings to \n.
302+
content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
303+
304+
// Release modifiers so pasted text isn't treated as Ctrl/Alt combos.
305+
$rootScope.$broadcast('guacSyntheticKeyup', 0xFFE3); // Left Ctrl
306+
$rootScope.$broadcast('guacSyntheticKeyup', 0xFFE4); // Right Ctrl
307+
$rootScope.$broadcast('guacSyntheticKeyup', 0xFFE9); // Left Alt
308+
$rootScope.$broadcast('guacSyntheticKeyup', 0xFFEA); // Right Alt
309+
310+
sendString(content);
311+
312+
releaseStickyKeys();
313+
314+
// Reset the text input box to its normal padded cursor position.
315+
resetTextInputTarget(TEXT_INPUT_PADDING);
316+
317+
}, false);
289318
target.addEventListener("input", function(e) {
290319

291320
// Ignore input events during text composition

0 commit comments

Comments
 (0)