ui.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /*
  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)
  6. *
  7. * See README.md for usage and integration instructions.
  8. */
  9. "use strict";
  10. /*jslint white: false, browser: true */
  11. /*global window, $D, Util, WebUtil, RFB, Display */
  12. // Load supporting scripts
  13. window.onscriptsload = function () { UI.load(); };
  14. Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
  15. "input.js", "display.js", "jsunzip.js", "rfb.js",
  16. "keysym.js"]);
  17. var UI = {
  18. rfb_state : 'loaded',
  19. settingsOpen : false,
  20. connSettingsOpen : false,
  21. popupStatusOpen : false,
  22. clipboardOpen: false,
  23. keyboardVisible: false,
  24. hideKeyboardTimeout: null,
  25. extraKeysVisible: false,
  26. ctrlOn: false,
  27. altOn: false,
  28. // Setup rfb object, load settings from browser storage, then call
  29. // UI.init to setup the UI/menus
  30. load: function (callback) {
  31. WebUtil.initSettings(UI.start, callback);
  32. },
  33. // Render default UI and initialize settings menu
  34. start: function(callback) {
  35. var html = '', i, sheet, sheets, llevels, port;
  36. // Stylesheet selection dropdown
  37. sheet = WebUtil.selectStylesheet();
  38. sheets = WebUtil.getStylesheets();
  39. for (i = 0; i < sheets.length; i += 1) {
  40. UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
  41. }
  42. // Logging selection dropdown
  43. llevels = ['error', 'warn', 'info', 'debug'];
  44. for (i = 0; i < llevels.length; i += 1) {
  45. UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
  46. }
  47. // Settings with immediate effects
  48. UI.initSetting('logging', 'warn');
  49. WebUtil.init_logging(UI.getSetting('logging'));
  50. UI.initSetting('stylesheet', 'default');
  51. WebUtil.selectStylesheet(null);
  52. // call twice to get around webkit bug
  53. WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
  54. // if port == 80 (or 443) then it won't be present and should be
  55. // set manually
  56. port = window.location.port;
  57. if (!port) {
  58. if (window.location.protocol.substring(0,5) == 'https') {
  59. port = 443;
  60. }
  61. else if (window.location.protocol.substring(0,4) == 'http') {
  62. port = 80;
  63. }
  64. }
  65. /* Populate the controls if defaults are provided in the URL */
  66. UI.initSetting('host', window.location.hostname);
  67. UI.initSetting('port', port);
  68. UI.initSetting('password', '');
  69. UI.initSetting('encrypt', (window.location.protocol === "https:"));
  70. UI.initSetting('true_color', true);
  71. UI.initSetting('cursor', false);
  72. UI.initSetting('shared', true);
  73. UI.initSetting('view_only', false);
  74. UI.initSetting('connectTimeout', 2);
  75. UI.initSetting('path', 'websockify');
  76. UI.initSetting('repeaterID', '');
  77. UI.rfb = RFB({'target': $D('noVNC_canvas'),
  78. 'onUpdateState': UI.updateState,
  79. 'onClipboard': UI.clipReceive,
  80. 'onDesktopName': UI.updateDocumentTitle});
  81. UI.updateVisualState();
  82. // Unfocus clipboard when over the VNC area
  83. //$D('VNC_screen').onmousemove = function () {
  84. // var keyboard = UI.rfb.get_keyboard();
  85. // if ((! keyboard) || (! keyboard.get_focused())) {
  86. // $D('VNC_clipboard_text').blur();
  87. // }
  88. // };
  89. // Show mouse selector buttons on touch screen devices
  90. if ('ontouchstart' in document.documentElement) {
  91. // Show mobile buttons
  92. $D('noVNC_mobile_buttons').style.display = "inline";
  93. UI.setMouseButton();
  94. // Remove the address bar
  95. setTimeout(function() { window.scrollTo(0, 1); }, 100);
  96. UI.forceSetting('clip', true);
  97. $D('noVNC_clip').disabled = true;
  98. } else {
  99. UI.initSetting('clip', false);
  100. }
  101. //iOS Safari does not support CSS position:fixed.
  102. //This detects iOS devices and enables javascript workaround.
  103. if ((navigator.userAgent.match(/iPhone/i)) ||
  104. (navigator.userAgent.match(/iPod/i)) ||
  105. (navigator.userAgent.match(/iPad/i))) {
  106. //UI.setOnscroll();
  107. //UI.setResize();
  108. }
  109. UI.setBarPosition();
  110. $D('noVNC_host').focus();
  111. UI.setViewClip();
  112. Util.addEvent(window, 'resize', UI.setViewClip);
  113. Util.addEvent(window, 'beforeunload', function () {
  114. if (UI.rfb_state === 'normal') {
  115. return "You are currently connected.";
  116. }
  117. } );
  118. // Show description by default when hosted at for kanaka.github.com
  119. if (location.host === "kanaka.github.com") {
  120. // Open the description dialog
  121. $D('noVNC_description').style.display = "block";
  122. } else {
  123. // Open the connect panel on first load
  124. UI.toggleConnectPanel();
  125. }
  126. // Add mouse event click/focus/blur event handlers to the UI
  127. UI.addMouseHandlers();
  128. if (typeof callback === "function") {
  129. callback(UI.rfb);
  130. }
  131. },
  132. addMouseHandlers: function() {
  133. // Setup interface handlers that can't be inline
  134. $D("noVNC_view_drag_button").onclick = UI.setViewDrag;
  135. $D("noVNC_mouse_button0").onclick = function () { UI.setMouseButton(1); };
  136. $D("noVNC_mouse_button1").onclick = function () { UI.setMouseButton(2); };
  137. $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); };
  138. $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); };
  139. $D("showKeyboard").onclick = UI.showKeyboard;
  140. //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); };
  141. $D("keyboardinput").onblur = UI.keyInputBlur;
  142. $D("showExtraKeysButton").onclick = UI.showExtraKeys;
  143. $D("toggleCtrlButton").onclick = UI.toggleCtrl;
  144. $D("toggleAltButton").onclick = UI.toggleAlt;
  145. $D("sendTabButton").onclick = UI.sendTab;
  146. $D("sendEscButton").onclick = UI.sendEsc;
  147. $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel;
  148. $D("noVNC_status").onclick = UI.togglePopupStatusPanel;
  149. $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel;
  150. $D("clipboardButton").onclick = UI.toggleClipboardPanel;
  151. $D("settingsButton").onclick = UI.toggleSettingsPanel;
  152. $D("connectButton").onclick = UI.toggleConnectPanel;
  153. $D("disconnectButton").onclick = UI.disconnect;
  154. $D("descriptionButton").onclick = UI.toggleConnectPanel;
  155. $D("noVNC_clipboard_text").onfocus = UI.displayBlur;
  156. $D("noVNC_clipboard_text").onblur = UI.displayFocus;
  157. $D("noVNC_clipboard_text").onchange = UI.clipSend;
  158. $D("noVNC_clipboard_clear_button").onclick = UI.clipClear;
  159. $D("noVNC_settings_menu").onmouseover = UI.displayBlur;
  160. $D("noVNC_settings_menu").onmouseover = UI.displayFocus;
  161. $D("noVNC_apply").onclick = UI.settingsApply;
  162. $D("noVNC_connect_button").onclick = UI.connect;
  163. },
  164. // Read form control compatible setting from cookie
  165. getSetting: function(name) {
  166. var val, ctrl = $D('noVNC_' + name);
  167. val = WebUtil.readSetting(name);
  168. if (val !== null && ctrl.type === 'checkbox') {
  169. if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
  170. val = false;
  171. } else {
  172. val = true;
  173. }
  174. }
  175. return val;
  176. },
  177. // Update cookie and form control setting. If value is not set, then
  178. // updates from control to current cookie setting.
  179. updateSetting: function(name, value) {
  180. var i, ctrl = $D('noVNC_' + name);
  181. // Save the cookie for this session
  182. if (typeof value !== 'undefined') {
  183. WebUtil.writeSetting(name, value);
  184. }
  185. // Update the settings control
  186. value = UI.getSetting(name);
  187. if (ctrl.type === 'checkbox') {
  188. ctrl.checked = value;
  189. } else if (typeof ctrl.options !== 'undefined') {
  190. for (i = 0; i < ctrl.options.length; i += 1) {
  191. if (ctrl.options[i].value === value) {
  192. ctrl.selectedIndex = i;
  193. break;
  194. }
  195. }
  196. } else {
  197. /*Weird IE9 error leads to 'null' appearring
  198. in textboxes instead of ''.*/
  199. if (value === null) {
  200. value = "";
  201. }
  202. ctrl.value = value;
  203. }
  204. },
  205. // Save control setting to cookie
  206. saveSetting: function(name) {
  207. var val, ctrl = $D('noVNC_' + name);
  208. if (ctrl.type === 'checkbox') {
  209. val = ctrl.checked;
  210. } else if (typeof ctrl.options !== 'undefined') {
  211. val = ctrl.options[ctrl.selectedIndex].value;
  212. } else {
  213. val = ctrl.value;
  214. }
  215. WebUtil.writeSetting(name, val);
  216. //Util.Debug("Setting saved '" + name + "=" + val + "'");
  217. return val;
  218. },
  219. // Initial page load read/initialization of settings
  220. initSetting: function(name, defVal) {
  221. var val;
  222. // Check Query string followed by cookie
  223. val = WebUtil.getQueryVar(name);
  224. if (val === null) {
  225. val = WebUtil.readSetting(name, defVal);
  226. }
  227. UI.updateSetting(name, val);
  228. //Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
  229. return val;
  230. },
  231. // Force a setting to be a certain value
  232. forceSetting: function(name, val) {
  233. UI.updateSetting(name, val);
  234. return val;
  235. },
  236. // Show the popup status panel
  237. togglePopupStatusPanel: function() {
  238. var psp = $D('noVNC_popup_status_panel');
  239. if (UI.popupStatusOpen === true) {
  240. psp.style.display = "none";
  241. UI.popupStatusOpen = false;
  242. } else {
  243. psp.innerHTML = $D('noVNC_status').innerHTML;
  244. psp.style.display = "block";
  245. psp.style.left = window.innerWidth/2 -
  246. parseInt(window.getComputedStyle(psp, false).width)/2 -30 + "px";
  247. UI.popupStatusOpen = true;
  248. }
  249. },
  250. // Show the clipboard panel
  251. toggleClipboardPanel: function() {
  252. // Close the description panel
  253. $D('noVNC_description').style.display = "none";
  254. // Close settings if open
  255. if (UI.settingsOpen === true) {
  256. UI.settingsApply();
  257. UI.closeSettingsMenu();
  258. }
  259. // Close connection settings if open
  260. if (UI.connSettingsOpen === true) {
  261. UI.toggleConnectPanel();
  262. }
  263. // Close popup status panel if open
  264. if (UI.popupStatusOpen === true) {
  265. UI.togglePopupStatusPanel();
  266. }
  267. // Toggle Clipboard Panel
  268. if (UI.clipboardOpen === true) {
  269. $D('noVNC_clipboard').style.display = "none";
  270. $D('clipboardButton').className = "noVNC_status_button";
  271. UI.clipboardOpen = false;
  272. } else {
  273. $D('noVNC_clipboard').style.display = "block";
  274. $D('clipboardButton').className = "noVNC_status_button_selected";
  275. UI.clipboardOpen = true;
  276. }
  277. },
  278. // Show the connection settings panel/menu
  279. toggleConnectPanel: function() {
  280. // Close the description panel
  281. $D('noVNC_description').style.display = "none";
  282. // Close connection settings if open
  283. if (UI.settingsOpen === true) {
  284. UI.settingsApply();
  285. UI.closeSettingsMenu();
  286. $D('connectButton').className = "noVNC_status_button";
  287. }
  288. // Close clipboard panel if open
  289. if (UI.clipboardOpen === true) {
  290. UI.toggleClipboardPanel();
  291. }
  292. // Close popup status panel if open
  293. if (UI.popupStatusOpen === true) {
  294. UI.togglePopupStatusPanel();
  295. }
  296. // Toggle Connection Panel
  297. if (UI.connSettingsOpen === true) {
  298. $D('noVNC_controls').style.display = "none";
  299. $D('connectButton').className = "noVNC_status_button";
  300. UI.connSettingsOpen = false;
  301. UI.saveSetting('host');
  302. UI.saveSetting('port');
  303. //UI.saveSetting('password');
  304. } else {
  305. $D('noVNC_controls').style.display = "block";
  306. $D('connectButton').className = "noVNC_status_button_selected";
  307. UI.connSettingsOpen = true;
  308. $D('noVNC_host').focus();
  309. }
  310. },
  311. // Toggle the settings menu:
  312. // On open, settings are refreshed from saved cookies.
  313. // On close, settings are applied
  314. toggleSettingsPanel: function() {
  315. // Close the description panel
  316. $D('noVNC_description').style.display = "none";
  317. if (UI.settingsOpen) {
  318. UI.settingsApply();
  319. UI.closeSettingsMenu();
  320. } else {
  321. UI.updateSetting('encrypt');
  322. UI.updateSetting('true_color');
  323. if (UI.rfb.get_display().get_cursor_uri()) {
  324. UI.updateSetting('cursor');
  325. } else {
  326. UI.updateSetting('cursor', false);
  327. $D('noVNC_cursor').disabled = true;
  328. }
  329. UI.updateSetting('clip');
  330. UI.updateSetting('shared');
  331. UI.updateSetting('view_only');
  332. UI.updateSetting('connectTimeout');
  333. UI.updateSetting('path');
  334. UI.updateSetting('repeaterID');
  335. UI.updateSetting('stylesheet');
  336. UI.updateSetting('logging');
  337. UI.openSettingsMenu();
  338. }
  339. },
  340. // Open menu
  341. openSettingsMenu: function() {
  342. // Close the description panel
  343. $D('noVNC_description').style.display = "none";
  344. // Close clipboard panel if open
  345. if (UI.clipboardOpen === true) {
  346. UI.toggleClipboardPanel();
  347. }
  348. // Close connection settings if open
  349. if (UI.connSettingsOpen === true) {
  350. UI.toggleConnectPanel();
  351. }
  352. // Close popup status panel if open
  353. if (UI.popupStatusOpen === true) {
  354. UI.togglePopupStatusPanel();
  355. }
  356. $D('noVNC_settings').style.display = "block";
  357. $D('settingsButton').className = "noVNC_status_button_selected";
  358. UI.settingsOpen = true;
  359. },
  360. // Close menu (without applying settings)
  361. closeSettingsMenu: function() {
  362. $D('noVNC_settings').style.display = "none";
  363. $D('settingsButton').className = "noVNC_status_button";
  364. UI.settingsOpen = false;
  365. },
  366. // Save/apply settings when 'Apply' button is pressed
  367. settingsApply: function() {
  368. //Util.Debug(">> settingsApply");
  369. UI.saveSetting('encrypt');
  370. UI.saveSetting('true_color');
  371. if (UI.rfb.get_display().get_cursor_uri()) {
  372. UI.saveSetting('cursor');
  373. }
  374. UI.saveSetting('clip');
  375. UI.saveSetting('shared');
  376. UI.saveSetting('view_only');
  377. UI.saveSetting('connectTimeout');
  378. UI.saveSetting('path');
  379. UI.saveSetting('repeaterID');
  380. UI.saveSetting('stylesheet');
  381. UI.saveSetting('logging');
  382. // Settings with immediate (non-connected related) effect
  383. WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
  384. WebUtil.init_logging(UI.getSetting('logging'));
  385. UI.setViewClip();
  386. UI.setViewDrag(UI.rfb.get_viewportDrag());
  387. //Util.Debug("<< settingsApply");
  388. },
  389. setPassword: function() {
  390. UI.rfb.sendPassword($D('noVNC_password').value);
  391. //Reset connect button.
  392. $D('noVNC_connect_button').value = "Connect";
  393. $D('noVNC_connect_button').onclick = UI.Connect;
  394. //Hide connection panel.
  395. UI.toggleConnectPanel();
  396. return false;
  397. },
  398. sendCtrlAltDel: function() {
  399. UI.rfb.sendCtrlAltDel();
  400. },
  401. setMouseButton: function(num) {
  402. var b, blist = [0, 1,2,4], button;
  403. if (typeof num === 'undefined') {
  404. // Disable mouse buttons
  405. num = -1;
  406. }
  407. if (UI.rfb) {
  408. UI.rfb.get_mouse().set_touchButton(num);
  409. }
  410. for (b = 0; b < blist.length; b++) {
  411. button = $D('noVNC_mouse_button' + blist[b]);
  412. if (blist[b] === num) {
  413. button.style.display = "";
  414. } else {
  415. button.style.display = "none";
  416. /*
  417. button.style.backgroundColor = "black";
  418. button.style.color = "lightgray";
  419. button.style.backgroundColor = "";
  420. button.style.color = "";
  421. */
  422. }
  423. }
  424. },
  425. updateState: function(rfb, state, oldstate, msg) {
  426. var s, sb, c, d, cad, vd, klass;
  427. UI.rfb_state = state;
  428. switch (state) {
  429. case 'failed':
  430. case 'fatal':
  431. klass = "noVNC_status_error";
  432. break;
  433. case 'normal':
  434. klass = "noVNC_status_normal";
  435. break;
  436. case 'disconnected':
  437. $D('noVNC_logo').style.display = "block";
  438. // Fall through
  439. case 'loaded':
  440. klass = "noVNC_status_normal";
  441. break;
  442. case 'password':
  443. UI.toggleConnectPanel();
  444. $D('noVNC_connect_button').value = "Send Password";
  445. $D('noVNC_connect_button').onclick = UI.setPassword;
  446. $D('noVNC_password').focus();
  447. klass = "noVNC_status_warn";
  448. break;
  449. default:
  450. klass = "noVNC_status_warn";
  451. break;
  452. }
  453. if (typeof(msg) !== 'undefined') {
  454. $D('noVNC-control-bar').setAttribute("class", klass);
  455. $D('noVNC_status').innerHTML = msg;
  456. }
  457. UI.updateVisualState();
  458. },
  459. // Disable/enable controls depending on connection state
  460. updateVisualState: function() {
  461. var connected = UI.rfb_state === 'normal' ? true : false;
  462. //Util.Debug(">> updateVisualState");
  463. $D('noVNC_encrypt').disabled = connected;
  464. $D('noVNC_true_color').disabled = connected;
  465. if (UI.rfb && UI.rfb.get_display() &&
  466. UI.rfb.get_display().get_cursor_uri()) {
  467. $D('noVNC_cursor').disabled = connected;
  468. } else {
  469. UI.updateSetting('cursor', false);
  470. $D('noVNC_cursor').disabled = true;
  471. }
  472. $D('noVNC_shared').disabled = connected;
  473. $D('noVNC_view_only').disabled = connected;
  474. $D('noVNC_connectTimeout').disabled = connected;
  475. $D('noVNC_path').disabled = connected;
  476. $D('noVNC_repeaterID').disabled = connected;
  477. if (connected) {
  478. UI.setViewClip();
  479. UI.setMouseButton(1);
  480. $D('clipboardButton').style.display = "inline";
  481. $D('showKeyboard').style.display = "inline";
  482. $D('noVNC_extra_keys').style.display = "";
  483. $D('sendCtrlAltDelButton').style.display = "inline";
  484. } else {
  485. UI.setMouseButton();
  486. $D('clipboardButton').style.display = "none";
  487. $D('showKeyboard').style.display = "none";
  488. $D('noVNC_extra_keys').style.display = "none";
  489. $D('sendCtrlAltDelButton').style.display = "none";
  490. }
  491. // State change disables viewport dragging.
  492. // It is enabled (toggled) by direct click on the button
  493. UI.setViewDrag(false);
  494. switch (UI.rfb_state) {
  495. case 'fatal':
  496. case 'failed':
  497. case 'loaded':
  498. case 'disconnected':
  499. $D('connectButton').style.display = "";
  500. $D('disconnectButton').style.display = "none";
  501. break;
  502. default:
  503. $D('connectButton').style.display = "none";
  504. $D('disconnectButton').style.display = "";
  505. break;
  506. }
  507. //Util.Debug("<< updateVisualState");
  508. },
  509. // Display the desktop name in the document title
  510. updateDocumentTitle: function(rfb, name) {
  511. document.title = name + " - noVNC";
  512. },
  513. clipReceive: function(rfb, text) {
  514. Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
  515. $D('noVNC_clipboard_text').value = text;
  516. Util.Debug("<< UI.clipReceive");
  517. },
  518. connect: function() {
  519. var host, port, password, path;
  520. UI.closeSettingsMenu();
  521. UI.toggleConnectPanel();
  522. host = $D('noVNC_host').value;
  523. port = $D('noVNC_port').value;
  524. password = $D('noVNC_password').value;
  525. path = $D('noVNC_path').value;
  526. if ((!host) || (!port)) {
  527. throw("Must set host and port");
  528. }
  529. UI.rfb.set_encrypt(UI.getSetting('encrypt'));
  530. UI.rfb.set_true_color(UI.getSetting('true_color'));
  531. UI.rfb.set_local_cursor(UI.getSetting('cursor'));
  532. UI.rfb.set_shared(UI.getSetting('shared'));
  533. UI.rfb.set_view_only(UI.getSetting('view_only'));
  534. UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
  535. UI.rfb.set_repeaterID(UI.getSetting('repeaterID'));
  536. UI.rfb.connect(host, port, password, path);
  537. //Close dialog.
  538. setTimeout(UI.setBarPosition, 100);
  539. $D('noVNC_logo').style.display = "none";
  540. },
  541. disconnect: function() {
  542. UI.closeSettingsMenu();
  543. UI.rfb.disconnect();
  544. $D('noVNC_logo').style.display = "block";
  545. UI.connSettingsOpen = false;
  546. UI.toggleConnectPanel();
  547. },
  548. displayBlur: function() {
  549. UI.rfb.get_keyboard().set_focused(false);
  550. UI.rfb.get_mouse().set_focused(false);
  551. },
  552. displayFocus: function() {
  553. UI.rfb.get_keyboard().set_focused(true);
  554. UI.rfb.get_mouse().set_focused(true);
  555. },
  556. clipClear: function() {
  557. $D('noVNC_clipboard_text').value = "";
  558. UI.rfb.clipboardPasteFrom("");
  559. },
  560. clipSend: function() {
  561. var text = $D('noVNC_clipboard_text').value;
  562. Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "...");
  563. UI.rfb.clipboardPasteFrom(text);
  564. Util.Debug("<< UI.clipSend");
  565. },
  566. // Enable/disable and configure viewport clipping
  567. setViewClip: function(clip) {
  568. var display, cur_clip, pos, new_w, new_h;
  569. if (UI.rfb) {
  570. display = UI.rfb.get_display();
  571. } else {
  572. return;
  573. }
  574. cur_clip = display.get_viewport();
  575. if (typeof(clip) !== 'boolean') {
  576. // Use current setting
  577. clip = UI.getSetting('clip');
  578. }
  579. if (clip && !cur_clip) {
  580. // Turn clipping on
  581. UI.updateSetting('clip', true);
  582. } else if (!clip && cur_clip) {
  583. // Turn clipping off
  584. UI.updateSetting('clip', false);
  585. display.set_viewport(false);
  586. $D('noVNC_canvas').style.position = 'static';
  587. display.viewportChange();
  588. }
  589. if (UI.getSetting('clip')) {
  590. // If clipping, update clipping settings
  591. $D('noVNC_canvas').style.position = 'absolute';
  592. pos = Util.getPosition($D('noVNC_canvas'));
  593. new_w = window.innerWidth - pos.x;
  594. new_h = window.innerHeight - pos.y;
  595. display.set_viewport(true);
  596. display.viewportChange(0, 0, new_w, new_h);
  597. }
  598. },
  599. // Toggle/set/unset the viewport drag/move button
  600. setViewDrag: function(drag) {
  601. var vmb = $D('noVNC_view_drag_button');
  602. if (!UI.rfb) { return; }
  603. if (UI.rfb_state === 'normal' &&
  604. UI.rfb.get_display().get_viewport()) {
  605. vmb.style.display = "inline";
  606. } else {
  607. vmb.style.display = "none";
  608. }
  609. if (typeof(drag) === "undefined" ||
  610. typeof(drag) === "object") {
  611. // If not specified, then toggle
  612. drag = !UI.rfb.get_viewportDrag();
  613. }
  614. if (drag) {
  615. vmb.className = "noVNC_status_button_selected";
  616. UI.rfb.set_viewportDrag(true);
  617. } else {
  618. vmb.className = "noVNC_status_button";
  619. UI.rfb.set_viewportDrag(false);
  620. }
  621. },
  622. // On touch devices, show the OS keyboard
  623. showKeyboard: function() {
  624. if(UI.keyboardVisible === false) {
  625. $D('keyboardinput').focus();
  626. UI.keyboardVisible = true;
  627. $D('showKeyboard').className = "noVNC_status_button_selected";
  628. } else if(UI.keyboardVisible === true) {
  629. $D('keyboardinput').blur();
  630. $D('showKeyboard').className = "noVNC_status_button";
  631. UI.keyboardVisible = false;
  632. }
  633. },
  634. keepKeyboard: function() {
  635. clearTimeout(UI.hideKeyboardTimeout);
  636. if(UI.keyboardVisible === true) {
  637. $D('keyboardinput').focus();
  638. $D('showKeyboard').className = "noVNC_status_button_selected";
  639. } else if(UI.keyboardVisible === false) {
  640. $D('keyboardinput').blur();
  641. $D('showKeyboard').className = "noVNC_status_button";
  642. }
  643. },
  644. keyInputBlur: function() {
  645. $D('showKeyboard').className = "noVNC_status_button";
  646. //Weird bug in iOS if you change keyboardVisible
  647. //here it does not actually occur so next time
  648. //you click keyboard icon it doesnt work.
  649. UI.hideKeyboardTimeout = setTimeout(function() { UI.setKeyboard(); },100);
  650. },
  651. showExtraKeys: function() {
  652. UI.keepKeyboard();
  653. if(UI.extraKeysVisible === false) {
  654. $D('toggleCtrlButton').style.display = "inline";
  655. $D('toggleAltButton').style.display = "inline";
  656. $D('sendTabButton').style.display = "inline";
  657. $D('sendEscButton').style.display = "inline";
  658. $D('showExtraKeysButton').className = "noVNC_status_button_selected";
  659. UI.extraKeysVisible = true;
  660. } else if(UI.extraKeysVisible === true) {
  661. $D('toggleCtrlButton').style.display = "";
  662. $D('toggleAltButton').style.display = "";
  663. $D('sendTabButton').style.display = "";
  664. $D('sendEscButton').style.display = "";
  665. $D('showExtraKeysButton').className = "noVNC_status_button";
  666. UI.extraKeysVisible = false;
  667. }
  668. },
  669. toggleCtrl: function() {
  670. UI.keepKeyboard();
  671. if(UI.ctrlOn === false) {
  672. UI.rfb.sendKey(XK_Control_L, true);
  673. $D('toggleCtrlButton').className = "noVNC_status_button_selected";
  674. UI.ctrlOn = true;
  675. } else if(UI.ctrlOn === true) {
  676. UI.rfb.sendKey(XK_Control_L, false);
  677. $D('toggleCtrlButton').className = "noVNC_status_button";
  678. UI.ctrlOn = false;
  679. }
  680. },
  681. toggleAlt: function() {
  682. UI.keepKeyboard();
  683. if(UI.altOn === false) {
  684. UI.rfb.sendKey(XK_Alt_L, true);
  685. $D('toggleAltButton').className = "noVNC_status_button_selected";
  686. UI.altOn = true;
  687. } else if(UI.altOn === true) {
  688. UI.rfb.sendKey(XK_Alt_L, false);
  689. $D('toggleAltButton').className = "noVNC_status_button";
  690. UI.altOn = false;
  691. }
  692. },
  693. sendTab: function() {
  694. UI.keepKeyboard();
  695. UI.rfb.sendKey(XK_Tab);
  696. },
  697. sendEsc: function() {
  698. UI.keepKeyboard();
  699. UI.rfb.sendKey(XK_Escape);
  700. },
  701. setKeyboard: function() {
  702. UI.keyboardVisible = false;
  703. },
  704. // iOS < Version 5 does not support position fixed. Javascript workaround:
  705. setOnscroll: function() {
  706. window.onscroll = function() {
  707. UI.setBarPosition();
  708. };
  709. },
  710. setResize: function () {
  711. window.onResize = function() {
  712. UI.setBarPosition();
  713. };
  714. },
  715. //Helper to add options to dropdown.
  716. addOption: function(selectbox,text,value )
  717. {
  718. var optn = document.createElement("OPTION");
  719. optn.text = text;
  720. optn.value = value;
  721. selectbox.options.add(optn);
  722. },
  723. setBarPosition: function() {
  724. $D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px';
  725. $D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px';
  726. var vncwidth = $D('noVNC_screen').style.offsetWidth;
  727. $D('noVNC-control-bar').style.width = vncwidth + 'px';
  728. }
  729. };