mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 00:23:21 +00:00 
			
		
		
		
	GUAC-326: Add support for text input. Fix bug in handling of Ctrl-Alt-Shift (keys need to be released).
This commit is contained in:
		| @@ -199,18 +199,24 @@ GuacUI.Client = { | |||||||
|     "KEYBOARD_AUTO_RESIZE_INTERVAL" : 30,  /* milliseconds */ |     "KEYBOARD_AUTO_RESIZE_INTERVAL" : 30,  /* milliseconds */ | ||||||
|     "RECONNECT_PERIOD"              : 15,  /* seconds */ |     "RECONNECT_PERIOD"              : 15,  /* seconds */ | ||||||
|  |  | ||||||
|     /* UI Components */ |     /* Main application area */ | ||||||
|  |  | ||||||
|     "viewport"          : document.getElementById("viewportClone"), |     "viewport"          : document.getElementById("viewportClone"), | ||||||
|     "main"              : document.getElementById("main"), |     "main"              : document.getElementById("main"), | ||||||
|  |     "display"           : document.getElementById("display"), | ||||||
|  |     "notification_area" : document.getElementById("notificationArea"), | ||||||
|  |     "target"            : document.getElementById("target"), | ||||||
|  |  | ||||||
|  |     /* Menu */ | ||||||
|  |  | ||||||
|     "menu"              : document.getElementById("menu"), |     "menu"              : document.getElementById("menu"), | ||||||
|     "menu_title"        : document.getElementById("menu-title"), |     "menu_title"        : document.getElementById("menu-title"), | ||||||
|     "display"           : document.getElementById("display"), |  | ||||||
|     "target"            : document.getElementById("target"), |  | ||||||
|     "clipboard"         : document.getElementById("clipboard"), |     "clipboard"         : document.getElementById("clipboard"), | ||||||
|     "relative_radio"    : document.getElementById("relative"), |     "relative_radio"    : document.getElementById("relative"), | ||||||
|     "absolute_radio"    : document.getElementById("absolute"), |     "absolute_radio"    : document.getElementById("absolute"), | ||||||
|     "notification_area" : document.getElementById("notificationArea"), |     "ime_none_radio"    : document.getElementById("ime-none"), | ||||||
|  |     "ime_text_radio"    : document.getElementById("ime-text"), | ||||||
|  |     "ime_osk_radio"     : document.getElementById("ime-osk"), | ||||||
|  |  | ||||||
|     /* Expected Input Rectangle */ |     /* Expected Input Rectangle */ | ||||||
|  |  | ||||||
| @@ -233,6 +239,11 @@ GuacUI.Client = { | |||||||
|     "touch_screen"     : null, |     "touch_screen"     : null, | ||||||
|     "touch_pad"        : null, |     "touch_pad"        : null, | ||||||
|  |  | ||||||
|  |     /* Text input */ | ||||||
|  |  | ||||||
|  |     "ime_expected"    : false, | ||||||
|  |     "ime_enabled"     : false, | ||||||
|  |  | ||||||
|     /* Clipboard */ |     /* Clipboard */ | ||||||
|  |  | ||||||
|     "clipboard_integration_enabled" : undefined |     "clipboard_integration_enabled" : undefined | ||||||
| @@ -1308,6 +1319,19 @@ GuacUI.Client.attach = function(guac) { | |||||||
|         if (GuacUI.Client.isMenuShown()) |         if (GuacUI.Client.isMenuShown()) | ||||||
|             return true; |             return true; | ||||||
|  |  | ||||||
|  |         // Allow key events for specific keys if IME enabled | ||||||
|  |         if (GuacUI.Client.ime_enabled | ||||||
|  |             && keysym !== 0x0020  /* Space */ | ||||||
|  |             && keysym !== 0xFF08  /* Backspace */ | ||||||
|  |             && keysym !== 0xFF09  /* Tab */ | ||||||
|  |             && keysym !== 0xFF0D  /* Enter */ | ||||||
|  |             && keysym !== 0xFF51  /* Left */ | ||||||
|  |             && keysym !== 0xFF52  /* Up */ | ||||||
|  |             && keysym !== 0xFF53  /* Right */ | ||||||
|  |             && keysym !== 0xFF54  /* Down */ | ||||||
|  |             && keysym !== 0xFFFF) /* Delete */ | ||||||
|  |             return true; | ||||||
|  |  | ||||||
|         GuacUI.Client.attachedClient.sendKeyEvent(pressed, keysym); |         GuacUI.Client.attachedClient.sendKeyEvent(pressed, keysym); | ||||||
|         return false; |         return false; | ||||||
|  |  | ||||||
| @@ -1356,8 +1380,12 @@ GuacUI.Client.attach = function(guac) { | |||||||
|         // If lifting up on shift, toggle menu visibility if rest of gesture |         // If lifting up on shift, toggle menu visibility if rest of gesture | ||||||
|         // conditions satisfied |         // conditions satisfied | ||||||
|         if (show_keyboard_gesture_possible && keysym === 0xFFE1  |         if (show_keyboard_gesture_possible && keysym === 0xFFE1  | ||||||
|             && keyboard.pressed[0xFFE3] && keyboard.pressed[0xFFE9]) |             && keyboard.pressed[0xFFE3] && keyboard.pressed[0xFFE9]) { | ||||||
|  |                 __send_key(0, 0xFFE1); | ||||||
|  |                 __send_key(0, 0xFFE9); | ||||||
|  |                 __send_key(0, 0xFFE3); | ||||||
|                 GuacUI.Client.showMenu(!GuacUI.Client.isMenuShown()); |                 GuacUI.Client.showMenu(!GuacUI.Client.isMenuShown()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // Detect if no keys are pressed |         // Detect if no keys are pressed | ||||||
|         var reset_gesture = true; |         var reset_gesture = true; | ||||||
| @@ -1738,6 +1766,162 @@ GuacUI.Client.attach = function(guac) { | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Update input method mode when changed | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     GuacUI.Client.ime_none_radio.onclick = | ||||||
|  |     GuacUI.Client.ime_none_radio.onchange = function() { | ||||||
|  |         GuacUI.Client.ime_expected = false; | ||||||
|  |         GuacUI.Client.target.blur(); | ||||||
|  |         GuacUI.Client.OnScreenKeyboard.hide(); | ||||||
|  |         GuacUI.Client.showMenu(false); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     GuacUI.Client.ime_text_radio.onclick = | ||||||
|  |     GuacUI.Client.ime_text_radio.onchange = function() { | ||||||
|  |         GuacUI.Client.ime_expected = true; | ||||||
|  |         GuacUI.Client.target.focus(); | ||||||
|  |         GuacUI.Client.OnScreenKeyboard.hide(); | ||||||
|  |         GuacUI.Client.showMenu(false); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     GuacUI.Client.ime_osk_radio.onclick = | ||||||
|  |     GuacUI.Client.ime_osk_radio.onchange = function() { | ||||||
|  |         GuacUI.Client.ime_expected = false; | ||||||
|  |         GuacUI.Client.target.blur(); | ||||||
|  |         GuacUI.Client.OnScreenKeyboard.show(); | ||||||
|  |         GuacUI.Client.showMenu(false); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Text input | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     function keysym_from_codepoint(codepoint) { | ||||||
|  |  | ||||||
|  |         // Keysyms for control characters | ||||||
|  |         if (codepoint <= 0x1F || (codepoint >= 0x7F && codepoint <= 0x9F)) | ||||||
|  |             return 0xFF00 | codepoint; | ||||||
|  |  | ||||||
|  |         // Keysyms for ASCII chars | ||||||
|  |         if (codepoint >= 0x0000 && codepoint <= 0x00FF) | ||||||
|  |             return codepoint; | ||||||
|  |  | ||||||
|  |         // Keysyms for Unicode | ||||||
|  |         if (codepoint >= 0x0100 && codepoint <= 0x10FFFF) | ||||||
|  |             return 0x01000000 | codepoint; | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function send_keysym(keysym) { | ||||||
|  |  | ||||||
|  |         var guac = GuacUI.Client.attachedClient; | ||||||
|  |         if (!guac) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         guac.sendKeyEvent(1, keysym); | ||||||
|  |         guac.sendKeyEvent(0, keysym); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function send_codepoint(codepoint) { | ||||||
|  |  | ||||||
|  |         if (codepoint === 10) { | ||||||
|  |             send_keysym(0xFF0D); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         var keysym = keysym_from_codepoint(codepoint); | ||||||
|  |         if (keysym) | ||||||
|  |             send_keysym(keysym); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var ime_notify_timeout = null; | ||||||
|  |  | ||||||
|  |     GuacUI.Client.target.onfocus = function() { | ||||||
|  |  | ||||||
|  |         // Acknowledge and synchronize state change | ||||||
|  |         GuacUI.Client.OnScreenKeyboard.hide(); | ||||||
|  |         GuacUI.Client.ime_text_radio.checked = true; | ||||||
|  |         GuacUI.Client.ime_enabled = true; | ||||||
|  |  | ||||||
|  |         // If unexpected, try to reset state back | ||||||
|  |         if (!GuacUI.Client.ime_expected) | ||||||
|  |             GuacUI.Client.target.blur(); | ||||||
|  |  | ||||||
|  |         // Reset content | ||||||
|  |         GuacUI.Client.target.value = new Array(257).join("\u200B"); | ||||||
|  |         GuacUI.Client.target.setSelectionRange(128, 128); | ||||||
|  |  | ||||||
|  |         // Notify of change if settled within 50ms | ||||||
|  |         window.clearTimeout(ime_notify_timeout); | ||||||
|  |         ime_notify_timeout = window.setTimeout(function() { | ||||||
|  |             GuacUI.Client.showNotification("Text input mode ON"); | ||||||
|  |         }, 100); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     GuacUI.Client.target.onblur = function() { | ||||||
|  |  | ||||||
|  |         // Acknowledge and synchronize state change | ||||||
|  |         GuacUI.Client.OnScreenKeyboard.hide(); | ||||||
|  |         GuacUI.Client.ime_none_radio.checked = true; | ||||||
|  |         GuacUI.Client.ime_enabled = false; | ||||||
|  |  | ||||||
|  |         // If unexpected, try to reset state back | ||||||
|  |         if (GuacUI.Client.ime_expected) | ||||||
|  |             GuacUI.Client.target.focus(); | ||||||
|  |  | ||||||
|  |         // Notify of change if settled within 50ms | ||||||
|  |         window.clearTimeout(ime_notify_timeout); | ||||||
|  |         ime_notify_timeout = window.setTimeout(function() { | ||||||
|  |             GuacUI.Client.showNotification("Text input mode OFF"); | ||||||
|  |         }, 100); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     GuacUI.Client.target.addEventListener("input", function(e) { | ||||||
|  |  | ||||||
|  |         var i; | ||||||
|  |         var content = GuacUI.Client.target.value; | ||||||
|  |  | ||||||
|  |         // If content removed, update | ||||||
|  |         if (content.length < 256) { | ||||||
|  |  | ||||||
|  |             // Calculate number of backspaces and send | ||||||
|  |             var backspace_count = 128 - GuacUI.Client.target.selectionStart; | ||||||
|  |             for (i=0; i<backspace_count; i++) | ||||||
|  |                 send_keysym(0xFF08); | ||||||
|  |  | ||||||
|  |             // Calculate number of deletes and send | ||||||
|  |             var delete_count = 256 - content.length - backspace_count; | ||||||
|  |             for (i=0; i<delete_count; i++) | ||||||
|  |                 send_keysym(0xFFFF); | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         else { | ||||||
|  |  | ||||||
|  |             // Send keys for added content | ||||||
|  |             for (i=0; i<content.length; i++) { | ||||||
|  |                 var codepoint = content.charCodeAt(i); | ||||||
|  |                 if (codepoint !== 0x200B) | ||||||
|  |                     send_codepoint(codepoint); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Reset content | ||||||
|  |         GuacUI.Client.target.value = new Array(257).join("\u200B"); | ||||||
|  |         GuacUI.Client.target.setSelectionRange(128, 128); | ||||||
|  |  | ||||||
|  |     }, false); | ||||||
|  |  | ||||||
|  |  | ||||||
|     // Prevent default on all touch events |     // Prevent default on all touch events | ||||||
|     document.addEventListener("touchstart", function(e) { |     document.addEventListener("touchstart", function(e) { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -543,6 +543,7 @@ p.hint { | |||||||
|     width: 480px; |     width: 480px; | ||||||
|     background: #EEE; |     background: #EEE; | ||||||
|     box-shadow: inset -1px 0 2px white, 1px 0 2px black; |     box-shadow: inset -1px 0 2px white, 1px 0 2px black; | ||||||
|  |     z-index: 10; | ||||||
| } | } | ||||||
|  |  | ||||||
| #menu .content { | #menu .content { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user