浏览代码

Fixes issue 344 - problem with backspace on Android.

samhed 11 年之前
父节点
当前提交
0bb6a8c50e
共有 1 个文件被更改,包括 66 次插入24 次删除
  1. 66 24
      include/ui.js

+ 66 - 24
include/ui.js

@@ -13,6 +13,7 @@
 
 
 // Load supporting scripts
 // Load supporting scripts
 window.onscriptsload = function () { UI.load(); };
 window.onscriptsload = function () { UI.load(); };
+window.onload = function () { UI.keyboardinputReset(); };
 Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
 Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
                    "keysymdef.js", "keyboard.js", "input.js", "display.js",
                    "keysymdef.js", "keyboard.js", "input.js", "display.js",
                    "jsunzip.js", "rfb.js", "keysym.js"]);
                    "jsunzip.js", "rfb.js", "keysym.js"]);
@@ -26,6 +27,8 @@ popupStatusOpen : false,
 clipboardOpen: false,
 clipboardOpen: false,
 keyboardVisible: false,
 keyboardVisible: false,
 hideKeyboardTimeout: null,
 hideKeyboardTimeout: null,
+lastKeyboardinput: null,
+defaultKeyboardinputLen: 100,
 extraKeysVisible: false,
 extraKeysVisible: false,
 ctrlOn: false,
 ctrlOn: false,
 altOn: false,
 altOn: false,
@@ -807,7 +810,8 @@ showKeyboard: function() {
     l = kbi.value.length;
     l = kbi.value.length;
     if(UI.keyboardVisible === false) {
     if(UI.keyboardVisible === false) {
         kbi.focus();
         kbi.focus();
-        kbi.setSelectionRange(l, l); // Move the caret to the end
+        try { kbi.setSelectionRange(l, l); } // Move the caret to the end
+        catch (err) {} // setSelectionRange is undefined in Google Chrome
         UI.keyboardVisible = true;
         UI.keyboardVisible = true;
         skb.className = "noVNC_status_button_selected";
         skb.className = "noVNC_status_button_selected";
     } else if(UI.keyboardVisible === true) {
     } else if(UI.keyboardVisible === true) {
@@ -828,33 +832,71 @@ keepKeyboard: function() {
     }
     }
 },
 },
 
 
-// When keypress events are left uncought, catch the input events from
-// the keyboardinput element instead and send the corresponding key events.
+keyboardinputReset: function() {
+    var kbi = $D('keyboardinput');
+    kbi.value = Array(UI.defaultKeyboardinputLen).join("_");
+    UI.lastKeyboardinput = kbi.value;
+},
+
+// When normal keyboard events are left uncought, use the input events from
+// the keyboardinput element instead and generate the corresponding key events.
+// This code is required since some browsers on Android are inconsistent in
+// sending keyCodes in the normal keyboard events when using on screen keyboards.
 keyInput: function(event) {
 keyInput: function(event) {
-    var elem, input, len;
-    elem = $D('keyboardinput');
-    input = event.target.value;
-    len = (elem.selectionStart > input.length) ? elem.selectionStart : input.length;
-
-    if (len < 1) { // something removed?
-        UI.rfb.sendKey(0xff08); // send BACKSPACE
-    } else if (len > 1) { // new input?
-        for (var i = len-1; i > 0; i -= 1) {
-            // HTML does not consider trailing whitespaces as a part of the string
-            // and they are therefore undefined.
-            if (input[len-i] !== undefined) {
-                UI.rfb.sendKey(input.charCodeAt(len-i)); // send charCode
-            } else {
-                UI.rfb.sendKey(0x0020); // send SPACE
-            }
+    var newValue, oldValue, newLen, oldLen;
+    newValue = event.target.value;
+    oldValue = UI.lastKeyboardinput;
+
+    try {
+        // Try to check caret position since whitespace at the end
+        // will not be considered by value.length in some browsers
+        newLen = Math.max(event.target.selectionStart, newValue.length);
+    } catch (err) {
+        // selectionStart is undefined in Google Chrome
+        newLen = newValue.length;
+    }
+    oldLen = oldValue.length;
+
+    var backspaces;
+    var inputs = newLen - oldLen;
+    if (inputs < 0)
+        backspaces = -inputs;
+    else
+        backspaces = 0;
+
+    // Compare the old string with the new to account for
+    // text-corrections or other input that modify existing text
+    for (var i = 0; i < Math.min(oldLen, newLen); i++) {
+        if (newValue.charAt(i) != oldValue.charAt(i)) {
+            inputs = newLen - i;
+            backspaces = oldLen - i;
+            break;
         }
         }
     }
     }
 
 
-    // In order to be able to delete text which has been written in
-    // another session there has to always be text in the
-    // keyboardinput element with which backspace can interact.
-    // We also need to reset the input field text to avoid overflow.
-    elem.value = '\u00a0';
+    // Send the key events
+    for (var i = 0; i < backspaces; i++)
+        UI.rfb.sendKey(XK_BackSpace);
+    for (var i = newLen - inputs; i < newLen; i++)
+        UI.rfb.sendKey(newValue.charCodeAt(i));
+
+    // Control the text content length in the keyboardinput element
+    if (newLen > 2 * UI.defaultKeyboardinputLen) {
+        UI.keyboardinputReset();
+    } else if (newLen < 1) {
+        // There always have to be some text in the keyboardinput
+        // element with which backspace can interact.
+        UI.keyboardinputReset();
+        // This sometimes causes the keyboard to disappear for a second
+        // but it is required for the android keyboard to recognize that
+        // text has been added to the field
+        event.target.blur();
+        // This has to be ran outside of the input handler in order to work
+        setTimeout(function() { UI.keepKeyboard(); }, 0);
+
+    } else {
+        UI.lastKeyboardinput = newValue;
+    }
 },
 },
 
 
 keyInputBlur: function() {
 keyInputBlur: function() {