ui.js 25 KB

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