@illgrenoble/webx-client 1.8.1 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/README.md +1 -1
  2. package/dist/WebXClient.d.ts +0 -1
  3. package/dist/WebXClient.js +8 -3
  4. package/dist/WebXClient.js.map +1 -1
  5. package/dist/WebXEngine.d.ts +4 -0
  6. package/dist/WebXEngine.js +7 -0
  7. package/dist/WebXEngine.js.map +1 -0
  8. package/dist/display/WebXCursor.d.ts +1 -0
  9. package/dist/display/WebXCursor.js +9 -0
  10. package/dist/display/WebXCursor.js.map +1 -1
  11. package/dist/display/WebXDisplay.d.ts +18 -0
  12. package/dist/display/WebXDisplay.js +47 -4
  13. package/dist/display/WebXDisplay.js.map +1 -1
  14. package/dist/display/WebXMaterial.d.ts +14 -0
  15. package/dist/display/WebXMaterial.js +140 -0
  16. package/dist/display/WebXMaterial.js.map +1 -0
  17. package/dist/display/WebXMaterialProvider.d.ts +8 -0
  18. package/dist/display/WebXMaterialProvider.js +71 -0
  19. package/dist/display/WebXMaterialProvider.js.map +1 -0
  20. package/dist/display/WebXTextureFactory.d.ts +10 -0
  21. package/dist/display/WebXTextureFactory.js +21 -0
  22. package/dist/display/WebXTextureFactory.js.map +1 -1
  23. package/dist/display/WebXWindow.d.ts +32 -0
  24. package/dist/display/WebXWindow.js +84 -6
  25. package/dist/display/WebXWindow.js.map +1 -1
  26. package/dist/display/WebXWindowProperties.d.ts +5 -0
  27. package/dist/display/WebXWindowProperties.js +1 -0
  28. package/dist/display/WebXWindowProperties.js.map +1 -1
  29. package/dist/input/GuacamoleKeyboard.js +1532 -0
  30. package/dist/input/WebXKeyboard.d.ts +10 -232
  31. package/dist/input/WebXKeyboard.js +31 -594
  32. package/dist/input/WebXKeyboard.js.map +1 -1
  33. package/dist/input/WebXNewKeyboard.d.ts +62 -0
  34. package/dist/input/WebXNewKeyboard.js +94 -0
  35. package/dist/input/WebXNewKeyboard.js.map +1 -0
  36. package/dist/input/index.d.ts +0 -1
  37. package/dist/input/index.js +0 -1
  38. package/dist/input/index.js.map +1 -1
  39. package/dist/input/keyboard/WebXKeyboardUtils.js +1 -2
  40. package/dist/input/keyboard/WebXKeyboardUtils.js.map +1 -1
  41. package/dist/instruction/WebXInstructionType.d.ts +5 -1
  42. package/dist/instruction/WebXInstructionType.js +6 -0
  43. package/dist/instruction/WebXInstructionType.js.map +1 -1
  44. package/dist/instruction/WebXShapeInstruction.d.ts +18 -0
  45. package/dist/instruction/WebXShapeInstruction.js +23 -0
  46. package/dist/instruction/WebXShapeInstruction.js.map +1 -0
  47. package/dist/instruction/index.d.ts +1 -0
  48. package/dist/instruction/index.js +1 -0
  49. package/dist/instruction/index.js.map +1 -1
  50. package/dist/lib/GuacamoleKeyboard.js +1290 -0
  51. package/dist/lib/GuacamoleKeyboard.js.map +1 -0
  52. package/dist/message/WebXMessageType.d.ts +5 -1
  53. package/dist/message/WebXMessageType.js +4 -0
  54. package/dist/message/WebXMessageType.js.map +1 -1
  55. package/dist/message/WebXShapeMessage.d.ts +31 -0
  56. package/dist/message/WebXShapeMessage.js +29 -0
  57. package/dist/message/WebXShapeMessage.js.map +1 -0
  58. package/dist/message/index.d.ts +1 -0
  59. package/dist/message/index.js +1 -0
  60. package/dist/message/index.js.map +1 -1
  61. package/dist/src/WebXClient.d.ts +261 -0
  62. package/dist/src/WebXClient.js +571 -0
  63. package/dist/src/WebXClient.js.map +1 -0
  64. package/dist/src/WebXEngine.d.ts +4 -0
  65. package/dist/src/WebXEngine.js +7 -0
  66. package/dist/src/WebXEngine.js.map +1 -0
  67. package/dist/src/display/WebXCursor.d.ts +88 -0
  68. package/dist/src/display/WebXCursor.js +150 -0
  69. package/dist/src/display/WebXCursor.js.map +1 -0
  70. package/dist/src/display/WebXCursorFactory.d.ts +36 -0
  71. package/dist/src/display/WebXCursorFactory.js +59 -0
  72. package/dist/src/display/WebXCursorFactory.js.map +1 -0
  73. package/dist/src/display/WebXDisplay.d.ts +226 -0
  74. package/dist/src/display/WebXDisplay.js +424 -0
  75. package/dist/src/display/WebXDisplay.js.map +1 -0
  76. package/dist/src/display/WebXMaterial.d.ts +14 -0
  77. package/dist/src/display/WebXMaterial.js +140 -0
  78. package/dist/src/display/WebXMaterial.js.map +1 -0
  79. package/dist/src/display/WebXSubImage.d.ts +50 -0
  80. package/dist/src/display/WebXSubImage.js +26 -0
  81. package/dist/src/display/WebXSubImage.js.map +1 -0
  82. package/dist/src/display/WebXTextureFactory.d.ts +54 -0
  83. package/dist/src/display/WebXTextureFactory.js +160 -0
  84. package/dist/src/display/WebXTextureFactory.js.map +1 -0
  85. package/dist/src/display/WebXWindow.d.ts +241 -0
  86. package/dist/src/display/WebXWindow.js +438 -0
  87. package/dist/src/display/WebXWindow.js.map +1 -0
  88. package/dist/src/display/WebXWindowProperties.d.ts +44 -0
  89. package/dist/src/display/WebXWindowProperties.js +25 -0
  90. package/dist/src/display/WebXWindowProperties.js.map +1 -0
  91. package/dist/src/display/index.d.ts +7 -0
  92. package/dist/src/display/index.js +24 -0
  93. package/dist/src/display/index.js.map +1 -0
  94. package/dist/src/index.d.ts +7 -0
  95. package/dist/src/index.js +24 -0
  96. package/dist/src/index.js.map +1 -0
  97. package/dist/src/input/WebXKeyboard.d.ts +265 -0
  98. package/dist/src/input/WebXKeyboard.js +632 -0
  99. package/dist/src/input/WebXKeyboard.js.map +1 -0
  100. package/dist/src/input/WebXMouse.d.ts +125 -0
  101. package/dist/src/input/WebXMouse.js +231 -0
  102. package/dist/src/input/WebXMouse.js.map +1 -0
  103. package/dist/src/input/index.d.ts +4 -0
  104. package/dist/src/input/index.js +21 -0
  105. package/dist/src/input/index.js.map +1 -0
  106. package/dist/src/input/keyboard/WebXKeyEvent.d.ts +79 -0
  107. package/dist/src/input/keyboard/WebXKeyEvent.js +324 -0
  108. package/dist/src/input/keyboard/WebXKeyEvent.js.map +1 -0
  109. package/dist/src/input/keyboard/WebXKeyPressEvent.d.ts +30 -0
  110. package/dist/src/input/keyboard/WebXKeyPressEvent.js +44 -0
  111. package/dist/src/input/keyboard/WebXKeyPressEvent.js.map +1 -0
  112. package/dist/src/input/keyboard/WebXKeyUpEvent.d.ts +33 -0
  113. package/dist/src/input/keyboard/WebXKeyUpEvent.js +31 -0
  114. package/dist/src/input/keyboard/WebXKeyUpEvent.js.map +1 -0
  115. package/dist/src/input/keyboard/WebXKeyboardModifierState.d.ts +108 -0
  116. package/dist/src/input/keyboard/WebXKeyboardModifierState.js +148 -0
  117. package/dist/src/input/keyboard/WebXKeyboardModifierState.js.map +1 -0
  118. package/dist/src/input/keyboard/WebXKeyboardUtils.d.ts +25 -0
  119. package/dist/src/input/keyboard/WebXKeyboardUtils.js +63 -0
  120. package/dist/src/input/keyboard/WebXKeyboardUtils.js.map +1 -0
  121. package/dist/src/input/keyboard/WebXKeydownEvent.d.ts +46 -0
  122. package/dist/src/input/keyboard/WebXKeydownEvent.js +66 -0
  123. package/dist/src/input/keyboard/WebXKeydownEvent.js.map +1 -0
  124. package/dist/src/input/keyboard/index.d.ts +6 -0
  125. package/dist/src/input/keyboard/index.js +23 -0
  126. package/dist/src/input/keyboard/index.js.map +1 -0
  127. package/dist/src/input/mouse/WebXMouseState.d.ts +190 -0
  128. package/dist/src/input/mouse/WebXMouseState.js +217 -0
  129. package/dist/src/input/mouse/WebXMouseState.js.map +1 -0
  130. package/dist/src/input/mouse/index.d.ts +1 -0
  131. package/dist/src/input/mouse/index.js +18 -0
  132. package/dist/src/input/mouse/index.js.map +1 -0
  133. package/dist/src/instruction/WebXClipboardInstruction.d.ts +18 -0
  134. package/dist/src/instruction/WebXClipboardInstruction.js +23 -0
  135. package/dist/src/instruction/WebXClipboardInstruction.js.map +1 -0
  136. package/dist/src/instruction/WebXConnectInstruction.d.ts +19 -0
  137. package/dist/src/instruction/WebXConnectInstruction.js +24 -0
  138. package/dist/src/instruction/WebXConnectInstruction.js.map +1 -0
  139. package/dist/src/instruction/WebXCursorImageInstruction.d.ts +18 -0
  140. package/dist/src/instruction/WebXCursorImageInstruction.js +23 -0
  141. package/dist/src/instruction/WebXCursorImageInstruction.js.map +1 -0
  142. package/dist/src/instruction/WebXDataAckInstruction.d.ts +25 -0
  143. package/dist/src/instruction/WebXDataAckInstruction.js +26 -0
  144. package/dist/src/instruction/WebXDataAckInstruction.js.map +1 -0
  145. package/dist/src/instruction/WebXImageInstruction.d.ts +18 -0
  146. package/dist/src/instruction/WebXImageInstruction.js +23 -0
  147. package/dist/src/instruction/WebXImageInstruction.js.map +1 -0
  148. package/dist/src/instruction/WebXInstruction.d.ts +29 -0
  149. package/dist/src/instruction/WebXInstruction.js +28 -0
  150. package/dist/src/instruction/WebXInstruction.js.map +1 -0
  151. package/dist/src/instruction/WebXInstructionResponse.d.ts +66 -0
  152. package/dist/src/instruction/WebXInstructionResponse.js +78 -0
  153. package/dist/src/instruction/WebXInstructionResponse.js.map +1 -0
  154. package/dist/src/instruction/WebXInstructionType.d.ts +63 -0
  155. package/dist/src/instruction/WebXInstructionType.js +96 -0
  156. package/dist/src/instruction/WebXInstructionType.js.map +1 -0
  157. package/dist/src/instruction/WebXKeyboardInstruction.d.ts +23 -0
  158. package/dist/src/instruction/WebXKeyboardInstruction.js +25 -0
  159. package/dist/src/instruction/WebXKeyboardInstruction.js.map +1 -0
  160. package/dist/src/instruction/WebXMouseInstruction.d.ts +28 -0
  161. package/dist/src/instruction/WebXMouseInstruction.js +27 -0
  162. package/dist/src/instruction/WebXMouseInstruction.js.map +1 -0
  163. package/dist/src/instruction/WebXPongInstruction.d.ts +18 -0
  164. package/dist/src/instruction/WebXPongInstruction.js +23 -0
  165. package/dist/src/instruction/WebXPongInstruction.js.map +1 -0
  166. package/dist/src/instruction/WebXQualityInstruction.d.ts +19 -0
  167. package/dist/src/instruction/WebXQualityInstruction.js +24 -0
  168. package/dist/src/instruction/WebXQualityInstruction.js.map +1 -0
  169. package/dist/src/instruction/WebXScreenInstruction.d.ts +12 -0
  170. package/dist/src/instruction/WebXScreenInstruction.js +20 -0
  171. package/dist/src/instruction/WebXScreenInstruction.js.map +1 -0
  172. package/dist/src/instruction/WebXShapeInstruction.d.ts +18 -0
  173. package/dist/src/instruction/WebXShapeInstruction.js +23 -0
  174. package/dist/src/instruction/WebXShapeInstruction.js.map +1 -0
  175. package/dist/src/instruction/WebXWindowsInstruction.d.ts +13 -0
  176. package/dist/src/instruction/WebXWindowsInstruction.js +21 -0
  177. package/dist/src/instruction/WebXWindowsInstruction.js.map +1 -0
  178. package/dist/src/instruction/index.d.ts +15 -0
  179. package/dist/src/instruction/index.js +32 -0
  180. package/dist/src/instruction/index.js.map +1 -0
  181. package/dist/src/message/WebXClipboardMessage.d.ts +19 -0
  182. package/dist/src/message/WebXClipboardMessage.js +23 -0
  183. package/dist/src/message/WebXClipboardMessage.js.map +1 -0
  184. package/dist/src/message/WebXConnectionMessage.d.ts +12 -0
  185. package/dist/src/message/WebXConnectionMessage.js +20 -0
  186. package/dist/src/message/WebXConnectionMessage.js.map +1 -0
  187. package/dist/src/message/WebXCursorImageMessage.d.ts +46 -0
  188. package/dist/src/message/WebXCursorImageMessage.js +35 -0
  189. package/dist/src/message/WebXCursorImageMessage.js.map +1 -0
  190. package/dist/src/message/WebXImageMessage.d.ts +41 -0
  191. package/dist/src/message/WebXImageMessage.js +33 -0
  192. package/dist/src/message/WebXImageMessage.js.map +1 -0
  193. package/dist/src/message/WebXMessage.d.ts +24 -0
  194. package/dist/src/message/WebXMessage.js +23 -0
  195. package/dist/src/message/WebXMessage.js.map +1 -0
  196. package/dist/src/message/WebXMessageType.d.ts +59 -0
  197. package/dist/src/message/WebXMessageType.js +64 -0
  198. package/dist/src/message/WebXMessageType.js.map +1 -0
  199. package/dist/src/message/WebXMouseMessage.d.ts +30 -0
  200. package/dist/src/message/WebXMouseMessage.js +29 -0
  201. package/dist/src/message/WebXMouseMessage.js.map +1 -0
  202. package/dist/src/message/WebXNopMessage.d.ts +10 -0
  203. package/dist/src/message/WebXNopMessage.js +18 -0
  204. package/dist/src/message/WebXNopMessage.js.map +1 -0
  205. package/dist/src/message/WebXPingMessage.d.ts +13 -0
  206. package/dist/src/message/WebXPingMessage.js +21 -0
  207. package/dist/src/message/WebXPingMessage.js.map +1 -0
  208. package/dist/src/message/WebXQualityMessage.d.ts +39 -0
  209. package/dist/src/message/WebXQualityMessage.js +32 -0
  210. package/dist/src/message/WebXQualityMessage.js.map +1 -0
  211. package/dist/src/message/WebXScreenMessage.d.ts +37 -0
  212. package/dist/src/message/WebXScreenMessage.js +29 -0
  213. package/dist/src/message/WebXScreenMessage.js.map +1 -0
  214. package/dist/src/message/WebXShapeMessage.d.ts +31 -0
  215. package/dist/src/message/WebXShapeMessage.js +29 -0
  216. package/dist/src/message/WebXShapeMessage.js.map +1 -0
  217. package/dist/src/message/WebXSubImagesMessage.d.ts +31 -0
  218. package/dist/src/message/WebXSubImagesMessage.js +29 -0
  219. package/dist/src/message/WebXSubImagesMessage.js.map +1 -0
  220. package/dist/src/message/WebXWindowsMessage.d.ts +21 -0
  221. package/dist/src/message/WebXWindowsMessage.js +25 -0
  222. package/dist/src/message/WebXWindowsMessage.js.map +1 -0
  223. package/dist/src/message/index.d.ts +14 -0
  224. package/dist/src/message/index.js +31 -0
  225. package/dist/src/message/index.js.map +1 -0
  226. package/dist/src/tracer/WebXDebugImageMessageHandler.d.ts +48 -0
  227. package/dist/src/tracer/WebXDebugImageMessageHandler.js +102 -0
  228. package/dist/src/tracer/WebXDebugImageMessageHandler.js.map +1 -0
  229. package/dist/src/tracer/WebXHandler.d.ts +14 -0
  230. package/dist/src/tracer/WebXHandler.js +3 -0
  231. package/dist/src/tracer/WebXHandler.js.map +1 -0
  232. package/dist/src/tracer/WebXInstructionHandler.d.ts +21 -0
  233. package/dist/src/tracer/WebXInstructionHandler.js +13 -0
  234. package/dist/src/tracer/WebXInstructionHandler.js.map +1 -0
  235. package/dist/src/tracer/WebXMessageHandler.d.ts +21 -0
  236. package/dist/src/tracer/WebXMessageHandler.js +13 -0
  237. package/dist/src/tracer/WebXMessageHandler.js.map +1 -0
  238. package/dist/src/tracer/WebXStatsHandler.d.ts +23 -0
  239. package/dist/src/tracer/WebXStatsHandler.js +13 -0
  240. package/dist/src/tracer/WebXStatsHandler.js.map +1 -0
  241. package/dist/src/tracer/index.d.ts +5 -0
  242. package/dist/src/tracer/index.js +22 -0
  243. package/dist/src/tracer/index.js.map +1 -0
  244. package/dist/src/transport/WebXBinarySerializer.d.ts +31 -0
  245. package/dist/src/transport/WebXBinarySerializer.js +63 -0
  246. package/dist/src/transport/WebXBinarySerializer.js.map +1 -0
  247. package/dist/src/transport/WebXInstructionBuffer.d.ts +55 -0
  248. package/dist/src/transport/WebXInstructionBuffer.js +109 -0
  249. package/dist/src/transport/WebXInstructionBuffer.js.map +1 -0
  250. package/dist/src/transport/WebXInstructionEncoder.d.ts +181 -0
  251. package/dist/src/transport/WebXInstructionEncoder.js +294 -0
  252. package/dist/src/transport/WebXInstructionEncoder.js.map +1 -0
  253. package/dist/src/transport/WebXMessageBuffer.d.ts +80 -0
  254. package/dist/src/transport/WebXMessageBuffer.js +104 -0
  255. package/dist/src/transport/WebXMessageBuffer.js.map +1 -0
  256. package/dist/src/transport/WebXMessageDecoder.d.ts +108 -0
  257. package/dist/src/transport/WebXMessageDecoder.js +332 -0
  258. package/dist/src/transport/WebXMessageDecoder.js.map +1 -0
  259. package/dist/src/transport/index.d.ts +5 -0
  260. package/dist/src/transport/index.js +22 -0
  261. package/dist/src/transport/index.js.map +1 -0
  262. package/dist/src/tunnel/WebXTunnel.d.ts +93 -0
  263. package/dist/src/tunnel/WebXTunnel.js +156 -0
  264. package/dist/src/tunnel/WebXTunnel.js.map +1 -0
  265. package/dist/src/tunnel/WebXWebSocketTunnel.d.ts +40 -0
  266. package/dist/src/tunnel/WebXWebSocketTunnel.js +88 -0
  267. package/dist/src/tunnel/WebXWebSocketTunnel.js.map +1 -0
  268. package/dist/src/tunnel/index.d.ts +2 -0
  269. package/dist/src/tunnel/index.js +19 -0
  270. package/dist/src/tunnel/index.js.map +1 -0
  271. package/dist/src/utils/WebXColorGenerator.d.ts +24 -0
  272. package/dist/src/utils/WebXColorGenerator.js +46 -0
  273. package/dist/src/utils/WebXColorGenerator.js.map +1 -0
  274. package/dist/src/utils/WebXVersion.d.ts +34 -0
  275. package/dist/src/utils/WebXVersion.js +25 -0
  276. package/dist/src/utils/WebXVersion.js.map +1 -0
  277. package/dist/src/utils/index.d.ts +2 -0
  278. package/dist/src/utils/index.js +19 -0
  279. package/dist/src/utils/index.js.map +1 -0
  280. package/dist/tracer/WebXDebugImageMessageHandler.js +1 -0
  281. package/dist/tracer/WebXDebugImageMessageHandler.js.map +1 -1
  282. package/dist/transport/WebXInstructionEncoder.d.ts +14 -0
  283. package/dist/transport/WebXInstructionEncoder.js +23 -0
  284. package/dist/transport/WebXInstructionEncoder.js.map +1 -1
  285. package/dist/transport/WebXMessageDecoder.d.ts +7 -0
  286. package/dist/transport/WebXMessageDecoder.js +34 -3
  287. package/dist/transport/WebXMessageDecoder.js.map +1 -1
  288. package/dist/utils/WebXVersion.d.ts +4 -0
  289. package/dist/utils/WebXVersion.js +1 -0
  290. package/dist/utils/WebXVersion.js.map +1 -1
  291. package/package.json +5 -3
@@ -0,0 +1,1290 @@
1
+ /* eslint-disable */
2
+ /*
3
+ * Licensed to the Apache Software Foundation (ASF) under one
4
+ * or more contributor license agreements. See the NOTICE file
5
+ * distributed with this work for additional information
6
+ * regarding copyright ownership. The ASF licenses this file
7
+ * to you under the Apache License, Version 2.0 (the
8
+ * "License"); you may not use this file except in compliance
9
+ * with the License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing,
14
+ * software distributed under the License is distributed on an
15
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ * KIND, either express or implied. See the License for the
17
+ * specific language governing permissions and limitations
18
+ * under the License.
19
+ */
20
+ var Guacamole = Guacamole || {};
21
+ /**
22
+ * Provides cross-browser and cross-keyboard keyboard for a specific element.
23
+ * Browser and keyboard layout variation is abstracted away, providing events
24
+ * which represent keys as their corresponding X11 keysym.
25
+ *
26
+ * @constructor
27
+ * @param {Element|Document} [element]
28
+ * The Element to use to provide keyboard events. If omitted, at least one
29
+ * Element must be manually provided through the listenTo() function for
30
+ * the Guacamole.Keyboard instance to have any effect.
31
+ */
32
+ Guacamole.Keyboard = function Keyboard(element) {
33
+ /**
34
+ * Reference to this Guacamole.Keyboard.
35
+ *
36
+ * @private
37
+ * @type {!Guacamole.Keyboard}
38
+ */
39
+ var guac_keyboard = this;
40
+ /**
41
+ * An integer value which uniquely identifies this Guacamole.Keyboard
42
+ * instance with respect to other Guacamole.Keyboard instances.
43
+ *
44
+ * @private
45
+ * @type {!number}
46
+ */
47
+ var guacKeyboardID = Guacamole.Keyboard._nextID++;
48
+ /**
49
+ * The name of the property which is added to event objects via markEvent()
50
+ * to note that they have already been handled by this Guacamole.Keyboard.
51
+ *
52
+ * @private
53
+ * @constant
54
+ * @type {!string}
55
+ */
56
+ var EVENT_MARKER = '_GUAC_KEYBOARD_HANDLED_BY_' + guacKeyboardID;
57
+ /**
58
+ * Fired whenever the user presses a key with the element associated
59
+ * with this Guacamole.Keyboard in focus.
60
+ *
61
+ * @event
62
+ * @param {!number} keysym
63
+ * The keysym of the key being pressed.
64
+ *
65
+ * @return {!boolean}
66
+ * true if the key event should be allowed through to the browser,
67
+ * false otherwise.
68
+ */
69
+ this.onkeydown = null;
70
+ /**
71
+ * Fired whenever the user releases a key with the element associated
72
+ * with this Guacamole.Keyboard in focus.
73
+ *
74
+ * @event
75
+ * @param {!number} keysym
76
+ * The keysym of the key being released.
77
+ */
78
+ this.onkeyup = null;
79
+ /**
80
+ * Set of known platform-specific or browser-specific quirks which must be
81
+ * accounted for to properly interpret key events, even if the only way to
82
+ * reliably detect that quirk is to platform/browser-sniff.
83
+ *
84
+ * @private
85
+ * @type {!Object.<string, boolean>}
86
+ */
87
+ var quirks = {
88
+ /**
89
+ * Whether keyup events are universally unreliable.
90
+ *
91
+ * @type {!boolean}
92
+ */
93
+ keyupUnreliable: false,
94
+ /**
95
+ * Whether the Alt key is actually a modifier for typable keys and is
96
+ * thus never used for keyboard shortcuts.
97
+ *
98
+ * @type {!boolean}
99
+ */
100
+ altIsTypableOnly: false,
101
+ /**
102
+ * Whether we can rely on receiving a keyup event for the Caps Lock
103
+ * key.
104
+ *
105
+ * @type {!boolean}
106
+ */
107
+ capsLockKeyupUnreliable: false
108
+ };
109
+ // Set quirk flags depending on platform/browser, if such information is
110
+ // available
111
+ if (navigator && navigator.platform) {
112
+ // All keyup events are unreliable on iOS (sadly)
113
+ if (navigator.platform.match(/ipad|iphone|ipod/i))
114
+ quirks.keyupUnreliable = true;
115
+ // The Alt key on Mac is never used for keyboard shortcuts, and the
116
+ // Caps Lock key never dispatches keyup events
117
+ else if (navigator.platform.match(/^mac/i)) {
118
+ quirks.altIsTypableOnly = true;
119
+ quirks.capsLockKeyupUnreliable = true;
120
+ }
121
+ }
122
+ /**
123
+ * A key event having a corresponding timestamp. This event is non-specific.
124
+ * Its subclasses should be used instead when recording specific key
125
+ * events.
126
+ *
127
+ * @private
128
+ * @constructor
129
+ * @param {KeyboardEvent} [orig]
130
+ * The relevant DOM keyboard event.
131
+ */
132
+ var KeyEvent = function KeyEvent(orig) {
133
+ /**
134
+ * Reference to this key event.
135
+ *
136
+ * @private
137
+ * @type {!KeyEvent}
138
+ */
139
+ var key_event = this;
140
+ /**
141
+ * The JavaScript key code of the key pressed. For most events (keydown
142
+ * and keyup), this is a scancode-like value related to the position of
143
+ * the key on the US English "Qwerty" keyboard. For keypress events,
144
+ * this is the Unicode codepoint of the character that would be typed
145
+ * by the key pressed.
146
+ *
147
+ * @type {!number}
148
+ */
149
+ this.keyCode = orig ? (orig.which || orig.keyCode) : 0;
150
+ /**
151
+ * The legacy DOM3 "keyIdentifier" of the key pressed, as defined at:
152
+ * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent
153
+ *
154
+ * @type {!string}
155
+ */
156
+ this.keyIdentifier = orig && orig.keyIdentifier;
157
+ /**
158
+ * The standard name of the key pressed, as defined at:
159
+ * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent
160
+ *
161
+ * @type {!string}
162
+ */
163
+ this.key = orig && orig.key;
164
+ /**
165
+ * The location on the keyboard corresponding to the key pressed, as
166
+ * defined at:
167
+ * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent
168
+ *
169
+ * @type {!number}
170
+ */
171
+ this.location = orig ? getEventLocation(orig) : 0;
172
+ /**
173
+ * The state of all local keyboard modifiers at the time this event was
174
+ * received.
175
+ *
176
+ * @type {!Guacamole.Keyboard.ModifierState}
177
+ */
178
+ this.modifiers = orig ? Guacamole.Keyboard.ModifierState.fromKeyboardEvent(orig) : new Guacamole.Keyboard.ModifierState();
179
+ /**
180
+ * An arbitrary timestamp in milliseconds, indicating this event's
181
+ * position in time relative to other events.
182
+ *
183
+ * @type {!number}
184
+ */
185
+ this.timestamp = new Date().getTime();
186
+ /**
187
+ * Whether the default action of this key event should be prevented.
188
+ *
189
+ * @type {!boolean}
190
+ */
191
+ this.defaultPrevented = false;
192
+ /**
193
+ * The keysym of the key associated with this key event, as determined
194
+ * by a best-effort guess using available event properties and keyboard
195
+ * state.
196
+ *
197
+ * @type {number}
198
+ */
199
+ this.keysym = null;
200
+ /**
201
+ * Whether the keysym value of this key event is known to be reliable.
202
+ * If false, the keysym may still be valid, but it's only a best guess,
203
+ * and future key events may be a better source of information.
204
+ *
205
+ * @type {!boolean}
206
+ */
207
+ this.reliable = false;
208
+ /**
209
+ * Returns the number of milliseconds elapsed since this event was
210
+ * received.
211
+ *
212
+ * @return {!number}
213
+ * The number of milliseconds elapsed since this event was
214
+ * received.
215
+ */
216
+ this.getAge = function () {
217
+ return new Date().getTime() - key_event.timestamp;
218
+ };
219
+ };
220
+ /**
221
+ * Information related to the pressing of a key, which need not be a key
222
+ * associated with a printable character. The presence or absence of any
223
+ * information within this object is browser-dependent.
224
+ *
225
+ * @private
226
+ * @constructor
227
+ * @augments Guacamole.Keyboard.KeyEvent
228
+ * @param {!KeyboardEvent} orig
229
+ * The relevant DOM "keydown" event.
230
+ */
231
+ var KeydownEvent = function KeydownEvent(orig) {
232
+ // We extend KeyEvent
233
+ KeyEvent.call(this, orig);
234
+ // If key is known from keyCode or DOM3 alone, use that
235
+ this.keysym = keysym_from_key_identifier(this.key, this.location)
236
+ || keysym_from_keycode(this.keyCode, this.location);
237
+ /**
238
+ * Whether the keyup following this keydown event is known to be
239
+ * reliable. If false, we cannot rely on the keyup event to occur.
240
+ *
241
+ * @type {!boolean}
242
+ */
243
+ this.keyupReliable = !quirks.keyupUnreliable;
244
+ // DOM3 and keyCode are reliable sources if the corresponding key is
245
+ // not a printable key
246
+ if (this.keysym && !isPrintable(this.keysym))
247
+ this.reliable = true;
248
+ // Use legacy keyIdentifier as a last resort, if it looks sane
249
+ if (!this.keysym && key_identifier_sane(this.keyCode, this.keyIdentifier))
250
+ this.keysym = keysym_from_key_identifier(this.keyIdentifier, this.location, this.modifiers.shift);
251
+ // If a key is pressed while meta is held down, the keyup will
252
+ // never be sent in Chrome (bug #108404)
253
+ if (this.modifiers.meta && this.keysym !== 0xFFE7 && this.keysym !== 0xFFE8)
254
+ this.keyupReliable = false;
255
+ // We cannot rely on receiving keyup for Caps Lock on certain platforms
256
+ else if (this.keysym === 0xFFE5 && quirks.capsLockKeyupUnreliable)
257
+ this.keyupReliable = false;
258
+ // Determine whether default action for Alt+combinations must be prevented
259
+ var prevent_alt = !this.modifiers.ctrl && !quirks.altIsTypableOnly;
260
+ // If alt is typeable only, and this is actually an alt key event, treat as AltGr instead
261
+ if (quirks.altIsTypableOnly && (this.keysym === 0xFFE9 || this.keysym === 0xFFEA))
262
+ this.keysym = 0xFE03;
263
+ // Determine whether default action for Ctrl+combinations must be prevented
264
+ var prevent_ctrl = !this.modifiers.alt;
265
+ // We must rely on the (potentially buggy) keyIdentifier if preventing
266
+ // the default action is important
267
+ if ((prevent_ctrl && this.modifiers.ctrl)
268
+ || (prevent_alt && this.modifiers.alt)
269
+ || this.modifiers.meta
270
+ || this.modifiers.hyper)
271
+ this.reliable = true;
272
+ // Record most recently known keysym by associated key code
273
+ recentKeysym[this.keyCode] = this.keysym;
274
+ };
275
+ KeydownEvent.prototype = new KeyEvent();
276
+ /**
277
+ * Information related to the pressing of a key, which MUST be
278
+ * associated with a printable character. The presence or absence of any
279
+ * information within this object is browser-dependent.
280
+ *
281
+ * @private
282
+ * @constructor
283
+ * @augments Guacamole.Keyboard.KeyEvent
284
+ * @param {!KeyboardEvent} orig
285
+ * The relevant DOM "keypress" event.
286
+ */
287
+ var KeypressEvent = function KeypressEvent(orig) {
288
+ // We extend KeyEvent
289
+ KeyEvent.call(this, orig);
290
+ // Pull keysym from char code
291
+ this.keysym = keysym_from_charcode(this.keyCode);
292
+ // Keypress is always reliable
293
+ this.reliable = true;
294
+ };
295
+ KeypressEvent.prototype = new KeyEvent();
296
+ /**
297
+ * Information related to the releasing of a key, which need not be a key
298
+ * associated with a printable character. The presence or absence of any
299
+ * information within this object is browser-dependent.
300
+ *
301
+ * @private
302
+ * @constructor
303
+ * @augments Guacamole.Keyboard.KeyEvent
304
+ * @param {!KeyboardEvent} orig
305
+ * The relevant DOM "keyup" event.
306
+ */
307
+ var KeyupEvent = function KeyupEvent(orig) {
308
+ // We extend KeyEvent
309
+ KeyEvent.call(this, orig);
310
+ // If key is known from keyCode or DOM3 alone, use that (keyCode is
311
+ // still more reliable for keyup when dead keys are in use)
312
+ this.keysym = keysym_from_keycode(this.keyCode, this.location)
313
+ || keysym_from_key_identifier(this.key, this.location);
314
+ // Fall back to the most recently pressed keysym associated with the
315
+ // keyCode if the inferred key doesn't seem to actually be pressed
316
+ if (!guac_keyboard.pressed[this.keysym])
317
+ this.keysym = recentKeysym[this.keyCode] || this.keysym;
318
+ // Keyup is as reliable as it will ever be
319
+ this.reliable = true;
320
+ };
321
+ KeyupEvent.prototype = new KeyEvent();
322
+ /**
323
+ * An array of recorded events, which can be instances of the private
324
+ * KeydownEvent, KeypressEvent, and KeyupEvent classes.
325
+ *
326
+ * @private
327
+ * @type {!KeyEvent[]}
328
+ */
329
+ var eventLog = [];
330
+ /**
331
+ * Map of known JavaScript keycodes which do not map to typable characters
332
+ * to their X11 keysym equivalents.
333
+ *
334
+ * @private
335
+ * @type {!Object.<number, number[]>}
336
+ */
337
+ var keycodeKeysyms = {
338
+ 8: [0xFF08], // backspace
339
+ 9: [0xFF09], // tab
340
+ 12: [0xFF0B, 0xFF0B, 0xFF0B, 0xFFB5], // clear / KP 5
341
+ 13: [0xFF0D], // enter
342
+ 16: [0xFFE1, 0xFFE1, 0xFFE2], // shift
343
+ 17: [0xFFE3, 0xFFE3, 0xFFE4], // ctrl
344
+ 18: [0xFFE9, 0xFFE9, 0xFFEA], // alt
345
+ 19: [0xFF13], // pause/break
346
+ 20: [0xFFE5], // caps lock
347
+ 27: [0xFF1B], // escape
348
+ 32: [0x0020], // space
349
+ 33: [0xFF55, 0xFF55, 0xFF55, 0xFFB9], // page up / KP 9
350
+ 34: [0xFF56, 0xFF56, 0xFF56, 0xFFB3], // page down / KP 3
351
+ 35: [0xFF57, 0xFF57, 0xFF57, 0xFFB1], // end / KP 1
352
+ 36: [0xFF50, 0xFF50, 0xFF50, 0xFFB7], // home / KP 7
353
+ 37: [0xFF51, 0xFF51, 0xFF51, 0xFFB4], // left arrow / KP 4
354
+ 38: [0xFF52, 0xFF52, 0xFF52, 0xFFB8], // up arrow / KP 8
355
+ 39: [0xFF53, 0xFF53, 0xFF53, 0xFFB6], // right arrow / KP 6
356
+ 40: [0xFF54, 0xFF54, 0xFF54, 0xFFB2], // down arrow / KP 2
357
+ 45: [0xFF63, 0xFF63, 0xFF63, 0xFFB0], // insert / KP 0
358
+ 46: [0xFFFF, 0xFFFF, 0xFFFF, 0xFFAE], // delete / KP decimal
359
+ 91: [0xFFE7], // left windows/command key (meta_l)
360
+ 92: [0xFFE8], // right window/command key (meta_r)
361
+ 93: [0xFF67], // menu key
362
+ 96: [0xFFB0], // KP 0
363
+ 97: [0xFFB1], // KP 1
364
+ 98: [0xFFB2], // KP 2
365
+ 99: [0xFFB3], // KP 3
366
+ 100: [0xFFB4], // KP 4
367
+ 101: [0xFFB5], // KP 5
368
+ 102: [0xFFB6], // KP 6
369
+ 103: [0xFFB7], // KP 7
370
+ 104: [0xFFB8], // KP 8
371
+ 105: [0xFFB9], // KP 9
372
+ 106: [0xFFAA], // KP multiply
373
+ 107: [0xFFAB], // KP add
374
+ 109: [0xFFAD], // KP subtract
375
+ 110: [0xFFAE], // KP decimal
376
+ 111: [0xFFAF], // KP divide
377
+ 112: [0xFFBE], // f1
378
+ 113: [0xFFBF], // f2
379
+ 114: [0xFFC0], // f3
380
+ 115: [0xFFC1], // f4
381
+ 116: [0xFFC2], // f5
382
+ 117: [0xFFC3], // f6
383
+ 118: [0xFFC4], // f7
384
+ 119: [0xFFC5], // f8
385
+ 120: [0xFFC6], // f9
386
+ 121: [0xFFC7], // f10
387
+ 122: [0xFFC8], // f11
388
+ 123: [0xFFC9], // f12
389
+ 144: [0xFF7F], // num lock
390
+ 145: [0xFF14], // scroll lock
391
+ 225: [0xFE03] // altgraph (iso_level3_shift)
392
+ };
393
+ /**
394
+ * Map of known JavaScript keyidentifiers which do not map to typable
395
+ * characters to their unshifted X11 keysym equivalents.
396
+ *
397
+ * @private
398
+ * @type {!Object.<string, number[]>}
399
+ */
400
+ var keyidentifier_keysym = {
401
+ "Again": [0xFF66],
402
+ "AllCandidates": [0xFF3D],
403
+ "Alphanumeric": [0xFF30],
404
+ "Alt": [0xFFE9, 0xFFE9, 0xFFEA],
405
+ "Attn": [0xFD0E],
406
+ "AltGraph": [0xFE03],
407
+ "ArrowDown": [0xFF54],
408
+ "ArrowLeft": [0xFF51],
409
+ "ArrowRight": [0xFF53],
410
+ "ArrowUp": [0xFF52],
411
+ "Backspace": [0xFF08],
412
+ "CapsLock": [0xFFE5],
413
+ "Cancel": [0xFF69],
414
+ "Clear": [0xFF0B],
415
+ "Convert": [0xFF23],
416
+ "Copy": [0xFD15],
417
+ "Crsel": [0xFD1C],
418
+ "CrSel": [0xFD1C],
419
+ "CodeInput": [0xFF37],
420
+ "Compose": [0xFF20],
421
+ "Control": [0xFFE3, 0xFFE3, 0xFFE4],
422
+ "ContextMenu": [0xFF67],
423
+ "Delete": [0xFFFF],
424
+ "Down": [0xFF54],
425
+ "End": [0xFF57],
426
+ "Enter": [0xFF0D],
427
+ "EraseEof": [0xFD06],
428
+ "Escape": [0xFF1B],
429
+ "Execute": [0xFF62],
430
+ "Exsel": [0xFD1D],
431
+ "ExSel": [0xFD1D],
432
+ "F1": [0xFFBE],
433
+ "F2": [0xFFBF],
434
+ "F3": [0xFFC0],
435
+ "F4": [0xFFC1],
436
+ "F5": [0xFFC2],
437
+ "F6": [0xFFC3],
438
+ "F7": [0xFFC4],
439
+ "F8": [0xFFC5],
440
+ "F9": [0xFFC6],
441
+ "F10": [0xFFC7],
442
+ "F11": [0xFFC8],
443
+ "F12": [0xFFC9],
444
+ "F13": [0xFFCA],
445
+ "F14": [0xFFCB],
446
+ "F15": [0xFFCC],
447
+ "F16": [0xFFCD],
448
+ "F17": [0xFFCE],
449
+ "F18": [0xFFCF],
450
+ "F19": [0xFFD0],
451
+ "F20": [0xFFD1],
452
+ "F21": [0xFFD2],
453
+ "F22": [0xFFD3],
454
+ "F23": [0xFFD4],
455
+ "F24": [0xFFD5],
456
+ "Find": [0xFF68],
457
+ "GroupFirst": [0xFE0C],
458
+ "GroupLast": [0xFE0E],
459
+ "GroupNext": [0xFE08],
460
+ "GroupPrevious": [0xFE0A],
461
+ "FullWidth": null,
462
+ "HalfWidth": null,
463
+ "HangulMode": [0xFF31],
464
+ "Hankaku": [0xFF29],
465
+ "HanjaMode": [0xFF34],
466
+ "Help": [0xFF6A],
467
+ "Hiragana": [0xFF25],
468
+ "HiraganaKatakana": [0xFF27],
469
+ "Home": [0xFF50],
470
+ "Hyper": [0xFFED, 0xFFED, 0xFFEE],
471
+ "Insert": [0xFF63],
472
+ "JapaneseHiragana": [0xFF25],
473
+ "JapaneseKatakana": [0xFF26],
474
+ "JapaneseRomaji": [0xFF24],
475
+ "JunjaMode": [0xFF38],
476
+ "KanaMode": [0xFF2D],
477
+ "KanjiMode": [0xFF21],
478
+ "Katakana": [0xFF26],
479
+ "Left": [0xFF51],
480
+ "Meta": [0xFFE7, 0xFFE7, 0xFFE8],
481
+ "ModeChange": [0xFF7E],
482
+ "NonConvert": [0xFF22],
483
+ "NumLock": [0xFF7F],
484
+ "PageDown": [0xFF56],
485
+ "PageUp": [0xFF55],
486
+ "Pause": [0xFF13],
487
+ "Play": [0xFD16],
488
+ "PreviousCandidate": [0xFF3E],
489
+ "PrintScreen": [0xFF61],
490
+ "Redo": [0xFF66],
491
+ "Right": [0xFF53],
492
+ "Romaji": [0xFF24],
493
+ "RomanCharacters": null,
494
+ "Scroll": [0xFF14],
495
+ "Select": [0xFF60],
496
+ "Separator": [0xFFAC],
497
+ "Shift": [0xFFE1, 0xFFE1, 0xFFE2],
498
+ "SingleCandidate": [0xFF3C],
499
+ "Super": [0xFFEB, 0xFFEB, 0xFFEC],
500
+ "Tab": [0xFF09],
501
+ "UIKeyInputDownArrow": [0xFF54],
502
+ "UIKeyInputEscape": [0xFF1B],
503
+ "UIKeyInputLeftArrow": [0xFF51],
504
+ "UIKeyInputRightArrow": [0xFF53],
505
+ "UIKeyInputUpArrow": [0xFF52],
506
+ "Up": [0xFF52],
507
+ "Undo": [0xFF65],
508
+ "Win": [0xFFE7, 0xFFE7, 0xFFE8],
509
+ "Zenkaku": [0xFF28],
510
+ "ZenkakuHankaku": [0xFF2A]
511
+ };
512
+ /**
513
+ * All keysyms which should not repeat when held down.
514
+ *
515
+ * @private
516
+ * @type {!Object.<number, boolean>}
517
+ */
518
+ var no_repeat = {
519
+ 0xFE03: true, // ISO Level 3 Shift (AltGr)
520
+ 0xFFE1: true, // Left shift
521
+ 0xFFE2: true, // Right shift
522
+ 0xFFE3: true, // Left ctrl
523
+ 0xFFE4: true, // Right ctrl
524
+ 0xFFE5: true, // Caps Lock
525
+ 0xFFE7: true, // Left meta
526
+ 0xFFE8: true, // Right meta
527
+ 0xFFE9: true, // Left alt
528
+ 0xFFEA: true, // Right alt
529
+ 0xFFEB: true, // Left super/hyper
530
+ 0xFFEC: true // Right super/hyper
531
+ };
532
+ /**
533
+ * All modifiers and their states.
534
+ *
535
+ * @type {!Guacamole.Keyboard.ModifierState}
536
+ */
537
+ this.modifiers = new Guacamole.Keyboard.ModifierState();
538
+ /**
539
+ * The state of every key, indexed by keysym. If a particular key is
540
+ * pressed, the value of pressed for that keysym will be true. If a key
541
+ * is not currently pressed, it will not be defined.
542
+ *
543
+ * @type {!Object.<number, boolean>}
544
+ */
545
+ this.pressed = {};
546
+ /**
547
+ * The state of every key, indexed by keysym, for strictly those keys whose
548
+ * status has been indirectly determined thorugh observation of other key
549
+ * events. If a particular key is implicitly pressed, the value of
550
+ * implicitlyPressed for that keysym will be true. If a key
551
+ * is not currently implicitly pressed (the key is not pressed OR the state
552
+ * of the key is explicitly known), it will not be defined.
553
+ *
554
+ * @private
555
+ * @type {!Object.<number, boolean>}
556
+ */
557
+ var implicitlyPressed = {};
558
+ /**
559
+ * The last result of calling the onkeydown handler for each key, indexed
560
+ * by keysym. This is used to prevent/allow default actions for key events,
561
+ * even when the onkeydown handler cannot be called again because the key
562
+ * is (theoretically) still pressed.
563
+ *
564
+ * @private
565
+ * @type {!Object.<number, boolean>}
566
+ */
567
+ var last_keydown_result = {};
568
+ /**
569
+ * The keysym most recently associated with a given keycode when keydown
570
+ * fired. This object maps keycodes to keysyms.
571
+ *
572
+ * @private
573
+ * @type {!Object.<number, number>}
574
+ */
575
+ var recentKeysym = {};
576
+ /**
577
+ * Timeout before key repeat starts.
578
+ *
579
+ * @private
580
+ * @type {number}
581
+ */
582
+ var key_repeat_timeout = null;
583
+ /**
584
+ * Interval which presses and releases the last key pressed while that
585
+ * key is still being held down.
586
+ *
587
+ * @private
588
+ * @type {number}
589
+ */
590
+ var key_repeat_interval = null;
591
+ /**
592
+ * Given an array of keysyms indexed by location, returns the keysym
593
+ * for the given location, or the keysym for the standard location if
594
+ * undefined.
595
+ *
596
+ * @private
597
+ * @param {number[]} keysyms
598
+ * An array of keysyms, where the index of the keysym in the array is
599
+ * the location value.
600
+ *
601
+ * @param {!number} location
602
+ * The location on the keyboard corresponding to the key pressed, as
603
+ * defined at: http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent
604
+ */
605
+ var get_keysym = function get_keysym(keysyms, location) {
606
+ if (!keysyms)
607
+ return null;
608
+ return keysyms[location] || keysyms[0];
609
+ };
610
+ /**
611
+ * Returns true if the given keysym corresponds to a printable character,
612
+ * false otherwise.
613
+ *
614
+ * @param {!number} keysym
615
+ * The keysym to check.
616
+ *
617
+ * @returns {!boolean}
618
+ * true if the given keysym corresponds to a printable character,
619
+ * false otherwise.
620
+ */
621
+ var isPrintable = function isPrintable(keysym) {
622
+ // Keysyms with Unicode equivalents are printable
623
+ return (keysym >= 0x00 && keysym <= 0xFF)
624
+ || (keysym & 0xFFFF0000) === 0x01000000;
625
+ };
626
+ function keysym_from_key_identifier(identifier, location, shifted) {
627
+ if (!identifier)
628
+ return null;
629
+ var typedCharacter;
630
+ // If identifier is U+xxxx, decode Unicode character
631
+ var unicodePrefixLocation = identifier.indexOf("U+");
632
+ if (unicodePrefixLocation >= 0) {
633
+ var hex = identifier.substring(unicodePrefixLocation + 2);
634
+ typedCharacter = String.fromCharCode(parseInt(hex, 16));
635
+ }
636
+ // If single character and not keypad, use that as typed character
637
+ else if (identifier.length === 1 && location !== 3)
638
+ typedCharacter = identifier;
639
+ // Otherwise, look up corresponding keysym
640
+ else
641
+ return get_keysym(keyidentifier_keysym[identifier], location);
642
+ // Alter case if necessary
643
+ if (shifted === true)
644
+ typedCharacter = typedCharacter.toUpperCase();
645
+ else if (shifted === false)
646
+ typedCharacter = typedCharacter.toLowerCase();
647
+ // Get codepoint
648
+ var codepoint = typedCharacter.charCodeAt(0);
649
+ return keysym_from_charcode(codepoint);
650
+ }
651
+ function isControlCharacter(codepoint) {
652
+ return codepoint <= 0x1F || (codepoint >= 0x7F && codepoint <= 0x9F);
653
+ }
654
+ function keysym_from_charcode(codepoint) {
655
+ // Keysyms for control characters
656
+ if (isControlCharacter(codepoint))
657
+ return 0xFF00 | codepoint;
658
+ // Keysyms for ASCII chars
659
+ if (codepoint >= 0x0000 && codepoint <= 0x00FF)
660
+ return codepoint;
661
+ // Keysyms for Unicode
662
+ if (codepoint >= 0x0100 && codepoint <= 0x10FFFF)
663
+ return 0x01000000 | codepoint;
664
+ return null;
665
+ }
666
+ function keysym_from_keycode(keyCode, location) {
667
+ return get_keysym(keycodeKeysyms[keyCode], location);
668
+ }
669
+ /**
670
+ * Heuristically detects if the legacy keyIdentifier property of
671
+ * a keydown/keyup event looks incorrectly derived. Chrome, and
672
+ * presumably others, will produce the keyIdentifier by assuming
673
+ * the keyCode is the Unicode codepoint for that key. This is not
674
+ * correct in all cases.
675
+ *
676
+ * @private
677
+ * @param {!number} keyCode
678
+ * The keyCode from a browser keydown/keyup event.
679
+ *
680
+ * @param {string} keyIdentifier
681
+ * The legacy keyIdentifier from a browser keydown/keyup event.
682
+ *
683
+ * @returns {!boolean}
684
+ * true if the keyIdentifier looks sane, false if the keyIdentifier
685
+ * appears incorrectly derived or is missing entirely.
686
+ */
687
+ var key_identifier_sane = function key_identifier_sane(keyCode, keyIdentifier) {
688
+ // Missing identifier is not sane
689
+ if (!keyIdentifier)
690
+ return false;
691
+ // Assume non-Unicode keyIdentifier values are sane
692
+ var unicodePrefixLocation = keyIdentifier.indexOf("U+");
693
+ if (unicodePrefixLocation === -1)
694
+ return true;
695
+ // If the Unicode codepoint isn't identical to the keyCode,
696
+ // then the identifier is likely correct
697
+ var codepoint = parseInt(keyIdentifier.substring(unicodePrefixLocation + 2), 16);
698
+ if (keyCode !== codepoint)
699
+ return true;
700
+ // The keyCodes for A-Z and 0-9 are actually identical to their
701
+ // Unicode codepoints
702
+ if ((keyCode >= 65 && keyCode <= 90) || (keyCode >= 48 && keyCode <= 57))
703
+ return true;
704
+ // The keyIdentifier does NOT appear sane
705
+ return false;
706
+ };
707
+ /**
708
+ * Marks a key as pressed, firing the keydown event if registered. Key
709
+ * repeat for the pressed key will start after a delay if that key is
710
+ * not a modifier. The return value of this function depends on the
711
+ * return value of the keydown event handler, if any.
712
+ *
713
+ * @param {number} keysym
714
+ * The keysym of the key to press.
715
+ *
716
+ * @return {boolean}
717
+ * true if event should NOT be canceled, false otherwise.
718
+ */
719
+ this.press = function (keysym) {
720
+ // Don't bother with pressing the key if the key is unknown
721
+ if (keysym === null)
722
+ return;
723
+ // Only press if released
724
+ if (!guac_keyboard.pressed[keysym]) {
725
+ // Mark key as pressed
726
+ guac_keyboard.pressed[keysym] = true;
727
+ // Send key event
728
+ if (guac_keyboard.onkeydown) {
729
+ var result = guac_keyboard.onkeydown(keysym);
730
+ last_keydown_result[keysym] = result;
731
+ // Stop any current repeat
732
+ window.clearTimeout(key_repeat_timeout);
733
+ window.clearInterval(key_repeat_interval);
734
+ // Repeat after a delay as long as pressed
735
+ if (!no_repeat[keysym])
736
+ key_repeat_timeout = window.setTimeout(function () {
737
+ key_repeat_interval = window.setInterval(function () {
738
+ guac_keyboard.onkeyup(keysym);
739
+ guac_keyboard.onkeydown(keysym);
740
+ }, 50);
741
+ }, 500);
742
+ return result;
743
+ }
744
+ }
745
+ // Return the last keydown result by default, resort to false if unknown
746
+ return last_keydown_result[keysym] || false;
747
+ };
748
+ /**
749
+ * Marks a key as released, firing the keyup event if registered.
750
+ *
751
+ * @param {number} keysym
752
+ * The keysym of the key to release.
753
+ */
754
+ this.release = function (keysym) {
755
+ // Only release if pressed
756
+ if (guac_keyboard.pressed[keysym]) {
757
+ // Mark key as released
758
+ delete guac_keyboard.pressed[keysym];
759
+ delete implicitlyPressed[keysym];
760
+ // Stop repeat
761
+ window.clearTimeout(key_repeat_timeout);
762
+ window.clearInterval(key_repeat_interval);
763
+ // Send key event
764
+ if (keysym !== null && guac_keyboard.onkeyup)
765
+ guac_keyboard.onkeyup(keysym);
766
+ }
767
+ };
768
+ /**
769
+ * Presses and releases the keys necessary to type the given string of
770
+ * text.
771
+ *
772
+ * @param {!string} str
773
+ * The string to type.
774
+ */
775
+ this.type = function type(str) {
776
+ // Press/release the key corresponding to each character in the string
777
+ for (var i = 0; i < str.length; i++) {
778
+ // Determine keysym of current character
779
+ var codepoint = str.codePointAt ? str.codePointAt(i) : str.charCodeAt(i);
780
+ var keysym = keysym_from_charcode(codepoint);
781
+ // Press and release key for current character
782
+ guac_keyboard.press(keysym);
783
+ guac_keyboard.release(keysym);
784
+ }
785
+ };
786
+ /**
787
+ * Resets the state of this keyboard, releasing all keys, and firing keyup
788
+ * events for each released key.
789
+ */
790
+ this.reset = function () {
791
+ // Release all pressed keys
792
+ for (var keysym in guac_keyboard.pressed)
793
+ guac_keyboard.release(parseInt(keysym));
794
+ // Clear event log
795
+ eventLog = [];
796
+ };
797
+ /**
798
+ * Resynchronizes the remote state of the given modifier with its
799
+ * corresponding local modifier state, as dictated by
800
+ * {@link KeyEvent#modifiers} within the given key event, by pressing or
801
+ * releasing keysyms.
802
+ *
803
+ * @private
804
+ * @param {!string} modifier
805
+ * The name of the {@link Guacamole.Keyboard.ModifierState} property
806
+ * being updated.
807
+ *
808
+ * @param {!number[]} keysyms
809
+ * The keysyms which represent the modifier being updated.
810
+ *
811
+ * @param {!KeyEvent} keyEvent
812
+ * Guacamole's current best interpretation of the key event being
813
+ * processed.
814
+ */
815
+ var updateModifierState = function updateModifierState(modifier, keysyms, keyEvent) {
816
+ var localState = keyEvent.modifiers[modifier];
817
+ var remoteState = guac_keyboard.modifiers[modifier];
818
+ var i;
819
+ // Do not trust changes in modifier state for events directly involving
820
+ // that modifier: (1) the flag may erroneously be cleared despite
821
+ // another version of the same key still being held and (2) the change
822
+ // in flag may be due to the current event being processed, thus
823
+ // updating things here is at best redundant and at worst incorrect
824
+ if (keysyms.indexOf(keyEvent.keysym) !== -1)
825
+ return;
826
+ // Release all related keys if modifier is implicitly released
827
+ if (remoteState && localState === false) {
828
+ for (i = 0; i < keysyms.length; i++) {
829
+ guac_keyboard.release(keysyms[i]);
830
+ }
831
+ }
832
+ // Press if modifier is implicitly pressed
833
+ else if (!remoteState && localState) {
834
+ // Verify that modifier flag isn't already pressed or already set
835
+ // due to another version of the same key being held down
836
+ for (i = 0; i < keysyms.length; i++) {
837
+ if (guac_keyboard.pressed[keysyms[i]])
838
+ return;
839
+ }
840
+ // Mark as implicitly pressed only if there is other information
841
+ // within the key event relating to a different key. Some
842
+ // platforms, such as iOS, will send essentially empty key events
843
+ // for modifier keys, using only the modifier flags to signal the
844
+ // identity of the key.
845
+ var keysym = keysyms[0];
846
+ if (keyEvent.keysym)
847
+ implicitlyPressed[keysym] = true;
848
+ guac_keyboard.press(keysym);
849
+ }
850
+ };
851
+ /**
852
+ * Given a keyboard event, updates the remote key state to match the local
853
+ * modifier state and remote based on the modifier flags within the event.
854
+ * This function pays no attention to keycodes.
855
+ *
856
+ * @private
857
+ * @param {!KeyEvent} keyEvent
858
+ * Guacamole's current best interpretation of the key event being
859
+ * processed.
860
+ */
861
+ var syncModifierStates = function syncModifierStates(keyEvent) {
862
+ // Resync state of alt
863
+ updateModifierState('alt', [
864
+ 0xFFE9, // Left alt
865
+ 0xFFEA, // Right alt
866
+ 0xFE03 // AltGr
867
+ ], keyEvent);
868
+ // Resync state of shift
869
+ updateModifierState('shift', [
870
+ 0xFFE1, // Left shift
871
+ 0xFFE2 // Right shift
872
+ ], keyEvent);
873
+ // Resync state of ctrl
874
+ updateModifierState('ctrl', [
875
+ 0xFFE3, // Left ctrl
876
+ 0xFFE4 // Right ctrl
877
+ ], keyEvent);
878
+ // Resync state of meta
879
+ updateModifierState('meta', [
880
+ 0xFFE7, // Left meta
881
+ 0xFFE8 // Right meta
882
+ ], keyEvent);
883
+ // Resync state of hyper
884
+ updateModifierState('hyper', [
885
+ 0xFFEB, // Left super/hyper
886
+ 0xFFEC // Right super/hyper
887
+ ], keyEvent);
888
+ // Update state
889
+ guac_keyboard.modifiers = keyEvent.modifiers;
890
+ };
891
+ /**
892
+ * Returns whether all currently pressed keys were implicitly pressed. A
893
+ * key is implicitly pressed if its status was inferred indirectly from
894
+ * inspection of other key events.
895
+ *
896
+ * @private
897
+ * @returns {!boolean}
898
+ * true if all currently pressed keys were implicitly pressed, false
899
+ * otherwise.
900
+ */
901
+ var isStateImplicit = function isStateImplicit() {
902
+ for (var keysym in guac_keyboard.pressed) {
903
+ if (!implicitlyPressed[keysym])
904
+ return false;
905
+ }
906
+ return true;
907
+ };
908
+ /**
909
+ * Reads through the event log, removing events from the head of the log
910
+ * when the corresponding true key presses are known (or as known as they
911
+ * can be).
912
+ *
913
+ * @private
914
+ * @return {boolean}
915
+ * Whether the default action of the latest event should be prevented.
916
+ */
917
+ function interpret_events() {
918
+ // Do not prevent default if no event could be interpreted
919
+ var handled_event = interpret_event();
920
+ if (!handled_event)
921
+ return false;
922
+ // Interpret as much as possible
923
+ var last_event;
924
+ do {
925
+ last_event = handled_event;
926
+ handled_event = interpret_event();
927
+ } while (handled_event !== null);
928
+ // Reset keyboard state if we cannot expect to receive any further
929
+ // keyup events
930
+ if (isStateImplicit())
931
+ guac_keyboard.reset();
932
+ return last_event.defaultPrevented;
933
+ }
934
+ /**
935
+ * Releases Ctrl+Alt, if both are currently pressed and the given keysym
936
+ * looks like a key that may require AltGr.
937
+ *
938
+ * @private
939
+ * @param {!number} keysym
940
+ * The key that was just pressed.
941
+ */
942
+ var release_simulated_altgr = function release_simulated_altgr(keysym) {
943
+ // Both Ctrl+Alt must be pressed if simulated AltGr is in use
944
+ if (!guac_keyboard.modifiers.ctrl || !guac_keyboard.modifiers.alt)
945
+ return;
946
+ // Assume [A-Z] never require AltGr
947
+ if (keysym >= 0x0041 && keysym <= 0x005A)
948
+ return;
949
+ // Assume [a-z] never require AltGr
950
+ if (keysym >= 0x0061 && keysym <= 0x007A)
951
+ return;
952
+ // Release Ctrl+Alt if the keysym is printable
953
+ if (keysym <= 0xFF || (keysym & 0xFF000000) === 0x01000000) {
954
+ guac_keyboard.release(0xFFE3); // Left ctrl
955
+ guac_keyboard.release(0xFFE4); // Right ctrl
956
+ guac_keyboard.release(0xFFE9); // Left alt
957
+ guac_keyboard.release(0xFFEA); // Right alt
958
+ }
959
+ };
960
+ /**
961
+ * Reads through the event log, interpreting the first event, if possible,
962
+ * and returning that event. If no events can be interpreted, due to a
963
+ * total lack of events or the need for more events, null is returned. Any
964
+ * interpreted events are automatically removed from the log.
965
+ *
966
+ * @private
967
+ * @return {KeyEvent}
968
+ * The first key event in the log, if it can be interpreted, or null
969
+ * otherwise.
970
+ */
971
+ var interpret_event = function interpret_event() {
972
+ // Peek at first event in log
973
+ var first = eventLog[0];
974
+ if (!first)
975
+ return null;
976
+ // Keydown event
977
+ if (first instanceof KeydownEvent) {
978
+ var keysym = null;
979
+ var accepted_events = [];
980
+ // Defer handling of Meta until it is known to be functioning as a
981
+ // modifier (it may otherwise actually be an alternative method for
982
+ // pressing a single key, such as Meta+Left for Home on ChromeOS)
983
+ if (first.keysym === 0xFFE7 || first.keysym === 0xFFE8) {
984
+ // Defer handling until further events exist to provide context
985
+ if (eventLog.length === 1)
986
+ return null;
987
+ // Drop keydown if it turns out Meta does not actually apply
988
+ if (eventLog[1].keysym !== first.keysym) {
989
+ if (!eventLog[1].modifiers.meta)
990
+ return eventLog.shift();
991
+ }
992
+ // Drop duplicate keydown events while waiting to determine
993
+ // whether to acknowledge Meta (browser may repeat keydown
994
+ // while the key is held)
995
+ else if (eventLog[1] instanceof KeydownEvent)
996
+ return eventLog.shift();
997
+ }
998
+ // If event itself is reliable, no need to wait for other events
999
+ if (first.reliable) {
1000
+ keysym = first.keysym;
1001
+ accepted_events = eventLog.splice(0, 1);
1002
+ }
1003
+ // If keydown is immediately followed by a keypress, use the indicated character
1004
+ else if (eventLog[1] instanceof KeypressEvent) {
1005
+ keysym = eventLog[1].keysym;
1006
+ accepted_events = eventLog.splice(0, 2);
1007
+ }
1008
+ // If keydown is immediately followed by anything else, then no
1009
+ // keypress can possibly occur to clarify this event, and we must
1010
+ // handle it now
1011
+ else if (eventLog[1]) {
1012
+ keysym = first.keysym;
1013
+ accepted_events = eventLog.splice(0, 1);
1014
+ }
1015
+ // Fire a key press if valid events were found
1016
+ if (accepted_events.length > 0) {
1017
+ syncModifierStates(first);
1018
+ if (keysym) {
1019
+ // Fire event
1020
+ release_simulated_altgr(keysym);
1021
+ var defaultPrevented = !guac_keyboard.press(keysym);
1022
+ recentKeysym[first.keyCode] = keysym;
1023
+ // Release the key now if we cannot rely on the associated
1024
+ // keyup event
1025
+ if (!first.keyupReliable)
1026
+ guac_keyboard.release(keysym);
1027
+ // Record whether default was prevented
1028
+ for (var i = 0; i < accepted_events.length; i++)
1029
+ accepted_events[i].defaultPrevented = defaultPrevented;
1030
+ }
1031
+ return first;
1032
+ }
1033
+ } // end if keydown
1034
+ // Keyup event
1035
+ else if (first instanceof KeyupEvent && !quirks.keyupUnreliable) {
1036
+ // Release specific key if known
1037
+ var keysym = first.keysym;
1038
+ if (keysym) {
1039
+ guac_keyboard.release(keysym);
1040
+ delete recentKeysym[first.keyCode];
1041
+ first.defaultPrevented = true;
1042
+ }
1043
+ // Otherwise, fall back to releasing all keys
1044
+ else {
1045
+ guac_keyboard.reset();
1046
+ return first;
1047
+ }
1048
+ syncModifierStates(first);
1049
+ return eventLog.shift();
1050
+ } // end if keyup
1051
+ // Ignore any other type of event (keypress by itself is invalid, and
1052
+ // unreliable keyup events should simply be dumped)
1053
+ else
1054
+ return eventLog.shift();
1055
+ // No event interpreted
1056
+ return null;
1057
+ };
1058
+ /**
1059
+ * Returns the keyboard location of the key associated with the given
1060
+ * keyboard event. The location differentiates key events which otherwise
1061
+ * have the same keycode, such as left shift vs. right shift.
1062
+ *
1063
+ * @private
1064
+ * @param {!KeyboardEvent} e
1065
+ * A JavaScript keyboard event, as received through the DOM via a
1066
+ * "keydown", "keyup", or "keypress" handler.
1067
+ *
1068
+ * @returns {!number}
1069
+ * The location of the key event on the keyboard, as defined at:
1070
+ * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent
1071
+ */
1072
+ var getEventLocation = function getEventLocation(e) {
1073
+ // Use standard location, if possible
1074
+ if ('location' in e)
1075
+ return e.location;
1076
+ // Failing that, attempt to use deprecated keyLocation
1077
+ if ('keyLocation' in e)
1078
+ return e.keyLocation;
1079
+ // If no location is available, assume left side
1080
+ return 0;
1081
+ };
1082
+ /**
1083
+ * Attempts to mark the given Event as having been handled by this
1084
+ * Guacamole.Keyboard. If the Event has already been marked as handled,
1085
+ * false is returned.
1086
+ *
1087
+ * @param {!Event} e
1088
+ * The Event to mark.
1089
+ *
1090
+ * @returns {!boolean}
1091
+ * true if the given Event was successfully marked, false if the given
1092
+ * Event was already marked.
1093
+ */
1094
+ var markEvent = function markEvent(e) {
1095
+ // Fail if event is already marked
1096
+ if (e[EVENT_MARKER])
1097
+ return false;
1098
+ // Mark event otherwise
1099
+ e[EVENT_MARKER] = true;
1100
+ return true;
1101
+ };
1102
+ /**
1103
+ * Attaches event listeners to the given Element, automatically translating
1104
+ * received key, input, and composition events into simple keydown/keyup
1105
+ * events signalled through this Guacamole.Keyboard's onkeydown and
1106
+ * onkeyup handlers.
1107
+ *
1108
+ * @param {!(Element|Document)} element
1109
+ * The Element to attach event listeners to for the sake of handling
1110
+ * key or input events.
1111
+ */
1112
+ this.listenTo = function listenTo(element) {
1113
+ // When key pressed
1114
+ element.addEventListener("keydown", function (e) {
1115
+ // Only intercept if handler set
1116
+ if (!guac_keyboard.onkeydown)
1117
+ return;
1118
+ // Ignore events which have already been handled
1119
+ if (!markEvent(e))
1120
+ return;
1121
+ var keydownEvent = new KeydownEvent(e);
1122
+ // Ignore (but do not prevent) the event if explicitly marked as composing,
1123
+ // or when the "composition" keycode sent by some browsers when an IME is in use
1124
+ // (see: http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html)
1125
+ if (e.isComposing || keydownEvent.keyCode === 229)
1126
+ return;
1127
+ // Log event
1128
+ eventLog.push(keydownEvent);
1129
+ // Interpret as many events as possible, prevent default if indicated
1130
+ if (interpret_events())
1131
+ e.preventDefault();
1132
+ }, true);
1133
+ // When key pressed
1134
+ element.addEventListener("keypress", function (e) {
1135
+ // Only intercept if handler set
1136
+ if (!guac_keyboard.onkeydown && !guac_keyboard.onkeyup)
1137
+ return;
1138
+ // Ignore events which have already been handled
1139
+ if (!markEvent(e))
1140
+ return;
1141
+ // Log event
1142
+ eventLog.push(new KeypressEvent(e));
1143
+ // Interpret as many events as possible, prevent default if indicated
1144
+ if (interpret_events())
1145
+ e.preventDefault();
1146
+ }, true);
1147
+ // When key released
1148
+ element.addEventListener("keyup", function (e) {
1149
+ // Only intercept if handler set
1150
+ if (!guac_keyboard.onkeyup)
1151
+ return;
1152
+ // Ignore events which have already been handled
1153
+ if (!markEvent(e))
1154
+ return;
1155
+ e.preventDefault();
1156
+ // Log event, call for interpretation
1157
+ eventLog.push(new KeyupEvent(e));
1158
+ interpret_events();
1159
+ }, true);
1160
+ /**
1161
+ * Handles the given "input" event, typing the data within the input text.
1162
+ *
1163
+ * @private
1164
+ * @param {!InputEvent} e
1165
+ * The "input" event to handle.
1166
+ */
1167
+ var handleInput = function handleInput(e) {
1168
+ // Only intercept if handler set
1169
+ if (!guac_keyboard.onkeydown && !guac_keyboard.onkeyup)
1170
+ return;
1171
+ // Ignore events which have already been handled
1172
+ if (!markEvent(e))
1173
+ return;
1174
+ // Type all content written
1175
+ if (e.data && !e.isComposing)
1176
+ guac_keyboard.type(e.data);
1177
+ };
1178
+ /**
1179
+ * Handles the given "compositionstart" event, automatically removing
1180
+ * the "input" event handler, as "input" events should only be handled
1181
+ * if composition events are not provided by the browser.
1182
+ *
1183
+ * @private
1184
+ * @param {!CompositionEvent} e
1185
+ * The "compositionstart" event to handle.
1186
+ */
1187
+ var handleCompositionStart = function handleCompositionStart(e) {
1188
+ // Remove the "input" event handler now that the browser is known
1189
+ // to send composition events
1190
+ element.removeEventListener("input", handleInput, false);
1191
+ };
1192
+ /**
1193
+ * Handles the given "compositionend" event, typing the data within the
1194
+ * composed text.
1195
+ *
1196
+ * @private
1197
+ * @param {!CompositionEvent} e
1198
+ * The "compositionend" event to handle.
1199
+ */
1200
+ var handleCompositionEnd = function handleCompositionEnd(e) {
1201
+ // Only intercept if handler set
1202
+ if (!guac_keyboard.onkeydown && !guac_keyboard.onkeyup)
1203
+ return;
1204
+ // Ignore events which have already been handled
1205
+ if (!markEvent(e))
1206
+ return;
1207
+ // Type all content written
1208
+ if (e.data)
1209
+ guac_keyboard.type(e.data);
1210
+ };
1211
+ // Automatically type text entered into the wrapped field
1212
+ element.addEventListener("input", handleInput, false);
1213
+ element.addEventListener("compositionend", handleCompositionEnd, false);
1214
+ element.addEventListener("compositionstart", handleCompositionStart, false);
1215
+ };
1216
+ // Listen to given element, if any
1217
+ if (element)
1218
+ guac_keyboard.listenTo(element);
1219
+ };
1220
+ /**
1221
+ * The unique numerical identifier to assign to the next Guacamole.Keyboard
1222
+ * instance.
1223
+ *
1224
+ * @private
1225
+ * @type {!number}
1226
+ */
1227
+ Guacamole.Keyboard._nextID = 0;
1228
+ /**
1229
+ * The state of all supported keyboard modifiers.
1230
+ * @constructor
1231
+ */
1232
+ Guacamole.Keyboard.ModifierState = function () {
1233
+ /**
1234
+ * Whether shift is currently pressed.
1235
+ *
1236
+ * @type {!boolean}
1237
+ */
1238
+ this.shift = false;
1239
+ /**
1240
+ * Whether ctrl is currently pressed.
1241
+ *
1242
+ * @type {!boolean}
1243
+ */
1244
+ this.ctrl = false;
1245
+ /**
1246
+ * Whether alt is currently pressed.
1247
+ *
1248
+ * @type {!boolean}
1249
+ */
1250
+ this.alt = false;
1251
+ /**
1252
+ * Whether meta (apple key) is currently pressed.
1253
+ *
1254
+ * @type {!boolean}
1255
+ */
1256
+ this.meta = false;
1257
+ /**
1258
+ * Whether hyper (windows key) is currently pressed.
1259
+ *
1260
+ * @type {!boolean}
1261
+ */
1262
+ this.hyper = false;
1263
+ };
1264
+ /**
1265
+ * Returns the modifier state applicable to the keyboard event given.
1266
+ *
1267
+ * @param {!KeyboardEvent} e
1268
+ * The keyboard event to read.
1269
+ *
1270
+ * @returns {!Guacamole.Keyboard.ModifierState}
1271
+ * The current state of keyboard modifiers.
1272
+ */
1273
+ Guacamole.Keyboard.ModifierState.fromKeyboardEvent = function (e) {
1274
+ var state = new Guacamole.Keyboard.ModifierState();
1275
+ // Assign states from old flags
1276
+ state.shift = e.shiftKey;
1277
+ state.ctrl = e.ctrlKey;
1278
+ state.alt = e.altKey;
1279
+ state.meta = e.metaKey;
1280
+ // Use DOM3 getModifierState() for others
1281
+ if (e.getModifierState) {
1282
+ state.hyper = e.getModifierState("OS")
1283
+ || e.getModifierState("Super")
1284
+ || e.getModifierState("Hyper")
1285
+ || e.getModifierState("Win");
1286
+ }
1287
+ return state;
1288
+ };
1289
+ module.exports = Guacamole;
1290
+ //# sourceMappingURL=GuacamoleKeyboard.js.map