9import * as Log from
'../core/util/logging.js';
10import _, { l10n } from
'./localization.js';
11import { isTouchDevice, isMac, isIOS, isAndroid, isChromeOS, isSafari,
12 hasScrollbarGutter, dragThreshold }
13 from
'../core/util/browser.js';
14import { setCapture, getPointerEvent } from
'../core/util/events.js';
15import KeyTable from
"../core/input/keysym.js";
16import keysyms from
"../core/input/keysymdef.js";
17import Keyboard from
"../core/input/keyboard.js";
18import RFB from
"../core/rfb_multi.js";
19import * as WebUtil from
"./webutil.js";
21const PAGE_TITLE =
"noVNC_multi";
23const LINGUAS = [
"cs",
"de",
"el",
"es",
"fr",
"hr",
"hu",
"it",
"ja",
"ko",
"nl",
"pl",
"pt_BR",
"ru",
"sv",
"tr",
"zh_CN",
"zh_TW"];
36 hideKeyboardTimeout:
null,
37 idleControlbarTimeout:
null,
38 closeControlbarTimeout:
null,
40 controlbarGrabbed:
false,
41 controlbarDrag:
false,
42 controlbarMouseDownClientY: 0,
43 controlbarMouseDownOffsetY: 0,
45 lastKeyboardinput:
null,
46 defaultKeyboardinputLen: 100,
48 inhibitReconnect:
true,
49 reconnectCallback:
null,
50 reconnectPassword:
null,
52 async start(options={}) {
56 UI.customSettings = options.settings || {};
57 if (UI.customSettings.defaults === undefined) {
58 UI.customSettings.defaults = {};
60 if (UI.customSettings.mandatory === undefined) {
61 UI.customSettings.mandatory = {};
66 await l10n.setup(LINGUAS,
"app/locale/");
68 Log.Error(
"Failed to load translations: " + err);
72 await WebUtil.initSettings();
75 if (document.readyState !==
"interactive" && document.readyState !==
"complete") {
76 await
new Promise((resolve, reject) => {
77 document.addEventListener(
'DOMContentLoaded', resolve);
88 if (!window.isSecureContext) {
90 UI.showStatus(_(
"Running without HTTPS is not recommended, crashes or other issues are likely."),
'error');
95 let response = await fetch(
'./package.json');
97 throw Error(
"" + response.status +
" " + response.statusText);
100 let packageInfo = await response.json();
101 Array.from(document.getElementsByClassName(
'noVNC_version')).forEach(el => el.innerText = packageInfo.version);
103 Log.Error(
"Couldn't fetch package.json: " + err);
104 Array.from(document.getElementsByClassName(
'noVNC_version_wrapper'))
105 .concat(Array.from(document.getElementsByClassName(
'noVNC_version_separator')))
106 .forEach(el => el.style.display =
'none');
111 document.documentElement.classList.add(
"noVNC_touch");
113 setTimeout(() => window.scrollTo(0, 1), 100);
117 if (WebUtil.readSetting(
'controlbar_pos') ===
'right') {
118 UI.toggleControlbarSide();
124 UI.addControlbarHandlers();
125 UI.addTouchSpecificHandlers();
126 UI.addExtraKeysHandlers();
127 UI.addMachineHandlers();
128 UI.addConnectionControlHandlers();
129 UI.addClipboardHandlers();
130 UI.addSettingsHandlers();
131 document.getElementById(
"noVNC_status")
132 .addEventListener(
'click', UI.hideStatus);
135 UI.keyboardinputReset();
139 UI.updateVisualState(
'init');
141 document.documentElement.classList.remove(
"noVNC_loading");
143 let autoconnect = UI.getSetting(
'autoconnect');
158 (document.documentElement.requestFullscreen ||
159 document.documentElement.mozRequestFullScreen ||
160 document.documentElement.webkitRequestFullscreen ||
161 document.body.msRequestFullscreen)) {
162 document.getElementById(
'noVNC_fullscreen_button')
163 .classList.remove(
"noVNC_hidden");
164 UI.addFullscreenHandlers();
170 const llevels = [
'error',
'warn',
'info',
'debug'];
171 for (let i = 0; i < llevels.length; i += 1) {
172 UI.addOption(document.getElementById(
'noVNC_setting_logging'), llevels[i], llevels[i]);
176 UI.initSetting(
'logging',
'warn');
180 UI.NbRFB = WebUtil.getConfigVar(
'NbRFB', 0);
182 UI.setupSettingLabels();
185 UI.initSetting(
'host',
'');
186 UI.initSetting(
'port', 0);
187 UI.initSetting(
'encrypt', (window.location.protocol ===
"https:"));
188 UI.initSetting(
'password');
189 UI.initSetting(
'autoconnect',
false);
190 UI.initSetting(
'view_clip',
false);
191 UI.initSetting(
'resize',
'off');
192 UI.initSetting(
'quality', 6);
193 UI.initSetting(
'compression', 2);
194 UI.initSetting(
'shared',
true);
195 UI.initSetting(
'bell',
'on');
196 UI.initSetting(
'view_only',
false);
197 UI.initSetting(
'show_dot',
false);
198 UI.initSetting(
'path',
'websockify');
199 UI.initSetting(
'repeaterID',
'');
200 UI.initSetting(
'reconnect',
false);
201 UI.initSetting(
'reconnect_delay', 5000);
204 setupSettingLabels() {
205 const labels = document.getElementsByTagName(
'LABEL');
206 for (let i = 0; i < labels.length; i++) {
207 const htmlFor = labels[i].htmlFor;
209 const elem = document.getElementById(htmlFor);
210 if (elem) elem.label = labels[i];
213 const children = labels[i].children;
214 for (let j = 0; j < children.length; j++) {
215 if (children[j].form !== undefined) {
216 children[j].label = labels[i];
230 addControlbarHandlers() {
231 document.getElementById(
"noVNC_control_bar")
232 .addEventListener(
'mousemove', UI.activateControlbar);
233 document.getElementById(
"noVNC_control_bar")
234 .addEventListener(
'mouseup', UI.activateControlbar);
235 document.getElementById(
"noVNC_control_bar")
236 .addEventListener(
'mousedown', UI.activateControlbar);
237 document.getElementById(
"noVNC_control_bar")
238 .addEventListener(
'keydown', UI.activateControlbar);
240 document.getElementById(
"noVNC_control_bar")
241 .addEventListener(
'mousedown', UI.keepControlbar);
242 document.getElementById(
"noVNC_control_bar")
243 .addEventListener(
'keydown', UI.keepControlbar);
245 document.getElementById(
"noVNC_view_drag_button")
246 .addEventListener(
'click', UI.toggleViewDrag);
248 document.getElementById(
"noVNC_control_bar_handle")
249 .addEventListener(
'mousedown', UI.controlbarHandleMouseDown);
250 document.getElementById(
"noVNC_control_bar_handle")
251 .addEventListener(
'mouseup', UI.controlbarHandleMouseUp);
252 document.getElementById(
"noVNC_control_bar_handle")
253 .addEventListener(
'mousemove', UI.dragControlbarHandle);
255 window.addEventListener(
'resize', UI.updateControlbarHandle);
257 const exps = document.getElementsByClassName(
"noVNC_expander");
258 for (let i = 0;i < exps.length;i++) {
259 exps[i].addEventListener(
'click', UI.toggleExpander);
263 addTouchSpecificHandlers() {
264 document.getElementById(
"noVNC_keyboard_button")
265 .addEventListener(
'click', UI.toggleVirtualKeyboard);
267 UI.touchKeyboard =
new Keyboard(document.getElementById(
'noVNC_keyboardinput'));
268 UI.touchKeyboard.onkeyevent = UI.keyEvent;
269 UI.touchKeyboard.grab();
270 document.getElementById(
"noVNC_keyboardinput")
271 .addEventListener(
'input', UI.keyInput);
272 document.getElementById(
"noVNC_keyboardinput")
273 .addEventListener(
'focus', UI.onfocusVirtualKeyboard);
274 document.getElementById(
"noVNC_keyboardinput")
275 .addEventListener(
'blur', UI.onblurVirtualKeyboard);
276 document.getElementById(
"noVNC_keyboardinput")
277 .addEventListener(
'submit', () =>
false);
279 document.documentElement
280 .addEventListener(
'mousedown', UI.keepVirtualKeyboard,
true);
282 document.getElementById(
"noVNC_control_bar")
283 .addEventListener(
'touchstart', UI.activateControlbar);
284 document.getElementById(
"noVNC_control_bar")
285 .addEventListener(
'touchmove', UI.activateControlbar);
286 document.getElementById(
"noVNC_control_bar")
287 .addEventListener(
'touchend', UI.activateControlbar);
288 document.getElementById(
"noVNC_control_bar")
289 .addEventListener(
'input', UI.activateControlbar);
291 document.getElementById(
"noVNC_control_bar")
292 .addEventListener(
'touchstart', UI.keepControlbar);
293 document.getElementById(
"noVNC_control_bar")
294 .addEventListener(
'input', UI.keepControlbar);
296 document.getElementById(
"noVNC_control_bar_handle")
297 .addEventListener(
'touchstart', UI.controlbarHandleMouseDown);
298 document.getElementById(
"noVNC_control_bar_handle")
299 .addEventListener(
'touchend', UI.controlbarHandleMouseUp);
300 document.getElementById(
"noVNC_control_bar_handle")
301 .addEventListener(
'touchmove', UI.dragControlbarHandle);
304 addExtraKeysHandlers() {
305 document.getElementById(
"noVNC_toggle_extra_keys_button")
306 .addEventListener(
'click', UI.toggleExtraKeys);
307 document.getElementById(
"noVNC_toggle_ctrl_button")
308 .addEventListener(
'click', UI.toggleCtrl);
309 document.getElementById(
"noVNC_toggle_windows_button")
310 .addEventListener(
'click', UI.toggleWindows);
311 document.getElementById(
"noVNC_toggle_alt_button")
312 .addEventListener(
'click', UI.toggleAlt);
313 document.getElementById(
"noVNC_send_tab_button")
314 .addEventListener(
'click', UI.sendTab);
315 document.getElementById(
"noVNC_send_esc_button")
316 .addEventListener(
'click', UI.sendEsc);
317 document.getElementById(
"noVNC_send_ctrl_alt_del_button")
318 .addEventListener(
'click', UI.sendCtrlAltDel);
321 addMachineHandlers() {
322 document.getElementById(
"noVNC_shutdown_button")
323 .addEventListener(
'click', () => {
for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].machineShutdown()}});
324 document.getElementById(
"noVNC_reboot_button")
325 .addEventListener(
'click', () => {
for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].machineReboot()}});
326 document.getElementById(
"noVNC_reset_button")
327 .addEventListener(
'click', () => {
for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].machineReset()}});
328 document.getElementById(
"noVNC_power_button")
329 .addEventListener(
'click', UI.togglePowerPanel);
332 addConnectionControlHandlers() {
333 document.getElementById(
"noVNC_disconnect_button")
334 .addEventListener(
'click', UI.disconnect);
335 document.getElementById(
"noVNC_connect_button")
336 .addEventListener(
'click', UI.connect);
337 document.getElementById(
"noVNC_cancel_reconnect_button")
338 .addEventListener(
'click', UI.cancelReconnect);
340 document.getElementById(
"noVNC_approve_server_button")
341 .addEventListener(
'click', UI.approveServer);
342 document.getElementById(
"noVNC_reject_server_button")
343 .addEventListener(
'click', UI.rejectServer);
344 document.getElementById(
"noVNC_credentials_button")
345 .addEventListener(
'click', UI.setCredentials);
348 addClipboardHandlers() {
349 document.getElementById(
"noVNC_clipboard_button")
350 .addEventListener(
'click', UI.toggleClipboardPanel);
351 document.getElementById(
"noVNC_clipboard_text")
352 .addEventListener(
'change', UI.clipboardSend);
357 addSettingChangeHandler(name, changeFunc) {
358 const settingElem = document.getElementById(
"noVNC_setting_" + name);
359 if (changeFunc === undefined) {
360 changeFunc = () => UI.saveSetting(name);
363 settingElem.addEventListener(
'change', changeFunc);
367 addSettingsHandlers() {
368 document.getElementById(
"noVNC_settings_button")
369 .addEventListener(
'click', UI.toggleSettingsPanel);
371 UI.addSettingChangeHandler(
'encrypt');
372 UI.addSettingChangeHandler(
'resize');
373 UI.addSettingChangeHandler(
'resize', UI.applyResizeMode);
374 UI.addSettingChangeHandler(
'resize', UI.updateViewClip);
375 UI.addSettingChangeHandler(
'quality');
376 UI.addSettingChangeHandler(
'quality', UI.updateQuality);
377 UI.addSettingChangeHandler(
'compression');
378 UI.addSettingChangeHandler(
'compression', UI.updateCompression);
379 UI.addSettingChangeHandler(
'view_clip');
380 UI.addSettingChangeHandler(
'view_clip', UI.updateViewClip);
381 UI.addSettingChangeHandler(
'shared');
382 UI.addSettingChangeHandler(
'view_only');
383 UI.addSettingChangeHandler(
'view_only', UI.updateViewOnly);
384 UI.addSettingChangeHandler(
'show_dot');
385 UI.addSettingChangeHandler(
'show_dot', UI.updateShowDotCursor);
386 UI.addSettingChangeHandler(
'host');
387 UI.addSettingChangeHandler(
'port');
388 UI.addSettingChangeHandler(
'path');
389 UI.addSettingChangeHandler(
'repeaterID');
390 UI.addSettingChangeHandler(
'logging');
391 UI.addSettingChangeHandler(
'logging', UI.updateLogging);
392 UI.addSettingChangeHandler(
'reconnect');
393 UI.addSettingChangeHandler(
'reconnect_delay');
396 addFullscreenHandlers() {
397 document.getElementById(
"noVNC_fullscreen_button")
398 .addEventListener(
'click', UI.toggleFullscreen);
400 window.addEventListener(
'fullscreenchange', UI.updateFullscreenButton);
401 window.addEventListener(
'mozfullscreenchange', UI.updateFullscreenButton);
402 window.addEventListener(
'webkitfullscreenchange', UI.updateFullscreenButton);
403 window.addEventListener(
'msfullscreenchange', UI.updateFullscreenButton);
413 updateVisualState(state) {
415 document.documentElement.classList.remove(
"noVNC_connecting");
416 document.documentElement.classList.remove(
"noVNC_connected");
417 document.documentElement.classList.remove(
"noVNC_disconnecting");
418 document.documentElement.classList.remove(
"noVNC_reconnecting");
420 const transitionElem = document.getElementById(
"noVNC_transition_text");
425 transitionElem.textContent = _(
"Connecting...");
426 document.documentElement.classList.add(
"noVNC_connecting");
429 document.documentElement.classList.add(
"noVNC_connected");
431 case 'disconnecting':
432 transitionElem.textContent = _(
"Disconnecting...");
433 document.documentElement.classList.add(
"noVNC_disconnecting");
438 transitionElem.textContent = _(
"Reconnecting...");
439 document.documentElement.classList.add(
"noVNC_reconnecting");
442 Log.Error(
"Invalid visual state: " + state);
443 UI.showStatus(_(
"Internal error"),
'error');
450 UI.disableSetting(
'encrypt');
451 UI.disableSetting(
'shared');
452 UI.disableSetting(
'host');
453 UI.disableSetting(
'port');
454 UI.disableSetting(
'path');
455 UI.disableSetting(
'repeaterID');
458 UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
460 UI.enableSetting(
'encrypt');
461 UI.enableSetting(
'shared');
462 UI.enableSetting(
'host');
463 UI.enableSetting(
'port');
464 UI.enableSetting(
'path');
465 UI.enableSetting(
'repeaterID');
466 UI.updatePowerButton();
473 document.getElementById(
'noVNC_verify_server_dlg')
474 .classList.remove(
'noVNC_open');
475 document.getElementById(
'noVNC_credentials_dlg')
476 .classList.remove(
'noVNC_open');
479 showStatus(text, statusType, time) {
480 const statusElem = document.getElementById(
'noVNC_status');
482 if (typeof statusType ===
'undefined') {
483 statusType =
'normal';
488 if (statusElem.classList.contains(
"noVNC_open")) {
489 if (statusElem.classList.contains(
"noVNC_status_error")) {
492 if (statusElem.classList.contains(
"noVNC_status_warn") &&
493 statusType ===
'normal') {
498 clearTimeout(UI.statusTimeout);
500 switch (statusType) {
502 statusElem.classList.remove(
"noVNC_status_warn");
503 statusElem.classList.remove(
"noVNC_status_normal");
504 statusElem.classList.add(
"noVNC_status_error");
508 statusElem.classList.remove(
"noVNC_status_error");
509 statusElem.classList.remove(
"noVNC_status_normal");
510 statusElem.classList.add(
"noVNC_status_warn");
515 statusElem.classList.remove(
"noVNC_status_error");
516 statusElem.classList.remove(
"noVNC_status_warn");
517 statusElem.classList.add(
"noVNC_status_normal");
521 statusElem.textContent = text;
522 statusElem.classList.add(
"noVNC_open");
525 if (typeof time ===
'undefined') {
530 if (statusType !==
'error') {
531 UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
536 clearTimeout(UI.statusTimeout);
537 document.getElementById(
'noVNC_status').classList.remove(
"noVNC_open");
540 activateControlbar(event) {
541 clearTimeout(UI.idleControlbarTimeout);
544 document.getElementById(
'noVNC_control_bar_anchor')
545 .classList.remove(
"noVNC_idle");
546 UI.idleControlbarTimeout = window.setTimeout(UI.idleControlbar, 2000);
551 if (document.getElementById(
'noVNC_control_bar')
552 .contains(document.activeElement) && document.hasFocus()) {
553 UI.activateControlbar();
557 document.getElementById(
'noVNC_control_bar_anchor')
558 .classList.add(
"noVNC_idle");
562 clearTimeout(UI.closeControlbarTimeout);
566 document.getElementById(
'noVNC_control_bar')
567 .classList.add(
"noVNC_open");
572 document.getElementById(
'noVNC_control_bar')
573 .classList.remove(
"noVNC_open");
582 if (document.getElementById(
'noVNC_control_bar')
583 .classList.contains(
"noVNC_open")) {
584 UI.closeControlbar();
590 toggleControlbarSide() {
593 const bar = document.getElementById(
'noVNC_control_bar');
594 const barDisplayStyle = window.getComputedStyle(bar).display;
595 if (barDisplayStyle !==
'none') {
596 bar.style.transitionDuration =
'0s';
597 bar.addEventListener(
'transitionend', () => bar.style.transitionDuration =
'');
600 const anchor = document.getElementById(
'noVNC_control_bar_anchor');
601 if (anchor.classList.contains(
"noVNC_right")) {
602 WebUtil.writeSetting(
'controlbar_pos',
'left');
603 anchor.classList.remove(
"noVNC_right");
605 WebUtil.writeSetting(
'controlbar_pos',
'right');
606 anchor.classList.add(
"noVNC_right");
610 UI.controlbarDrag =
true;
613 UI.showControlbarHint(
false,
false);
616 showControlbarHint(show, animate=
true) {
617 const hint = document.getElementById(
'noVNC_control_bar_hint');
620 hint.classList.remove(
"noVNC_notransition");
622 hint.classList.add(
"noVNC_notransition");
626 hint.classList.add(
"noVNC_active");
628 hint.classList.remove(
"noVNC_active");
632 dragControlbarHandle(e) {
633 if (!UI.controlbarGrabbed)
return;
635 const ptr = getPointerEvent(e);
637 const anchor = document.getElementById(
'noVNC_control_bar_anchor');
638 if (ptr.clientX < (window.innerWidth * 0.1)) {
639 if (anchor.classList.contains(
"noVNC_right")) {
640 UI.toggleControlbarSide();
642 }
else if (ptr.clientX > (window.innerWidth * 0.9)) {
643 if (!anchor.classList.contains(
"noVNC_right")) {
644 UI.toggleControlbarSide();
648 if (!UI.controlbarDrag) {
649 const dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY);
651 if (dragDistance < dragThreshold)
return;
653 UI.controlbarDrag =
true;
656 const eventY = ptr.clientY - UI.controlbarMouseDownOffsetY;
658 UI.moveControlbarHandle(eventY);
663 UI.activateControlbar();
667 moveControlbarHandle(viewportRelativeY) {
668 const handle = document.getElementById(
"noVNC_control_bar_handle");
669 const handleHeight = handle.getBoundingClientRect().height;
670 const controlbarBounds = document.getElementById(
"noVNC_control_bar")
671 .getBoundingClientRect();
675 if (handleHeight === 0 || controlbarBounds.height === 0) {
679 let newY = viewportRelativeY;
682 if (newY < controlbarBounds.top + margin) {
684 newY = controlbarBounds.top + margin;
686 }
else if (newY > controlbarBounds.top +
687 controlbarBounds.height - handleHeight - margin) {
689 newY = controlbarBounds.top +
690 controlbarBounds.height - handleHeight - margin;
694 if (controlbarBounds.height < (handleHeight + margin * 2)) {
695 newY = controlbarBounds.top +
696 (controlbarBounds.height - handleHeight) / 2;
700 const parentRelativeY = newY - controlbarBounds.top;
701 handle.style.transform =
"translateY(" + parentRelativeY +
"px)";
704 updateControlbarHandle() {
707 const handle = document.getElementById(
"noVNC_control_bar_handle");
708 const handleBounds = handle.getBoundingClientRect();
709 UI.moveControlbarHandle(handleBounds.top);
712 controlbarHandleMouseUp(e) {
713 if ((e.type ==
"mouseup") && (e.button != 0))
return;
716 if (UI.controlbarGrabbed && !UI.controlbarDrag) {
717 UI.toggleControlbar();
721 UI.activateControlbar();
723 UI.controlbarGrabbed =
false;
724 UI.showControlbarHint(
false);
727 controlbarHandleMouseDown(e) {
728 if ((e.type ==
"mousedown") && (e.button != 0))
return;
730 const ptr = getPointerEvent(e);
732 const handle = document.getElementById(
"noVNC_control_bar_handle");
733 const bounds = handle.getBoundingClientRect();
736 if (e.type ===
"mousedown") {
740 UI.controlbarGrabbed =
true;
741 UI.controlbarDrag =
false;
743 UI.showControlbarHint(
true);
745 UI.controlbarMouseDownClientY = ptr.clientY;
746 UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top;
750 UI.activateControlbar();
754 if (this.classList.contains(
"noVNC_open")) {
755 this.classList.remove(
"noVNC_open");
757 this.classList.add(
"noVNC_open");
768 initSetting(name, defVal) {
770 if (name in UI.customSettings.defaults) {
771 defVal = UI.customSettings.defaults[name];
774 let val = WebUtil.getConfigVar(name);
776 val = WebUtil.readSetting(name, defVal);
778 WebUtil.setSetting(name, val);
779 UI.updateSetting(name);
781 if (name in UI.customSettings.mandatory) {
782 val = UI.customSettings.mandatory[name];
783 UI.forceSetting(name, val);
789 forceSetting(name, val) {
790 WebUtil.setSetting(name, val);
791 UI.updateSetting(name);
792 UI.disableSetting(name);
797 updateSetting(name) {
800 let value = UI.getSetting(name);
802 let ctrl = document.getElementById(
'noVNC_setting_' + name);
804 let name_ = name.replace(/[0-9]*$/,
'');
805 ctrl = document.getElementById(
'noVNC_setting_' + name_);
812 if (ctrl.type ===
'checkbox') {
813 ctrl.checked = value;
814 }
else if (typeof ctrl.options !==
'undefined') {
815 for (let i = 0; i < ctrl.options.length; i += 1) {
816 if (ctrl.options[i].value === value) {
817 ctrl.selectedIndex = i;
828 let ctrl = document.getElementById(
'noVNC_setting_' + name);
830 let name_ = name.replace(/[0-9]*$/,
'');
831 ctrl = document.getElementById(
'noVNC_setting_' + name_);
833 if (ctrl ===
null)
return null;
836 if (ctrl.type ===
'checkbox') {
838 }
else if (typeof ctrl.options !==
'undefined') {
839 val = ctrl.options[ctrl.selectedIndex].value;
843 WebUtil.writeSetting(name, val);
849 let ctrl = document.getElementById(
'noVNC_setting_' + name);
851 let name_ = name.replace(/[0-9]*$/,
'');
852 ctrl = document.getElementById(
'noVNC_setting_' + name_);
855 let val = WebUtil.readSetting(name);
856 if (typeof val !==
'undefined' && val !==
null &&
857 ctrl !==
null && ctrl.type ===
'checkbox') {
858 if (val.toString().toLowerCase() in {
'0': 1,
'no': 1,
'false': 1}) {
867 disableSetting(name) {
868 let ctrl = document.getElementById(
'noVNC_setting_' + name);
870 let name_ = name.replace(/[0-9]*$/,
'');
871 ctrl = document.getElementById(
'noVNC_setting_' + name_);
874 ctrl.disabled =
true;
875 if (ctrl.label !== undefined) {
876 ctrl.label.classList.add(
'noVNC_disabled');
881 enableSetting(name) {
882 let ctrl = document.getElementById(
'noVNC_setting_' + name);
884 let name_ = name.replace(/[0-9]*$/,
'');
885 ctrl = document.getElementById(
'noVNC_setting_' + name_);
888 ctrl.disabled =
false;
889 if (ctrl.label !== undefined) {
890 ctrl.label.classList.remove(
'noVNC_disabled');
902 UI.closeSettingsPanel();
903 UI.closePowerPanel();
904 UI.closeClipboardPanel();
914 openSettingsPanel() {
919 UI.updateSetting(
'encrypt');
920 UI.updateSetting(
'view_clip');
921 UI.updateSetting(
'resize');
922 UI.updateSetting(
'quality');
923 UI.updateSetting(
'compression');
924 UI.updateSetting(
'shared');
925 UI.updateSetting(
'view_only');
926 UI.updateSetting(
'path');
927 UI.updateSetting(
'repeaterID');
928 UI.updateSetting(
'logging');
929 UI.updateSetting(
'reconnect');
930 UI.updateSetting(
'reconnect_delay');
932 document.getElementById(
'noVNC_settings')
933 .classList.add(
"noVNC_open");
934 document.getElementById(
'noVNC_settings_button')
935 .classList.add(
"noVNC_selected");
938 closeSettingsPanel() {
939 document.getElementById(
'noVNC_settings')
940 .classList.remove(
"noVNC_open");
941 document.getElementById(
'noVNC_settings_button')
942 .classList.remove(
"noVNC_selected");
945 toggleSettingsPanel() {
946 if (document.getElementById(
'noVNC_settings')
947 .classList.contains(
"noVNC_open")) {
948 UI.closeSettingsPanel();
950 UI.openSettingsPanel();
964 document.getElementById(
'noVNC_power')
965 .classList.add(
"noVNC_open");
966 document.getElementById(
'noVNC_power_button')
967 .classList.add(
"noVNC_selected");
971 document.getElementById(
'noVNC_power')
972 .classList.remove(
"noVNC_open");
973 document.getElementById(
'noVNC_power_button')
974 .classList.remove(
"noVNC_selected");
978 if (document.getElementById(
'noVNC_power')
979 .classList.contains(
"noVNC_open")) {
980 UI.closePowerPanel();
987 updatePowerButton() {
988 if (UI.connected && UI.rfb[0] &&
989 UI.rfb[0].capabilities.power &&
990 !UI.rfb[0].viewOnly) {
991 document.getElementById(
'noVNC_power_button')
992 .classList.remove(
"noVNC_hidden");
994 document.getElementById(
'noVNC_power_button')
995 .classList.add(
"noVNC_hidden");
997 UI.closePowerPanel();
1007 openClipboardPanel() {
1008 UI.closeAllPanels();
1009 UI.openControlbar();
1011 document.getElementById(
'noVNC_clipboard')
1012 .classList.add(
"noVNC_open");
1013 document.getElementById(
'noVNC_clipboard_button')
1014 .classList.add(
"noVNC_selected");
1017 closeClipboardPanel() {
1018 document.getElementById(
'noVNC_clipboard')
1019 .classList.remove(
"noVNC_open");
1020 document.getElementById(
'noVNC_clipboard_button')
1021 .classList.remove(
"noVNC_selected");
1024 toggleClipboardPanel() {
1025 if (document.getElementById(
'noVNC_clipboard')
1026 .classList.contains(
"noVNC_open")) {
1027 UI.closeClipboardPanel();
1029 UI.openClipboardPanel();
1033 clipboardReceive(e) {
1034 Log.Debug(
">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) +
"...");
1035 document.getElementById(
'noVNC_clipboard_text').value = e.detail.text;
1036 Log.Debug(
"<< UI.clipboardReceive");
1040 const text = document.getElementById(
'noVNC_clipboard_text').value;
1041 Log.Debug(
">> UI.clipboardSend: " + text.substr(0, 40) +
"...");
1042 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].clipboardPasteFrom(text); }
1043 Log.Debug(
"<< UI.clipboardSend");
1052 openConnectPanel() {
1053 document.getElementById(
'noVNC_connect_dlg')
1054 .classList.add(
"noVNC_open");
1057 closeConnectPanel() {
1058 document.getElementById(
'noVNC_connect_dlg')
1059 .classList.remove(
"noVNC_open");
1062 connect(event, password) {
1065 if (typeof UI.rfb[0] !==
'undefined') {
1069 var host =
new Array();
1070 var port =
new Array();
1071 var path =
new Array();
1073 for(var i=0; i<UI.NbRFB; i++) {
1074 host[i] = WebUtil.getConfigVar(
'host'+i);
1075 port[i] = WebUtil.getConfigVar(
'port'+i);
1076 path[i] = WebUtil.getConfigVar(
'path'+i);
1077 console.log(
"RFB n°"+i+
" parameters (host,port) : ",host[i],port[i]);
1080 if (typeof password ===
'undefined') {
1081 password =
new Array();
1082 for(var i=0; i<UI.NbRFB; i++) {
1083 password[i] = WebUtil.getConfigVar(
'password'+i);
1085 password[i] = UI.getSetting(
'password');
1088 UI.reconnectPassword = password;
1091 if (password ===
null) {
1092 password = undefined;
1097 if (!host[0] && !UI.getSetting(
'host') && !UI.getSetting(
'path')) {
1098 Log.Error(
"Can't connect when host is empty.");
1099 UI.showStatus(_(
"Must set host"),
'error');
1103 UI.closeConnectPanel();
1104 UI.updateVisualState(
'connecting');
1106 for(var i=0; i<UI.NbRFB; i++) {
1110 url =
new URL(
"https://" + host[i]);
1111 let encryptParam = WebUtil.getConfigVar(
'encrypt'+i);
1112 let useEncrypt = (encryptParam !==
null) ? encryptParam : UI.getSetting(
'encrypt');
1114 url.protocol = useEncrypt ?
'wss:' :
'ws:';
1119 url =
new URL(
"./" + (path[i] || UI.getSetting(
'path')), url);
1121 url =
new URL((path[i] || UI.getSetting(
'path')), location.href);
1122 url.protocol = (window.location.protocol ===
"https:") ?
'wss:' :
'ws:';
1127 shared: UI.getSetting(
'shared'),
1128 repeaterID: UI.getSetting(
'repeaterID'),
1129 credentials: { password: password[i] }
1133 options.overlap =
true;
1136 UI.rfb[i] =
new RFB(document.getElementById(
'noVNC_container'),
1140 Log.Error(
"Failed to connect to server: " + exc);
1141 UI.updateVisualState(
'disconnected');
1142 UI.showStatus(_(
"Failed to connect to server: ") + exc,
'error');
1146 UI.rfb[i].addEventListener(
"connect", UI.connectFinished);
1147 UI.rfb[i].addEventListener(
"disconnect", UI.disconnectFinished);
1148 UI.rfb[i].addEventListener(
"serververification", UI.serverVerify);
1149 UI.rfb[i].addEventListener(
"credentialsrequired", UI.credentials);
1150 UI.rfb[i].addEventListener(
"securityfailure", UI.securityFailed);
1151 UI.rfb[i].addEventListener(
"clippingviewport", UI.updateViewDrag);
1152 UI.rfb[i].addEventListener(
"capabilities", UI.updatePowerButton);
1153 UI.rfb[i].addEventListener(
"clipboard", UI.clipboardReceive);
1154 UI.rfb[i].addEventListener(
"bell", UI.bell);
1155 UI.rfb[i].addEventListener(
"desktopname", UI.updateDesktopName);
1157 UI.rfb[i].clipViewport = UI.getSetting(
'view_clip');
1158 UI.rfb[i].scaleViewport = UI.getSetting(
'resize') ===
'scale';
1159 UI.rfb[i].resizeSession = UI.getSetting(
'resize') ===
'remote';
1160 UI.rfb[i].qualityLevel = parseInt(UI.getSetting(
'quality'));
1161 UI.rfb[i].compressionLevel = parseInt(UI.getSetting(
'compression'));
1162 UI.rfb[i].showDotCursor = UI.getSetting(
'show_dot');
1165 UI.updateViewOnly();
1169 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].disconnect() };
1171 UI.connected =
false;
1174 UI.inhibitReconnect =
true;
1176 UI.updateVisualState(
'disconnecting');
1182 UI.reconnectCallback =
null;
1185 if (UI.inhibitReconnect) {
1189 UI.connect(
null, UI.reconnectPassword);
1193 if (UI.reconnectCallback !==
null) {
1194 clearTimeout(UI.reconnectCallback);
1195 UI.reconnectCallback =
null;
1198 UI.updateVisualState(
'disconnected');
1200 UI.openControlbar();
1201 UI.openConnectPanel();
1204 connectFinished(e) {
1205 UI.connected =
true;
1206 UI.inhibitReconnect =
false;
1209 let isEncrypted = WebUtil.getConfigVar(
'encrypt0');
1210 if (isEncrypted ===
null) isEncrypted = UI.getSetting(
'encrypt');
1213 msg = _(
"Connected (encrypted) to ") + UI.desktopName;
1215 msg = _(
"Connected (unencrypted) to ") + UI.desktopName;
1218 UI.updateVisualState(
'connected');
1220 UI.updateBeforeUnload();
1226 disconnectFinished(e) {
1227 const wasConnected = UI.connected;
1233 UI.connected =
false;
1235 for(var i=0; i<UI.NbRFB; i++) {
1236 UI.rfb[i] = undefined;
1239 if (!e.detail.clean) {
1240 UI.updateVisualState(
'disconnected');
1242 UI.showStatus(_(
"Something went wrong, connection is closed"),
1245 UI.showStatus(_(
"Failed to connect to server"),
'error');
1249 if (UI.getSetting(
'reconnect',
false) ===
true && !UI.inhibitReconnect) {
1250 UI.updateVisualState(
'reconnecting');
1252 const delay = parseInt(UI.getSetting(
'reconnect_delay'));
1253 UI.reconnectCallback = setTimeout(UI.reconnect, delay);
1256 UI.updateVisualState(
'disconnected');
1257 UI.showStatus(_(
"Disconnected"),
'normal');
1260 UI.updateBeforeUnload();
1262 document.title = PAGE_TITLE;
1264 UI.openControlbar();
1265 UI.openConnectPanel();
1273 if (
'reason' in e.detail) {
1274 msg = _(
"New connection has been rejected with reason: ") +
1277 msg = _(
"New connection has been rejected");
1279 UI.showStatus(msg,
'error');
1282 handleBeforeUnload(e) {
1289 e.returnValue = _(
"Are you sure you want to disconnect the session?");
1292 updateBeforeUnload() {
1294 window.removeEventListener(
"beforeunload", UI.handleBeforeUnload);
1295 if (UI.rfb && UI.rfb[0] && !UI.rfb[0].viewOnly && UI.connected) {
1296 window.addEventListener(
"beforeunload", UI.handleBeforeUnload);
1306 async serverVerify(e) {
1307 const type = e.detail.type;
1308 if (type ===
'RSA') {
1309 const publickey = e.detail.publickey;
1310 let fingerprint = await window.crypto.subtle.digest(
"SHA-1", publickey);
1312 fingerprint = Array.from(
new Uint8Array(fingerprint).slice(0, 8)).map(
1313 x => x.toString(16).padStart(2,
'0')).join(
'-');
1314 document.getElementById(
'noVNC_verify_server_dlg').classList.add(
'noVNC_open');
1315 document.getElementById(
'noVNC_fingerprint').innerHTML = fingerprint;
1321 document.getElementById(
'noVNC_verify_server_dlg').classList.remove(
'noVNC_open');
1322 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].approveServer() };
1327 document.getElementById(
'noVNC_verify_server_dlg').classList.remove(
'noVNC_open');
1340 document.getElementById(
"noVNC_username_block").classList.remove(
"noVNC_hidden");
1341 document.getElementById(
"noVNC_password_block").classList.remove(
"noVNC_hidden");
1343 let inputFocus =
"none";
1344 if (e.detail.types.indexOf(
"username") === -1) {
1345 document.getElementById(
"noVNC_username_block").classList.add(
"noVNC_hidden");
1347 inputFocus = inputFocus ===
"none" ?
"noVNC_username_input" : inputFocus;
1349 if (e.detail.types.indexOf(
"password") === -1) {
1350 document.getElementById(
"noVNC_password_block").classList.add(
"noVNC_hidden");
1352 inputFocus = inputFocus ===
"none" ?
"noVNC_password_input" : inputFocus;
1354 document.getElementById(
'noVNC_credentials_dlg')
1355 .classList.add(
'noVNC_open');
1357 setTimeout(() => document
1358 .getElementById(inputFocus).focus(), 100);
1360 Log.Warn(
"Server asked for credentials");
1361 UI.showStatus(_(
"Credentials are required"),
"warning");
1368 let inputElemUsername = document.getElementById(
'noVNC_username_input');
1369 const username = inputElemUsername.value;
1371 let inputElemPassword = document.getElementById(
'noVNC_password_input');
1372 const password = inputElemPassword.value;
1374 inputElemPassword.value =
"";
1376 for(var i=0; i<UI.NbRFB; i++) {
1377 if (UI.rfb[i]) UI.rfb[i].sendCredentials({ username: username, password: password });
1379 UI.reconnectPassword = password;
1380 document.getElementById(
'noVNC_credentials_dlg')
1381 .classList.remove(
'noVNC_open');
1390 toggleFullscreen() {
1391 if (document.fullscreenElement ||
1392 document.mozFullScreenElement ||
1393 document.webkitFullscreenElement ||
1394 document.msFullscreenElement) {
1395 if (document.exitFullscreen) {
1396 document.exitFullscreen();
1397 }
else if (document.mozCancelFullScreen) {
1398 document.mozCancelFullScreen();
1399 }
else if (document.webkitExitFullscreen) {
1400 document.webkitExitFullscreen();
1401 }
else if (document.msExitFullscreen) {
1402 document.msExitFullscreen();
1405 if (document.documentElement.requestFullscreen) {
1406 document.documentElement.requestFullscreen();
1407 }
else if (document.documentElement.mozRequestFullScreen) {
1408 document.documentElement.mozRequestFullScreen();
1409 }
else if (document.documentElement.webkitRequestFullscreen) {
1410 document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
1411 }
else if (document.body.msRequestFullscreen) {
1412 document.body.msRequestFullscreen();
1415 UI.updateFullscreenButton();
1418 updateFullscreenButton() {
1419 if (document.fullscreenElement ||
1420 document.mozFullScreenElement ||
1421 document.webkitFullscreenElement ||
1422 document.msFullscreenElement ) {
1423 document.getElementById(
'noVNC_fullscreen_button')
1424 .classList.add(
"noVNC_selected");
1426 document.getElementById(
'noVNC_fullscreen_button')
1427 .classList.remove(
"noVNC_selected");
1439 if (!UI.rfb || !UI.rfb[0])
return;
1441 for(var i=0; i<UI.NbRFB; i++) {
1443 UI.rfb[i].scaleViewport = UI.getSetting(
'resize') ===
'scale';
1444 UI.rfb[i].resizeSession = UI.getSetting(
'resize') ===
'remote';
1459 if (!UI.rfb || !UI.rfb[0])
return;
1461 const scaling = UI.getSetting(
'resize') ===
'scale';
1469 let brokenScrollbars =
false;
1471 if (!hasScrollbarGutter) {
1472 if (isIOS() || isAndroid() || isMac() || isChromeOS()) {
1473 brokenScrollbars =
true;
1479 UI.forceSetting(
'view_clip',
false);
1480 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].clipViewport =
false; }
1481 }
else if (brokenScrollbars) {
1482 UI.forceSetting(
'view_clip',
true);
1483 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].clipViewport =
true; }
1485 UI.enableSetting(
'view_clip');
1486 for(var i=0; i<UI.NbRFB; i++) {
if (UI.rfb[i]) UI.rfb[i].clipViewport = UI.getSetting(
'view_clip'); }
1491 UI.updateViewDrag();
1501 if (!UI.rfb || !UI.rfb[0])
return;
1503 for(var i=0; i<UI.NbRFB; i++) {
1504 if(UI.rfb[i]) UI.rfb[i].dragViewport = !UI.rfb[i].dragViewport;
1506 UI.updateViewDrag();
1510 if (!UI.connected)
return;
1512 const viewDragButton = document.getElementById(
'noVNC_view_drag_button');
1514 if ((!UI.rfb[0].clipViewport || !UI.rfb[0].clippingViewport) &&
1515 UI.rfb[0].dragViewport) {
1518 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].dragViewport =
false; }
1521 if (UI.rfb[0].dragViewport) {
1522 viewDragButton.classList.add(
"noVNC_selected");
1524 viewDragButton.classList.remove(
"noVNC_selected");
1527 if (UI.rfb[0].clipViewport) {
1528 viewDragButton.classList.remove(
"noVNC_hidden");
1530 viewDragButton.classList.add(
"noVNC_hidden");
1533 viewDragButton.disabled = !UI.rfb[0].clippingViewport;
1543 if (!UI.rfb || !UI.rfb[0])
return;
1545 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].qualityLevel = parseInt(UI.getSetting(
'quality')) };
1554 updateCompression() {
1555 if (!UI.rfb || !UI.rfb[0])
return;
1557 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].compressionLevel = parseInt(UI.getSetting(
'compression')) };
1566 showVirtualKeyboard() {
1567 if (!isTouchDevice)
return;
1569 const input = document.getElementById(
'noVNC_keyboardinput');
1571 if (document.activeElement == input)
return;
1576 const l = input.value.length;
1578 input.setSelectionRange(l, l);
1584 hideVirtualKeyboard() {
1585 if (!isTouchDevice)
return;
1587 const input = document.getElementById(
'noVNC_keyboardinput');
1589 if (document.activeElement != input)
return;
1594 toggleVirtualKeyboard() {
1595 if (document.getElementById(
'noVNC_keyboard_button')
1596 .classList.contains(
"noVNC_selected")) {
1597 UI.hideVirtualKeyboard();
1599 UI.showVirtualKeyboard();
1603 onfocusVirtualKeyboard(event) {
1604 document.getElementById(
'noVNC_keyboard_button')
1605 .classList.add(
"noVNC_selected");
1606 if (UI.rfb && UI.rfb[0]) {
1607 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].focusOnClick =
false; }
1611 onblurVirtualKeyboard(event) {
1612 document.getElementById(
'noVNC_keyboard_button')
1613 .classList.remove(
"noVNC_selected");
1614 if (UI.rfb && UI.rfb[0]) {
1615 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].focusOnClick =
true; }
1619 keepVirtualKeyboard(event) {
1620 const input = document.getElementById(
'noVNC_keyboardinput');
1623 if (document.activeElement != input) {
1629 if (event.target.form !== undefined) {
1630 switch (event.target.type) {
1639 case 'select-multiple':
1644 event.preventDefault();
1647 keyboardinputReset() {
1648 const kbi = document.getElementById(
'noVNC_keyboardinput');
1649 kbi.value =
new Array(UI.defaultKeyboardinputLen).join(
"_");
1650 UI.lastKeyboardinput = kbi.value;
1653 keyEvent(keysym, code, down) {
1654 if (!UI.rfb || !UI.rfb[0])
return;
1656 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].sendKey(keysym, code, down) };
1665 if (!UI.rfb || !UI.rfb[0])
return;
1667 const newValue =
event.target.value;
1669 if (!UI.lastKeyboardinput) {
1670 UI.keyboardinputReset();
1672 const oldValue = UI.lastKeyboardinput;
1678 newLen = Math.max(event.target.selectionStart, newValue.length);
1681 newLen = newValue.length;
1683 const oldLen = oldValue.length;
1685 let inputs = newLen - oldLen;
1686 let backspaces = inputs < 0 ? -inputs : 0;
1690 for (let i = 0; i < Math.min(oldLen, newLen); i++) {
1691 if (newValue.charAt(i) != oldValue.charAt(i)) {
1692 inputs = newLen - i;
1693 backspaces = oldLen - i;
1699 for (let i = 0; i < backspaces; i++) {
1700 for(var j=0; j<UI.NbRFB; j++) {
if(UI.rfb[j]) UI.rfb[j].sendKey(KeyTable.XK_BackSpace,
"Backspace") };
1702 for (let i = newLen - inputs; i < newLen; i++) {
1703 for(var j=0; j<UI.NbRFB; j++) {
if(UI.rfb[j]) UI.rfb[j].sendKey(keysyms.lookup(newValue.charCodeAt(i))) };
1707 if (newLen > 2 * UI.defaultKeyboardinputLen) {
1708 UI.keyboardinputReset();
1709 }
else if (newLen < 1) {
1712 UI.keyboardinputReset();
1716 event.target.blur();
1718 setTimeout(event.target.focus.bind(event.target), 0);
1720 UI.lastKeyboardinput = newValue;
1731 UI.closeAllPanels();
1732 UI.openControlbar();
1734 document.getElementById(
'noVNC_modifiers')
1735 .classList.add(
"noVNC_open");
1736 document.getElementById(
'noVNC_toggle_extra_keys_button')
1737 .classList.add(
"noVNC_selected");
1741 document.getElementById(
'noVNC_modifiers')
1742 .classList.remove(
"noVNC_open");
1743 document.getElementById(
'noVNC_toggle_extra_keys_button')
1744 .classList.remove(
"noVNC_selected");
1748 if (document.getElementById(
'noVNC_modifiers')
1749 .classList.contains(
"noVNC_open")) {
1750 UI.closeExtraKeys();
1757 UI.sendKey(KeyTable.XK_Escape,
"Escape");
1761 UI.sendKey(KeyTable.XK_Tab,
"Tab");
1765 const btn = document.getElementById(
'noVNC_toggle_ctrl_button');
1766 if (btn.classList.contains(
"noVNC_selected")) {
1767 UI.sendKey(KeyTable.XK_Control_L,
"ControlLeft",
false);
1768 btn.classList.remove(
"noVNC_selected");
1770 UI.sendKey(KeyTable.XK_Control_L,
"ControlLeft",
true);
1771 btn.classList.add(
"noVNC_selected");
1776 const btn = document.getElementById(
'noVNC_toggle_windows_button');
1777 if (btn.classList.contains(
"noVNC_selected")) {
1778 UI.sendKey(KeyTable.XK_Super_L,
"MetaLeft",
false);
1779 btn.classList.remove(
"noVNC_selected");
1781 UI.sendKey(KeyTable.XK_Super_L,
"MetaLeft",
true);
1782 btn.classList.add(
"noVNC_selected");
1787 const btn = document.getElementById(
'noVNC_toggle_alt_button');
1788 if (btn.classList.contains(
"noVNC_selected")) {
1789 UI.sendKey(KeyTable.XK_Alt_L,
"AltLeft",
false);
1790 btn.classList.remove(
"noVNC_selected");
1792 UI.sendKey(KeyTable.XK_Alt_L,
"AltLeft",
true);
1793 btn.classList.add(
"noVNC_selected");
1798 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].sendCtrlAltDel() };
1800 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].focus() };
1801 UI.idleControlbar();
1804 sendKey(keysym, code, down) {
1805 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].sendKey(keysym, code, down) };
1813 if (document.getElementById(
'noVNC_keyboard_button')
1814 .classList.contains(
"noVNC_selected")) {
1815 document.getElementById(
'noVNC_keyboardinput').focus();
1817 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].focus() };
1821 UI.idleControlbar();
1831 if (!UI.rfb || !UI.rfb[0])
return;
1833 for(var i=0; i<UI.NbRFB; i++) {
1834 if(UI.rfb[i]) UI.rfb[i].viewOnly = UI.getSetting(
'view_only');
1837 UI.updateBeforeUnload();
1840 if (UI.rfb[0].viewOnly) {
1841 document.getElementById(
'noVNC_keyboard_button')
1842 .classList.add(
'noVNC_hidden');
1843 document.getElementById(
'noVNC_toggle_extra_keys_button')
1844 .classList.add(
'noVNC_hidden');
1845 document.getElementById(
'noVNC_clipboard_button')
1846 .classList.add(
'noVNC_hidden');
1848 document.getElementById(
'noVNC_keyboard_button')
1849 .classList.remove(
'noVNC_hidden');
1850 document.getElementById(
'noVNC_toggle_extra_keys_button')
1851 .classList.remove(
'noVNC_hidden');
1852 document.getElementById(
'noVNC_clipboard_button')
1853 .classList.remove(
'noVNC_hidden');
1857 updateShowDotCursor() {
1858 if (!UI.rfb || !UI.rfb[0])
return;
1859 for(var i=0; i<UI.NbRFB; i++) {
if(UI.rfb[i]) UI.rfb[i].showDotCursor = UI.getSetting(
'show_dot') };
1863 WebUtil.initLogging(UI.getSetting(
'logging'));
1866 updateDesktopName(e) {
1867 UI.desktopName = e.detail.name;
1869 document.title = e.detail.name +
" - " + PAGE_TITLE;
1873 if (UI.getSetting(
'bell') ===
'on') {
1874 const promise = document.getElementById(
'noVNC_bell').play();
1877 promise.catch((e) => {
1878 if (e.name ===
"NotAllowedError") {
1883 Log.Error(
"Unable to play bell: " + e);
1891 addOption(selectbox, text, value) {
1892 const optn = document.createElement(
"OPTION");
1895 selectbox.options.add(optn);