Merge branch 'master' of https://github.com/kanaka/noVNC into ctrlalttabesc

Conflicts:
	include/ui.js
	vnc.html
This commit is contained in:
samhed 2013-10-11 17:20:49 +02:00
commit f4f72e9db9
6 changed files with 93 additions and 71 deletions

View File

@ -645,9 +645,9 @@ function onMouseDisable(e) {
evt = (e ? e : window.event); evt = (e ? e : window.event);
pos = Util.getEventPosition(e, conf.target, conf.scale); pos = Util.getEventPosition(e, conf.target, conf.scale);
/* Stop propagation if inside canvas area */ /* Stop propagation if inside canvas area */
if ((pos.x >= 0) && (pos.y >= 0) && if ((pos.realx >= 0) && (pos.realy >= 0) &&
(pos.x < conf.target.offsetWidth) && (pos.realx < conf.target.offsetWidth) &&
(pos.y < conf.target.offsetHeight)) { (pos.realy < conf.target.offsetHeight)) {
//Util.Debug("mouse event disabled"); //Util.Debug("mouse event disabled");
Util.stopEvent(e); Util.stopEvent(e);
return false; return false;

View File

@ -103,7 +103,6 @@ var that = {}, // Public API methods
fb_height = 0, fb_height = 0,
fb_name = "", fb_name = "",
last_req_time = 0,
rre_chunk_sz = 100, rre_chunk_sz = 100,
timing = { timing = {
@ -148,9 +147,6 @@ Util.conf_defaults(conf, that, defaults, [
['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'], ['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 // Callback functions
['onUpdateState', 'rw', 'func', function() { }, ['onUpdateState', 'rw', 'func', function() { },
'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '], 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '],
@ -403,7 +399,7 @@ updateState = function(state, statusMsg) {
} }
if (msgTimer) { if (msgTimer) {
clearInterval(msgTimer); clearTimeout(msgTimer);
msgTimer = null; msgTimer = null;
} }
@ -444,13 +440,13 @@ updateState = function(state, statusMsg) {
if (connTimer && (rfb_state !== 'connect')) { if (connTimer && (rfb_state !== 'connect')) {
Util.Debug("Clearing connect timer"); Util.Debug("Clearing connect timer");
clearInterval(connTimer); clearTimeout(connTimer);
connTimer = null; connTimer = null;
} }
if (disconnTimer && (rfb_state !== 'disconnect')) { if (disconnTimer && (rfb_state !== 'disconnect')) {
Util.Debug("Clearing disconnect timer"); Util.Debug("Clearing disconnect timer");
clearInterval(disconnTimer); clearTimeout(disconnTimer);
disconnTimer = null; disconnTimer = null;
} }
@ -569,44 +565,18 @@ function genDES(password, challenge) {
return (new DES(passwd)).encrypt(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 // overridable for testing
checkEvents = function() { checkEvents = function() {
var now; if (rfb_state === 'normal' && !viewportDragging && mouse_arr.length > 0) {
if (rfb_state === 'normal' && !viewportDragging) { ws.send(mouse_arr);
if (! flushClient()) { mouse_arr = [];
now = new Date().getTime();
if (now > last_req_time + conf.fbu_req_rate) {
last_req_time = now;
ws.send(fbUpdateRequests());
}
}
} }
setTimeout(checkEvents, conf.check_rate);
}; };
keyPress = function(keysym, down) { keyPress = function(keysym, down) {
var arr;
if (conf.view_only) { return; } // View only, skip keyboard events if (conf.view_only) { return; } // View only, skip keyboard events
arr = keyEvent(keysym, down); ws.send(keyEvent(keysym, down));
arr = arr.concat(fbUpdateRequests());
ws.send(arr);
}; };
mouseButton = function(x, y, down, bmask) { mouseButton = function(x, y, down, bmask) {
@ -625,7 +595,6 @@ mouseButton = function(x, y, down, bmask) {
return; return;
} else { } else {
viewportDragging = false; viewportDragging = false;
ws.send(fbUpdateRequests()); // Force immediate redraw
} }
} }
@ -633,7 +602,8 @@ mouseButton = function(x, y, down, bmask) {
mouse_arr = mouse_arr.concat( mouse_arr = mouse_arr.concat(
pointerEvent(display.absX(x), display.absY(y)) ); pointerEvent(display.absX(x), display.absY(y)) );
flushClient(); ws.send(mouse_arr);
mouse_arr = [];
}; };
mouseMove = function(x, y) { mouseMove = function(x, y) {
@ -656,7 +626,9 @@ mouseMove = function(x, y) {
if (conf.view_only) { return; } // View only, skip mouse events if (conf.view_only) { return; } // View only, skip mouse events
mouse_arr = mouse_arr.concat( 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 = pixelFormat();
response = response.concat(clientEncodings()); response = response.concat(clientEncodings());
response = response.concat(fbUpdateRequests()); response = response.concat(fbUpdateRequests()); // initial fbu-request
timing.fbu_rt_start = (new Date()).getTime(); timing.fbu_rt_start = (new Date()).getTime();
timing.pixels = 0; timing.pixels = 0;
ws.send(response); ws.send(response);
/* Start pushing/polling */ checkEvents();
setTimeout(checkEvents, conf.check_rate);
if (conf.encrypt) { if (conf.encrypt) {
updateState('normal', "Connected (encrypted) to: " + fb_name); updateState('normal', "Connected (encrypted) to: " + fb_name);
@ -934,6 +905,10 @@ normal_msg = function() {
switch (msg_type) { switch (msg_type) {
case 0: // FramebufferUpdate case 0: // FramebufferUpdate
ret = framebufferUpdate(); // false means need more data ret = framebufferUpdate(); // false means need more data
if (ret) {
// only allow one outstanding fbu-request at a time
ws.send(fbUpdateRequests());
}
break; break;
case 1: // SetColourMapEntries case 1: // SetColourMapEntries
Util.Debug("SetColourMapEntries"); Util.Debug("SetColourMapEntries");
@ -1596,8 +1571,6 @@ encHandlers.DesktopSize = function set_desktopsize() {
conf.onFBResize(that, fb_width, fb_height); conf.onFBResize(that, fb_width, fb_height);
display.resize(fb_width, fb_height); display.resize(fb_width, fb_height);
timing.fbu_rt_start = (new Date()).getTime(); timing.fbu_rt_start = (new Date()).getTime();
// Send a new non-incremental request
ws.send(fbUpdateRequests());
FBU.bytes = 0; FBU.bytes = 0;
FBU.rects -= 1; FBU.rects -= 1;
@ -1823,7 +1796,6 @@ that.sendCtrlAltDel = function() {
arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete
arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt
arr = arr.concat(keyEvent(0xFFE3, 0)); // Control arr = arr.concat(keyEvent(0xFFE3, 0)); // Control
arr = arr.concat(fbUpdateRequests());
ws.send(arr); ws.send(arr);
}; };
@ -1840,7 +1812,6 @@ that.sendKey = function(code, down) {
arr = arr.concat(keyEvent(code, 1)); arr = arr.concat(keyEvent(code, 1));
arr = arr.concat(keyEvent(code, 0)); arr = arr.concat(keyEvent(code, 0));
} }
arr = arr.concat(fbUpdateRequests());
ws.send(arr); ws.send(arr);
}; };

View File

@ -29,6 +29,7 @@ hideKeyboardTimeout: null,
extraKeysVisible: false, extraKeysVisible: false,
ctrlOn: false, ctrlOn: false,
altOn: false, altOn: false,
isTouchDevice: false,
// Setup rfb object, load settings from browser storage, then call // Setup rfb object, load settings from browser storage, then call
// UI.init to setup the UI/menus // UI.init to setup the UI/menus
@ -38,7 +39,9 @@ load: function (callback) {
// Render default UI and initialize settings menu // Render default UI and initialize settings menu
start: function(callback) { 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 // Stylesheet selection dropdown
sheet = WebUtil.selectStylesheet(); sheet = WebUtil.selectStylesheet();
@ -80,7 +83,7 @@ start: function(callback) {
UI.initSetting('password', ''); UI.initSetting('password', '');
UI.initSetting('encrypt', (window.location.protocol === "https:")); UI.initSetting('encrypt', (window.location.protocol === "https:"));
UI.initSetting('true_color', true); UI.initSetting('true_color', true);
UI.initSetting('cursor', false); UI.initSetting('cursor', !UI.isTouchDevice);
UI.initSetting('shared', true); UI.initSetting('shared', true);
UI.initSetting('view_only', false); UI.initSetting('view_only', false);
UI.initSetting('connectTimeout', 2); UI.initSetting('connectTimeout', 2);
@ -91,6 +94,15 @@ start: function(callback) {
'onUpdateState': UI.updateState, 'onUpdateState': UI.updateState,
'onClipboard': UI.clipReceive, 'onClipboard': UI.clipReceive,
'onDesktopName': UI.updateDocumentTitle}); 'onDesktopName': UI.updateDocumentTitle});
autoconnect = WebUtil.getQueryVar('autoconnect', false);
if (autoconnect === 'true' || autoconnect == '1') {
autoconnect = true;
UI.connect();
} else {
autoconnect = false;
}
UI.updateVisualState(); UI.updateVisualState();
// Unfocus clipboard when over the VNC area // Unfocus clipboard when over the VNC area
@ -102,7 +114,7 @@ start: function(callback) {
// }; // };
// Show mouse selector buttons on touch screen devices // Show mouse selector buttons on touch screen devices
if ('ontouchstart' in document.documentElement) { if (UI.isTouchDevice) {
// Show mobile buttons // Show mobile buttons
$D('noVNC_mobile_buttons').style.display = "inline"; $D('noVNC_mobile_buttons').style.display = "inline";
UI.setMouseButton(); UI.setMouseButton();
@ -140,8 +152,10 @@ start: function(callback) {
// Open the description dialog // Open the description dialog
$D('noVNC_description').style.display = "block"; $D('noVNC_description').style.display = "block";
} else { } else {
// Open the connect panel on first load // Show the connect panel on first load unless autoconnecting
UI.toggleConnectPanel(); if (autoconnect === UI.connSettingsOpen) {
UI.toggleConnectPanel();
}
} }
// Add mouse event click/focus/blur event handlers to the UI // 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_button2").onclick = function () { UI.setMouseButton(4); };
$D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); }; $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); };
$D("showKeyboard").onclick = UI.showKeyboard; $D("showKeyboard").onclick = UI.showKeyboard;
//$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); };
$D("keyboardinput").oninput = UI.keyInput;
$D("keyboardinput").onblur = UI.keyInputBlur; $D("keyboardinput").onblur = UI.keyInputBlur;
$D("showExtraKeysButton").onclick = UI.showExtraKeys; $D("showExtraKeysButton").onclick = UI.showExtraKeys;
@ -367,7 +382,7 @@ toggleSettingsPanel: function() {
if (UI.rfb.get_display().get_cursor_uri()) { if (UI.rfb.get_display().get_cursor_uri()) {
UI.updateSetting('cursor'); UI.updateSetting('cursor');
} else { } else {
UI.updateSetting('cursor', false); UI.updateSetting('cursor', !UI.isTouchDevice);
$D('noVNC_cursor').disabled = true; $D('noVNC_cursor').disabled = true;
} }
UI.updateSetting('clip'); UI.updateSetting('clip');
@ -529,7 +544,7 @@ updateVisualState: function() {
UI.rfb.get_display().get_cursor_uri()) { UI.rfb.get_display().get_cursor_uri()) {
$D('noVNC_cursor').disabled = connected; $D('noVNC_cursor').disabled = connected;
} else { } else {
UI.updateSetting('cursor', false); UI.updateSetting('cursor', !UI.isTouchDevice);
$D('noVNC_cursor').disabled = true; $D('noVNC_cursor').disabled = true;
} }
$D('noVNC_shared').disabled = connected; $D('noVNC_shared').disabled = connected;
@ -715,13 +730,18 @@ setViewDrag: function(drag) {
// On touch devices, show the OS keyboard // On touch devices, show the OS keyboard
showKeyboard: function() { showKeyboard: function() {
var kbi, skb, l;
kbi = $D('keyboardinput');
skb = $D('showKeyboard');
l = kbi.value.length;
if(UI.keyboardVisible === false) { if(UI.keyboardVisible === false) {
$D('keyboardinput').focus(); kbi.focus();
kbi.setSelectionRange(l, l); // Move the caret to the end
UI.keyboardVisible = true; UI.keyboardVisible = true;
$D('showKeyboard').className = "noVNC_status_button_selected"; skb.className = "noVNC_status_button_selected";
} else if(UI.keyboardVisible === true) { } else if(UI.keyboardVisible === true) {
$D('keyboardinput').blur(); kbi.blur();
$D('showKeyboard').className = "noVNC_status_button"; skb.className = "noVNC_status_button";
UI.keyboardVisible = false; 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() { keyInputBlur: function() {
$D('showKeyboard').className = "noVNC_status_button"; $D('showKeyboard').className = "noVNC_status_button";
//Weird bug in iOS if you change keyboardVisible //Weird bug in iOS if you change keyboardVisible

View File

@ -298,9 +298,11 @@ Util.getEventPosition = function (e, obj, scale) {
if (typeof scale === "undefined") { if (typeof scale === "undefined") {
scale = 1; scale = 1;
} }
var x = Math.max(Math.min(docX - pos.x, obj.width-1), 0); var realx = docX - pos.x;
var y = Math.max(Math.min(docY - pos.y, obj.height-1), 0); var realy = docY - pos.y;
return {'x': x / scale, 'y': y / scale}; 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};
}; };

View File

@ -66,7 +66,7 @@
<input type="image" src="images/keyboard.png" <input type="image" src="images/keyboard.png"
id="showKeyboard" class="noVNC_status_button" id="showKeyboard" class="noVNC_status_button"
value="Keyboard" title="Show Keyboard"/> value="Keyboard" title="Show Keyboard"/>
<input type="email" autocapitalize="off" autocorrect="off" <input type="text" autocapitalize="off" autocorrect="off"
id="keyboardinput" class=""/> id="keyboardinput" class=""/>
<div id="noVNC_extra_keys"> <div id="noVNC_extra_keys">
<input type="image" src="images/showextrakeys.png" <input type="image" src="images/showextrakeys.png"

View File

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<!-- <!--
noVNC example: simple example using default UI noVNC example: simple example using default UI
Copyright (C) 2012 Joel Martin Copyright (C) 2012 Joel Martin
Copyright (C) 2013 Samuel Mannehed for Cendio AB Copyright (C) 2013 Samuel Mannehed for Cendio AB
@ -128,12 +128,12 @@
// if port == 80 (or 443) then it won't be present and should be // if port == 80 (or 443) then it won't be present and should be
// set manually // set manually
if (!port) { if (!port) {
if (window.location.protocol.substring(0,4) == 'http') { if (window.location.protocol.substring(0,5) == 'https') {
port = 80;
}
else if (window.location.protocol.substring(0,5) == 'https') {
port = 443; port = 443;
} }
else if (window.location.protocol.substring(0,4) == 'http') {
port = 80;
}
} }
// If a token variable is passed in, set the parameter in a cookie. // If a token variable is passed in, set the parameter in a cookie.