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:
Michael Jumper
2014-04-22 18:50:04 -07:00
parent f091971928
commit 8f7f240232
2 changed files with 190 additions and 5 deletions

View File

@@ -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) {

View File

@@ -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 {