ui.js 27 KB

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