]>
git.proxmox.com Git - mirror_novnc.git/blob - include/ui.js
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2012 Joel Martin
4 * Copyright (C) 2013 Samuel Mannehed for Cendio AB
5 * Licensed under MPL 2.0 (see LICENSE.txt)
7 * See README.md for usage and integration instructions.
11 /*jslint white: false, browser: true */
12 /*global window, $D, Util, WebUtil, RFB, Display */
14 // Load supporting scripts
15 window
.onscriptsload = function () { UI
.load(); };
16 Util
.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
17 "input.js", "display.js", "jsunzip.js", "rfb.js",
24 connSettingsOpen
: false,
25 popupStatusOpen
: false,
27 keyboardVisible
: false,
28 hideKeyboardTimeout
: null,
29 extraKeysVisible
: false,
34 // Setup rfb object, load settings from browser storage, then call
35 // UI.init to setup the UI/menus
36 load: function (callback
) {
37 WebUtil
.initSettings(UI
.start
, callback
);
40 // Render default UI and initialize settings menu
41 start: function(callback
) {
42 var html
= '', i
, sheet
, sheets
, llevels
, port
, autoconnect
;
44 UI
.isTouchDevice
= 'ontouchstart' in document
.documentElement
;
46 // Stylesheet selection dropdown
47 sheet
= WebUtil
.selectStylesheet();
48 sheets
= WebUtil
.getStylesheets();
49 for (i
= 0; i
< sheets
.length
; i
+= 1) {
50 UI
.addOption($D('noVNC_stylesheet'),sheets
[i
].title
, sheets
[i
].title
);
53 // Logging selection dropdown
54 llevels
= ['error', 'warn', 'info', 'debug'];
55 for (i
= 0; i
< llevels
.length
; i
+= 1) {
56 UI
.addOption($D('noVNC_logging'),llevels
[i
], llevels
[i
]);
59 // Settings with immediate effects
60 UI
.initSetting('logging', 'warn');
61 WebUtil
.init_logging(UI
.getSetting('logging'));
63 UI
.initSetting('stylesheet', 'default');
64 WebUtil
.selectStylesheet(null);
65 // call twice to get around webkit bug
66 WebUtil
.selectStylesheet(UI
.getSetting('stylesheet'));
68 // if port == 80 (or 443) then it won't be present and should be
70 port
= window
.location
.port
;
72 if (window
.location
.protocol
.substring(0,5) == 'https') {
75 else if (window
.location
.protocol
.substring(0,4) == 'http') {
80 /* Populate the controls if defaults are provided in the URL */
81 UI
.initSetting('host', window
.location
.hostname
);
82 UI
.initSetting('port', port
);
83 UI
.initSetting('password', '');
84 UI
.initSetting('encrypt', (window
.location
.protocol
=== "https:"));
85 UI
.initSetting('true_color', true);
86 UI
.initSetting('cursor', !UI
.isTouchDevice
);
87 UI
.initSetting('shared', true);
88 UI
.initSetting('view_only', false);
89 UI
.initSetting('connectTimeout', 2);
90 UI
.initSetting('path', 'websockify');
91 UI
.initSetting('repeaterID', '');
93 UI
.rfb
= RFB({'target': $D('noVNC_canvas'),
94 'onUpdateState': UI
.updateState
,
95 'onClipboard': UI
.clipReceive
,
96 'onDesktopName': UI
.updateDocumentTitle
});
98 autoconnect
= WebUtil
.getQueryVar('autoconnect', false);
99 if (autoconnect
=== 'true' || autoconnect
== '1') {
106 UI
.updateVisualState();
108 // Unfocus clipboard when over the VNC area
109 //$D('VNC_screen').onmousemove = function () {
110 // var keyboard = UI.rfb.get_keyboard();
111 // if ((! keyboard) || (! keyboard.get_focused())) {
112 // $D('VNC_clipboard_text').blur();
116 // Show mouse selector buttons on touch screen devices
117 if (UI
.isTouchDevice
) {
118 // Show mobile buttons
119 $D('noVNC_mobile_buttons').style
.display
= "inline";
121 // Remove the address bar
122 setTimeout(function() { window
.scrollTo(0, 1); }, 100);
123 UI
.forceSetting('clip', true);
124 $D('noVNC_clip').disabled
= true;
126 UI
.initSetting('clip', false);
129 //iOS Safari does not support CSS position:fixed.
130 //This detects iOS devices and enables javascript workaround.
131 if ((navigator
.userAgent
.match(/iPhone/i)) ||
132 (navigator
.userAgent
.match(/iPod/i)) ||
133 (navigator
.userAgent
.match(/iPad/i))) {
139 $D('noVNC_host').focus();
142 Util
.addEvent(window
, 'resize', UI
.setViewClip
);
144 Util
.addEvent(window
, 'beforeunload', function () {
145 if (UI
.rfb_state
=== 'normal') {
146 return "You are currently connected.";
150 // Show description by default when hosted at for kanaka.github.com
151 if (location
.host
=== "kanaka.github.com") {
152 // Open the description dialog
153 $D('noVNC_description').style
.display
= "block";
155 // Show the connect panel on first load unless autoconnecting
156 if (autoconnect
=== UI
.connSettingsOpen
) {
157 UI
.toggleConnectPanel();
161 // Add mouse event click/focus/blur event handlers to the UI
162 UI
.addMouseHandlers();
164 if (typeof callback
=== "function") {
169 addMouseHandlers: function() {
170 // Setup interface handlers that can't be inline
171 $D("noVNC_view_drag_button").onclick
= UI
.setViewDrag
;
172 $D("noVNC_mouse_button0").onclick = function () { UI
.setMouseButton(1); };
173 $D("noVNC_mouse_button1").onclick = function () { UI
.setMouseButton(2); };
174 $D("noVNC_mouse_button2").onclick = function () { UI
.setMouseButton(4); };
175 $D("noVNC_mouse_button4").onclick = function () { UI
.setMouseButton(0); };
176 $D("showKeyboard").onclick
= UI
.showKeyboard
;
178 $D("keyboardinput").oninput
= UI
.keyInput
;
179 $D("keyboardinput").onblur
= UI
.keyInputBlur
;
181 $D("showExtraKeysButton").onclick
= UI
.showExtraKeys
;
182 $D("toggleCtrlButton").onclick
= UI
.toggleCtrl
;
183 $D("toggleAltButton").onclick
= UI
.toggleAlt
;
184 $D("sendTabButton").onclick
= UI
.sendTab
;
185 $D("sendEscButton").onclick
= UI
.sendEsc
;
187 $D("sendCtrlAltDelButton").onclick
= UI
.sendCtrlAltDel
;
188 $D("noVNC_status").onclick
= UI
.togglePopupStatusPanel
;
189 $D("noVNC_popup_status_panel").onclick
= UI
.togglePopupStatusPanel
;
190 $D("clipboardButton").onclick
= UI
.toggleClipboardPanel
;
191 $D("settingsButton").onclick
= UI
.toggleSettingsPanel
;
192 $D("connectButton").onclick
= UI
.toggleConnectPanel
;
193 $D("disconnectButton").onclick
= UI
.disconnect
;
194 $D("descriptionButton").onclick
= UI
.toggleConnectPanel
;
196 $D("noVNC_clipboard_text").onfocus
= UI
.displayBlur
;
197 $D("noVNC_clipboard_text").onblur
= UI
.displayFocus
;
198 $D("noVNC_clipboard_text").onchange
= UI
.clipSend
;
199 $D("noVNC_clipboard_clear_button").onclick
= UI
.clipClear
;
201 $D("noVNC_settings_menu").onmouseover
= UI
.displayBlur
;
202 $D("noVNC_settings_menu").onmouseover
= UI
.displayFocus
;
203 $D("noVNC_apply").onclick
= UI
.settingsApply
;
205 $D("noVNC_connect_button").onclick
= UI
.connect
;
208 // Read form control compatible setting from cookie
209 getSetting: function(name
) {
210 var val
, ctrl
= $D('noVNC_' + name
);
211 val
= WebUtil
.readSetting(name
);
212 if (val
!== null && ctrl
.type
=== 'checkbox') {
213 if (val
.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
222 // Update cookie and form control setting. If value is not set, then
223 // updates from control to current cookie setting.
224 updateSetting: function(name
, value
) {
226 var i
, ctrl
= $D('noVNC_' + name
);
227 // Save the cookie for this session
228 if (typeof value
!== 'undefined') {
229 WebUtil
.writeSetting(name
, value
);
232 // Update the settings control
233 value
= UI
.getSetting(name
);
235 if (ctrl
.type
=== 'checkbox') {
236 ctrl
.checked
= value
;
238 } else if (typeof ctrl
.options
!== 'undefined') {
239 for (i
= 0; i
< ctrl
.options
.length
; i
+= 1) {
240 if (ctrl
.options
[i
].value
=== value
) {
241 ctrl
.selectedIndex
= i
;
246 /*Weird IE9 error leads to 'null' appearring
247 in textboxes instead of ''.*/
248 if (value
=== null) {
255 // Save control setting to cookie
256 saveSetting: function(name
) {
257 var val
, ctrl
= $D('noVNC_' + name
);
258 if (ctrl
.type
=== 'checkbox') {
260 } else if (typeof ctrl
.options
!== 'undefined') {
261 val
= ctrl
.options
[ctrl
.selectedIndex
].value
;
265 WebUtil
.writeSetting(name
, val
);
266 //Util.Debug("Setting saved '" + name + "=" + val + "'");
270 // Initial page load read/initialization of settings
271 initSetting: function(name
, defVal
) {
274 // Check Query string followed by cookie
275 val
= WebUtil
.getQueryVar(name
);
277 val
= WebUtil
.readSetting(name
, defVal
);
279 UI
.updateSetting(name
, val
);
280 //Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
284 // Force a setting to be a certain value
285 forceSetting: function(name
, val
) {
286 UI
.updateSetting(name
, val
);
291 // Show the popup status panel
292 togglePopupStatusPanel: function() {
293 var psp
= $D('noVNC_popup_status_panel');
294 if (UI
.popupStatusOpen
=== true) {
295 psp
.style
.display
= "none";
296 UI
.popupStatusOpen
= false;
298 psp
.innerHTML
= $D('noVNC_status').innerHTML
;
299 psp
.style
.display
= "block";
300 psp
.style
.left
= window
.innerWidth
/2 -
301 parseInt(window
.getComputedStyle(psp
, false).width
)/2 -30 + "px";
302 UI
.popupStatusOpen
= true;
306 // Show the clipboard panel
307 toggleClipboardPanel: function() {
308 // Close the description panel
309 $D('noVNC_description').style
.display
= "none";
310 // Close settings if open
311 if (UI
.settingsOpen
=== true) {
313 UI
.closeSettingsMenu();
315 // Close connection settings if open
316 if (UI
.connSettingsOpen
=== true) {
317 UI
.toggleConnectPanel();
319 // Close popup status panel if open
320 if (UI
.popupStatusOpen
=== true) {
321 UI
.togglePopupStatusPanel();
323 // Toggle Clipboard Panel
324 if (UI
.clipboardOpen
=== true) {
325 $D('noVNC_clipboard').style
.display
= "none";
326 $D('clipboardButton').className
= "noVNC_status_button";
327 UI
.clipboardOpen
= false;
329 $D('noVNC_clipboard').style
.display
= "block";
330 $D('clipboardButton').className
= "noVNC_status_button_selected";
331 UI
.clipboardOpen
= true;
335 // Show the connection settings panel/menu
336 toggleConnectPanel: function() {
337 // Close the description panel
338 $D('noVNC_description').style
.display
= "none";
339 // Close connection settings if open
340 if (UI
.settingsOpen
=== true) {
342 UI
.closeSettingsMenu();
343 $D('connectButton').className
= "noVNC_status_button";
345 // Close clipboard panel if open
346 if (UI
.clipboardOpen
=== true) {
347 UI
.toggleClipboardPanel();
349 // Close popup status panel if open
350 if (UI
.popupStatusOpen
=== true) {
351 UI
.togglePopupStatusPanel();
354 // Toggle Connection Panel
355 if (UI
.connSettingsOpen
=== true) {
356 $D('noVNC_controls').style
.display
= "none";
357 $D('connectButton').className
= "noVNC_status_button";
358 UI
.connSettingsOpen
= false;
359 UI
.saveSetting('host');
360 UI
.saveSetting('port');
361 //UI.saveSetting('password');
363 $D('noVNC_controls').style
.display
= "block";
364 $D('connectButton').className
= "noVNC_status_button_selected";
365 UI
.connSettingsOpen
= true;
366 $D('noVNC_host').focus();
370 // Toggle the settings menu:
371 // On open, settings are refreshed from saved cookies.
372 // On close, settings are applied
373 toggleSettingsPanel: function() {
374 // Close the description panel
375 $D('noVNC_description').style
.display
= "none";
376 if (UI
.settingsOpen
) {
378 UI
.closeSettingsMenu();
380 UI
.updateSetting('encrypt');
381 UI
.updateSetting('true_color');
382 if (UI
.rfb
.get_display().get_cursor_uri()) {
383 UI
.updateSetting('cursor');
385 UI
.updateSetting('cursor', !UI
.isTouchDevice
);
386 $D('noVNC_cursor').disabled
= true;
388 UI
.updateSetting('clip');
389 UI
.updateSetting('shared');
390 UI
.updateSetting('view_only');
391 UI
.updateSetting('connectTimeout');
392 UI
.updateSetting('path');
393 UI
.updateSetting('repeaterID');
394 UI
.updateSetting('stylesheet');
395 UI
.updateSetting('logging');
397 UI
.openSettingsMenu();
402 openSettingsMenu: function() {
403 // Close the description panel
404 $D('noVNC_description').style
.display
= "none";
405 // Close clipboard panel if open
406 if (UI
.clipboardOpen
=== true) {
407 UI
.toggleClipboardPanel();
409 // Close connection settings if open
410 if (UI
.connSettingsOpen
=== true) {
411 UI
.toggleConnectPanel();
413 // Close popup status panel if open
414 if (UI
.popupStatusOpen
=== true) {
415 UI
.togglePopupStatusPanel();
417 $D('noVNC_settings').style
.display
= "block";
418 $D('settingsButton').className
= "noVNC_status_button_selected";
419 UI
.settingsOpen
= true;
422 // Close menu (without applying settings)
423 closeSettingsMenu: function() {
424 $D('noVNC_settings').style
.display
= "none";
425 $D('settingsButton').className
= "noVNC_status_button";
426 UI
.settingsOpen
= false;
429 // Save/apply settings when 'Apply' button is pressed
430 settingsApply: function() {
431 //Util.Debug(">> settingsApply");
432 UI
.saveSetting('encrypt');
433 UI
.saveSetting('true_color');
434 if (UI
.rfb
.get_display().get_cursor_uri()) {
435 UI
.saveSetting('cursor');
437 UI
.saveSetting('clip');
438 UI
.saveSetting('shared');
439 UI
.saveSetting('view_only');
440 UI
.saveSetting('connectTimeout');
441 UI
.saveSetting('path');
442 UI
.saveSetting('repeaterID');
443 UI
.saveSetting('stylesheet');
444 UI
.saveSetting('logging');
446 // Settings with immediate (non-connected related) effect
447 WebUtil
.selectStylesheet(UI
.getSetting('stylesheet'));
448 WebUtil
.init_logging(UI
.getSetting('logging'));
450 UI
.setViewDrag(UI
.rfb
.get_viewportDrag());
451 //Util.Debug("<< settingsApply");
456 setPassword: function() {
457 UI
.rfb
.sendPassword($D('noVNC_password').value
);
458 //Reset connect button.
459 $D('noVNC_connect_button').value
= "Connect";
460 $D('noVNC_connect_button').onclick
= UI
.Connect
;
461 //Hide connection panel.
462 UI
.toggleConnectPanel();
466 sendCtrlAltDel: function() {
467 UI
.rfb
.sendCtrlAltDel();
470 setMouseButton: function(num
) {
471 var b
, blist
= [0, 1,2,4], button
;
473 if (typeof num
=== 'undefined') {
474 // Disable mouse buttons
478 UI
.rfb
.get_mouse().set_touchButton(num
);
481 for (b
= 0; b
< blist
.length
; b
++) {
482 button
= $D('noVNC_mouse_button' + blist
[b
]);
483 if (blist
[b
] === num
) {
484 button
.style
.display
= "";
486 button
.style
.display
= "none";
488 button.style.backgroundColor = "black";
489 button.style.color = "lightgray";
490 button.style.backgroundColor = "";
491 button.style.color = "";
497 updateState: function(rfb
, state
, oldstate
, msg
) {
498 var s
, sb
, c
, d
, cad
, vd
, klass
;
499 UI
.rfb_state
= state
;
503 klass
= "noVNC_status_error";
506 klass
= "noVNC_status_normal";
509 $D('noVNC_logo').style
.display
= "block";
512 klass
= "noVNC_status_normal";
515 UI
.toggleConnectPanel();
517 $D('noVNC_connect_button').value
= "Send Password";
518 $D('noVNC_connect_button').onclick
= UI
.setPassword
;
519 $D('noVNC_password').focus();
521 klass
= "noVNC_status_warn";
524 klass
= "noVNC_status_warn";
528 if (typeof(msg
) !== 'undefined') {
529 $D('noVNC-control-bar').setAttribute("class", klass
);
530 $D('noVNC_status').innerHTML
= msg
;
533 UI
.updateVisualState();
536 // Disable/enable controls depending on connection state
537 updateVisualState: function() {
538 var connected
= UI
.rfb_state
=== 'normal' ? true : false;
540 //Util.Debug(">> updateVisualState");
541 $D('noVNC_encrypt').disabled
= connected
;
542 $D('noVNC_true_color').disabled
= connected
;
543 if (UI
.rfb
&& UI
.rfb
.get_display() &&
544 UI
.rfb
.get_display().get_cursor_uri()) {
545 $D('noVNC_cursor').disabled
= connected
;
547 UI
.updateSetting('cursor', !UI
.isTouchDevice
);
548 $D('noVNC_cursor').disabled
= true;
550 $D('noVNC_shared').disabled
= connected
;
551 $D('noVNC_view_only').disabled
= connected
;
552 $D('noVNC_connectTimeout').disabled
= connected
;
553 $D('noVNC_path').disabled
= connected
;
554 $D('noVNC_repeaterID').disabled
= connected
;
558 UI
.setMouseButton(1);
559 $D('clipboardButton').style
.display
= "inline";
560 $D('showKeyboard').style
.display
= "inline";
561 $D('noVNC_extra_keys').style
.display
= "";
562 $D('sendCtrlAltDelButton').style
.display
= "inline";
565 $D('clipboardButton').style
.display
= "none";
566 $D('showKeyboard').style
.display
= "none";
567 $D('noVNC_extra_keys').style
.display
= "none";
568 $D('sendCtrlAltDelButton').style
.display
= "none";
571 // State change disables viewport dragging.
572 // It is enabled (toggled) by direct click on the button
573 UI
.setViewDrag(false);
575 switch (UI
.rfb_state
) {
580 $D('connectButton').style
.display
= "";
581 $D('disconnectButton').style
.display
= "none";
584 $D('connectButton').style
.display
= "none";
585 $D('disconnectButton').style
.display
= "";
589 //Util.Debug("<< updateVisualState");
593 // Display the desktop name in the document title
594 updateDocumentTitle: function(rfb
, name
) {
595 document
.title
= name
+ " - noVNC";
599 clipReceive: function(rfb
, text
) {
600 Util
.Debug(">> UI.clipReceive: " + text
.substr(0,40) + "...");
601 $D('noVNC_clipboard_text').value
= text
;
602 Util
.Debug("<< UI.clipReceive");
606 connect: function() {
607 var host
, port
, password
, path
;
609 UI
.closeSettingsMenu();
610 UI
.toggleConnectPanel();
612 host
= $D('noVNC_host').value
;
613 port
= $D('noVNC_port').value
;
614 password
= $D('noVNC_password').value
;
615 path
= $D('noVNC_path').value
;
616 if ((!host
) || (!port
)) {
617 throw("Must set host and port");
620 UI
.rfb
.set_encrypt(UI
.getSetting('encrypt'));
621 UI
.rfb
.set_true_color(UI
.getSetting('true_color'));
622 UI
.rfb
.set_local_cursor(UI
.getSetting('cursor'));
623 UI
.rfb
.set_shared(UI
.getSetting('shared'));
624 UI
.rfb
.set_view_only(UI
.getSetting('view_only'));
625 UI
.rfb
.set_connectTimeout(UI
.getSetting('connectTimeout'));
626 UI
.rfb
.set_repeaterID(UI
.getSetting('repeaterID'));
628 UI
.rfb
.connect(host
, port
, password
, path
);
631 setTimeout(UI
.setBarPosition
, 100);
632 $D('noVNC_logo').style
.display
= "none";
635 disconnect: function() {
636 UI
.closeSettingsMenu();
639 $D('noVNC_logo').style
.display
= "block";
640 UI
.connSettingsOpen
= false;
641 UI
.toggleConnectPanel();
644 displayBlur: function() {
645 UI
.rfb
.get_keyboard().set_focused(false);
646 UI
.rfb
.get_mouse().set_focused(false);
649 displayFocus: function() {
650 UI
.rfb
.get_keyboard().set_focused(true);
651 UI
.rfb
.get_mouse().set_focused(true);
654 clipClear: function() {
655 $D('noVNC_clipboard_text').value
= "";
656 UI
.rfb
.clipboardPasteFrom("");
659 clipSend: function() {
660 var text
= $D('noVNC_clipboard_text').value
;
661 Util
.Debug(">> UI.clipSend: " + text
.substr(0,40) + "...");
662 UI
.rfb
.clipboardPasteFrom(text
);
663 Util
.Debug("<< UI.clipSend");
667 // Enable/disable and configure viewport clipping
668 setViewClip: function(clip
) {
669 var display
, cur_clip
, pos
, new_w
, new_h
;
672 display
= UI
.rfb
.get_display();
677 cur_clip
= display
.get_viewport();
679 if (typeof(clip
) !== 'boolean') {
680 // Use current setting
681 clip
= UI
.getSetting('clip');
684 if (clip
&& !cur_clip
) {
686 UI
.updateSetting('clip', true);
687 } else if (!clip
&& cur_clip
) {
689 UI
.updateSetting('clip', false);
690 display
.set_viewport(false);
691 $D('noVNC_canvas').style
.position
= 'static';
692 display
.viewportChange();
694 if (UI
.getSetting('clip')) {
695 // If clipping, update clipping settings
696 $D('noVNC_canvas').style
.position
= 'absolute';
697 pos
= Util
.getPosition($D('noVNC_canvas'));
698 new_w
= window
.innerWidth
- pos
.x
;
699 new_h
= window
.innerHeight
- pos
.y
;
700 display
.set_viewport(true);
701 display
.viewportChange(0, 0, new_w
, new_h
);
705 // Toggle/set/unset the viewport drag/move button
706 setViewDrag: function(drag
) {
707 var vmb
= $D('noVNC_view_drag_button');
708 if (!UI
.rfb
) { return; }
710 if (UI
.rfb_state
=== 'normal' &&
711 UI
.rfb
.get_display().get_viewport()) {
712 vmb
.style
.display
= "inline";
714 vmb
.style
.display
= "none";
717 if (typeof(drag
) === "undefined" ||
718 typeof(drag
) === "object") {
719 // If not specified, then toggle
720 drag
= !UI
.rfb
.get_viewportDrag();
723 vmb
.className
= "noVNC_status_button_selected";
724 UI
.rfb
.set_viewportDrag(true);
726 vmb
.className
= "noVNC_status_button";
727 UI
.rfb
.set_viewportDrag(false);
731 // On touch devices, show the OS keyboard
732 showKeyboard: function() {
734 kbi
= $D('keyboardinput');
735 skb
= $D('showKeyboard');
736 l
= kbi
.value
.length
;
737 if(UI
.keyboardVisible
=== false) {
739 kbi
.setSelectionRange(l
, l
); // Move the caret to the end
740 UI
.keyboardVisible
= true;
741 skb
.className
= "noVNC_status_button_selected";
742 } else if(UI
.keyboardVisible
=== true) {
744 skb
.className
= "noVNC_status_button";
745 UI
.keyboardVisible
= false;
749 keepKeyboard: function() {
750 clearTimeout(UI
.hideKeyboardTimeout
);
751 if(UI
.keyboardVisible
=== true) {
752 $D('keyboardinput').focus();
753 $D('showKeyboard').className
= "noVNC_status_button_selected";
754 } else if(UI
.keyboardVisible
=== false) {
755 $D('keyboardinput').blur();
756 $D('showKeyboard').className
= "noVNC_status_button";
760 // When keypress events are left uncought, catch the input events from
761 // the keyboardinput element instead and send the corresponding key events.
762 keyInput: function(event
) {
763 var elem
, input
, len
;
764 elem
= $D('keyboardinput');
765 input
= event
.target
.value
;
766 len
= (elem
.selectionStart
> input
.length
) ? elem
.selectionStart
: input
.length
;
768 if (len
< 1) { // something removed?
769 UI
.rfb
.sendKey(0xff08); // send BACKSPACE
770 } else if (len
> 1) { // new input?
771 for (var i
= len
-1; i
> 0; i
-= 1) {
772 // HTML does not consider trailing whitespaces as a part of the string
773 // and they are therefore undefined.
774 if (input
[len
-i
] !== undefined) {
775 UI
.rfb
.sendKey(input
.charCodeAt(len
-i
)); // send charCode
777 UI
.rfb
.sendKey(0x0020); // send SPACE
782 // In order to be able to delete text which has been written in
783 // another session there has to always be text in the
784 // keyboardinput element with which backspace can interact.
785 // We also need to reset the input field text to avoid overflow.
789 keyInputBlur: function() {
790 $D('showKeyboard').className
= "noVNC_status_button";
791 //Weird bug in iOS if you change keyboardVisible
792 //here it does not actually occur so next time
793 //you click keyboard icon it doesnt work.
794 UI
.hideKeyboardTimeout
= setTimeout(function() { UI
.setKeyboard(); },100);
797 showExtraKeys: function() {
799 if(UI
.extraKeysVisible
=== false) {
800 $D('toggleCtrlButton').style
.display
= "inline";
801 $D('toggleAltButton').style
.display
= "inline";
802 $D('sendTabButton').style
.display
= "inline";
803 $D('sendEscButton').style
.display
= "inline";
804 $D('showExtraKeysButton').className
= "noVNC_status_button_selected";
805 UI
.extraKeysVisible
= true;
806 } else if(UI
.extraKeysVisible
=== true) {
807 $D('toggleCtrlButton').style
.display
= "";
808 $D('toggleAltButton').style
.display
= "";
809 $D('sendTabButton').style
.display
= "";
810 $D('sendEscButton').style
.display
= "";
811 $D('showExtraKeysButton').className
= "noVNC_status_button";
812 UI
.extraKeysVisible
= false;
816 toggleCtrl: function() {
818 if(UI
.ctrlOn
=== false) {
819 UI
.rfb
.sendKey(XK_Control_L
, true);
820 $D('toggleCtrlButton').className
= "noVNC_status_button_selected";
822 } else if(UI
.ctrlOn
=== true) {
823 UI
.rfb
.sendKey(XK_Control_L
, false);
824 $D('toggleCtrlButton').className
= "noVNC_status_button";
829 toggleAlt: function() {
831 if(UI
.altOn
=== false) {
832 UI
.rfb
.sendKey(XK_Alt_L
, true);
833 $D('toggleAltButton').className
= "noVNC_status_button_selected";
835 } else if(UI
.altOn
=== true) {
836 UI
.rfb
.sendKey(XK_Alt_L
, false);
837 $D('toggleAltButton').className
= "noVNC_status_button";
842 sendTab: function() {
844 UI
.rfb
.sendKey(XK_Tab
);
847 sendEsc: function() {
849 UI
.rfb
.sendKey(XK_Escape
);
852 setKeyboard: function() {
853 UI
.keyboardVisible
= false;
856 // iOS < Version 5 does not support position fixed. Javascript workaround:
857 setOnscroll: function() {
858 window
.onscroll = function() {
863 setResize: function () {
864 window
.onResize = function() {
869 //Helper to add options to dropdown.
870 addOption: function(selectbox
,text
,value
)
872 var optn
= document
.createElement("OPTION");
875 selectbox
.options
.add(optn
);
878 setBarPosition: function() {
879 $D('noVNC-control-bar').style
.top
= (window
.pageYOffset
) + 'px';
880 $D('noVNC_mobile_buttons').style
.left
= (window
.pageXOffset
) + 'px';
882 var vncwidth
= $D('noVNC_screen').style
.offsetWidth
;
883 $D('noVNC-control-bar').style
.width
= vncwidth
+ 'px';