diff --git a/include/input.js b/include/input.js index 03f1d7e..8f0c650 100644 --- a/include/input.js +++ b/include/input.js @@ -645,9 +645,9 @@ function onMouseDisable(e) { evt = (e ? e : window.event); pos = Util.getEventPosition(e, conf.target, conf.scale); /* Stop propagation if inside canvas area */ - if ((pos.x >= 0) && (pos.y >= 0) && - (pos.x < conf.target.offsetWidth) && - (pos.y < conf.target.offsetHeight)) { + if ((pos.realx >= 0) && (pos.realy >= 0) && + (pos.realx < conf.target.offsetWidth) && + (pos.realy < conf.target.offsetHeight)) { //Util.Debug("mouse event disabled"); Util.stopEvent(e); return false; diff --git a/include/rfb.js b/include/rfb.js index 16ae76d..9832877 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -103,7 +103,6 @@ var that = {}, // Public API methods fb_height = 0, fb_name = "", - last_req_time = 0, rre_chunk_sz = 100, timing = { @@ -148,9 +147,6 @@ Util.conf_defaults(conf, that, defaults, [ ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'], - ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], - ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'], - // Callback functions ['onUpdateState', 'rw', 'func', function() { }, 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '], @@ -403,7 +399,7 @@ updateState = function(state, statusMsg) { } if (msgTimer) { - clearInterval(msgTimer); + clearTimeout(msgTimer); msgTimer = null; } @@ -444,13 +440,13 @@ updateState = function(state, statusMsg) { if (connTimer && (rfb_state !== 'connect')) { Util.Debug("Clearing connect timer"); - clearInterval(connTimer); + clearTimeout(connTimer); connTimer = null; } if (disconnTimer && (rfb_state !== 'disconnect')) { Util.Debug("Clearing disconnect timer"); - clearInterval(disconnTimer); + clearTimeout(disconnTimer); disconnTimer = null; } @@ -569,44 +565,18 @@ function genDES(password, challenge) { return (new DES(passwd)).encrypt(challenge); } -function flushClient() { - if (mouse_arr.length > 0) { - //send(mouse_arr.concat(fbUpdateRequests())); - ws.send(mouse_arr); - setTimeout(function() { - ws.send(fbUpdateRequests()); - }, 50); - - mouse_arr = []; - return true; - } else { - return false; - } -} - // overridable for testing checkEvents = function() { - var now; - if (rfb_state === 'normal' && !viewportDragging) { - if (! flushClient()) { - now = new Date().getTime(); - if (now > last_req_time + conf.fbu_req_rate) { - last_req_time = now; - ws.send(fbUpdateRequests()); - } - } + if (rfb_state === 'normal' && !viewportDragging && mouse_arr.length > 0) { + ws.send(mouse_arr); + mouse_arr = []; } - setTimeout(checkEvents, conf.check_rate); }; keyPress = function(keysym, down) { - var arr; - if (conf.view_only) { return; } // View only, skip keyboard events - arr = keyEvent(keysym, down); - arr = arr.concat(fbUpdateRequests()); - ws.send(arr); + ws.send(keyEvent(keysym, down)); }; mouseButton = function(x, y, down, bmask) { @@ -625,7 +595,6 @@ mouseButton = function(x, y, down, bmask) { return; } else { viewportDragging = false; - ws.send(fbUpdateRequests()); // Force immediate redraw } } @@ -633,7 +602,8 @@ mouseButton = function(x, y, down, bmask) { mouse_arr = mouse_arr.concat( pointerEvent(display.absX(x), display.absY(y)) ); - flushClient(); + ws.send(mouse_arr); + mouse_arr = []; }; mouseMove = function(x, y) { @@ -656,7 +626,9 @@ mouseMove = function(x, y) { if (conf.view_only) { return; } // View only, skip mouse events mouse_arr = mouse_arr.concat( - pointerEvent(display.absX(x), display.absY(y)) ); + pointerEvent(display.absX(x), display.absY(y))); + + checkEvents(); }; @@ -900,13 +872,12 @@ init_msg = function() { response = pixelFormat(); response = response.concat(clientEncodings()); - response = response.concat(fbUpdateRequests()); + response = response.concat(fbUpdateRequests()); // initial fbu-request timing.fbu_rt_start = (new Date()).getTime(); timing.pixels = 0; ws.send(response); - /* Start pushing/polling */ - setTimeout(checkEvents, conf.check_rate); + checkEvents(); if (conf.encrypt) { updateState('normal', "Connected (encrypted) to: " + fb_name); @@ -934,6 +905,10 @@ normal_msg = function() { switch (msg_type) { case 0: // FramebufferUpdate ret = framebufferUpdate(); // false means need more data + if (ret) { + // only allow one outstanding fbu-request at a time + ws.send(fbUpdateRequests()); + } break; case 1: // SetColourMapEntries Util.Debug("SetColourMapEntries"); @@ -1596,8 +1571,6 @@ encHandlers.DesktopSize = function set_desktopsize() { conf.onFBResize(that, fb_width, fb_height); display.resize(fb_width, fb_height); timing.fbu_rt_start = (new Date()).getTime(); - // Send a new non-incremental request - ws.send(fbUpdateRequests()); FBU.bytes = 0; FBU.rects -= 1; @@ -1823,7 +1796,6 @@ that.sendCtrlAltDel = function() { arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt arr = arr.concat(keyEvent(0xFFE3, 0)); // Control - arr = arr.concat(fbUpdateRequests()); ws.send(arr); }; @@ -1840,7 +1812,6 @@ that.sendKey = function(code, down) { arr = arr.concat(keyEvent(code, 1)); arr = arr.concat(keyEvent(code, 0)); } - arr = arr.concat(fbUpdateRequests()); ws.send(arr); }; diff --git a/include/ui.js b/include/ui.js index 45a6beb..40972cc 100644 --- a/include/ui.js +++ b/include/ui.js @@ -29,6 +29,7 @@ hideKeyboardTimeout: null, extraKeysVisible: false, ctrlOn: false, altOn: false, +isTouchDevice: false, // Setup rfb object, load settings from browser storage, then call // UI.init to setup the UI/menus @@ -38,7 +39,9 @@ load: function (callback) { // Render default UI and initialize settings menu start: function(callback) { - var html = '', i, sheet, sheets, llevels, port; + var html = '', i, sheet, sheets, llevels, port, autoconnect; + + UI.isTouchDevice = 'ontouchstart' in document.documentElement; // Stylesheet selection dropdown sheet = WebUtil.selectStylesheet(); @@ -80,7 +83,7 @@ start: function(callback) { UI.initSetting('password', ''); UI.initSetting('encrypt', (window.location.protocol === "https:")); UI.initSetting('true_color', true); - UI.initSetting('cursor', false); + UI.initSetting('cursor', !UI.isTouchDevice); UI.initSetting('shared', true); UI.initSetting('view_only', false); UI.initSetting('connectTimeout', 2); @@ -91,6 +94,15 @@ start: function(callback) { 'onUpdateState': UI.updateState, 'onClipboard': UI.clipReceive, 'onDesktopName': UI.updateDocumentTitle}); + + autoconnect = WebUtil.getQueryVar('autoconnect', false); + if (autoconnect === 'true' || autoconnect == '1') { + autoconnect = true; + UI.connect(); + } else { + autoconnect = false; + } + UI.updateVisualState(); // Unfocus clipboard when over the VNC area @@ -102,7 +114,7 @@ start: function(callback) { // }; // Show mouse selector buttons on touch screen devices - if ('ontouchstart' in document.documentElement) { + if (UI.isTouchDevice) { // Show mobile buttons $D('noVNC_mobile_buttons').style.display = "inline"; UI.setMouseButton(); @@ -140,8 +152,10 @@ start: function(callback) { // Open the description dialog $D('noVNC_description').style.display = "block"; } else { - // Open the connect panel on first load - UI.toggleConnectPanel(); + // Show the connect panel on first load unless autoconnecting + if (autoconnect === UI.connSettingsOpen) { + UI.toggleConnectPanel(); + } } // Add mouse event click/focus/blur event handlers to the UI @@ -160,7 +174,8 @@ addMouseHandlers: function() { $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); }; $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); }; $D("showKeyboard").onclick = UI.showKeyboard; - //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); }; + + $D("keyboardinput").oninput = UI.keyInput; $D("keyboardinput").onblur = UI.keyInputBlur; $D("showExtraKeysButton").onclick = UI.showExtraKeys; @@ -367,7 +382,7 @@ toggleSettingsPanel: function() { if (UI.rfb.get_display().get_cursor_uri()) { UI.updateSetting('cursor'); } else { - UI.updateSetting('cursor', false); + UI.updateSetting('cursor', !UI.isTouchDevice); $D('noVNC_cursor').disabled = true; } UI.updateSetting('clip'); @@ -529,7 +544,7 @@ updateVisualState: function() { UI.rfb.get_display().get_cursor_uri()) { $D('noVNC_cursor').disabled = connected; } else { - UI.updateSetting('cursor', false); + UI.updateSetting('cursor', !UI.isTouchDevice); $D('noVNC_cursor').disabled = true; } $D('noVNC_shared').disabled = connected; @@ -715,13 +730,18 @@ setViewDrag: function(drag) { // On touch devices, show the OS keyboard showKeyboard: function() { + var kbi, skb, l; + kbi = $D('keyboardinput'); + skb = $D('showKeyboard'); + l = kbi.value.length; if(UI.keyboardVisible === false) { - $D('keyboardinput').focus(); + kbi.focus(); + kbi.setSelectionRange(l, l); // Move the caret to the end UI.keyboardVisible = true; - $D('showKeyboard').className = "noVNC_status_button_selected"; + skb.className = "noVNC_status_button_selected"; } else if(UI.keyboardVisible === true) { - $D('keyboardinput').blur(); - $D('showKeyboard').className = "noVNC_status_button"; + kbi.blur(); + skb.className = "noVNC_status_button"; UI.keyboardVisible = false; } }, @@ -737,6 +757,35 @@ keepKeyboard: function() { } }, +// When keypress events are left uncought, catch the input events from +// the keyboardinput element instead and send the corresponding key events. +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 + } + } + } + + // 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 = "x"; +}, + keyInputBlur: function() { $D('showKeyboard').className = "noVNC_status_button"; //Weird bug in iOS if you change keyboardVisible diff --git a/include/util.js b/include/util.js index dd1f252..8893591 100644 --- a/include/util.js +++ b/include/util.js @@ -298,9 +298,11 @@ Util.getEventPosition = function (e, obj, scale) { if (typeof scale === "undefined") { scale = 1; } - var x = Math.max(Math.min(docX - pos.x, obj.width-1), 0); - var y = Math.max(Math.min(docY - pos.y, obj.height-1), 0); - return {'x': x / scale, 'y': y / scale}; + var realx = docX - pos.x; + var realy = docY - pos.y; + var x = Math.max(Math.min(realx, obj.width-1), 0); + var y = Math.max(Math.min(realy, obj.height-1), 0); + return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale}; }; diff --git a/vnc.html b/vnc.html index ae95551..8b8847c 100644 --- a/vnc.html +++ b/vnc.html @@ -66,7 +66,7 @@ -
-