input.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * noVNC: HTML5 VNC client
  3. * Copyright (C) 2011 Joel Martin
  4. * Licensed under LGPL-3 (see LICENSE.txt)
  5. */
  6. /*jslint browser: true, white: false, bitwise: false */
  7. /*global window, Util */
  8. //
  9. // Keyboard event handler
  10. //
  11. function Keyboard(conf) {
  12. "use strict";
  13. conf = conf || {}; // Configuration
  14. var that = {}; // Public API interface
  15. // Configuration settings
  16. function cdef(v, type, defval, desc) {
  17. Util.conf_default(conf, that, v, type, defval, desc); }
  18. // Capability settings, default can be overridden
  19. cdef('target', 'dom', document, 'DOM element that grabs keyboard input');
  20. cdef('focused', 'bool', true, 'Capture and send key strokes');
  21. cdef('keyPress', 'func', null, 'Handler for key press/release');
  22. that.set_target = function () { throw("target cannot be changed"); }
  23. //
  24. // Private functions
  25. //
  26. function onKeyDown(e) {
  27. //Util.Debug("keydown: " + that.getKeysym(e));
  28. if (! conf.focused) {
  29. return true;
  30. }
  31. if (conf.keyPress) {
  32. conf.keyPress(that.getKeysym(e), 1, e.ctrlKey, e.shiftKey, e.altKey);
  33. }
  34. Util.stopEvent(e);
  35. return false;
  36. }
  37. function onKeyUp(e) {
  38. //Util.Debug("keyup: " + that.getKeysym(e));
  39. if (! conf.focused) {
  40. return true;
  41. }
  42. if (conf.keyPress) {
  43. conf.keyPress(that.getKeysym(e), 0, e.ctrlKey, e.shiftKey, e.altKey);
  44. }
  45. Util.stopEvent(e);
  46. return false;
  47. }
  48. function onKeyPress(e) {
  49. //Util.Debug("keypress: " + e.charCode);
  50. if (! conf.focused) {
  51. return true;
  52. }
  53. // Stop keypress events. Necessary for Opera because stopping
  54. // keydown and keyup events still results in a keypress event.
  55. Util.stopEvent(e);
  56. return false;
  57. }
  58. //
  59. // Public API interface functions
  60. //
  61. /* Translate DOM key down/up event to keysym value */
  62. that.getKeysym = function getKeysym(e) {
  63. var evt, keysym;
  64. evt = (e ? e : window.event);
  65. /*
  66. Util.Debug(">> getKeysym - keyCode: " + evt.keyCode + ", which: " + evt.which +
  67. ", charCode: " + evt.charCode + ", keyIdentifier: " + evt.keyIdentifier +
  68. ", altKey: " + evt.altKey + ", ctrlKey: " + evt.ctrlKey +
  69. ", shiftKey: " + evt.shiftKey + ", metaKey: " + evt.metaKey +
  70. ", type: " + evt.type + ", keyLocation: " + evt.keyLocation);
  71. */
  72. /* Remap modifier and special keys */
  73. switch ( evt.keyCode ) {
  74. case 8 : keysym = 0xFF08; break; // BACKSPACE
  75. case 9 : keysym = 0xFF09; break; // TAB
  76. case 13 : keysym = 0xFF0D; break; // ENTER
  77. case 27 : keysym = 0xFF1B; break; // ESCAPE
  78. case 45 : keysym = 0xFF63; break; // INSERT
  79. case 46 : keysym = 0xFFFF; break; // DELETE
  80. case 36 : keysym = 0xFF50; break; // HOME
  81. case 35 : keysym = 0xFF57; break; // END
  82. case 33 : keysym = 0xFF55; break; // PAGE_UP
  83. case 34 : keysym = 0xFF56; break; // PAGE_DOWN
  84. case 37 : keysym = 0xFF51; break; // LEFT
  85. case 38 : keysym = 0xFF52; break; // UP
  86. case 39 : keysym = 0xFF53; break; // RIGHT
  87. case 40 : keysym = 0xFF54; break; // DOWN
  88. case 112 : keysym = 0xFFBE; break; // F1
  89. case 113 : keysym = 0xFFBF; break; // F2
  90. case 114 : keysym = 0xFFC0; break; // F3
  91. case 115 : keysym = 0xFFC1; break; // F4
  92. case 116 : keysym = 0xFFC2; break; // F5
  93. case 117 : keysym = 0xFFC3; break; // F6
  94. case 118 : keysym = 0xFFC4; break; // F7
  95. case 119 : keysym = 0xFFC5; break; // F8
  96. case 120 : keysym = 0xFFC6; break; // F9
  97. case 121 : keysym = 0xFFC7; break; // F10
  98. case 122 : keysym = 0xFFC8; break; // F11
  99. case 123 : keysym = 0xFFC9; break; // F12
  100. case 16 : keysym = 0xFFE1; break; // SHIFT
  101. case 17 : keysym = 0xFFE3; break; // CONTROL
  102. //case 18 : keysym = 0xFFE7; break; // Left Meta (Mac Option)
  103. case 18 : keysym = 0xFFE9; break; // Left ALT (Mac Command)
  104. default : keysym = evt.keyCode; break;
  105. }
  106. /* Remap symbols */
  107. switch (keysym) {
  108. case 186 : keysym = 59; break; // ; (IE)
  109. case 187 : keysym = 61; break; // = (IE)
  110. case 188 : keysym = 44; break; // , (Mozilla, IE)
  111. case 109 : // - (Mozilla, Opera)
  112. if (Util.Engine.gecko || Util.Engine.presto) {
  113. keysym = 45; }
  114. break;
  115. case 189 : keysym = 45; break; // - (IE)
  116. case 190 : keysym = 46; break; // . (Mozilla, IE)
  117. case 191 : keysym = 47; break; // / (Mozilla, IE)
  118. case 192 : keysym = 96; break; // ` (Mozilla, IE)
  119. case 219 : keysym = 91; break; // [ (Mozilla, IE)
  120. case 220 : keysym = 92; break; // \ (Mozilla, IE)
  121. case 221 : keysym = 93; break; // ] (Mozilla, IE)
  122. case 222 : keysym = 39; break; // ' (Mozilla, IE)
  123. }
  124. /* Remap shifted and unshifted keys */
  125. if (!!evt.shiftKey) {
  126. switch (keysym) {
  127. case 48 : keysym = 41 ; break; // ) (shifted 0)
  128. case 49 : keysym = 33 ; break; // ! (shifted 1)
  129. case 50 : keysym = 64 ; break; // @ (shifted 2)
  130. case 51 : keysym = 35 ; break; // # (shifted 3)
  131. case 52 : keysym = 36 ; break; // $ (shifted 4)
  132. case 53 : keysym = 37 ; break; // % (shifted 5)
  133. case 54 : keysym = 94 ; break; // ^ (shifted 6)
  134. case 55 : keysym = 38 ; break; // & (shifted 7)
  135. case 56 : keysym = 42 ; break; // * (shifted 8)
  136. case 57 : keysym = 40 ; break; // ( (shifted 9)
  137. case 59 : keysym = 58 ; break; // : (shifted `)
  138. case 61 : keysym = 43 ; break; // + (shifted ;)
  139. case 44 : keysym = 60 ; break; // < (shifted ,)
  140. case 45 : keysym = 95 ; break; // _ (shifted -)
  141. case 46 : keysym = 62 ; break; // > (shifted .)
  142. case 47 : keysym = 63 ; break; // ? (shifted /)
  143. case 96 : keysym = 126; break; // ~ (shifted `)
  144. case 91 : keysym = 123; break; // { (shifted [)
  145. case 92 : keysym = 124; break; // | (shifted \)
  146. case 93 : keysym = 125; break; // } (shifted ])
  147. case 39 : keysym = 34 ; break; // " (shifted ')
  148. }
  149. } else if ((keysym >= 65) && (keysym <=90)) {
  150. /* Remap unshifted A-Z */
  151. keysym += 32;
  152. } else if (evt.keyLocation === 3) {
  153. // numpad keys
  154. switch (keysym) {
  155. case 96 : keysym = 48; break; // 0
  156. case 97 : keysym = 49; break; // 1
  157. case 98 : keysym = 50; break; // 2
  158. case 99 : keysym = 51; break; // 3
  159. case 100: keysym = 52; break; // 4
  160. case 101: keysym = 53; break; // 5
  161. case 102: keysym = 54; break; // 6
  162. case 103: keysym = 55; break; // 7
  163. case 104: keysym = 56; break; // 8
  164. case 105: keysym = 57; break; // 9
  165. case 109: keysym = 45; break; // -
  166. case 110: keysym = 46; break; // .
  167. case 111: keysym = 47; break; // /
  168. }
  169. }
  170. return keysym;
  171. };
  172. that.grab = function() {
  173. //Util.Debug(">> Keyboard.grab");
  174. var c = conf.target;
  175. Util.addEvent(c, 'keydown', onKeyDown);
  176. Util.addEvent(c, 'keyup', onKeyUp);
  177. Util.addEvent(c, 'keypress', onKeyPress);
  178. //Util.Debug("<< Keyboard.grab");
  179. };
  180. that.ungrab = function() {
  181. //Util.Debug(">> Keyboard.ungrab");
  182. var c = conf.target;
  183. Util.removeEvent(c, 'keydown', onKeyDown);
  184. Util.removeEvent(c, 'keyup', onKeyUp);
  185. Util.removeEvent(c, 'keypress', onKeyPress);
  186. //Util.Debug(">> Keyboard.ungrab");
  187. };
  188. return that; // Return the public API interface
  189. } // End of Keyboard()
  190. //
  191. // Mouse event handler
  192. //
  193. function Mouse(conf) {
  194. "use strict";
  195. conf = conf || {}; // Configuration
  196. var that = {}; // Public API interface
  197. // Configuration settings
  198. function cdef(v, type, defval, desc) {
  199. Util.conf_default(conf, that, v, type, defval, desc); }
  200. // Capability settings, default can be overridden
  201. cdef('target', 'dom', document, 'DOM element that grabs mouse input');
  202. cdef('focused', 'bool', true, 'Capture and send mouse clicks/movement');
  203. cdef('mouseButton', 'func', null, 'Handler for mouse button click/release');
  204. cdef('mouseMove', 'func', null, 'Handler for mouse movement');
  205. that.set_target = function () { throw("target cannot be changed"); }
  206. //
  207. // Private functions
  208. //
  209. function onMouseButton(e, down) {
  210. var evt, pos, bmask;
  211. if (! conf.focused) {
  212. return true;
  213. }
  214. evt = (e ? e : window.event);
  215. pos = Util.getEventPosition(e, conf.target, conf.scale);
  216. if (evt.which) {
  217. /* everything except IE */
  218. bmask = 1 << evt.button;
  219. } else {
  220. /* IE including 9 */
  221. bmask = (evt.button & 0x1) + // Left
  222. (evt.button & 0x2) * 2 + // Right
  223. (evt.button & 0x4) / 2; // Middle
  224. }
  225. //Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
  226. // " bmask: " + bmask + "(evt.button: " + evt.button + ")");
  227. if (conf.mouseButton) {
  228. conf.mouseButton(pos.x, pos.y, down, bmask);
  229. }
  230. Util.stopEvent(e);
  231. return false;
  232. }
  233. function onMouseDown(e) {
  234. onMouseButton(e, 1);
  235. }
  236. function onMouseUp(e) {
  237. onMouseButton(e, 0);
  238. }
  239. function onMouseWheel(e) {
  240. var evt, pos, bmask, wheelData;
  241. if (! conf.focused) {
  242. return true;
  243. }
  244. evt = (e ? e : window.event);
  245. pos = Util.getEventPosition(e, conf.target, conf.scale);
  246. wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
  247. if (wheelData > 0) {
  248. bmask = 1 << 3;
  249. } else {
  250. bmask = 1 << 4;
  251. }
  252. //Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
  253. if (conf.mouseButton) {
  254. conf.mouseButton(pos.x, pos.y, 1, bmask);
  255. conf.mouseButton(pos.x, pos.y, 0, bmask);
  256. }
  257. Util.stopEvent(e);
  258. return false;
  259. }
  260. function onMouseMove(e) {
  261. var evt, pos;
  262. if (! conf.focused) {
  263. return true;
  264. }
  265. evt = (e ? e : window.event);
  266. pos = Util.getEventPosition(e, conf.target, conf.scale);
  267. //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
  268. if (conf.mouseMove) {
  269. conf.mouseMove(pos.x, pos.y);
  270. }
  271. }
  272. function onMouseDisable(e) {
  273. var evt, pos;
  274. if (! conf.focused) {
  275. return true;
  276. }
  277. evt = (e ? e : window.event);
  278. pos = Util.getEventPosition(e, conf.target, conf.scale);
  279. /* Stop propagation if inside canvas area */
  280. if ((pos.x >= 0) && (pos.y >= 0) &&
  281. (pos.x < conf.target.offsetWidth) &&
  282. (pos.y < conf.target.offsetHeight)) {
  283. //Util.Debug("mouse event disabled");
  284. Util.stopEvent(e);
  285. return false;
  286. }
  287. //Util.Debug("mouse event not disabled");
  288. return true;
  289. }
  290. //
  291. // Public API interface functions
  292. //
  293. that.grab = function() {
  294. //Util.Debug(">> Mouse.grab");
  295. var c = conf.target;
  296. Util.addEvent(c, 'mousedown', onMouseDown);
  297. Util.addEvent(c, 'mouseup', onMouseUp);
  298. Util.addEvent(c, 'mousemove', onMouseMove);
  299. Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
  300. onMouseWheel);
  301. /* Work around right and middle click browser behaviors */
  302. Util.addEvent(document, 'click', onMouseDisable);
  303. Util.addEvent(document.body, 'contextmenu', onMouseDisable);
  304. //Util.Debug("<< Mouse.grab");
  305. };
  306. that.ungrab = function() {
  307. //Util.Debug(">> Mouse.ungrab");
  308. var c = conf.target;
  309. Util.removeEvent(c, 'mousedown', onMouseDown);
  310. Util.removeEvent(c, 'mouseup', onMouseUp);
  311. Util.removeEvent(c, 'mousemove', onMouseMove);
  312. Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
  313. onMouseWheel);
  314. /* Work around right and middle click browser behaviors */
  315. Util.removeEvent(document, 'click', onMouseDisable);
  316. Util.removeEvent(document.body, 'contextmenu', onMouseDisable);
  317. //Util.Debug(">> Mouse.ungrab");
  318. };
  319. return that; // Return the public API interface
  320. } // End of Mouse()