From ec34af8f6133f5b5603f47b0c3f91bde60e6d9b5 Mon Sep 17 00:00:00 2001 From: jalf Date: Fri, 5 Apr 2013 13:45:27 +0200 Subject: [PATCH 001/100] Use wss when creating localhost connection to detect binary support Some browsers (Firefox) reject unencrypted ws connections if the hosting page uses https by throwing an exception when you create the websocket object. NoVNC interprets this as binary being unsupported, and falls back to base64. If we instead connect to wss://localhost, the websocket object can be created regardless of whether the hosting page is on http or https. --- include/websock.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/websock.js b/include/websock.js index 01a24c3f..b8cc46f6 100644 --- a/include/websock.js +++ b/include/websock.js @@ -282,7 +282,7 @@ function init(protocols) { // TODO: this sucks, the property should exist on the prototype // but it does not. try { - if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { + if (bt && ('binaryType' in (new WebSocket("wss://localhost:17523")))) { Util.Info("Detected binaryType support in WebSockets"); wsbt = true; } From c3c51ed32bed6334a54aead8649810e6b44c9549 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 25 Apr 2013 09:52:10 -0500 Subject: [PATCH 002/100] Sync with websockify. Pull in websockify 4725aa7. - Update to c0855c6cae of web-socket-js - Update both the submodule and the swf build. The submodule now contains the unobfuscated source for swfobject.js which should make websockify more DFSG compliant. - Remove Hixie support. iOS 6 now includes HyBi support which means there is no remaining platform that needs Hixie. --- include/web-socket-js-project | 2 +- include/web-socket-js/WebSocketMain.swf | Bin 177114 -> 177139 bytes utils/websocket.py | 149 +++++------------------- 3 files changed, 28 insertions(+), 123 deletions(-) diff --git a/include/web-socket-js-project b/include/web-socket-js-project index 7677e7a9..c0855c6c 160000 --- a/include/web-socket-js-project +++ b/include/web-socket-js-project @@ -1 +1 @@ -Subproject commit 7677e7a954561cc44dac7659219bef768c904b62 +Subproject commit c0855c6caec589c33acc22b6ee5e562287e65f3d diff --git a/include/web-socket-js/WebSocketMain.swf b/include/web-socket-js/WebSocketMain.swf index 8174466912475a494681e9436844f4bf90d909f9..f286c81aacc954953086a97dfff7e4e18e78b6bc 100644 GIT binary patch delta 160622 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

Hv6p(> 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', - int(num1), int(num2), key3)).digest()) # # WebSocketServer logging/output functions @@ -444,16 +409,10 @@ Sec-WebSocket-Accept: %s\r if bufs: for buf in bufs: - if self.version.startswith("hybi"): - if self.base64: - encbuf, lenhead, lentail = self.encode_hybi( - buf, opcode=1, base64=True) - else: - encbuf, lenhead, lentail = self.encode_hybi( - buf, opcode=2, base64=False) - + if self.base64: + encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=1, base64=True) else: - encbuf, lenhead, lentail = self.encode_hixie(buf) + encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=2, base64=False) if self.rec: self.rec.write("%s,\n" % @@ -498,41 +457,21 @@ Sec-WebSocket-Accept: %s\r self.recv_part = None while buf: - if self.version.startswith("hybi"): - - frame = self.decode_hybi(buf, base64=self.base64) - #print("Received buf: %s, frame: %s" % (repr(buf), frame)) - - if frame['payload'] == None: - # Incomplete/partial frame - self.traffic("}.") - if frame['left'] > 0: - self.recv_part = buf[-frame['left']:] - break - else: - if frame['opcode'] == 0x8: # connection close - closed = {'code': frame['close_code'], - 'reason': frame['close_reason']} - break + frame = self.decode_hybi(buf, base64=self.base64) + #print("Received buf: %s, frame: %s" % (repr(buf), frame)) + if frame['payload'] == None: + # Incomplete/partial frame + self.traffic("}.") + if frame['left'] > 0: + self.recv_part = buf[-frame['left']:] + break else: - if buf[0:2] == s2b('\xff\x00'): - closed = {'code': 1000, - 'reason': "Client sent orderly close frame"} + if frame['opcode'] == 0x8: # connection close + closed = {'code': frame['close_code'], + 'reason': frame['close_reason']} break - elif buf[0:2] == s2b('\x00\xff'): - buf = buf[2:] - continue # No-op - - elif buf.count(s2b('\xff')) == 0: - # Partial frame - self.traffic("}.") - self.recv_part = buf - break - - frame = self.decode_hixie(buf) - self.traffic("}") if self.rec: @@ -560,17 +499,9 @@ Sec-WebSocket-Accept: %s\r def send_close(self, code=1000, reason=''): """ Send a WebSocket orderly close frame. """ - if self.version.startswith("hybi"): - msg = pack(">H%ds" % len(reason), code, reason) - - buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False) - self.client.send(buf) - - elif self.version == "hixie-76": - buf = s2b('\xff\x00') - self.client.send(buf) - - # No orderly close for 75 + msg = pack(">H%ds" % len(reason), code, reason) + buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False) + self.client.send(buf) def do_websocket_handshake(self, headers, path): h = self.headers = headers @@ -612,28 +543,7 @@ Sec-WebSocket-Accept: %s\r response += "\r\n" else: - # Hixie version of the protocol (75 or 76) - - if h.get('key3'): - trailer = self.gen_md5(h) - pre = "Sec-" - self.version = "hixie-76" - else: - trailer = "" - pre = "" - self.version = "hixie-75" - - # We only support base64 in Hixie era - self.base64 = True - - response = self.server_handshake_hixie % (pre, - h['Origin'], pre, self.scheme, h['Host'], path) - - if 'base64' in protocols: - response += "%sWebSocket-Protocol: base64\r\n" % pre - else: - self.msg("Warning: client does not report 'base64' protocol support") - response += "\r\n" + trailer + raise self.EClose("Missing Sec-WebSocket-Version header. Hixie protocols not supported.") return response @@ -957,11 +867,6 @@ class WSRequestHandler(SimpleHTTPRequestHandler): if (self.headers.get('upgrade') and self.headers.get('upgrade').lower() == 'websocket'): - if (self.headers.get('sec-websocket-key1') or - self.headers.get('websocket-key1')): - # For Hixie-76 read out the key hash - self.headers.__setitem__('key3', self.rfile.read(8)) - # Just indicate that an WebSocket upgrade is needed self.last_code = 101 self.last_message = "101 Switching Protocols" From dfcedffc16a278815f56b78d6543f524fd4ba1cc Mon Sep 17 00:00:00 2001 From: samhed Date: Mon, 22 Jul 2013 15:46:59 +0200 Subject: [PATCH 003/100] Make noVNC follow the RFB protocol and keep only one outstanding framebufferUpdate request at a time. --- include/rfb.js | 51 +++++++++++++------------------------------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index 16ae76d5..c15bc30d 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -103,7 +103,6 @@ var that = {}, // Public API methods fb_height = 0, fb_name = "", - last_req_time = 0, rre_chunk_sz = 100, timing = { @@ -148,9 +147,6 @@ Util.conf_defaults(conf, that, defaults, [ ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'], - ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], - ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'], - // Callback functions ['onUpdateState', 'rw', 'func', function() { }, 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '], @@ -569,44 +565,18 @@ function genDES(password, challenge) { return (new DES(passwd)).encrypt(challenge); } -function flushClient() { - if (mouse_arr.length > 0) { - //send(mouse_arr.concat(fbUpdateRequests())); - ws.send(mouse_arr); - setTimeout(function() { - ws.send(fbUpdateRequests()); - }, 50); - - mouse_arr = []; - return true; - } else { - return false; - } -} - // overridable for testing checkEvents = function() { - var now; - if (rfb_state === 'normal' && !viewportDragging) { - if (! flushClient()) { - now = new Date().getTime(); - if (now > last_req_time + conf.fbu_req_rate) { - last_req_time = now; - ws.send(fbUpdateRequests()); - } - } + if (rfb_state === 'normal' && !viewportDragging && mouse_arr.length > 0) { + ws.send(mouse_arr); + mouse_arr = []; } - setTimeout(checkEvents, conf.check_rate); }; keyPress = function(keysym, down) { - var arr; - if (conf.view_only) { return; } // View only, skip keyboard events - arr = keyEvent(keysym, down); - arr = arr.concat(fbUpdateRequests()); - ws.send(arr); + ws.send(keyEvent(keysym, down)); }; mouseButton = function(x, y, down, bmask) { @@ -633,7 +603,8 @@ mouseButton = function(x, y, down, bmask) { mouse_arr = mouse_arr.concat( pointerEvent(display.absX(x), display.absY(y)) ); - flushClient(); + ws.send(mouse_arr); + mouse_arr = []; }; mouseMove = function(x, y) { @@ -656,7 +627,9 @@ mouseMove = function(x, y) { if (conf.view_only) { return; } // View only, skip mouse events mouse_arr = mouse_arr.concat( - pointerEvent(display.absX(x), display.absY(y)) ); + pointerEvent(display.absX(x), display.absY(y))); + + checkEvents(); }; @@ -905,8 +878,7 @@ init_msg = function() { timing.pixels = 0; ws.send(response); - /* Start pushing/polling */ - setTimeout(checkEvents, conf.check_rate); + checkEvents(); if (conf.encrypt) { updateState('normal', "Connected (encrypted) to: " + fb_name); @@ -934,6 +906,9 @@ normal_msg = function() { switch (msg_type) { case 0: // FramebufferUpdate ret = framebufferUpdate(); // false means need more data + if (ret) { + ws.send(fbUpdateRequests()); + } break; case 1: // SetColourMapEntries Util.Debug("SetColourMapEntries"); From 41c66fbfcd31472f82c4a12bb712a2d798e1b477 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 25 Jul 2013 12:48:44 +0200 Subject: [PATCH 004/100] Added new images for the extra keys --- images/alt.png | Bin 0 -> 339 bytes images/ctrl.png | Bin 0 -> 354 bytes images/esc.png | Bin 0 -> 385 bytes images/showextrakeys.png | Bin 0 -> 735 bytes images/tab.png | Bin 0 -> 387 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/alt.png create mode 100644 images/ctrl.png create mode 100644 images/esc.png create mode 100644 images/showextrakeys.png create mode 100644 images/tab.png diff --git a/images/alt.png b/images/alt.png new file mode 100644 index 0000000000000000000000000000000000000000..d42af7b421b9f1193620cb4a7114f1df27886d1c GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)y9AGfn3c|@SfJ1YPZ!4!kK=DA?d4@Mvg-UsUjQv!4@3E(23Sx$<4+2dh>^&G&f67BAwO*^{~A)gQHlw4ThU?9=P7U#iY$ zoU@gULH+&Szpr+?q{tjL>$J>$WYr(E@cJVsj=AZ~_m3?|T-1=LlQ4TyhX?0_FWA34~+4u?EKa`a+$6maEEblBXv zqublI^Z5ssChmi=1rK>`n#>Cpc5LscXyxJQ&70LIB0IC{X&RH3tZ?$3uhC)uAAQ%~ z=dm#0#6w#pC2J)m-^*`i-jt|dOLJh#dSJNyOLkI^a{|+uvu}bz`JFkM*S+>@X!rHq z_o7j{y!=7c)kEp~_RqX&X~247rqA8G!CuF+|LYjD=OyU#_5bp}sYKbLh*2~7a?){X-J literal 0 HcmV?d00001 diff --git a/images/esc.png b/images/esc.png new file mode 100644 index 0000000000000000000000000000000000000000..ece5f7cbef684a41f4a7bb9d632e4cb2310d6b5d GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)y9AG<$XUxK0|o|0K2I0N5Rc<;r)=~(;vmpwt~763 z(rf03YMC%Gv!>p;`x=s-3jg3Sv+J08Hk7^Wk+j5=)(kI8VZ)Z0e~+b2TwvK-mAbF2 z{@d)ElGk?5n>TO1$DHDGXL8aMJSYA45_?{oD9s()th9+WhB^2Fuf*zCdB(y{77Tew z&kS1%{uE|Re6Mm~@64I2-aW6}r=)cIK&W#;RvKH+>Qzztr;B)Z{7}kVtXRpGB`8_- zo?X|~X2#5`rF$<%rB3&A;!r=3y(X+NI`nR)$B{ESr#C&d_Xb*BZ7(n}k>jDxsd>+C zaTaJQEjIC;?vf&+TE00gNaUzi!N1irSGP000>X1^@s6#OZ}&00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3J*792=g7&T0Sv0&Gb{ zK~zY`y;U)56hRdJ-ppi!CtQjM#~p&_LBP(=X7C5tSO^h>^eIGa36M2V8-Xh|B|c z0YCsW^8Y^p1OTrA>=4nxq$KMA7Do8L0eDPA`$bOYTou6Q5WwB?-B01PwB;o+fp z@6A9JPGh|HW^;3MYIb&(lu~2>JOprWOfs+X(zO7*G{&IWY)S}WI)qTwS_1&I)`+60 zs=k~97!Nf5{J2{SKSYZsk! zq|T{@Q;fA%^7^l4S+>${x24zX0RVcv9@_1;WLdVNwO;Mx$$S4qYyEJ{)3QZGpGKVQ zol@%Q+}s@P?d=IOf3Vg*D|!~HBfiQIZhFw~y}v0UHRs&Y_V#w_oLlObbksbl7bJR= zW!a-Biry2^oe}TWL6&6?c6WEL1K79Lh9b~<$*uY=B349xlweX3xmDIsHAW{M0OxBN zM#hm`x?LGbnNFs>_XJ?74D&DZq%~Aq4WMI;iJAF}QtEy|Z#01TB4*CS_6MPNtqWrX RMSuVR002ovPDHLkV1j-yMWX-! literal 0 HcmV?d00001 diff --git a/images/tab.png b/images/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..84134872a881a627f745a432a3c951254cda26cb GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)y9AGr(VqkNfCexMc)B=-cpQH_#nA7tgMe!?hZ5_{ zMsAl!Od$nK=NL4coJ!_2I4fwan^WPez236Q zxV~)Pmbreb!~RE$eG$IAmU)pz*R|Ls(Q=zi{&XKq&Aq}nY2Dc~42<~)YG*C`o4+Gi zfzhrp-BY~xz4ptrjS(^y&#NZ29sIEF7IV+@&p+#?rS3j(MVx!X=$#3b5uMxna)02 zw(86+ea1O6Bj-JL&z$wG@ph=1;^e&(PHLnW`jei;9RARTq fhprAg`;}G9rs2;o<>%Ld!NuU|>gTe~DWM4f3=5y^ literal 0 HcmV?d00001 From 53c01a2353d1f1d539e5568ea8552d4565ba42f2 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 25 Jul 2013 12:49:37 +0200 Subject: [PATCH 005/100] Added the extra keys Ctrl, Alt, Tab and Esc to the control bar. --- include/base.css | 55 ++++++++++++++++++++++++++++++++ include/ui.js | 81 +++++++++++++++++++++++++++++++++++++++++++++++- vnc.html | 17 ++++++++++ 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/include/base.css b/include/base.css index 0578619e..cc6575f3 100644 --- a/include/base.css +++ b/include/base.css @@ -62,6 +62,14 @@ html { display: none; } +#noVNC_extra_keys { + display: inline; + list-style-type: none; + padding: 0px; + margin: 0px; + position: relative; +} + .noVNC-buttons-left { float: left; z-index: 1; @@ -404,6 +412,31 @@ html { width: 100%; } +#noVNC_extra_keys { + float: none; + top: 0px; +} + +#noVNC_extra_keys li { + display: inline; +} + +#showExtraKeysButton { + display: none; +} +#toggleCtrlButton { + display: inline; +} +#toggleAltButton { + display: inline; +} +#sendTabButton { + display: inline; +} +#sendEscButton { + display: inline; +} + @media screen and (max-width: 640px){ .noVNC_status_button { font-size: 10px; @@ -420,6 +453,28 @@ html { width: auto; float: left; } + #noVNC_extra_keys { + float: right; + top: -35px; + } + #noVNC_extra_keys li { + display: block; + } + #showExtraKeysButton { + display: inline; + } + #toggleCtrlButton { + display: none; + } + #toggleAltButton { + display: none; + } + #sendTabButton { + display: none; + } + #sendEscButton { + display: none; + } } @media screen and (min-width: 481px) and (max-width: 640px) { diff --git a/include/ui.js b/include/ui.js index b933d312..057a42fb 100644 --- a/include/ui.js +++ b/include/ui.js @@ -24,6 +24,10 @@ connSettingsOpen : false, popupStatusOpen : false, clipboardOpen: false, keyboardVisible: false, +hideKeyboardTimeout: null, +extraKeysVisible: false, +ctrlOn: false, +altOn: false, // Setup rfb object, load settings from browser storage, then call // UI.init to setup the UI/menus @@ -158,6 +162,12 @@ addMouseHandlers: function() { //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); }; $D("keyboardinput").onblur = UI.keyInputBlur; + $D("showExtraKeysButton").onclick = UI.showExtraKeys; + $D("toggleCtrlButton").onclick = UI.toggleCtrl; + $D("toggleAltButton").onclick = UI.toggleAlt; + $D("sendTabButton").onclick = UI.sendTab; + $D("sendEscButton").onclick = UI.sendEsc; + $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel; $D("noVNC_status").onclick = UI.togglePopupStatusPanel; $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel; @@ -532,13 +542,16 @@ updateVisualState: function() { UI.setMouseButton(1); $D('clipboardButton').style.display = "inline"; $D('showKeyboard').style.display = "inline"; + $D('noVNC_extra_keys').style.display = ""; $D('sendCtrlAltDelButton').style.display = "inline"; } else { UI.setMouseButton(); $D('clipboardButton').style.display = "none"; $D('showKeyboard').style.display = "none"; + $D('noVNC_extra_keys').style.display = "none"; $D('sendCtrlAltDelButton').style.display = "none"; } + // State change disables viewport dragging. // It is enabled (toggled) by direct click on the button UI.setViewDrag(false); @@ -712,12 +725,78 @@ showKeyboard: function() { } }, +keepKeyboard: function() { + clearTimeout(UI.hideKeyboardTimeout); + if(UI.keyboardVisible === true) { + $D('keyboardinput').focus(); + $D('showKeyboard').className = "noVNC_status_button_selected"; + } else if(UI.keyboardVisible === false) { + $D('keyboardinput').blur(); + $D('showKeyboard').className = "noVNC_status_button"; + } +}, + keyInputBlur: function() { $D('showKeyboard').className = "noVNC_status_button"; //Weird bug in iOS if you change keyboardVisible //here it does not actually occur so next time //you click keyboard icon it doesnt work. - setTimeout(function() { UI.setKeyboard(); },100); + UI.hideKeyboardTimeout = setTimeout(function() { UI.setKeyboard(); },100); +}, + +showExtraKeys: function() { + UI.keepKeyboard(); + if(UI.extraKeysVisible === false) { + $D('toggleCtrlButton').style.display = "inline"; + $D('toggleAltButton').style.display = "inline"; + $D('sendTabButton').style.display = "inline"; + $D('sendEscButton').style.display = "inline"; + $D('showExtraKeysButton').className = "noVNC_status_button_selected"; + UI.extraKeysVisible = true; + } else if(UI.extraKeysVisible === true) { + $D('toggleCtrlButton').style.display = ""; + $D('toggleAltButton').style.display = ""; + $D('sendTabButton').style.display = ""; + $D('sendEscButton').style.display = ""; + $D('showExtraKeysButton').className = "noVNC_status_button"; + UI.extraKeysVisible = false; + } +}, + +toggleCtrl: function() { + UI.keepKeyboard(); + if(UI.ctrlOn === false) { + UI.rfb.sendKey(0xFFE3, true); + $D('toggleCtrlButton').className = "noVNC_status_button_selected"; + UI.ctrlOn = true; + } else if(UI.ctrlOn === true) { + UI.rfb.sendKey(0xFFE3, false); + $D('toggleCtrlButton').className = "noVNC_status_button"; + UI.ctrlOn = false; + } +}, + +toggleAlt: function() { + UI.keepKeyboard(); + if(UI.altOn === false) { + UI.rfb.sendKey(0xFFE9, true); + $D('toggleAltButton').className = "noVNC_status_button_selected"; + UI.altOn = true; + } else if(UI.altOn === true) { + UI.rfb.sendKey(0xFFE9, false); + $D('toggleAltButton').className = "noVNC_status_button"; + UI.altOn = false; + } +}, + +sendTab: function() { + UI.keepKeyboard(); + UI.rfb.sendKey(0xFF09); +}, + +sendEsc: function() { + UI.keepKeyboard(); + UI.rfb.sendKey(0xFF1B); }, setKeyboard: function() { diff --git a/vnc.html b/vnc.html index 66b70259..306ab859 100644 --- a/vnc.html +++ b/vnc.html @@ -68,6 +68,23 @@ value="Keyboard" title="Show Keyboard"/> +

From 9d04096e58579922391d37bf6d5115dea709f991 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 25 Jul 2013 14:05:52 +0200 Subject: [PATCH 006/100] Tweaked the media sizing rules to match the new buttons to the left. --- include/base.css | 73 +++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/include/base.css b/include/base.css index cc6575f3..d4f8501e 100644 --- a/include/base.css +++ b/include/base.css @@ -410,34 +410,41 @@ html { z-index: 0; position: absolute; width: 100%; + margin-left: 0px; } #noVNC_extra_keys { float: none; top: 0px; } - #noVNC_extra_keys li { display: inline; } -#showExtraKeysButton { - display: none; -} -#toggleCtrlButton { - display: inline; -} -#toggleAltButton { - display: inline; -} -#sendTabButton { - display: inline; -} -#sendEscButton { - display: inline; +#showExtraKeysButton { display: none; } +#toggleCtrlButton { display: inline; } +#toggleAltButton { display: inline; } +#sendTabButton { display: inline; } +#sendEscButton { display: inline; } + +/* left-align the status text on lower resolutions */ +@media screen and (max-width: 800px){ + #noVNC_status { + z-index: 1; + position: relative; + width: auto; + float: left; + margin-left: 4px; + } } @media screen and (max-width: 640px){ + #noVNC_clipboard_text { + width: 410px; + } + #noVNC_logo { + font-size: 150px; + } .noVNC_status_button { font-size: 10px; } @@ -447,12 +454,6 @@ html { .noVNC-buttons-right { padding-right: 0px; } - #noVNC_status { - z-index: 1; - position: relative; - width: auto; - float: left; - } #noVNC_extra_keys { float: right; top: -35px; @@ -460,30 +461,12 @@ html { #noVNC_extra_keys li { display: block; } - #showExtraKeysButton { - display: inline; - } - #toggleCtrlButton { - display: none; - } - #toggleAltButton { - display: none; - } - #sendTabButton { - display: none; - } - #sendEscButton { - display: none; - } -} - -@media screen and (min-width: 481px) and (max-width: 640px) { - #noVNC_clipboard_text { - width: 410px; - } - #noVNC_logo { - font-size: 150px; - } + /* collapse the extra keys on lower resolutions */ + #showExtraKeysButton { display: inline; } + #toggleCtrlButton { display: none; } + #toggleAltButton { display: none; } + #sendTabButton { display: none; } + #sendEscButton { display: none; } } @media screen and (min-width: 321px) and (max-width: 480px) { From bd88b943938deddde09f8459b0b96ea82a542f12 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 25 Jul 2013 15:34:16 +0200 Subject: [PATCH 007/100] Switched from using a list to absolute positions to achieve more consistant behavior across different browsers. --- include/base.css | 47 +++++++++++++++++++++++++++-------------------- vnc.html | 34 +++++++++++++++++----------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/include/base.css b/include/base.css index d4f8501e..f57d20e3 100644 --- a/include/base.css +++ b/include/base.css @@ -413,14 +413,6 @@ html { margin-left: 0px; } -#noVNC_extra_keys { - float: none; - top: 0px; -} -#noVNC_extra_keys li { - display: inline; -} - #showExtraKeysButton { display: none; } #toggleCtrlButton { display: inline; } #toggleAltButton { display: inline; } @@ -454,19 +446,34 @@ html { .noVNC-buttons-right { padding-right: 0px; } - #noVNC_extra_keys { - float: right; - top: -35px; - } - #noVNC_extra_keys li { - display: block; - } /* collapse the extra keys on lower resolutions */ - #showExtraKeysButton { display: inline; } - #toggleCtrlButton { display: none; } - #toggleAltButton { display: none; } - #sendTabButton { display: none; } - #sendEscButton { display: none; } + #showExtraKeysButton { + display: inline; + } + #toggleCtrlButton { + display: none; + position: absolute; + top: 30px; + left: 0px; + } + #toggleAltButton { + display: none; + position: absolute; + top: 65px; + left: 0px; + } + #sendTabButton { + display: none; + position: absolute; + top: 100px; + left: 0px; + } + #sendEscButton { + display: none; + position: absolute; + top: 135px; + left: 0px; + } } @media screen and (min-width: 321px) and (max-width: 480px) { diff --git a/vnc.html b/vnc.html index 306ab859..ae95551e 100644 --- a/vnc.html +++ b/vnc.html @@ -68,23 +68,23 @@ value="Keyboard" title="Show Keyboard"/> -
    -
  • -
  • -
  • -
  • -
  • -
+
+ + + + + +
From 76e262134e5ba795f9cc77dcfb8dad5ece99ea70 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 29 Aug 2013 13:38:12 +0200 Subject: [PATCH 008/100] * Removed fbu-requests from the places I missed earlier. * Added a few clarifying comments. --- include/rfb.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index c15bc30d..53c38796 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -595,7 +595,6 @@ mouseButton = function(x, y, down, bmask) { return; } else { viewportDragging = false; - ws.send(fbUpdateRequests()); // Force immediate redraw } } @@ -873,7 +872,7 @@ init_msg = function() { response = pixelFormat(); response = response.concat(clientEncodings()); - response = response.concat(fbUpdateRequests()); + response = response.concat(fbUpdateRequests()); // initial fbu-request timing.fbu_rt_start = (new Date()).getTime(); timing.pixels = 0; ws.send(response); @@ -907,6 +906,7 @@ normal_msg = function() { case 0: // FramebufferUpdate ret = framebufferUpdate(); // false means need more data if (ret) { + // only allow one outstanding fbu-request at a time ws.send(fbUpdateRequests()); } break; @@ -1571,8 +1571,6 @@ encHandlers.DesktopSize = function set_desktopsize() { conf.onFBResize(that, fb_width, fb_height); display.resize(fb_width, fb_height); timing.fbu_rt_start = (new Date()).getTime(); - // Send a new non-incremental request - ws.send(fbUpdateRequests()); FBU.bytes = 0; FBU.rects -= 1; @@ -1798,7 +1796,6 @@ that.sendCtrlAltDel = function() { arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt arr = arr.concat(keyEvent(0xFFE3, 0)); // Control - arr = arr.concat(fbUpdateRequests()); ws.send(arr); }; @@ -1815,7 +1812,6 @@ that.sendKey = function(code, down) { arr = arr.concat(keyEvent(code, 1)); arr = arr.concat(keyEvent(code, 0)); } - arr = arr.concat(fbUpdateRequests()); ws.send(arr); }; From 04d6a8347f9638271255afc738f4b64d75919fe4 Mon Sep 17 00:00:00 2001 From: samhed Date: Thu, 29 Aug 2013 17:35:22 +0200 Subject: [PATCH 009/100] Added variables for the keysums to make the code easier to read. --- include/ui.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/include/ui.js b/include/ui.js index 057a42fb..50ca430e 100644 --- a/include/ui.js +++ b/include/ui.js @@ -764,39 +764,43 @@ showExtraKeys: function() { }, toggleCtrl: function() { + var ctrlKeysum = 0xFFE3; UI.keepKeyboard(); if(UI.ctrlOn === false) { - UI.rfb.sendKey(0xFFE3, true); + UI.rfb.sendKey(ctrlKeysum, true); $D('toggleCtrlButton').className = "noVNC_status_button_selected"; UI.ctrlOn = true; } else if(UI.ctrlOn === true) { - UI.rfb.sendKey(0xFFE3, false); + UI.rfb.sendKey(ctrlKeysum, false); $D('toggleCtrlButton').className = "noVNC_status_button"; UI.ctrlOn = false; } }, toggleAlt: function() { + var altKeysum = 0xFFE9; UI.keepKeyboard(); if(UI.altOn === false) { - UI.rfb.sendKey(0xFFE9, true); + UI.rfb.sendKey(altKeysum, true); $D('toggleAltButton').className = "noVNC_status_button_selected"; UI.altOn = true; } else if(UI.altOn === true) { - UI.rfb.sendKey(0xFFE9, false); + UI.rfb.sendKey(altKeysum, false); $D('toggleAltButton').className = "noVNC_status_button"; UI.altOn = false; } }, sendTab: function() { + var tabKeysum = 0xFF09; UI.keepKeyboard(); - UI.rfb.sendKey(0xFF09); + UI.rfb.sendKey(tabKeysum); }, sendEsc: function() { + var escKeysum = 0xFF1B; UI.keepKeyboard(); - UI.rfb.sendKey(0xFF1B); + UI.rfb.sendKey(escKeysum); }, setKeyboard: function() { From b4a979a07e6c4177015b7aaf74b53f9bdc9a55c6 Mon Sep 17 00:00:00 2001 From: samhed Date: Fri, 30 Aug 2013 15:41:46 +0200 Subject: [PATCH 010/100] Added a new file for the key symbols, using the well recognized names for the constants from X11: * The list is found in /usr/include/X11/keysymdef.h * I did only include the most common symbols for now.. --- LICENSE.txt | 1 + include/keysym.js | 376 ++++++++++++++++++++++++++++++++++++++++++++++ include/ui.js | 19 +-- 3 files changed, 385 insertions(+), 11 deletions(-) create mode 100644 include/keysym.js diff --git a/LICENSE.txt b/LICENSE.txt index c5aa5050..2d094089 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -10,6 +10,7 @@ is not limited to): include/display.js include/input.js include/jsunzip.js + include/keysym.js include/logo.js include/rfb.js include/ui.js diff --git a/include/keysym.js b/include/keysym.js new file mode 100644 index 00000000..a00d595e --- /dev/null +++ b/include/keysym.js @@ -0,0 +1,376 @@ +var XK_VoidSymbol = 0xffffff, /* Void symbol */ + +XK_BackSpace = 0xff08, /* Back space, back char */ +XK_Tab = 0xff09, +XK_Linefeed = 0xff0a, /* Linefeed, LF */ +XK_Clear = 0xff0b, +XK_Return = 0xff0d, /* Return, enter */ +XK_Pause = 0xff13, /* Pause, hold */ +XK_Scroll_Lock = 0xff14, +XK_Sys_Req = 0xff15, +XK_Escape = 0xff1b, +XK_Delete = 0xffff, /* Delete, rubout */ + +/* Cursor control & motion */ + +XK_Home = 0xff50, +XK_Left = 0xff51, /* Move left, left arrow */ +XK_Up = 0xff52, /* Move up, up arrow */ +XK_Right = 0xff53, /* Move right, right arrow */ +XK_Down = 0xff54, /* Move down, down arrow */ +XK_Prior = 0xff55, /* Prior, previous */ +XK_Page_Up = 0xff55, +XK_Next = 0xff56, /* Next */ +XK_Page_Down = 0xff56, +XK_End = 0xff57, /* EOL */ +XK_Begin = 0xff58, /* BOL */ + + +/* Misc functions */ + +XK_Select = 0xff60, /* Select, mark */ +XK_Print = 0xff61, +XK_Execute = 0xff62, /* Execute, run, do */ +XK_Insert = 0xff63, /* Insert, insert here */ +XK_Undo = 0xff65, +XK_Redo = 0xff66, /* Redo, again */ +XK_Menu = 0xff67, +XK_Find = 0xff68, /* Find, search */ +XK_Cancel = 0xff69, /* Cancel, stop, abort, exit */ +XK_Help = 0xff6a, /* Help */ +XK_Break = 0xff6b, +XK_Mode_switch = 0xff7e, /* Character set switch */ +XK_script_switch = 0xff7e, /* Alias for mode_switch */ +XK_Num_Lock = 0xff7f, + +/* Keypad functions, keypad numbers cleverly chosen to map to ASCII */ + +XK_KP_Space = 0xff80, /* Space */ +XK_KP_Tab = 0xff89, +XK_KP_Enter = 0xff8d, /* Enter */ +XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */ +XK_KP_F2 = 0xff92, +XK_KP_F3 = 0xff93, +XK_KP_F4 = 0xff94, +XK_KP_Home = 0xff95, +XK_KP_Left = 0xff96, +XK_KP_Up = 0xff97, +XK_KP_Right = 0xff98, +XK_KP_Down = 0xff99, +XK_KP_Prior = 0xff9a, +XK_KP_Page_Up = 0xff9a +XK_KP_Next = 0xff9b, +XK_KP_Page_Down = 0xff9b, +XK_KP_End = 0xff9c, +XK_KP_Begin = 0xff9d, +XK_KP_Insert = 0xff9e, +XK_KP_Delete = 0xff9f, +XK_KP_Equal = 0xffbd, /* Equals */ +XK_KP_Multiply = 0xffaa, +XK_KP_Add = 0xffab, +XK_KP_Separator = 0xffac, /* Separator, often comma */ +XK_KP_Subtract = 0xffad, +XK_KP_Decimal = 0xffae, +XK_KP_Divide = 0xffaf, + +XK_KP_0 = 0xffb0, +XK_KP_1 = 0xffb1, +XK_KP_2 = 0xffb2, +XK_KP_3 = 0xffb3, +XK_KP_4 = 0xffb4, +XK_KP_5 = 0xffb5, +XK_KP_6 = 0xffb6, +XK_KP_7 = 0xffb7, +XK_KP_8 = 0xffb8, +XK_KP_9 = 0xffb9, + +/* + * Auxiliary functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufacturers have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + +XK_F1 = 0xffbe, +XK_F2 = 0xffbf, +XK_F3 = 0xffc0, +XK_F4 = 0xffc1, +XK_F5 = 0xffc2, +XK_F6 = 0xffc3, +XK_F7 = 0xffc4, +XK_F8 = 0xffc5, +XK_F9 = 0xffc6, +XK_F10 = 0xffc7, +XK_F11 = 0xffc8, +XK_L1 = 0xffc8, +XK_F12 = 0xffc9, +XK_L2 = 0xffc9, +XK_F13 = 0xffca, +XK_L3 = 0xffca, +XK_F14 = 0xffcb, +XK_L4 = 0xffcb, +XK_F15 = 0xffcc, +XK_L5 = 0xffcc, +XK_F16 = 0xffcd, +XK_L6 = 0xffcd, +XK_F17 = 0xffce, +XK_L7 = 0xffce, +XK_F18 = 0xffcf, +XK_L8 = 0xffcf, +XK_F19 = 0xffd0, +XK_L9 = 0xffd0, +XK_F20 = 0xffd1, +XK_L10 = 0xffd1, +XK_F21 = 0xffd2, +XK_R1 = 0xffd2, +XK_F22 = 0xffd3, +XK_R2 = 0xffd3, +XK_F23 = 0xffd4, +XK_R3 = 0xffd4, +XK_F24 = 0xffd5, +XK_R4 = 0xffd5, +XK_F25 = 0xffd6, +XK_R5 = 0xffd6, +XK_F26 = 0xffd7, +XK_R6 = 0xffd7, +XK_F27 = 0xffd8, +XK_R7 = 0xffd8, +XK_F28 = 0xffd9, +XK_R8 = 0xffd9, +XK_F29 = 0xffda, +XK_R9 = 0xffda, +XK_F30 = 0xffdb, +XK_R10 = 0xffdb, +XK_F31 = 0xffdc, +XK_R11 = 0xffdc, +XK_F32 = 0xffdd, +XK_R12 = 0xffdd, +XK_F33 = 0xffde, +XK_R13 = 0xffde, +XK_F34 = 0xffdf, +XK_R14 = 0xffdf, +XK_F35 = 0xffe0, +XK_R15 = 0xffe0, + +/* Modifiers */ + +XK_Shift_L = 0xffe1, /* Left shift */ +XK_Shift_R = 0xffe2, /* Right shift */ +XK_Control_L = 0xffe3, /* Left control */ +XK_Control_R = 0xffe4, /* Right control */ +XK_Caps_Lock = 0xffe5, /* Caps lock */ +XK_Shift_Lock = 0xffe6, /* Shift lock */ + +XK_Meta_L = 0xffe7, /* Left meta */ +XK_Meta_R = 0xffe8, /* Right meta */ +XK_Alt_L = 0xffe9, /* Left alt */ +XK_Alt_R = 0xffea, /* Right alt */ +XK_Super_L = 0xffeb, /* Left super */ +XK_Super_R = 0xffec, /* Right super */ +XK_Hyper_L = 0xffed, /* Left hyper */ +XK_Hyper_R = 0xffee, /* Right hyper */ + +/* + * Latin 1 + * (ISO/IEC 8859-1 = Unicode U+0020..U+00FF) + * Byte 3 = 0 + */ + +XK_space = 0x0020, /* U+0020 SPACE */ +XK_exclam = 0x0021, /* U+0021 EXCLAMATION MARK */ +XK_quotedbl = 0x0022, /* U+0022 QUOTATION MARK */ +XK_numbersign = 0x0023, /* U+0023 NUMBER SIGN */ +XK_dollar = 0x0024, /* U+0024 DOLLAR SIGN */ +XK_percent = 0x0025, /* U+0025 PERCENT SIGN */ +XK_ampersand = 0x0026, /* U+0026 AMPERSAND */ +XK_apostrophe = 0x0027, /* U+0027 APOSTROPHE */ +XK_quoteright = 0x0027, /* deprecated */ +XK_parenleft = 0x0028, /* U+0028 LEFT PARENTHESIS */ +XK_parenright = 0x0029, /* U+0029 RIGHT PARENTHESIS */ +XK_asterisk = 0x002a, /* U+002A ASTERISK */ +XK_plus = 0x002b, /* U+002B PLUS SIGN */ +XK_comma = 0x002c, /* U+002C COMMA */ +XK_minus = 0x002d, /* U+002D HYPHEN-MINUS */ +XK_period = 0x002e, /* U+002E FULL STOP */ +XK_slash = 0x002f, /* U+002F SOLIDUS */ +XK_0 = 0x0030, /* U+0030 DIGIT ZERO */ +XK_1 = 0x0031, /* U+0031 DIGIT ONE */ +XK_2 = 0x0032, /* U+0032 DIGIT TWO */ +XK_3 = 0x0033, /* U+0033 DIGIT THREE */ +XK_4 = 0x0034, /* U+0034 DIGIT FOUR */ +XK_5 = 0x0035, /* U+0035 DIGIT FIVE */ +XK_6 = 0x0036, /* U+0036 DIGIT SIX */ +XK_7 = 0x0037, /* U+0037 DIGIT SEVEN */ +XK_8 = 0x0038, /* U+0038 DIGIT EIGHT */ +XK_9 = 0x0039, /* U+0039 DIGIT NINE */ +XK_colon = 0x003a, /* U+003A COLON */ +XK_semicolon = 0x003b, /* U+003B SEMICOLON */ +XK_less = 0x003c, /* U+003C LESS-THAN SIGN */ +XK_equal = 0x003d, /* U+003D EQUALS SIGN */ +XK_greater = 0x003e, /* U+003E GREATER-THAN SIGN */ +XK_question = 0x003f, /* U+003F QUESTION MARK */ +XK_at = 0x0040, /* U+0040 COMMERCIAL AT */ +XK_A = 0x0041, /* U+0041 LATIN CAPITAL LETTER A */ +XK_B = 0x0042, /* U+0042 LATIN CAPITAL LETTER B */ +XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */ +XK_D = 0x0044, /* U+0044 LATIN CAPITAL LETTER D */ +XK_E = 0x0045, /* U+0045 LATIN CAPITAL LETTER E */ +XK_F = 0x0046, /* U+0046 LATIN CAPITAL LETTER F */ +XK_G = 0x0047, /* U+0047 LATIN CAPITAL LETTER G */ +XK_H = 0x0048, /* U+0048 LATIN CAPITAL LETTER H */ +XK_I = 0x0049, /* U+0049 LATIN CAPITAL LETTER I */ +XK_J = 0x004a, /* U+004A LATIN CAPITAL LETTER J */ +XK_K = 0x004b, /* U+004B LATIN CAPITAL LETTER K */ +XK_L = 0x004c, /* U+004C LATIN CAPITAL LETTER L */ +XK_M = 0x004d, /* U+004D LATIN CAPITAL LETTER M */ +XK_N = 0x004e, /* U+004E LATIN CAPITAL LETTER N */ +XK_O = 0x004f, /* U+004F LATIN CAPITAL LETTER O */ +XK_P = 0x0050, /* U+0050 LATIN CAPITAL LETTER P */ +XK_Q = 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */ +XK_R = 0x0052, /* U+0052 LATIN CAPITAL LETTER R */ +XK_S = 0x0053, /* U+0053 LATIN CAPITAL LETTER S */ +XK_T = 0x0054, /* U+0054 LATIN CAPITAL LETTER T */ +XK_U = 0x0055, /* U+0055 LATIN CAPITAL LETTER U */ +XK_V = 0x0056, /* U+0056 LATIN CAPITAL LETTER V */ +XK_W = 0x0057, /* U+0057 LATIN CAPITAL LETTER W */ +XK_X = 0x0058, /* U+0058 LATIN CAPITAL LETTER X */ +XK_Y = 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */ +XK_Z = 0x005a, /* U+005A LATIN CAPITAL LETTER Z */ +XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */ +XK_backslash = 0x005c, /* U+005C REVERSE SOLIDUS */ +XK_bracketright = 0x005d, /* U+005D RIGHT SQUARE BRACKET */ +XK_asciicircum = 0x005e, /* U+005E CIRCUMFLEX ACCENT */ +XK_underscore = 0x005f, /* U+005F LOW LINE */ +XK_grave = 0x0060, /* U+0060 GRAVE ACCENT */ +XK_quoteleft = 0x0060, /* deprecated */ +XK_a = 0x0061, /* U+0061 LATIN SMALL LETTER A */ +XK_b = 0x0062, /* U+0062 LATIN SMALL LETTER B */ +XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */ +XK_d = 0x0064, /* U+0064 LATIN SMALL LETTER D */ +XK_e = 0x0065, /* U+0065 LATIN SMALL LETTER E */ +XK_f = 0x0066, /* U+0066 LATIN SMALL LETTER F */ +XK_g = 0x0067, /* U+0067 LATIN SMALL LETTER G */ +XK_h = 0x0068, /* U+0068 LATIN SMALL LETTER H */ +XK_i = 0x0069, /* U+0069 LATIN SMALL LETTER I */ +XK_j = 0x006a, /* U+006A LATIN SMALL LETTER J */ +XK_k = 0x006b, /* U+006B LATIN SMALL LETTER K */ +XK_l = 0x006c, /* U+006C LATIN SMALL LETTER L */ +XK_m = 0x006d, /* U+006D LATIN SMALL LETTER M */ +XK_n = 0x006e, /* U+006E LATIN SMALL LETTER N */ +XK_o = 0x006f, /* U+006F LATIN SMALL LETTER O */ +XK_p = 0x0070, /* U+0070 LATIN SMALL LETTER P */ +XK_q = 0x0071, /* U+0071 LATIN SMALL LETTER Q */ +XK_r = 0x0072, /* U+0072 LATIN SMALL LETTER R */ +XK_s = 0x0073, /* U+0073 LATIN SMALL LETTER S */ +XK_t = 0x0074, /* U+0074 LATIN SMALL LETTER T */ +XK_u = 0x0075, /* U+0075 LATIN SMALL LETTER U */ +XK_v = 0x0076, /* U+0076 LATIN SMALL LETTER V */ +XK_w = 0x0077, /* U+0077 LATIN SMALL LETTER W */ +XK_x = 0x0078, /* U+0078 LATIN SMALL LETTER X */ +XK_y = 0x0079, /* U+0079 LATIN SMALL LETTER Y */ +XK_z = 0x007a, /* U+007A LATIN SMALL LETTER Z */ +XK_braceleft = 0x007b, /* U+007B LEFT CURLY BRACKET */ +XK_bar = 0x007c, /* U+007C VERTICAL LINE */ +XK_braceright = 0x007d, /* U+007D RIGHT CURLY BRACKET */ +XK_asciitilde = 0x007e, /* U+007E TILDE */ + +XK_nobreakspace = 0x00a0, /* U+00A0 NO-BREAK SPACE */ +XK_exclamdown = 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */ +XK_cent = 0x00a2, /* U+00A2 CENT SIGN */ +XK_sterling = 0x00a3, /* U+00A3 POUND SIGN */ +XK_currency = 0x00a4, /* U+00A4 CURRENCY SIGN */ +XK_yen = 0x00a5, /* U+00A5 YEN SIGN */ +XK_brokenbar = 0x00a6, /* U+00A6 BROKEN BAR */ +XK_section = 0x00a7, /* U+00A7 SECTION SIGN */ +XK_diaeresis = 0x00a8, /* U+00A8 DIAERESIS */ +XK_copyright = 0x00a9, /* U+00A9 COPYRIGHT SIGN */ +XK_ordfeminine = 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */ +XK_guillemotleft = 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ +XK_notsign = 0x00ac, /* U+00AC NOT SIGN */ +XK_hyphen = 0x00ad, /* U+00AD SOFT HYPHEN */ +XK_registered = 0x00ae, /* U+00AE REGISTERED SIGN */ +XK_macron = 0x00af, /* U+00AF MACRON */ +XK_degree = 0x00b0, /* U+00B0 DEGREE SIGN */ +XK_plusminus = 0x00b1, /* U+00B1 PLUS-MINUS SIGN */ +XK_twosuperior = 0x00b2, /* U+00B2 SUPERSCRIPT TWO */ +XK_threesuperior = 0x00b3, /* U+00B3 SUPERSCRIPT THREE */ +XK_acute = 0x00b4, /* U+00B4 ACUTE ACCENT */ +XK_mu = 0x00b5, /* U+00B5 MICRO SIGN */ +XK_paragraph = 0x00b6, /* U+00B6 PILCROW SIGN */ +XK_periodcentered = 0x00b7, /* U+00B7 MIDDLE DOT */ +XK_cedilla = 0x00b8, /* U+00B8 CEDILLA */ +XK_onesuperior = 0x00b9, /* U+00B9 SUPERSCRIPT ONE */ +XK_masculine = 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */ +XK_guillemotright = 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ +XK_onequarter = 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */ +XK_onehalf = 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */ +XK_threequarters = 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */ +XK_questiondown = 0x00bf, /* U+00BF INVERTED QUESTION MARK */ +XK_Agrave = 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */ +XK_Aacute = 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */ +XK_Acircumflex = 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ +XK_Atilde = 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */ +XK_Adiaeresis = 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */ +XK_Aring = 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */ +XK_AE = 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */ +XK_Ccedilla = 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */ +XK_Egrave = 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */ +XK_Eacute = 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ +XK_Ecircumflex = 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ +XK_Ediaeresis = 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */ +XK_Igrave = 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */ +XK_Iacute = 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */ +XK_Icircumflex = 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ +XK_Idiaeresis = 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */ +XK_ETH = 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */ +XK_Eth = 0x00d0, /* deprecated */ +XK_Ntilde = 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */ +XK_Ograve = 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */ +XK_Oacute = 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */ +XK_Ocircumflex = 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ +XK_Otilde = 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */ +XK_Odiaeresis = 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */ +XK_multiply = 0x00d7, /* U+00D7 MULTIPLICATION SIGN */ +XK_Oslash = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ +XK_Ooblique = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ +XK_Ugrave = 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */ +XK_Uacute = 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */ +XK_Ucircumflex = 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ +XK_Udiaeresis = 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */ +XK_Yacute = 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */ +XK_THORN = 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */ +XK_Thorn = 0x00de, /* deprecated */ +XK_ssharp = 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */ +XK_agrave = 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */ +XK_aacute = 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */ +XK_acircumflex = 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */ +XK_atilde = 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */ +XK_adiaeresis = 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */ +XK_aring = 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */ +XK_ae = 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */ +XK_ccedilla = 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */ +XK_egrave = 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */ +XK_eacute = 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */ +XK_ecircumflex = 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */ +XK_ediaeresis = 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */ +XK_igrave = 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */ +XK_iacute = 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */ +XK_icircumflex = 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */ +XK_idiaeresis = 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */ +XK_eth = 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */ +XK_ntilde = 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */ +XK_ograve = 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */ +XK_oacute = 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */ +XK_ocircumflex = 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */ +XK_otilde = 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */ +XK_odiaeresis = 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */ +XK_division = 0x00f7, /* U+00F7 DIVISION SIGN */ +XK_oslash = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ +XK_ooblique = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ +XK_ugrave = 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */ +XK_uacute = 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */ +XK_ucircumflex = 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */ +XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */ +XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */ +XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */ +XK_ydiaeresis = 0x00ff; /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */ diff --git a/include/ui.js b/include/ui.js index 50ca430e..45a6beb4 100644 --- a/include/ui.js +++ b/include/ui.js @@ -14,7 +14,8 @@ // Load supporting scripts window.onscriptsload = function () { UI.load(); }; Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", - "input.js", "display.js", "jsunzip.js", "rfb.js"]); + "input.js", "display.js", "jsunzip.js", "rfb.js", + "keysym.js"]); var UI = { @@ -764,43 +765,39 @@ showExtraKeys: function() { }, toggleCtrl: function() { - var ctrlKeysum = 0xFFE3; UI.keepKeyboard(); if(UI.ctrlOn === false) { - UI.rfb.sendKey(ctrlKeysum, true); + UI.rfb.sendKey(XK_Control_L, true); $D('toggleCtrlButton').className = "noVNC_status_button_selected"; UI.ctrlOn = true; } else if(UI.ctrlOn === true) { - UI.rfb.sendKey(ctrlKeysum, false); + UI.rfb.sendKey(XK_Control_L, false); $D('toggleCtrlButton').className = "noVNC_status_button"; UI.ctrlOn = false; } }, toggleAlt: function() { - var altKeysum = 0xFFE9; UI.keepKeyboard(); if(UI.altOn === false) { - UI.rfb.sendKey(altKeysum, true); + UI.rfb.sendKey(XK_Alt_L, true); $D('toggleAltButton').className = "noVNC_status_button_selected"; UI.altOn = true; } else if(UI.altOn === true) { - UI.rfb.sendKey(altKeysum, false); + UI.rfb.sendKey(XK_Alt_L, false); $D('toggleAltButton').className = "noVNC_status_button"; UI.altOn = false; } }, sendTab: function() { - var tabKeysum = 0xFF09; UI.keepKeyboard(); - UI.rfb.sendKey(tabKeysum); + UI.rfb.sendKey(XK_Tab); }, sendEsc: function() { - var escKeysum = 0xFF1B; UI.keepKeyboard(); - UI.rfb.sendKey(escKeysum); + UI.rfb.sendKey(XK_Escape); }, setKeyboard: function() { From f901d9c9b8d328394494ab0fdabbb0038aa71056 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Mon, 28 Oct 2013 16:01:40 -0500 Subject: [PATCH 011/100] README: add core team and other cleanup. - Make the ProjectsCompanies-using-noVNC the canonical source for companies/project using noVNC and only give a brief summary here. - Drop the personal Amazon donate/thanks link. Keep the charities and ask for a tweet if so. --- README.md | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 538324f5..53d14402 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,19 @@ noVNC is a HTML5 VNC client that runs well in any modern browser including mobile browsers (iPhone/iPad and Android). -More than 16 companies/projects have integrated noVNC into their -products including [Ganeti Web +Many companies/projects have integrated noVNC including [Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr), -[OpenStack](http://www.openstack.org), and -[OpenNebula](http://opennebula.org/). See [the Projects and Companies -wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) -for more complete list. +[OpenStack](http://www.openstack.org), +[OpenNebula](http://opennebula.org/), and +[LibVNCServer](http://libvncserver.sourceforge.net). See [the Projects +and Companies wiki +page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) +for a more complete list with additional info and links. ### News/help/contact Notable commits, announcements and news are posted to -@
noVNC +@noVNC If you are a noVNC developer/integrator/user (or want to be) please join the Bugs and feature requests can be submitted via [github issues](https://github.com/kanaka/noVNC/issues). If you are looking for a place to start contributing to noVNC, a good place to start -would be the issues that I have marked as +would be the issues that are have marked as ["patchwelcome"](https://github.com/kanaka/noVNC/issues?labels=patchwelcome). -If you want to show appreciation for noVNC you could buy something off -my [Amazon wishlist](http://www.amazon.com/registry/wishlist/XTXFXK39IA8C/?reveal=unpurchased&sort=priority&layout=compact) or you could donate to a great non-profits such as: [Compassion +If you want to show appreciation for noVNC you could donate to a great +non-profits such as: [Compassion International](http://www.compassion.com/), [SIL](http://www.sil.org), [Habitat for Humanity](http://www.habitat.org), [Electronic Frontier Foundation](https://www.eff.org/), [Against Malaria Foundation](http://www.againstmalaria.com/), [Nothing But -Nets](http://www.nothingbutnets.net/), etc. +Nets](http://www.nothingbutnets.net/), etc. Please tweet @noVNC if you do. ### Features @@ -75,17 +77,18 @@ See more screenshots h * Fast Javascript Engine: this is not strictly a requirement, but without a fast Javascript engine, noVNC might be painfully slow. -* I maintain a more detailed browser compatibility list here. +* See the more detailed [browser compatibility wiki page](https://github.com/kanaka/noVNC/wiki/Browser-support). ### Server Requirements Unless you are using a VNC server with support for WebSockets -connections (such as [x11vnc/libvncserver](http://libvncserver.sourceforge.net/) or -[PocketVNC](http://www.pocketvnc.com/blog/?page_id=866)), -you need to use a WebSockets to TCP socket proxy. There is -a python proxy included ('websockify'). +connections (such as +[x11vnc/libvncserver](http://libvncserver.sourceforge.net/), +[QEMU](http://www.qemu.org/), or +[PocketVNC](http://www.pocketvnc.com/blog/?page_id=866)), you need to +use a WebSockets to TCP socket proxy. There is a python proxy included +('websockify'). ### Quick Start @@ -114,7 +117,13 @@ a python proxy included ('websockify'). ### Authors/Contributors -* noVNC : Joel Martin (github.com/kanaka) +* Core team: + * [Joel Martin](https://github.com/kanaka) + * [Samuel Mannehed](https://github.com/samhed) (Cendio) + * [Peter Åstrand](https://github.com/astrand) (Cendio) + * [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack) + +* Notable contributions: * UI and Icons : Chris Gordon * Original Logo : Michael Sersen * tight encoding : Michael Tinglof (Mercuri.ca) @@ -126,5 +135,3 @@ a python proxy included ('websockify'). * jsunzip : Erik Moller (github.com/operasoftware/jsunzip), * tinflate : Joergen Ibsen (ibsensoftware.com) * DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs) - - From ad941faddead705cd611921730054767a0b32dcd Mon Sep 17 00:00:00 2001 From: Takashi Natsume Date: Mon, 28 Oct 2013 12:02:30 +0000 Subject: [PATCH 012/100] Adds support for secure attribute on token cookie This patch adds support for the secure attribute on token cookies (sent by nova-novncproxy). If the https is used to transfer the cookie, the secure attribute is set thus restricting server requestes to secure conections only. This should prevent man-in-the-middle attacks. --- include/webutil.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/webutil.js b/include/webutil.js index ebf8e891..5ceccbef 100644 --- a/include/webutil.js +++ b/include/webutil.js @@ -1,6 +1,7 @@ /* * noVNC: HTML5 VNC client * Copyright (C) 2012 Joel Martin + * Copyright (C) 2013 NTT corp. * Licensed under MPL 2.0 (see LICENSE.txt) * * See README.md for usage and integration instructions. @@ -94,16 +95,20 @@ WebUtil.getQueryVar = function(name, defVal) { // No days means only for this browser session WebUtil.createCookie = function(name,value,days) { - var date, expires; + var date, expires, secure; if (days) { date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); expires = "; expires="+date.toGMTString(); - } - else { + } else { expires = ""; } - document.cookie = name+"="+value+expires+"; path=/"; + if (document.location.protocol === "https:") { + secure = "; secure"; + } else { + secure = ""; + } + document.cookie = name+"="+value+expires+"; path=/"+secure; }; WebUtil.readCookie = function(name, defaultValue) { From 75d69b9f621606c3b2db48e4778ff41307f65c6d Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Tue, 29 Oct 2013 14:38:24 -0500 Subject: [PATCH 013/100] Fix to relfect new github.io page base URL. --- include/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ui.js b/include/ui.js index 40972cc0..ad004e93 100644 --- a/include/ui.js +++ b/include/ui.js @@ -148,7 +148,7 @@ start: function(callback) { } ); // Show description by default when hosted at for kanaka.github.com - if (location.host === "kanaka.github.com") { + if (location.host === "kanaka.github.io") { // Open the description dialog $D('noVNC_description').style.display = "block"; } else { From 2af865923c6de0ee170893f4bb77abea96d75809 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Tue, 3 Dec 2013 15:33:34 -0500 Subject: [PATCH 014/100] Support Running Mocha Tests from the Console Previously, the only way to run the Mocha tests (in 'test.*.js') is to write a web page to wrap them (or use a provided one), and then load that file in a browser. This commit introduces a series of files to allow you to run the Mocha tests from the command line instead. Normally, Mocha tests can be run from the command line anyway. However, since this project was designed to work in web browsers and not node, the code doesn't contain the proper `require` calls, nor does it contain the proper `module.exports` declarations. Additionally, some of the code is dependent on having a browser environment. To overcome these issues, a headless browser environment is used. The command file introduced in the commit, `run_from_console.js`, can use one of two environments: ZombieJS, a pure-javascript headless browser simulator, or SpookyJS/CasperJS/PhantomJS, an actually WebKit-based environment. Because the environment-dependent code is separated out in to different files ('run_from_console.zombie.js' and 'run_from_console.casper.js'), the program can be safely used if only one of the supported environments is installed. Additionally, the command will automatically generate HTML and inject the required tests if there is no pre-existing HTML file (although you can still use pre-existing HTML files if you want to). The required NPM modules for the base program are: - commander - ansi - mocha (must be installed locally for the HTML files to use) - chai (must be installed locally for the HTML files to use) - temp For Zombie, you need: - zombie - q For Casper, you need: - casperjs (must be installed locally in order to work properly) - phantomjs - phantom - spooky The command itself can be invoked as $ node run_from_console.js -t html_files or $ node run_from_console.js -t js_test_files -i js_required_files In both cases, the 'files' options should be a comma-separated list of files. The first case runs pre-existing HTML files. The second case generates HTML files to run the specified Mocha tests, and injects the requirements specified as well. Additionally, there are extra arguments that apply to both forms: '-a' can be used to print all test results, not just the failures, '-c' may be used to force color to be enabled (when outputting to a pipe, such as when `less -R` is in use), and '-e' is used to set the environment. Use the '-h' or '--help' options to see a detailed description of all options, and their long-form versions. --- tests/run_from_console.casper.js | 90 ++++++++++++++ tests/run_from_console.js | 196 +++++++++++++++++++++++++++++++ tests/run_from_console.zombie.js | 73 ++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 tests/run_from_console.casper.js create mode 100755 tests/run_from_console.js create mode 100644 tests/run_from_console.zombie.js diff --git a/tests/run_from_console.casper.js b/tests/run_from_console.casper.js new file mode 100644 index 00000000..60b0926d --- /dev/null +++ b/tests/run_from_console.casper.js @@ -0,0 +1,90 @@ +var Spooky = require('spooky'); +var path = require('path'); + +var phantom_path = require('phantomjs').path; +var casper_path = path.resolve(__dirname, 'node_modules/casperjs/bin/casperjs'); +process.env['PHANTOMJS_EXECUTABLE'] = phantom_path; +var casper_opts = { + child: { + transport: 'http', + command: casper_path + }, + casper: { + logLevel: 'debug', + verbose: true + } +} + +var provide_emitter = function(file_paths) { + var spooky = new Spooky(casper_opts, function(err) { + if (err) { + if (err.stack) console.warn(err.stack); + else console.warn(err); + return; + } + spooky.start('about:blank'); + + file_paths.forEach(function(file_path, path_ind) { + spooky.thenOpen('file://'+file_path); + spooky.then([{ path_ind: path_ind }, function() { + var res_json = { + file_ind: path_ind + } + + res_json.num_tests = this.evaluate(function() { return document.querySelectorAll('li.test').length }); + res_json.num_passes = this.evaluate(function() { return document.querySelectorAll('li.test.pass').length }); + res_json.num_fails = this.evaluate(function() { return document.querySelectorAll('li.test.fail').length }); + res_json.num_slow = this.evaluate(function() { return document.querySelectorAll('li.test.pass:not(.fast)').length }); + res_json.duration = this.evaluate(function() { return document.querySelector('li.duration em').textContent }); + + res_json.suites = this.evaluate(function() { + var traverse_node = function(elem) { + if (elem.classList.contains('suite')) { + var res = { + type: 'suite', + name: elem.querySelector('h1').textContent, + has_subfailures: elem.querySelectorAll('li.test.fail').length > 0, + } + + var child_elems = elem.querySelector('ul').children; + res.children = Array.prototype.map.call(child_elems, traverse_node); + return res; + } + else { + var h2_content = elem.querySelector('h2').childNodes; + var res = { + type: 'test', + text: h2_content[0].textContent, + } + + if (elem.classList.contains('pass')) { + res.pass = true; + res.slow = !elem.classList.contains('fast'); + res.duration = h2_content[1].textContent; + } + else { + res.error = elem.querySelector('pre.error').textContent; + } + + return res; + } + } + var top_suites = document.querySelectorAll('#mocha-report > li.suite'); + return Array.prototype.map.call(top_suites, traverse_node); + }); + + res_json.replay = this.evaluate(function() { return document.querySelector('a.replay').textContent }); + + this.emit('test_ready', res_json); + }]); + }); + spooky.run(); + }); + + return spooky; +} + +module.exports = { + provide_emitter: provide_emitter, + name: 'SpookyJS (CapserJS on PhantomJS)' +} diff --git a/tests/run_from_console.js b/tests/run_from_console.js new file mode 100755 index 00000000..9d79ebe4 --- /dev/null +++ b/tests/run_from_console.js @@ -0,0 +1,196 @@ +#!/usr/bin/env node +var ansi = require('ansi'); +var program = require('commander'); +var path = require('path'); + +var make_list = function(val) { + return val.split(','); +} + +program + .option('-t, --tests ', 'Run the specified html-file-based test(s). \'testlist\' should be a comma-separated list', make_list, []) + .option('-a, --print-all', 'Print all tests, not just the failures') + .option('--disable-color', 'Explicitly disable color') + .option('-c, --color', 'Explicitly enable color (default is to use color when not outputting to a pipe)') + .option('-i, --auto-inject ', 'Treat the test list as a set of mocha JS files, and automatically generate HTML files with which to test test. \'includefiles\' should be a comma-separated list of paths to javascript files to include in each of the generated HTML files', make_list, null) + .option('-p, --provider ', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper') + .parse(process.argv); + +var file_paths = []; + +if (program.autoInject) { + var temp = require('temp'); + var fs = require('fs'); + temp.track(); + + var template = { + header: "\n\n\\n\n
", + script_tag: function(p) { return "" }, + footer: "\n\n" + }; + + template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/chai/chai.js')); + template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/mocha/mocha.js')); + template.header += "\n"; + + + template.header = program.autoInject.reduce(function(acc, sn) { + return acc + "\n" + template.script_tag(path.resolve(process.cwd(), sn)); + }, template.header); + + file_paths = program.tests.map(function(jsn, ind) { + var templ = template.header; + templ += "\n"; + templ += template.script_tag(path.resolve(process.cwd(), jsn)); + templ += template.footer; + + var tempfile = temp.openSync({ prefix: 'novnc-zombie-inject-', suffix: '-file_num-'+ind+'.html' }); + fs.writeSync(tempfile.fd, templ); + fs.closeSync(tempfile.fd); + return tempfile.path; + }); + +} +else { + file_paths = program.tests.map(function(fn) { + return path.resolve(process.cwd(), fn); + }); +} + +var failure_count = 0; + +var use_ansi = false; +if (program.color) use_ansi = true; +else if (program.disableColor) use_ansi = false; +else if (process.stdout.isTTY) use_ansi = true; + +var cursor = ansi(process.stdout, { enabled: use_ansi }); + +var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js')); + +cursor + .write("Running tests ") + .bold() + .write(program.tests.join(', ')) + .reset() + .grey() + .write(' using provider '+prov.name) + .reset() + .write("\n"); +//console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name); + +var provider = prov.provide_emitter(file_paths); +provider.on('test_ready', function(test_json) { + console.log(''); + + filename = program.tests[test_json.file_ind]; + + cursor.bold(); + console.log('Results for %s:', filename); + console.log(Array('Results for :'.length+filename.length+1).join('=')); + cursor.reset(); + + console.log(''); + + cursor.write(''+test_json.num_tests+' tests run, ') + cursor + .green() + .write(''+test_json.num_passes+' passed'); + if (test_json.num_slow > 0) { + cursor + .reset() + .write(' ('); + cursor + .yellow() + .write(''+test_json.num_slow+' slow') + .reset() + .write(')'); + } + cursor + .reset() + .write(', '); + cursor + .red() + .write(''+test_json.num_fails+' failed'); + cursor + .reset() + .write(' -- duration: '+test_json.duration+"\n"); + + console.log(''); + + if (test_json.num_fails > 0 || program.printAll) { + var traverse_tree = function(indentation, node) { + if (node.type == 'suite') { + if (!node.has_subfailures && !program.printAll) return; + + if (indentation == 0) { + cursor.bold(); + console.log(node.name); + console.log(Array(node.name.length+1).join('-')); + cursor.reset(); + } + else { + cursor + .write(Array(indentation+3).join('#')) + .bold() + .write(' '+node.name+' ') + .reset() + .write(Array(indentation+3).join('#')) + .write("\n"); + } + + console.log(''); + + for (var i = 0; i < node.children.length; i++) { + traverse_tree(indentation+1, node.children[i]); + } + } + else { + if (!node.pass) { + cursor.magenta(); + console.log('- failed: '+node.text+test_json.replay); + cursor.red(); + console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS, we get a stack trace too + cursor.reset(); + console.log(''); + } + else if (program.printAll) { + if (node.slow) cursor.yellow(); + else cursor.green(); + cursor + .write('- pass: '+node.text) + .grey() + .write(' ('+node.duration+') '); + /*if (node.slow) cursor.yellow(); + else cursor.green();*/ + cursor + //.write(test_json.replay) + .reset() + .write("\n"); + console.log(''); + } + } + } + + for (var i = 0; i < test_json.suites.length; i++) { + traverse_tree(0, test_json.suites[i]); + } + } + + if (test_json.num_fails == 0) { + cursor.fg.green(); + console.log('all tests passed :-)'); + cursor.reset(); + } +}); + +/*provider.on('console', function(line) { + //console.log(line); +});*/ + +/*gprom.finally(function(ph) { + ph.exit(); + // exit with a status code that actually gives information + if (program.exitWithFailureCount) process.exit(failure_count); +});*/ + diff --git a/tests/run_from_console.zombie.js b/tests/run_from_console.zombie.js new file mode 100644 index 00000000..5ae51846 --- /dev/null +++ b/tests/run_from_console.zombie.js @@ -0,0 +1,73 @@ +var Browser = require('zombie'); +var path = require('path'); +var EventEmitter = require('events').EventEmitter; +var Q = require('q'); + +var provide_emitter = function(file_paths) { + var emitter = new EventEmitter(); + + file_paths.reduce(function(prom, file_path, path_ind) { + return prom.then(function(browser) { + browser.visit('file://'+file_path, function() { + if (browser.error) throw new Error(browser.errors); + + var res_json = {}; + res_json.file_ind = path_ind; + + res_json.num_tests = browser.querySelectorAll('li.test').length; + res_json.num_fails = browser.querySelectorAll('li.test.fail').length; + res_json.num_passes = browser.querySelectorAll('li.test.pass').length; + res_json.num_slow = browser.querySelectorAll('li.test.pass:not(.fast)').length; + res_json.duration = browser.text('li.duration em'); + + var traverse_node = function(elem) { + var classList = elem.className.split(' '); + if (classList.indexOf('suite') > -1) { + var res = { + type: 'suite', + name: elem.querySelector('h1').textContent, + has_subfailures: elem.querySelectorAll('li.test.fail').length > 0 + } + + var child_elems = elem.querySelector('ul').children; + res.children = Array.prototype.map.call(child_elems, traverse_node); + return res; + } + else { + var h2_content = elem.querySelector('h2').childNodes; + var res = { + type: 'test', + text: h2_content[0].textContent + } + + if (classList.indexOf('pass') > -1) { + res.pass = true; + res.slow = classList.indexOf('fast') < 0; + res.duration = h2_content[1].textContent; + } + else { + res.error = elem.querySelector('pre.error').textContent; + } + + return res; + } + } + + var top_suites = browser.querySelectorAll('#mocha-report > li.suite'); + res_json.suites = Array.prototype.map.call(top_suites, traverse_node); + res_json.replay = browser.querySelector('a.replay').textContent; + + emitter.emit('test_ready', res_json); + }); + + return new Browser(); + }); + }, Q(new Browser())); + + return emitter; +} + +module.exports = { + provide_emitter: provide_emitter, + name: 'ZombieJS' +} From 1e570156f90e4d895508c013a345bfa0b85e4509 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Wed, 4 Dec 2013 15:39:20 -0500 Subject: [PATCH 015/100] Add support for Outputting Autogenerated Test HTML This commit introduces two flags, '-g' and '-o' to the `run_from_console.js`. Both flags do not run the tests. Instead, deal with the autogenerated HTML. The former outputs the paths to the autogenerated HTML temp files, and then pauses the program until Ctrl-C is pressed (or SIGINT is sent). The latter outputs the generated HTML for each files to STDIN with the names of the tests to which they belong. --- tests/run_from_console.js | 257 ++++++++++++++++++++++---------------- 1 file changed, 151 insertions(+), 106 deletions(-) diff --git a/tests/run_from_console.js b/tests/run_from_console.js index 9d79ebe4..4498345d 100755 --- a/tests/run_from_console.js +++ b/tests/run_from_console.js @@ -14,6 +14,8 @@ program .option('-c, --color', 'Explicitly enable color (default is to use color when not outputting to a pipe)') .option('-i, --auto-inject ', 'Treat the test list as a set of mocha JS files, and automatically generate HTML files with which to test test. \'includefiles\' should be a comma-separated list of paths to javascript files to include in each of the generated HTML files', make_list, null) .option('-p, --provider ', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper') + .option('-g, --generate-html', 'Instead of running the tests, just return the path to the generated HTML file, then wait for user interaction to exit (should be used with -i)') + .option('-o, --output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with -i)') .parse(process.argv); var file_paths = []; @@ -57,8 +59,6 @@ else { }); } -var failure_count = 0; - var use_ansi = false; if (program.color) use_ansi = true; else if (program.disableColor) use_ansi = false; @@ -66,131 +66,176 @@ else if (process.stdout.isTTY) use_ansi = true; var cursor = ansi(process.stdout, { enabled: use_ansi }); -var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js')); +if (program.outputHtml) { + var fs = require('fs'); + file_paths.forEach(function(path, path_ind) { + fs.readFile(path, function(err, data) { + if (err) { + console.warn(error.stack); + return; + } + + cursor + .bold() + .write(program.tests[path_ind]) + .reset() + .write("\n") + .write(Array(program.tests[path_ind].length+1).join('=')) + .write("\n\n") + .write(data) + .write("\n"); + }); + }); +} -cursor - .write("Running tests ") - .bold() - .write(program.tests.join(', ')) - .reset() - .grey() - .write(' using provider '+prov.name) - .reset() - .write("\n"); -//console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name); - -var provider = prov.provide_emitter(file_paths); -provider.on('test_ready', function(test_json) { +if (program.generateHtml) { + file_paths.forEach(function(path, path_ind) { + cursor + .bold() + .write(program.tests[path_ind]) + .write(": ") + .reset() + .write(path) + .write("\n"); + }); console.log(''); +} - filename = program.tests[test_json.file_ind]; +if (program.generateHtml) { + process.stdin.resume(); // pause until C-c + process.on('SIGINT', function() { + process.stdin.pause(); // exit + }); +} - cursor.bold(); - console.log('Results for %s:', filename); - console.log(Array('Results for :'.length+filename.length+1).join('=')); - cursor.reset(); +if (!program.outputHtml && !program.generateHtml) { + var failure_count = 0; - console.log(''); + var prov = require(path.resolve(__dirname, 'run_from_console.'+program.provider+'.js')); - cursor.write(''+test_json.num_tests+' tests run, ') cursor - .green() - .write(''+test_json.num_passes+' passed'); - if (test_json.num_slow > 0) { + .write("Running tests ") + .bold() + .write(program.tests.join(', ')) + .reset() + .grey() + .write(' using provider '+prov.name) + .reset() + .write("\n"); + //console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name); + + var provider = prov.provide_emitter(file_paths); + provider.on('test_ready', function(test_json) { + console.log(''); + + filename = program.tests[test_json.file_ind]; + + cursor.bold(); + console.log('Results for %s:', filename); + console.log(Array('Results for :'.length+filename.length+1).join('=')); + cursor.reset(); + + console.log(''); + + cursor.write(''+test_json.num_tests+' tests run, ') + cursor + .green() + .write(''+test_json.num_passes+' passed'); + if (test_json.num_slow > 0) { + cursor + .reset() + .write(' ('); + cursor + .yellow() + .write(''+test_json.num_slow+' slow') + .reset() + .write(')'); + } cursor .reset() - .write(' ('); + .write(', '); + cursor + .red() + .write(''+test_json.num_fails+' failed'); cursor - .yellow() - .write(''+test_json.num_slow+' slow') .reset() - .write(')'); - } - cursor - .reset() - .write(', '); - cursor - .red() - .write(''+test_json.num_fails+' failed'); - cursor - .reset() - .write(' -- duration: '+test_json.duration+"\n"); + .write(' -- duration: '+test_json.duration+"\n"); - console.log(''); + console.log(''); - if (test_json.num_fails > 0 || program.printAll) { - var traverse_tree = function(indentation, node) { - if (node.type == 'suite') { - if (!node.has_subfailures && !program.printAll) return; + if (test_json.num_fails > 0 || program.printAll) { + var traverse_tree = function(indentation, node) { + if (node.type == 'suite') { + if (!node.has_subfailures && !program.printAll) return; - if (indentation == 0) { - cursor.bold(); - console.log(node.name); - console.log(Array(node.name.length+1).join('-')); - cursor.reset(); + if (indentation == 0) { + cursor.bold(); + console.log(node.name); + console.log(Array(node.name.length+1).join('-')); + cursor.reset(); + } + else { + cursor + .write(Array(indentation+3).join('#')) + .bold() + .write(' '+node.name+' ') + .reset() + .write(Array(indentation+3).join('#')) + .write("\n"); + } + + console.log(''); + + for (var i = 0; i < node.children.length; i++) { + traverse_tree(indentation+1, node.children[i]); + } } else { - cursor - .write(Array(indentation+3).join('#')) - .bold() - .write(' '+node.name+' ') - .reset() - .write(Array(indentation+3).join('#')) - .write("\n"); - } - - console.log(''); - - for (var i = 0; i < node.children.length; i++) { - traverse_tree(indentation+1, node.children[i]); + if (!node.pass) { + cursor.magenta(); + console.log('- failed: '+node.text+test_json.replay); + cursor.red(); + console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS, we get a stack trace too + cursor.reset(); + console.log(''); + } + else if (program.printAll) { + if (node.slow) cursor.yellow(); + else cursor.green(); + cursor + .write('- pass: '+node.text) + .grey() + .write(' ('+node.duration+') '); + /*if (node.slow) cursor.yellow(); + else cursor.green();*/ + cursor + //.write(test_json.replay) + .reset() + .write("\n"); + console.log(''); + } } } - else { - if (!node.pass) { - cursor.magenta(); - console.log('- failed: '+node.text+test_json.replay); - cursor.red(); - console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS, we get a stack trace too - cursor.reset(); - console.log(''); - } - else if (program.printAll) { - if (node.slow) cursor.yellow(); - else cursor.green(); - cursor - .write('- pass: '+node.text) - .grey() - .write(' ('+node.duration+') '); - /*if (node.slow) cursor.yellow(); - else cursor.green();*/ - cursor - //.write(test_json.replay) - .reset() - .write("\n"); - console.log(''); - } + + for (var i = 0; i < test_json.suites.length; i++) { + traverse_tree(0, test_json.suites[i]); } } - for (var i = 0; i < test_json.suites.length; i++) { - traverse_tree(0, test_json.suites[i]); + if (test_json.num_fails == 0) { + cursor.fg.green(); + console.log('all tests passed :-)'); + cursor.reset(); } - } + }); - if (test_json.num_fails == 0) { - cursor.fg.green(); - console.log('all tests passed :-)'); - cursor.reset(); - } -}); - -/*provider.on('console', function(line) { - //console.log(line); -});*/ - -/*gprom.finally(function(ph) { - ph.exit(); - // exit with a status code that actually gives information - if (program.exitWithFailureCount) process.exit(failure_count); -});*/ + /*provider.on('console', function(line) { + //console.log(line); + });*/ + /*gprom.finally(function(ph) { + ph.exit(); + // exit with a status code that actually gives information + if (program.exitWithFailureCount) process.exit(failure_count); + });*/ +} From ae52883b938b24ff5f09a778e4baac1f5bd0c5c9 Mon Sep 17 00:00:00 2001 From: jalf Date: Wed, 27 Nov 2013 15:07:25 +0100 Subject: [PATCH 016/100] Keyboard Handling [1/8]: Parse keysymdef.h to produce Unicode -> keysym mappings table Add a node.js-based tool (utils/parse.js) to read keysymdef.h and produce a JavaScript file mapping Unicode code points to keysyms. Also add the generated table (include/keysymdef.js). --- include/keysymdef.js | 15 +++++++ utils/parse.js | 97 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 include/keysymdef.js create mode 100644 utils/parse.js diff --git a/include/keysymdef.js b/include/keysymdef.js new file mode 100644 index 00000000..0f052d2e --- /dev/null +++ b/include/keysymdef.js @@ -0,0 +1,15 @@ +// This file describes mappings from Unicode codepoints to the keysym values +// (and optionally, key names) expected by the RFB protocol +// How this file was generated: +// node /Users/jalf/dev/mi/novnc/utils/parse.js -d /opt/X11/include/X11/keysymdef.h +var keysyms = (function(){ + "use strict"; + var keynames = {"32":"space","33":"exclam","34":"quotedbl","35":"numbersign","36":"dollar","37":"percent","38":"ampersand","39":"quoteright","40":"parenleft","41":"parenright","42":"asterisk","43":"plus","44":"comma","45":"minus","46":"period","47":"slash","48":"0","49":"1","50":"2","51":"3","52":"4","53":"5","54":"6","55":"7","56":"8","57":"9","58":"colon","59":"semicolon","60":"less","61":"equal","62":"greater","63":"question","64":"at","65":"A","66":"B","67":"C","68":"D","69":"E","70":"F","71":"G","72":"H","73":"I","74":"J","75":"K","76":"L","77":"M","78":"N","79":"O","80":"P","81":"Q","82":"R","83":"S","84":"T","85":"U","86":"V","87":"W","88":"X","89":"Y","90":"Z","91":"bracketleft","92":"backslash","93":"bracketright","94":"asciicircum","95":"underscore","96":"quoteleft","97":"a","98":"b","99":"c","100":"d","101":"e","102":"f","103":"g","104":"h","105":"i","106":"j","107":"k","108":"l","109":"m","110":"n","111":"o","112":"p","113":"q","114":"r","115":"s","116":"t","117":"u","118":"v","119":"w","120":"x","121":"y","122":"z","123":"braceleft","124":"bar","125":"braceright","126":"asciitilde","160":"nobreakspace","161":"exclamdown","162":"cent","163":"sterling","164":"currency","165":"yen","166":"brokenbar","167":"section","168":"diaeresis","169":"copyright","170":"ordfeminine","171":"guillemotleft","172":"notsign","173":"hyphen","174":"registered","175":"macron","176":"degree","177":"plusminus","178":"twosuperior","179":"threesuperior","180":"acute","181":"mu","182":"paragraph","183":"periodcentered","184":"cedilla","185":"onesuperior","186":"masculine","187":"guillemotright","188":"onequarter","189":"onehalf","190":"threequarters","191":"questiondown","192":"Agrave","193":"Aacute","194":"Acircumflex","195":"Atilde","196":"Adiaeresis","197":"Aring","198":"AE","199":"Ccedilla","200":"Egrave","201":"Eacute","202":"Ecircumflex","203":"Ediaeresis","204":"Igrave","205":"Iacute","206":"Icircumflex","207":"Idiaeresis","208":"Eth","209":"Ntilde","210":"Ograve","211":"Oacute","212":"Ocircumflex","213":"Otilde","214":"Odiaeresis","215":"multiply","216":"Ooblique","217":"Ugrave","218":"Uacute","219":"Ucircumflex","220":"Udiaeresis","221":"Yacute","222":"Thorn","223":"ssharp","224":"agrave","225":"aacute","226":"acircumflex","227":"atilde","228":"adiaeresis","229":"aring","230":"ae","231":"ccedilla","232":"egrave","233":"eacute","234":"ecircumflex","235":"ediaeresis","236":"igrave","237":"iacute","238":"icircumflex","239":"idiaeresis","240":"eth","241":"ntilde","242":"ograve","243":"oacute","244":"ocircumflex","245":"otilde","246":"odiaeresis","247":"division","248":"ooblique","249":"ugrave","250":"uacute","251":"ucircumflex","252":"udiaeresis","253":"yacute","254":"thorn","255":"ydiaeresis","417":"Aogonek","418":"breve","419":"Lstroke","421":"Lcaron","422":"Sacute","425":"Scaron","426":"Scedilla","427":"Tcaron","428":"Zacute","430":"Zcaron","431":"Zabovedot","433":"aogonek","434":"ogonek","435":"lstroke","437":"lcaron","438":"sacute","439":"caron","441":"scaron","442":"scedilla","443":"tcaron","444":"zacute","445":"doubleacute","446":"zcaron","447":"zabovedot","448":"Racute","451":"Abreve","453":"Lacute","454":"Cacute","456":"Ccaron","458":"Eogonek","460":"Ecaron","463":"Dcaron","464":"Dstroke","465":"Nacute","466":"Ncaron","469":"Odoubleacute","472":"Rcaron","473":"Uring","475":"Udoubleacute","478":"Tcedilla","480":"racute","483":"abreve","485":"lacute","486":"cacute","488":"ccaron","490":"eogonek","492":"ecaron","495":"dcaron","496":"dstroke","497":"nacute","498":"ncaron","501":"odoubleacute","504":"rcaron","505":"uring","507":"udoubleacute","510":"tcedilla","511":"abovedot","673":"Hstroke","678":"Hcircumflex","681":"Iabovedot","683":"Gbreve","684":"Jcircumflex","689":"hstroke","694":"hcircumflex","697":"idotless","699":"gbreve","700":"jcircumflex","709":"Cabovedot","710":"Ccircumflex","725":"Gabovedot","728":"Gcircumflex","733":"Ubreve","734":"Scircumflex","741":"cabovedot","742":"ccircumflex","757":"gabovedot","760":"gcircumflex","765":"ubreve","766":"scircumflex","930":"kappa","931":"Rcedilla","933":"Itilde","934":"Lcedilla","938":"Emacron","939":"Gcedilla","940":"Tslash","947":"rcedilla","949":"itilde","950":"lcedilla","954":"emacron","955":"gcedilla","956":"tslash","957":"ENG","959":"eng","960":"Amacron","967":"Iogonek","972":"Eabovedot","975":"Imacron","977":"Ncedilla","978":"Omacron","979":"Kcedilla","985":"Uogonek","989":"Utilde","990":"Umacron","992":"amacron","999":"iogonek","1004":"eabovedot","1007":"imacron","1009":"ncedilla","1010":"omacron","1011":"kcedilla","1017":"uogonek","1021":"utilde","1022":"umacron","1150":"overline","1185":"kana_fullstop","1186":"kana_openingbracket","1187":"kana_closingbracket","1188":"kana_comma","1189":"kana_middledot","1190":"kana_WO","1191":"kana_a","1192":"kana_i","1193":"kana_u","1194":"kana_e","1195":"kana_o","1196":"kana_ya","1197":"kana_yu","1198":"kana_yo","1199":"kana_tu","1200":"prolongedsound","1201":"kana_A","1202":"kana_I","1203":"kana_U","1204":"kana_E","1205":"kana_O","1206":"kana_KA","1207":"kana_KI","1208":"kana_KU","1209":"kana_KE","1210":"kana_KO","1211":"kana_SA","1212":"kana_SHI","1213":"kana_SU","1214":"kana_SE","1215":"kana_SO","1216":"kana_TA","1217":"kana_TI","1218":"kana_TU","1219":"kana_TE","1220":"kana_TO","1221":"kana_NA","1222":"kana_NI","1223":"kana_NU","1224":"kana_NE","1225":"kana_NO","1226":"kana_HA","1227":"kana_HI","1228":"kana_HU","1229":"kana_HE","1230":"kana_HO","1231":"kana_MA","1232":"kana_MI","1233":"kana_MU","1234":"kana_ME","1235":"kana_MO","1236":"kana_YA","1237":"kana_YU","1238":"kana_YO","1239":"kana_RA","1240":"kana_RI","1241":"kana_RU","1242":"kana_RE","1243":"kana_RO","1244":"kana_WA","1245":"kana_N","1246":"voicedsound","1247":"semivoicedsound","1452":"Arabic_comma","1467":"Arabic_semicolon","1471":"Arabic_question_mark","1473":"Arabic_hamza","1474":"Arabic_maddaonalef","1475":"Arabic_hamzaonalef","1476":"Arabic_hamzaonwaw","1477":"Arabic_hamzaunderalef","1478":"Arabic_hamzaonyeh","1479":"Arabic_alef","1480":"Arabic_beh","1481":"Arabic_tehmarbuta","1482":"Arabic_teh","1483":"Arabic_theh","1484":"Arabic_jeem","1485":"Arabic_hah","1486":"Arabic_khah","1487":"Arabic_dal","1488":"Arabic_thal","1489":"Arabic_ra","1490":"Arabic_zain","1491":"Arabic_seen","1492":"Arabic_sheen","1493":"Arabic_sad","1494":"Arabic_dad","1495":"Arabic_tah","1496":"Arabic_zah","1497":"Arabic_ain","1498":"Arabic_ghain","1504":"Arabic_tatweel","1505":"Arabic_feh","1506":"Arabic_qaf","1507":"Arabic_kaf","1508":"Arabic_lam","1509":"Arabic_meem","1510":"Arabic_noon","1511":"Arabic_heh","1512":"Arabic_waw","1513":"Arabic_alefmaksura","1514":"Arabic_yeh","1515":"Arabic_fathatan","1516":"Arabic_dammatan","1517":"Arabic_kasratan","1518":"Arabic_fatha","1519":"Arabic_damma","1520":"Arabic_kasra","1521":"Arabic_shadda","1522":"Arabic_sukun","1697":"Serbian_dje","1698":"Macedonia_gje","1699":"Cyrillic_io","1700":"Ukranian_je","1701":"Macedonia_dse","1702":"Ukranian_i","1703":"Ukranian_yi","1704":"Serbian_je","1705":"Serbian_lje","1706":"Serbian_nje","1707":"Serbian_tshe","1708":"Macedonia_kje","1709":"Ukrainian_ghe_with_upturn","1710":"Byelorussian_shortu","1711":"Serbian_dze","1712":"numerosign","1713":"Serbian_DJE","1714":"Macedonia_GJE","1715":"Cyrillic_IO","1716":"Ukranian_JE","1717":"Macedonia_DSE","1718":"Ukranian_I","1719":"Ukranian_YI","1720":"Serbian_JE","1721":"Serbian_LJE","1722":"Serbian_NJE","1723":"Serbian_TSHE","1724":"Macedonia_KJE","1725":"Ukrainian_GHE_WITH_UPTURN","1726":"Byelorussian_SHORTU","1727":"Serbian_DZE","1728":"Cyrillic_yu","1729":"Cyrillic_a","1730":"Cyrillic_be","1731":"Cyrillic_tse","1732":"Cyrillic_de","1733":"Cyrillic_ie","1734":"Cyrillic_ef","1735":"Cyrillic_ghe","1736":"Cyrillic_ha","1737":"Cyrillic_i","1738":"Cyrillic_shorti","1739":"Cyrillic_ka","1740":"Cyrillic_el","1741":"Cyrillic_em","1742":"Cyrillic_en","1743":"Cyrillic_o","1744":"Cyrillic_pe","1745":"Cyrillic_ya","1746":"Cyrillic_er","1747":"Cyrillic_es","1748":"Cyrillic_te","1749":"Cyrillic_u","1750":"Cyrillic_zhe","1751":"Cyrillic_ve","1752":"Cyrillic_softsign","1753":"Cyrillic_yeru","1754":"Cyrillic_ze","1755":"Cyrillic_sha","1756":"Cyrillic_e","1757":"Cyrillic_shcha","1758":"Cyrillic_che","1759":"Cyrillic_hardsign","1760":"Cyrillic_YU","1761":"Cyrillic_A","1762":"Cyrillic_BE","1763":"Cyrillic_TSE","1764":"Cyrillic_DE","1765":"Cyrillic_IE","1766":"Cyrillic_EF","1767":"Cyrillic_GHE","1768":"Cyrillic_HA","1769":"Cyrillic_I","1770":"Cyrillic_SHORTI","1771":"Cyrillic_KA","1772":"Cyrillic_EL","1773":"Cyrillic_EM","1774":"Cyrillic_EN","1775":"Cyrillic_O","1776":"Cyrillic_PE","1777":"Cyrillic_YA","1778":"Cyrillic_ER","1779":"Cyrillic_ES","1780":"Cyrillic_TE","1781":"Cyrillic_U","1782":"Cyrillic_ZHE","1783":"Cyrillic_VE","1784":"Cyrillic_SOFTSIGN","1785":"Cyrillic_YERU","1786":"Cyrillic_ZE","1787":"Cyrillic_SHA","1788":"Cyrillic_E","1789":"Cyrillic_SHCHA","1790":"Cyrillic_CHE","1791":"Cyrillic_HARDSIGN","1953":"Greek_ALPHAaccent","1954":"Greek_EPSILONaccent","1955":"Greek_ETAaccent","1956":"Greek_IOTAaccent","1957":"Greek_IOTAdiaeresis","1959":"Greek_OMICRONaccent","1960":"Greek_UPSILONaccent","1961":"Greek_UPSILONdieresis","1963":"Greek_OMEGAaccent","1966":"Greek_accentdieresis","1967":"Greek_horizbar","1969":"Greek_alphaaccent","1970":"Greek_epsilonaccent","1971":"Greek_etaaccent","1972":"Greek_iotaaccent","1973":"Greek_iotadieresis","1974":"Greek_iotaaccentdieresis","1975":"Greek_omicronaccent","1976":"Greek_upsilonaccent","1977":"Greek_upsilondieresis","1978":"Greek_upsilonaccentdieresis","1979":"Greek_omegaaccent","1985":"Greek_ALPHA","1986":"Greek_BETA","1987":"Greek_GAMMA","1988":"Greek_DELTA","1989":"Greek_EPSILON","1990":"Greek_ZETA","1991":"Greek_ETA","1992":"Greek_THETA","1993":"Greek_IOTA","1994":"Greek_KAPPA","1995":"Greek_LAMBDA","1996":"Greek_MU","1997":"Greek_NU","1998":"Greek_XI","1999":"Greek_OMICRON","2000":"Greek_PI","2001":"Greek_RHO","2002":"Greek_SIGMA","2004":"Greek_TAU","2005":"Greek_UPSILON","2006":"Greek_PHI","2007":"Greek_CHI","2008":"Greek_PSI","2009":"Greek_OMEGA","2017":"Greek_alpha","2018":"Greek_beta","2019":"Greek_gamma","2020":"Greek_delta","2021":"Greek_epsilon","2022":"Greek_zeta","2023":"Greek_eta","2024":"Greek_theta","2025":"Greek_iota","2026":"Greek_kappa","2027":"Greek_lambda","2028":"Greek_mu","2029":"Greek_nu","2030":"Greek_xi","2031":"Greek_omicron","2032":"Greek_pi","2033":"Greek_rho","2034":"Greek_sigma","2035":"Greek_finalsmallsigma","2036":"Greek_tau","2037":"Greek_upsilon","2038":"Greek_phi","2039":"Greek_chi","2040":"Greek_psi","2041":"Greek_omega","2209":"leftradical","2210":"topleftradical","2211":"horizconnector","2212":"topintegral","2213":"botintegral","2214":"vertconnector","2215":"topleftsqbracket","2216":"botleftsqbracket","2217":"toprightsqbracket","2218":"botrightsqbracket","2219":"topleftparens","2220":"botleftparens","2221":"toprightparens","2222":"botrightparens","2223":"leftmiddlecurlybrace","2224":"rightmiddlecurlybrace","2225":"topleftsummation","2226":"botleftsummation","2227":"topvertsummationconnector","2228":"botvertsummationconnector","2229":"toprightsummation","2230":"botrightsummation","2231":"rightmiddlesummation","2236":"lessthanequal","2237":"notequal","2238":"greaterthanequal","2239":"integral","2240":"therefore","2241":"variation","2242":"infinity","2245":"nabla","2248":"approximate","2249":"similarequal","2253":"ifonlyif","2254":"implies","2255":"identical","2262":"radical","2266":"includedin","2267":"includes","2268":"intersection","2269":"union","2270":"logicaland","2271":"logicalor","2287":"partialderivative","2294":"function","2299":"leftarrow","2300":"uparrow","2301":"rightarrow","2302":"downarrow","2527":"blank","2528":"soliddiamond","2529":"checkerboard","2530":"ht","2531":"ff","2532":"cr","2533":"lf","2536":"nl","2537":"vt","2538":"lowrightcorner","2539":"uprightcorner","2540":"upleftcorner","2541":"lowleftcorner","2542":"crossinglines","2543":"horizlinescan1","2544":"horizlinescan3","2545":"horizlinescan5","2546":"horizlinescan7","2547":"horizlinescan9","2548":"leftt","2549":"rightt","2550":"bott","2551":"topt","2552":"vertbar","2721":"emspace","2722":"enspace","2723":"em3space","2724":"em4space","2725":"digitspace","2726":"punctspace","2727":"thinspace","2728":"hairspace","2729":"emdash","2730":"endash","2732":"signifblank","2734":"ellipsis","2735":"doubbaselinedot","2736":"onethird","2737":"twothirds","2738":"onefifth","2739":"twofifths","2740":"threefifths","2741":"fourfifths","2742":"onesixth","2743":"fivesixths","2744":"careof","2747":"figdash","2748":"leftanglebracket","2749":"decimalpoint","2750":"rightanglebracket","2751":"marker","2755":"oneeighth","2756":"threeeighths","2757":"fiveeighths","2758":"seveneighths","2761":"trademark","2762":"signaturemark","2763":"trademarkincircle","2764":"leftopentriangle","2765":"rightopentriangle","2766":"emopencircle","2767":"emopenrectangle","2768":"leftsinglequotemark","2769":"rightsinglequotemark","2770":"leftdoublequotemark","2771":"rightdoublequotemark","2772":"prescription","2773":"permille","2774":"minutes","2775":"seconds","2777":"latincross","2778":"hexagram","2779":"filledrectbullet","2780":"filledlefttribullet","2781":"filledrighttribullet","2782":"emfilledcircle","2783":"emfilledrect","2784":"enopencircbullet","2785":"enopensquarebullet","2786":"openrectbullet","2787":"opentribulletup","2788":"opentribulletdown","2789":"openstar","2790":"enfilledcircbullet","2791":"enfilledsqbullet","2792":"filledtribulletup","2793":"filledtribulletdown","2794":"leftpointer","2795":"rightpointer","2796":"club","2797":"diamond","2798":"heart","2800":"maltesecross","2801":"dagger","2802":"doubledagger","2803":"checkmark","2804":"ballotcross","2805":"musicalsharp","2806":"musicalflat","2807":"malesymbol","2808":"femalesymbol","2809":"telephone","2810":"telephonerecorder","2811":"phonographcopyright","2812":"caret","2813":"singlelowquotemark","2814":"doublelowquotemark","2815":"cursor","2979":"leftcaret","2982":"rightcaret","2984":"downcaret","2985":"upcaret","3008":"overbar","3010":"downtack","3011":"upshoe","3012":"downstile","3014":"underbar","3018":"jot","3020":"quad","3022":"uptack","3023":"circle","3027":"upstile","3030":"downshoe","3032":"rightshoe","3034":"leftshoe","3036":"lefttack","3068":"righttack","3295":"hebrew_doublelowline","3296":"hebrew_aleph","3297":"hebrew_beth","3298":"hebrew_gimmel","3299":"hebrew_daleth","3300":"hebrew_he","3301":"hebrew_waw","3302":"hebrew_zayin","3303":"hebrew_het","3304":"hebrew_teth","3305":"hebrew_yod","3306":"hebrew_finalkaph","3307":"hebrew_kaph","3308":"hebrew_lamed","3309":"hebrew_finalmem","3310":"hebrew_mem","3311":"hebrew_finalnun","3312":"hebrew_nun","3313":"hebrew_samekh","3314":"hebrew_ayin","3315":"hebrew_finalpe","3316":"hebrew_pe","3317":"hebrew_finalzadi","3318":"hebrew_zadi","3319":"hebrew_kuf","3320":"hebrew_resh","3321":"hebrew_shin","3322":"hebrew_taf","3489":"Thai_kokai","3490":"Thai_khokhai","3491":"Thai_khokhuat","3492":"Thai_khokhwai","3493":"Thai_khokhon","3494":"Thai_khorakhang","3495":"Thai_ngongu","3496":"Thai_chochan","3497":"Thai_choching","3498":"Thai_chochang","3499":"Thai_soso","3500":"Thai_chochoe","3501":"Thai_yoying","3502":"Thai_dochada","3503":"Thai_topatak","3504":"Thai_thothan","3505":"Thai_thonangmontho","3506":"Thai_thophuthao","3507":"Thai_nonen","3508":"Thai_dodek","3509":"Thai_totao","3510":"Thai_thothung","3511":"Thai_thothahan","3512":"Thai_thothong","3513":"Thai_nonu","3514":"Thai_bobaimai","3515":"Thai_popla","3516":"Thai_phophung","3517":"Thai_fofa","3518":"Thai_phophan","3519":"Thai_fofan","3520":"Thai_phosamphao","3521":"Thai_moma","3522":"Thai_yoyak","3523":"Thai_rorua","3524":"Thai_ru","3525":"Thai_loling","3526":"Thai_lu","3527":"Thai_wowaen","3528":"Thai_sosala","3529":"Thai_sorusi","3530":"Thai_sosua","3531":"Thai_hohip","3532":"Thai_lochula","3533":"Thai_oang","3534":"Thai_honokhuk","3535":"Thai_paiyannoi","3536":"Thai_saraa","3537":"Thai_maihanakat","3538":"Thai_saraaa","3539":"Thai_saraam","3540":"Thai_sarai","3541":"Thai_saraii","3542":"Thai_saraue","3543":"Thai_sarauee","3544":"Thai_sarau","3545":"Thai_sarauu","3546":"Thai_phinthu","3550":"Thai_maihanakat_maitho","3551":"Thai_baht","3552":"Thai_sarae","3553":"Thai_saraae","3554":"Thai_sarao","3555":"Thai_saraaimaimuan","3556":"Thai_saraaimaimalai","3557":"Thai_lakkhangyao","3558":"Thai_maiyamok","3559":"Thai_maitaikhu","3560":"Thai_maiek","3561":"Thai_maitho","3562":"Thai_maitri","3563":"Thai_maichattawa","3564":"Thai_thanthakhat","3565":"Thai_nikhahit","3568":"Thai_leksun","3569":"Thai_leknung","3570":"Thai_leksong","3571":"Thai_leksam","3572":"Thai_leksi","3573":"Thai_lekha","3574":"Thai_lekhok","3575":"Thai_lekchet","3576":"Thai_lekpaet","3577":"Thai_lekkao","3745":"Hangul_Kiyeog","3746":"Hangul_SsangKiyeog","3747":"Hangul_KiyeogSios","3748":"Hangul_Nieun","3749":"Hangul_NieunJieuj","3750":"Hangul_NieunHieuh","3751":"Hangul_Dikeud","3752":"Hangul_SsangDikeud","3753":"Hangul_Rieul","3754":"Hangul_RieulKiyeog","3755":"Hangul_RieulMieum","3756":"Hangul_RieulPieub","3757":"Hangul_RieulSios","3758":"Hangul_RieulTieut","3759":"Hangul_RieulPhieuf","3760":"Hangul_RieulHieuh","3761":"Hangul_Mieum","3762":"Hangul_Pieub","3763":"Hangul_SsangPieub","3764":"Hangul_PieubSios","3765":"Hangul_Sios","3766":"Hangul_SsangSios","3767":"Hangul_Ieung","3768":"Hangul_Jieuj","3769":"Hangul_SsangJieuj","3770":"Hangul_Cieuc","3771":"Hangul_Khieuq","3772":"Hangul_Tieut","3773":"Hangul_Phieuf","3774":"Hangul_Hieuh","3775":"Hangul_A","3776":"Hangul_AE","3777":"Hangul_YA","3778":"Hangul_YAE","3779":"Hangul_EO","3780":"Hangul_E","3781":"Hangul_YEO","3782":"Hangul_YE","3783":"Hangul_O","3784":"Hangul_WA","3785":"Hangul_WAE","3786":"Hangul_OE","3787":"Hangul_YO","3788":"Hangul_U","3789":"Hangul_WEO","3790":"Hangul_WE","3791":"Hangul_WI","3792":"Hangul_YU","3793":"Hangul_EU","3794":"Hangul_YI","3795":"Hangul_I","3796":"Hangul_J_Kiyeog","3797":"Hangul_J_SsangKiyeog","3798":"Hangul_J_KiyeogSios","3799":"Hangul_J_Nieun","3800":"Hangul_J_NieunJieuj","3801":"Hangul_J_NieunHieuh","3802":"Hangul_J_Dikeud","3803":"Hangul_J_Rieul","3804":"Hangul_J_RieulKiyeog","3805":"Hangul_J_RieulMieum","3806":"Hangul_J_RieulPieub","3807":"Hangul_J_RieulSios","3808":"Hangul_J_RieulTieut","3809":"Hangul_J_RieulPhieuf","3810":"Hangul_J_RieulHieuh","3811":"Hangul_J_Mieum","3812":"Hangul_J_Pieub","3813":"Hangul_J_PieubSios","3814":"Hangul_J_Sios","3815":"Hangul_J_SsangSios","3816":"Hangul_J_Ieung","3817":"Hangul_J_Jieuj","3818":"Hangul_J_Cieuc","3819":"Hangul_J_Khieuq","3820":"Hangul_J_Tieut","3821":"Hangul_J_Phieuf","3822":"Hangul_J_Hieuh","3823":"Hangul_RieulYeorinHieuh","3824":"Hangul_SunkyeongeumMieum","3825":"Hangul_SunkyeongeumPieub","3826":"Hangul_PanSios","3827":"Hangul_KkogjiDalrinIeung","3828":"Hangul_SunkyeongeumPhieuf","3829":"Hangul_YeorinHieuh","3830":"Hangul_AraeA","3831":"Hangul_AraeAE","3832":"Hangul_J_PanSios","3833":"Hangul_J_KkogjiDalrinIeung","3834":"Hangul_J_YeorinHieuh","3839":"Korean_Won","5052":"OE","5053":"oe","5054":"Ydiaeresis","8364":"EuroSign","64769":"3270_Duplicate","64770":"3270_FieldMark","64771":"3270_Right2","64772":"3270_Left2","64773":"3270_BackTab","64774":"3270_EraseEOF","64775":"3270_EraseInput","64776":"3270_Reset","64777":"3270_Quit","64778":"3270_PA1","64779":"3270_PA2","64780":"3270_PA3","64781":"3270_Test","64782":"3270_Attn","64783":"3270_CursorBlink","64784":"3270_AltCursor","64785":"3270_KeyClick","64786":"3270_Jump","64787":"3270_Ident","64788":"3270_Rule","64789":"3270_Copy","64790":"3270_Play","64791":"3270_Setup","64792":"3270_Record","64793":"3270_ChangeScreen","64794":"3270_DeleteWord","64795":"3270_ExSelect","64796":"3270_CursorSelect","64797":"3270_PrintScreen","64798":"3270_Enter","65025":"ISO_Lock","65026":"ISO_Level2_Latch","65027":"ISO_Level3_Shift","65028":"ISO_Level3_Latch","65029":"ISO_Level3_Lock","65030":"ISO_Group_Latch","65031":"ISO_Group_Lock","65032":"ISO_Next_Group","65033":"ISO_Next_Group_Lock","65034":"ISO_Prev_Group","65035":"ISO_Prev_Group_Lock","65036":"ISO_First_Group","65037":"ISO_First_Group_Lock","65038":"ISO_Last_Group","65039":"ISO_Last_Group_Lock","65041":"ISO_Level5_Shift","65042":"ISO_Level5_Latch","65043":"ISO_Level5_Lock","65056":"ISO_Left_Tab","65057":"ISO_Move_Line_Up","65058":"ISO_Move_Line_Down","65059":"ISO_Partial_Line_Up","65060":"ISO_Partial_Line_Down","65061":"ISO_Partial_Space_Left","65062":"ISO_Partial_Space_Right","65063":"ISO_Set_Margin_Left","65064":"ISO_Set_Margin_Right","65065":"ISO_Release_Margin_Left","65066":"ISO_Release_Margin_Right","65067":"ISO_Release_Both_Margins","65068":"ISO_Fast_Cursor_Left","65069":"ISO_Fast_Cursor_Right","65070":"ISO_Fast_Cursor_Up","65071":"ISO_Fast_Cursor_Down","65072":"ISO_Continuous_Underline","65073":"ISO_Discontinuous_Underline","65074":"ISO_Emphasize","65075":"ISO_Center_Object","65076":"ISO_Enter","65104":"dead_grave","65105":"dead_acute","65106":"dead_circumflex","65107":"dead_perispomeni","65108":"dead_macron","65109":"dead_breve","65110":"dead_abovedot","65111":"dead_diaeresis","65112":"dead_abovering","65113":"dead_doubleacute","65114":"dead_caron","65115":"dead_cedilla","65116":"dead_ogonek","65117":"dead_iota","65118":"dead_voiced_sound","65119":"dead_semivoiced_sound","65120":"dead_belowdot","65121":"dead_hook","65122":"dead_horn","65123":"dead_stroke","65124":"dead_psili","65125":"dead_dasia","65126":"dead_doublegrave","65127":"dead_belowring","65128":"dead_belowmacron","65129":"dead_belowcircumflex","65130":"dead_belowtilde","65131":"dead_belowbreve","65132":"dead_belowdiaeresis","65133":"dead_invertedbreve","65134":"dead_belowcomma","65135":"dead_currency","65136":"AccessX_Enable","65137":"AccessX_Feedback_Enable","65138":"RepeatKeys_Enable","65139":"SlowKeys_Enable","65140":"BounceKeys_Enable","65141":"StickyKeys_Enable","65142":"MouseKeys_Enable","65143":"MouseKeys_Accel_Enable","65144":"Overlay1_Enable","65145":"Overlay2_Enable","65146":"AudibleBell_Enable","65152":"dead_a","65153":"dead_A","65154":"dead_e","65155":"dead_E","65156":"dead_i","65157":"dead_I","65158":"dead_o","65159":"dead_O","65160":"dead_u","65161":"dead_U","65162":"dead_small_schwa","65163":"dead_capital_schwa","65164":"dead_greek","65184":"ch","65185":"Ch","65186":"CH","65187":"c_h","65188":"C_h","65189":"C_H","65232":"First_Virtual_Screen","65233":"Prev_Virtual_Screen","65234":"Next_Virtual_Screen","65236":"Last_Virtual_Screen","65237":"Terminate_Server","65248":"Pointer_Left","65249":"Pointer_Right","65250":"Pointer_Up","65251":"Pointer_Down","65252":"Pointer_UpLeft","65253":"Pointer_UpRight","65254":"Pointer_DownLeft","65255":"Pointer_DownRight","65256":"Pointer_Button_Dflt","65257":"Pointer_Button1","65258":"Pointer_Button2","65259":"Pointer_Button3","65260":"Pointer_Button4","65261":"Pointer_Button5","65262":"Pointer_DblClick_Dflt","65263":"Pointer_DblClick1","65264":"Pointer_DblClick2","65265":"Pointer_DblClick3","65266":"Pointer_DblClick4","65267":"Pointer_DblClick5","65268":"Pointer_Drag_Dflt","65269":"Pointer_Drag1","65270":"Pointer_Drag2","65271":"Pointer_Drag3","65272":"Pointer_Drag4","65273":"Pointer_EnableKeys","65274":"Pointer_Accelerate","65275":"Pointer_DfltBtnNext","65276":"Pointer_DfltBtnPrev","65277":"Pointer_Drag5","65288":"BackSpace","65289":"Tab","65290":"Linefeed","65291":"Clear","65293":"Return","65299":"Pause","65300":"Scroll_Lock","65301":"Sys_Req","65307":"Escape","65312":"Multi_key","65313":"Kanji","65314":"Muhenkan","65315":"Henkan","65316":"Romaji","65317":"Hiragana","65318":"Katakana","65319":"Hiragana_Katakana","65320":"Zenkaku","65321":"Hankaku","65322":"Zenkaku_Hankaku","65323":"Touroku","65324":"Massyo","65325":"Kana_Lock","65326":"Kana_Shift","65327":"Eisu_Shift","65328":"Eisu_toggle","65329":"Hangul","65330":"Hangul_Start","65331":"Hangul_End","65332":"Hangul_Hanja","65333":"Hangul_Jamo","65334":"Hangul_Romaja","65335":"Hangul_Codeinput","65336":"Hangul_Jeonja","65337":"Hangul_Banja","65338":"Hangul_PreHanja","65339":"Hangul_PostHanja","65340":"Hangul_SingleCandidate","65341":"Hangul_MultipleCandidate","65342":"Hangul_PreviousCandidate","65343":"Hangul_Special","65360":"Home","65361":"Left","65362":"Up","65363":"Right","65364":"Down","65365":"Page_Up","65366":"Page_Down","65367":"End","65368":"Begin","65376":"Select","65377":"Print","65378":"Execute","65379":"Insert","65381":"Undo","65382":"Redo","65383":"Menu","65384":"Find","65385":"Cancel","65386":"Help","65387":"Break","65406":"Hangul_switch","65407":"Num_Lock","65408":"KP_Space","65417":"KP_Tab","65421":"KP_Enter","65425":"KP_F1","65426":"KP_F2","65427":"KP_F3","65428":"KP_F4","65429":"KP_Home","65430":"KP_Left","65431":"KP_Up","65432":"KP_Right","65433":"KP_Down","65434":"KP_Page_Up","65435":"KP_Page_Down","65436":"KP_End","65437":"KP_Begin","65438":"KP_Insert","65439":"KP_Delete","65450":"KP_Multiply","65451":"KP_Add","65452":"KP_Separator","65453":"KP_Subtract","65454":"KP_Decimal","65455":"KP_Divide","65456":"KP_0","65457":"KP_1","65458":"KP_2","65459":"KP_3","65460":"KP_4","65461":"KP_5","65462":"KP_6","65463":"KP_7","65464":"KP_8","65465":"KP_9","65469":"KP_Equal","65470":"F1","65471":"F2","65472":"F3","65473":"F4","65474":"F5","65475":"F6","65476":"F7","65477":"F8","65478":"F9","65479":"F10","65480":"L1","65481":"L2","65482":"L3","65483":"L4","65484":"L5","65485":"L6","65486":"L7","65487":"L8","65488":"L9","65489":"L10","65490":"R1","65491":"R2","65492":"R3","65493":"R4","65494":"R5","65495":"R6","65496":"R7","65497":"R8","65498":"R9","65499":"R10","65500":"R11","65501":"R12","65502":"R13","65503":"R14","65504":"R15","65505":"Shift_L","65506":"Shift_R","65507":"Control_L","65508":"Control_R","65509":"Caps_Lock","65510":"Shift_Lock","65511":"Meta_L","65512":"Meta_R","65513":"Alt_L","65514":"Alt_R","65515":"Super_L","65516":"Super_R","65517":"Hyper_L","65518":"Hyper_R","65521":"braille_dot_1","65522":"braille_dot_2","65523":"braille_dot_3","65524":"braille_dot_4","65525":"braille_dot_5","65526":"braille_dot_6","65527":"braille_dot_7","65528":"braille_dot_8","65529":"braille_dot_9","65530":"braille_dot_10","65535":"Delete","16777215":"VoidSymbol","16777516":"Ibreve","16777517":"ibreve","16777588":"Wcircumflex","16777589":"wcircumflex","16777590":"Ycircumflex","16777591":"ycircumflex","16777615":"SCHWA","16777631":"Obarred","16777632":"Ohorn","16777633":"ohorn","16777647":"Uhorn","16777648":"uhorn","16777653":"Zstroke","16777654":"zstroke","16777655":"EZH","16777681":"Ocaron","16777682":"ocaron","16777702":"Gcaron","16777703":"gcaron","16777817":"schwa","16777845":"obarred","16777874":"ezh","16778386":"Cyrillic_GHE_bar","16778387":"Cyrillic_ghe_bar","16778390":"Cyrillic_ZHE_descender","16778391":"Cyrillic_zhe_descender","16778394":"Cyrillic_KA_descender","16778395":"Cyrillic_ka_descender","16778396":"Cyrillic_KA_vertstroke","16778397":"Cyrillic_ka_vertstroke","16778402":"Cyrillic_EN_descender","16778403":"Cyrillic_en_descender","16778414":"Cyrillic_U_straight","16778415":"Cyrillic_u_straight","16778416":"Cyrillic_U_straight_bar","16778417":"Cyrillic_u_straight_bar","16778418":"Cyrillic_HA_descender","16778419":"Cyrillic_ha_descender","16778422":"Cyrillic_CHE_descender","16778423":"Cyrillic_che_descender","16778424":"Cyrillic_CHE_vertstroke","16778425":"Cyrillic_che_vertstroke","16778426":"Cyrillic_SHHA","16778427":"Cyrillic_shha","16778456":"Cyrillic_SCHWA","16778457":"Cyrillic_schwa","16778466":"Cyrillic_I_macron","16778467":"Cyrillic_i_macron","16778472":"Cyrillic_O_bar","16778473":"Cyrillic_o_bar","16778478":"Cyrillic_U_macron","16778479":"Cyrillic_u_macron","16778545":"Armenian_AYB","16778546":"Armenian_BEN","16778547":"Armenian_GIM","16778548":"Armenian_DA","16778549":"Armenian_YECH","16778550":"Armenian_ZA","16778551":"Armenian_E","16778552":"Armenian_AT","16778553":"Armenian_TO","16778554":"Armenian_ZHE","16778555":"Armenian_INI","16778556":"Armenian_LYUN","16778557":"Armenian_KHE","16778558":"Armenian_TSA","16778559":"Armenian_KEN","16778560":"Armenian_HO","16778561":"Armenian_DZA","16778562":"Armenian_GHAT","16778563":"Armenian_TCHE","16778564":"Armenian_MEN","16778565":"Armenian_HI","16778566":"Armenian_NU","16778567":"Armenian_SHA","16778568":"Armenian_VO","16778569":"Armenian_CHA","16778570":"Armenian_PE","16778571":"Armenian_JE","16778572":"Armenian_RA","16778573":"Armenian_SE","16778574":"Armenian_VEV","16778575":"Armenian_TYUN","16778576":"Armenian_RE","16778577":"Armenian_TSO","16778578":"Armenian_VYUN","16778579":"Armenian_PYUR","16778580":"Armenian_KE","16778581":"Armenian_O","16778582":"Armenian_FE","16778586":"Armenian_apostrophe","16778587":"Armenian_shesht","16778588":"Armenian_amanak","16778589":"Armenian_but","16778590":"Armenian_paruyk","16778593":"Armenian_ayb","16778594":"Armenian_ben","16778595":"Armenian_gim","16778596":"Armenian_da","16778597":"Armenian_yech","16778598":"Armenian_za","16778599":"Armenian_e","16778600":"Armenian_at","16778601":"Armenian_to","16778602":"Armenian_zhe","16778603":"Armenian_ini","16778604":"Armenian_lyun","16778605":"Armenian_khe","16778606":"Armenian_tsa","16778607":"Armenian_ken","16778608":"Armenian_ho","16778609":"Armenian_dza","16778610":"Armenian_ghat","16778611":"Armenian_tche","16778612":"Armenian_men","16778613":"Armenian_hi","16778614":"Armenian_nu","16778615":"Armenian_sha","16778616":"Armenian_vo","16778617":"Armenian_cha","16778618":"Armenian_pe","16778619":"Armenian_je","16778620":"Armenian_ra","16778621":"Armenian_se","16778622":"Armenian_vev","16778623":"Armenian_tyun","16778624":"Armenian_re","16778625":"Armenian_tso","16778626":"Armenian_vyun","16778627":"Armenian_pyur","16778628":"Armenian_ke","16778629":"Armenian_o","16778630":"Armenian_fe","16778631":"Armenian_ligature_ew","16778633":"Armenian_verjaket","16778634":"Armenian_yentamna","16778835":"Arabic_madda_above","16778836":"Arabic_hamza_above","16778837":"Arabic_hamza_below","16778848":"Arabic_0","16778849":"Arabic_1","16778850":"Arabic_2","16778851":"Arabic_3","16778852":"Arabic_4","16778853":"Arabic_5","16778854":"Arabic_6","16778855":"Arabic_7","16778856":"Arabic_8","16778857":"Arabic_9","16778858":"Arabic_percent","16778864":"Arabic_superscript_alef","16778873":"Arabic_tteh","16778878":"Arabic_peh","16778886":"Arabic_tcheh","16778888":"Arabic_ddal","16778897":"Arabic_rreh","16778904":"Arabic_jeh","16778916":"Arabic_veh","16778921":"Arabic_keheh","16778927":"Arabic_gaf","16778938":"Arabic_noon_ghunna","16778942":"Arabic_heh_doachashmee","16778945":"Arabic_heh_goal","16778956":"Arabic_farsi_yeh","16778962":"Arabic_yeh_baree","16778964":"Arabic_fullstop","16778992":"Farsi_0","16778993":"Farsi_1","16778994":"Farsi_2","16778995":"Farsi_3","16778996":"Farsi_4","16778997":"Farsi_5","16778998":"Farsi_6","16778999":"Farsi_7","16779000":"Farsi_8","16779001":"Farsi_9","16780674":"Sinh_ng","16780675":"Sinh_h2","16780677":"Sinh_a","16780678":"Sinh_aa","16780679":"Sinh_ae","16780680":"Sinh_aee","16780681":"Sinh_i","16780682":"Sinh_ii","16780683":"Sinh_u","16780684":"Sinh_uu","16780685":"Sinh_ri","16780686":"Sinh_rii","16780687":"Sinh_lu","16780688":"Sinh_luu","16780689":"Sinh_e","16780690":"Sinh_ee","16780691":"Sinh_ai","16780692":"Sinh_o","16780693":"Sinh_oo","16780694":"Sinh_au","16780698":"Sinh_ka","16780699":"Sinh_kha","16780700":"Sinh_ga","16780701":"Sinh_gha","16780702":"Sinh_ng2","16780703":"Sinh_nga","16780704":"Sinh_ca","16780705":"Sinh_cha","16780706":"Sinh_ja","16780707":"Sinh_jha","16780708":"Sinh_nya","16780709":"Sinh_jnya","16780710":"Sinh_nja","16780711":"Sinh_tta","16780712":"Sinh_ttha","16780713":"Sinh_dda","16780714":"Sinh_ddha","16780715":"Sinh_nna","16780716":"Sinh_ndda","16780717":"Sinh_tha","16780718":"Sinh_thha","16780719":"Sinh_dha","16780720":"Sinh_dhha","16780721":"Sinh_na","16780723":"Sinh_ndha","16780724":"Sinh_pa","16780725":"Sinh_pha","16780726":"Sinh_ba","16780727":"Sinh_bha","16780728":"Sinh_ma","16780729":"Sinh_mba","16780730":"Sinh_ya","16780731":"Sinh_ra","16780733":"Sinh_la","16780736":"Sinh_va","16780737":"Sinh_sha","16780738":"Sinh_ssha","16780739":"Sinh_sa","16780740":"Sinh_ha","16780741":"Sinh_lla","16780742":"Sinh_fa","16780746":"Sinh_al","16780751":"Sinh_aa2","16780752":"Sinh_ae2","16780753":"Sinh_aee2","16780754":"Sinh_i2","16780755":"Sinh_ii2","16780756":"Sinh_u2","16780758":"Sinh_uu2","16780760":"Sinh_ru2","16780761":"Sinh_e2","16780762":"Sinh_ee2","16780763":"Sinh_ai2","16780764":"Sinh_o2","16780765":"Sinh_oo2","16780766":"Sinh_au2","16780767":"Sinh_lu2","16780786":"Sinh_ruu2","16780787":"Sinh_luu2","16780788":"Sinh_kunddaliya","16781520":"Georgian_an","16781521":"Georgian_ban","16781522":"Georgian_gan","16781523":"Georgian_don","16781524":"Georgian_en","16781525":"Georgian_vin","16781526":"Georgian_zen","16781527":"Georgian_tan","16781528":"Georgian_in","16781529":"Georgian_kan","16781530":"Georgian_las","16781531":"Georgian_man","16781532":"Georgian_nar","16781533":"Georgian_on","16781534":"Georgian_par","16781535":"Georgian_zhar","16781536":"Georgian_rae","16781537":"Georgian_san","16781538":"Georgian_tar","16781539":"Georgian_un","16781540":"Georgian_phar","16781541":"Georgian_khar","16781542":"Georgian_ghan","16781543":"Georgian_qar","16781544":"Georgian_shin","16781545":"Georgian_chin","16781546":"Georgian_can","16781547":"Georgian_jil","16781548":"Georgian_cil","16781549":"Georgian_char","16781550":"Georgian_xan","16781551":"Georgian_jhan","16781552":"Georgian_hae","16781553":"Georgian_he","16781554":"Georgian_hie","16781555":"Georgian_we","16781556":"Georgian_har","16781557":"Georgian_hoe","16781558":"Georgian_fi","16784898":"Babovedot","16784899":"babovedot","16784906":"Dabovedot","16784907":"dabovedot","16784926":"Fabovedot","16784927":"fabovedot","16784950":"Lbelowdot","16784951":"lbelowdot","16784960":"Mabovedot","16784961":"mabovedot","16784982":"Pabovedot","16784983":"pabovedot","16784992":"Sabovedot","16784993":"sabovedot","16785002":"Tabovedot","16785003":"tabovedot","16785024":"Wgrave","16785025":"wgrave","16785026":"Wacute","16785027":"wacute","16785028":"Wdiaeresis","16785029":"wdiaeresis","16785034":"Xabovedot","16785035":"xabovedot","16785056":"Abelowdot","16785057":"abelowdot","16785058":"Ahook","16785059":"ahook","16785060":"Acircumflexacute","16785061":"acircumflexacute","16785062":"Acircumflexgrave","16785063":"acircumflexgrave","16785064":"Acircumflexhook","16785065":"acircumflexhook","16785066":"Acircumflextilde","16785067":"acircumflextilde","16785068":"Acircumflexbelowdot","16785069":"acircumflexbelowdot","16785070":"Abreveacute","16785071":"abreveacute","16785072":"Abrevegrave","16785073":"abrevegrave","16785074":"Abrevehook","16785075":"abrevehook","16785076":"Abrevetilde","16785077":"abrevetilde","16785078":"Abrevebelowdot","16785079":"abrevebelowdot","16785080":"Ebelowdot","16785081":"ebelowdot","16785082":"Ehook","16785083":"ehook","16785084":"Etilde","16785085":"etilde","16785086":"Ecircumflexacute","16785087":"ecircumflexacute","16785088":"Ecircumflexgrave","16785089":"ecircumflexgrave","16785090":"Ecircumflexhook","16785091":"ecircumflexhook","16785092":"Ecircumflextilde","16785093":"ecircumflextilde","16785094":"Ecircumflexbelowdot","16785095":"ecircumflexbelowdot","16785096":"Ihook","16785097":"ihook","16785098":"Ibelowdot","16785099":"ibelowdot","16785100":"Obelowdot","16785101":"obelowdot","16785102":"Ohook","16785103":"ohook","16785104":"Ocircumflexacute","16785105":"ocircumflexacute","16785106":"Ocircumflexgrave","16785107":"ocircumflexgrave","16785108":"Ocircumflexhook","16785109":"ocircumflexhook","16785110":"Ocircumflextilde","16785111":"ocircumflextilde","16785112":"Ocircumflexbelowdot","16785113":"ocircumflexbelowdot","16785114":"Ohornacute","16785115":"ohornacute","16785116":"Ohorngrave","16785117":"ohorngrave","16785118":"Ohornhook","16785119":"ohornhook","16785120":"Ohorntilde","16785121":"ohorntilde","16785122":"Ohornbelowdot","16785123":"ohornbelowdot","16785124":"Ubelowdot","16785125":"ubelowdot","16785126":"Uhook","16785127":"uhook","16785128":"Uhornacute","16785129":"uhornacute","16785130":"Uhorngrave","16785131":"uhorngrave","16785132":"Uhornhook","16785133":"uhornhook","16785134":"Uhorntilde","16785135":"uhorntilde","16785136":"Uhornbelowdot","16785137":"uhornbelowdot","16785138":"Ygrave","16785139":"ygrave","16785140":"Ybelowdot","16785141":"ybelowdot","16785142":"Yhook","16785143":"yhook","16785144":"Ytilde","16785145":"ytilde","16785520":"zerosuperior","16785524":"foursuperior","16785525":"fivesuperior","16785526":"sixsuperior","16785527":"sevensuperior","16785528":"eightsuperior","16785529":"ninesuperior","16785536":"zerosubscript","16785537":"onesubscript","16785538":"twosubscript","16785539":"threesubscript","16785540":"foursubscript","16785541":"fivesubscript","16785542":"sixsubscript","16785543":"sevensubscript","16785544":"eightsubscript","16785545":"ninesubscript","16785568":"EcuSign","16785569":"ColonSign","16785570":"CruzeiroSign","16785571":"FFrancSign","16785572":"LiraSign","16785573":"MillSign","16785574":"NairaSign","16785575":"PesetaSign","16785576":"RupeeSign","16785577":"WonSign","16785578":"NewSheqelSign","16785579":"DongSign","16785922":"partdifferential","16785925":"emptyset","16785928":"elementof","16785929":"notelementof","16785931":"containsas","16785946":"squareroot","16785947":"cuberoot","16785948":"fourthroot","16785964":"dintegral","16785965":"tintegral","16785973":"because","16785991":"notapproxeq","16785992":"approxeq","16786018":"notidentical","16786019":"stricteq","16787456":"braille_blank","16787457":"braille_dots_1","16787458":"braille_dots_2","16787459":"braille_dots_12","16787460":"braille_dots_3","16787461":"braille_dots_13","16787462":"braille_dots_23","16787463":"braille_dots_123","16787464":"braille_dots_4","16787465":"braille_dots_14","16787466":"braille_dots_24","16787467":"braille_dots_124","16787468":"braille_dots_34","16787469":"braille_dots_134","16787470":"braille_dots_234","16787471":"braille_dots_1234","16787472":"braille_dots_5","16787473":"braille_dots_15","16787474":"braille_dots_25","16787475":"braille_dots_125","16787476":"braille_dots_35","16787477":"braille_dots_135","16787478":"braille_dots_235","16787479":"braille_dots_1235","16787480":"braille_dots_45","16787481":"braille_dots_145","16787482":"braille_dots_245","16787483":"braille_dots_1245","16787484":"braille_dots_345","16787485":"braille_dots_1345","16787486":"braille_dots_2345","16787487":"braille_dots_12345","16787488":"braille_dots_6","16787489":"braille_dots_16","16787490":"braille_dots_26","16787491":"braille_dots_126","16787492":"braille_dots_36","16787493":"braille_dots_136","16787494":"braille_dots_236","16787495":"braille_dots_1236","16787496":"braille_dots_46","16787497":"braille_dots_146","16787498":"braille_dots_246","16787499":"braille_dots_1246","16787500":"braille_dots_346","16787501":"braille_dots_1346","16787502":"braille_dots_2346","16787503":"braille_dots_12346","16787504":"braille_dots_56","16787505":"braille_dots_156","16787506":"braille_dots_256","16787507":"braille_dots_1256","16787508":"braille_dots_356","16787509":"braille_dots_1356","16787510":"braille_dots_2356","16787511":"braille_dots_12356","16787512":"braille_dots_456","16787513":"braille_dots_1456","16787514":"braille_dots_2456","16787515":"braille_dots_12456","16787516":"braille_dots_3456","16787517":"braille_dots_13456","16787518":"braille_dots_23456","16787519":"braille_dots_123456","16787520":"braille_dots_7","16787521":"braille_dots_17","16787522":"braille_dots_27","16787523":"braille_dots_127","16787524":"braille_dots_37","16787525":"braille_dots_137","16787526":"braille_dots_237","16787527":"braille_dots_1237","16787528":"braille_dots_47","16787529":"braille_dots_147","16787530":"braille_dots_247","16787531":"braille_dots_1247","16787532":"braille_dots_347","16787533":"braille_dots_1347","16787534":"braille_dots_2347","16787535":"braille_dots_12347","16787536":"braille_dots_57","16787537":"braille_dots_157","16787538":"braille_dots_257","16787539":"braille_dots_1257","16787540":"braille_dots_357","16787541":"braille_dots_1357","16787542":"braille_dots_2357","16787543":"braille_dots_12357","16787544":"braille_dots_457","16787545":"braille_dots_1457","16787546":"braille_dots_2457","16787547":"braille_dots_12457","16787548":"braille_dots_3457","16787549":"braille_dots_13457","16787550":"braille_dots_23457","16787551":"braille_dots_123457","16787552":"braille_dots_67","16787553":"braille_dots_167","16787554":"braille_dots_267","16787555":"braille_dots_1267","16787556":"braille_dots_367","16787557":"braille_dots_1367","16787558":"braille_dots_2367","16787559":"braille_dots_12367","16787560":"braille_dots_467","16787561":"braille_dots_1467","16787562":"braille_dots_2467","16787563":"braille_dots_12467","16787564":"braille_dots_3467","16787565":"braille_dots_13467","16787566":"braille_dots_23467","16787567":"braille_dots_123467","16787568":"braille_dots_567","16787569":"braille_dots_1567","16787570":"braille_dots_2567","16787571":"braille_dots_12567","16787572":"braille_dots_3567","16787573":"braille_dots_13567","16787574":"braille_dots_23567","16787575":"braille_dots_123567","16787576":"braille_dots_4567","16787577":"braille_dots_14567","16787578":"braille_dots_24567","16787579":"braille_dots_124567","16787580":"braille_dots_34567","16787581":"braille_dots_134567","16787582":"braille_dots_234567","16787583":"braille_dots_1234567","16787584":"braille_dots_8","16787585":"braille_dots_18","16787586":"braille_dots_28","16787587":"braille_dots_128","16787588":"braille_dots_38","16787589":"braille_dots_138","16787590":"braille_dots_238","16787591":"braille_dots_1238","16787592":"braille_dots_48","16787593":"braille_dots_148","16787594":"braille_dots_248","16787595":"braille_dots_1248","16787596":"braille_dots_348","16787597":"braille_dots_1348","16787598":"braille_dots_2348","16787599":"braille_dots_12348","16787600":"braille_dots_58","16787601":"braille_dots_158","16787602":"braille_dots_258","16787603":"braille_dots_1258","16787604":"braille_dots_358","16787605":"braille_dots_1358","16787606":"braille_dots_2358","16787607":"braille_dots_12358","16787608":"braille_dots_458","16787609":"braille_dots_1458","16787610":"braille_dots_2458","16787611":"braille_dots_12458","16787612":"braille_dots_3458","16787613":"braille_dots_13458","16787614":"braille_dots_23458","16787615":"braille_dots_123458","16787616":"braille_dots_68","16787617":"braille_dots_168","16787618":"braille_dots_268","16787619":"braille_dots_1268","16787620":"braille_dots_368","16787621":"braille_dots_1368","16787622":"braille_dots_2368","16787623":"braille_dots_12368","16787624":"braille_dots_468","16787625":"braille_dots_1468","16787626":"braille_dots_2468","16787627":"braille_dots_12468","16787628":"braille_dots_3468","16787629":"braille_dots_13468","16787630":"braille_dots_23468","16787631":"braille_dots_123468","16787632":"braille_dots_568","16787633":"braille_dots_1568","16787634":"braille_dots_2568","16787635":"braille_dots_12568","16787636":"braille_dots_3568","16787637":"braille_dots_13568","16787638":"braille_dots_23568","16787639":"braille_dots_123568","16787640":"braille_dots_4568","16787641":"braille_dots_14568","16787642":"braille_dots_24568","16787643":"braille_dots_124568","16787644":"braille_dots_34568","16787645":"braille_dots_134568","16787646":"braille_dots_234568","16787647":"braille_dots_1234568","16787648":"braille_dots_78","16787649":"braille_dots_178","16787650":"braille_dots_278","16787651":"braille_dots_1278","16787652":"braille_dots_378","16787653":"braille_dots_1378","16787654":"braille_dots_2378","16787655":"braille_dots_12378","16787656":"braille_dots_478","16787657":"braille_dots_1478","16787658":"braille_dots_2478","16787659":"braille_dots_12478","16787660":"braille_dots_3478","16787661":"braille_dots_13478","16787662":"braille_dots_23478","16787663":"braille_dots_123478","16787664":"braille_dots_578","16787665":"braille_dots_1578","16787666":"braille_dots_2578","16787667":"braille_dots_12578","16787668":"braille_dots_3578","16787669":"braille_dots_13578","16787670":"braille_dots_23578","16787671":"braille_dots_123578","16787672":"braille_dots_4578","16787673":"braille_dots_14578","16787674":"braille_dots_24578","16787675":"braille_dots_124578","16787676":"braille_dots_34578","16787677":"braille_dots_134578","16787678":"braille_dots_234578","16787679":"braille_dots_1234578","16787680":"braille_dots_678","16787681":"braille_dots_1678","16787682":"braille_dots_2678","16787683":"braille_dots_12678","16787684":"braille_dots_3678","16787685":"braille_dots_13678","16787686":"braille_dots_23678","16787687":"braille_dots_123678","16787688":"braille_dots_4678","16787689":"braille_dots_14678","16787690":"braille_dots_24678","16787691":"braille_dots_124678","16787692":"braille_dots_34678","16787693":"braille_dots_134678","16787694":"braille_dots_234678","16787695":"braille_dots_1234678","16787696":"braille_dots_5678","16787697":"braille_dots_15678","16787698":"braille_dots_25678","16787699":"braille_dots_125678","16787700":"braille_dots_35678","16787701":"braille_dots_135678","16787702":"braille_dots_235678","16787703":"braille_dots_1235678","16787704":"braille_dots_45678","16787705":"braille_dots_145678","16787706":"braille_dots_245678","16787707":"braille_dots_1245678","16787708":"braille_dots_345678","16787709":"braille_dots_1345678","16787710":"braille_dots_2345678","16787711":"braille_dots_12345678"}; + var codepoints = {"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"39":39,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"50":50,"51":51,"52":52,"53":53,"54":54,"55":55,"56":56,"57":57,"58":58,"59":59,"60":60,"61":61,"62":62,"63":63,"64":64,"65":65,"66":66,"67":67,"68":68,"69":69,"70":70,"71":71,"72":72,"73":73,"74":74,"75":75,"76":76,"77":77,"78":78,"79":79,"80":80,"81":81,"82":82,"83":83,"84":84,"85":85,"86":86,"87":87,"88":88,"89":89,"90":90,"91":91,"92":92,"93":93,"94":94,"95":95,"96":96,"97":97,"98":98,"99":99,"100":100,"101":101,"102":102,"103":103,"104":104,"105":105,"106":106,"107":107,"108":108,"109":109,"110":110,"111":111,"112":112,"113":113,"114":114,"115":115,"116":116,"117":117,"118":118,"119":119,"120":120,"121":121,"122":122,"123":123,"124":124,"125":125,"126":126,"160":160,"161":161,"162":162,"163":163,"164":164,"165":165,"166":166,"167":167,"168":168,"169":169,"170":170,"171":171,"172":172,"173":173,"174":174,"175":175,"176":176,"177":177,"178":178,"179":179,"180":180,"181":181,"182":182,"183":183,"184":184,"185":185,"186":186,"187":187,"188":188,"189":189,"190":190,"191":191,"192":192,"193":193,"194":194,"195":195,"196":196,"197":197,"198":198,"199":199,"200":200,"201":201,"202":202,"203":203,"204":204,"205":205,"206":206,"207":207,"208":208,"209":209,"210":210,"211":211,"212":212,"213":213,"214":214,"215":215,"216":216,"217":217,"218":218,"219":219,"220":220,"221":221,"222":222,"223":223,"224":224,"225":225,"226":226,"227":227,"228":228,"229":229,"230":230,"231":231,"232":232,"233":233,"234":234,"235":235,"236":236,"237":237,"238":238,"239":239,"240":240,"241":241,"242":242,"243":243,"244":244,"245":245,"246":246,"247":247,"248":248,"249":249,"250":250,"251":251,"252":252,"253":253,"254":254,"255":255,"256":960,"257":992,"258":451,"259":483,"260":417,"261":433,"262":454,"263":486,"264":710,"265":742,"266":709,"267":741,"268":456,"269":488,"270":463,"271":495,"272":464,"273":496,"274":938,"275":954,"278":972,"279":1004,"280":458,"281":490,"282":460,"283":492,"284":728,"285":760,"286":683,"287":699,"288":725,"289":757,"290":939,"291":955,"292":678,"293":694,"294":673,"295":689,"296":933,"297":949,"298":975,"299":1007,"300":16777516,"301":16777517,"302":967,"303":999,"304":681,"305":697,"308":684,"309":700,"310":979,"311":1011,"312":930,"313":453,"314":485,"315":934,"316":950,"317":421,"318":437,"321":419,"322":435,"323":465,"324":497,"325":977,"326":1009,"327":466,"328":498,"330":957,"331":959,"332":978,"333":1010,"336":469,"337":501,"338":5052,"339":5053,"340":448,"341":480,"342":931,"343":947,"344":472,"345":504,"346":422,"347":438,"348":734,"349":766,"350":426,"351":442,"352":425,"353":441,"354":478,"355":510,"356":427,"357":443,"358":940,"359":956,"360":989,"361":1021,"362":990,"363":1022,"364":733,"365":765,"366":473,"367":505,"368":475,"369":507,"370":985,"371":1017,"372":16777588,"373":16777589,"374":16777590,"375":16777591,"376":5054,"377":428,"378":444,"379":431,"380":447,"381":430,"382":446,"399":16777615,"402":2294,"415":16777631,"416":16777632,"417":16777633,"431":16777647,"432":16777648,"437":16777653,"438":16777654,"439":16777655,"466":16777681,"486":16777702,"487":16777703,"601":16777817,"629":16777845,"658":16777874,"711":439,"728":418,"729":511,"731":434,"733":445,"901":1966,"902":1953,"904":1954,"905":1955,"906":1956,"908":1959,"910":1960,"911":1963,"912":1974,"913":1985,"914":1986,"915":1987,"916":1988,"917":1989,"918":1990,"919":1991,"920":1992,"921":1993,"922":1994,"923":1995,"924":1996,"925":1997,"926":1998,"927":1999,"928":2000,"929":2001,"931":2002,"932":2004,"933":2005,"934":2006,"935":2007,"936":2008,"937":2009,"938":1957,"939":1961,"940":1969,"941":1970,"942":1971,"943":1972,"944":1978,"945":2017,"946":2018,"947":2019,"948":2020,"949":2021,"950":2022,"951":2023,"952":2024,"953":2025,"954":2026,"955":2027,"956":2028,"957":2029,"958":2030,"959":2031,"960":2032,"961":2033,"962":2035,"963":2034,"964":2036,"965":2037,"966":2038,"967":2039,"968":2040,"969":2041,"970":1973,"971":1977,"972":1975,"973":1976,"974":1979,"1025":1715,"1026":1713,"1027":1714,"1028":1716,"1029":1717,"1030":1718,"1031":1719,"1032":1720,"1033":1721,"1034":1722,"1035":1723,"1036":1724,"1038":1726,"1039":1727,"1040":1761,"1041":1762,"1042":1783,"1043":1767,"1044":1764,"1045":1765,"1046":1782,"1047":1786,"1048":1769,"1049":1770,"1050":1771,"1051":1772,"1052":1773,"1053":1774,"1054":1775,"1055":1776,"1056":1778,"1057":1779,"1058":1780,"1059":1781,"1060":1766,"1061":1768,"1062":1763,"1063":1790,"1064":1787,"1065":1789,"1066":1791,"1067":1785,"1068":1784,"1069":1788,"1070":1760,"1071":1777,"1072":1729,"1073":1730,"1074":1751,"1075":1735,"1076":1732,"1077":1733,"1078":1750,"1079":1754,"1080":1737,"1081":1738,"1082":1739,"1083":1740,"1084":1741,"1085":1742,"1086":1743,"1087":1744,"1088":1746,"1089":1747,"1090":1748,"1091":1749,"1092":1734,"1093":1736,"1094":1731,"1095":1758,"1096":1755,"1097":1757,"1098":1759,"1099":1753,"1100":1752,"1101":1756,"1102":1728,"1103":1745,"1105":1699,"1106":1697,"1107":1698,"1108":1700,"1109":1701,"1110":1702,"1111":1703,"1112":1704,"1113":1705,"1114":1706,"1115":1707,"1116":1708,"1118":1710,"1119":1711,"1168":1725,"1169":1709,"1170":16778386,"1171":16778387,"1174":16778390,"1175":16778391,"1178":16778394,"1179":16778395,"1180":16778396,"1181":16778397,"1186":16778402,"1187":16778403,"1198":16778414,"1199":16778415,"1200":16778416,"1201":16778417,"1202":16778418,"1203":16778419,"1206":16778422,"1207":16778423,"1208":16778424,"1209":16778425,"1210":16778426,"1211":16778427,"1240":16778456,"1241":16778457,"1250":16778466,"1251":16778467,"1256":16778472,"1257":16778473,"1262":16778478,"1263":16778479,"1329":16778545,"1330":16778546,"1331":16778547,"1332":16778548,"1333":16778549,"1334":16778550,"1335":16778551,"1336":16778552,"1337":16778553,"1338":16778554,"1339":16778555,"1340":16778556,"1341":16778557,"1342":16778558,"1343":16778559,"1344":16778560,"1345":16778561,"1346":16778562,"1347":16778563,"1348":16778564,"1349":16778565,"1350":16778566,"1351":16778567,"1352":16778568,"1353":16778569,"1354":16778570,"1355":16778571,"1356":16778572,"1357":16778573,"1358":16778574,"1359":16778575,"1360":16778576,"1361":16778577,"1362":16778578,"1363":16778579,"1364":16778580,"1365":16778581,"1366":16778582,"1370":16778586,"1371":16778587,"1372":16778588,"1373":16778589,"1374":16778590,"1377":16778593,"1378":16778594,"1379":16778595,"1380":16778596,"1381":16778597,"1382":16778598,"1383":16778599,"1384":16778600,"1385":16778601,"1386":16778602,"1387":16778603,"1388":16778604,"1389":16778605,"1390":16778606,"1391":16778607,"1392":16778608,"1393":16778609,"1394":16778610,"1395":16778611,"1396":16778612,"1397":16778613,"1398":16778614,"1399":16778615,"1400":16778616,"1401":16778617,"1402":16778618,"1403":16778619,"1404":16778620,"1405":16778621,"1406":16778622,"1407":16778623,"1408":16778624,"1409":16778625,"1410":16778626,"1411":16778627,"1412":16778628,"1413":16778629,"1414":16778630,"1415":16778631,"1417":16778633,"1418":16778634,"1488":3296,"1489":3297,"1490":3298,"1491":3299,"1492":3300,"1493":3301,"1494":3302,"1495":3303,"1496":3304,"1497":3305,"1498":3306,"1499":3307,"1500":3308,"1501":3309,"1502":3310,"1503":3311,"1504":3312,"1505":3313,"1506":3314,"1507":3315,"1508":3316,"1509":3317,"1510":3318,"1511":3319,"1512":3320,"1513":3321,"1514":3322,"1548":1452,"1563":1467,"1567":1471,"1569":1473,"1570":1474,"1571":1475,"1572":1476,"1573":1477,"1574":1478,"1575":1479,"1576":1480,"1577":1481,"1578":1482,"1579":1483,"1580":1484,"1581":1485,"1582":1486,"1583":1487,"1584":1488,"1585":1489,"1586":1490,"1587":1491,"1588":1492,"1589":1493,"1590":1494,"1591":1495,"1592":1496,"1593":1497,"1594":1498,"1600":1504,"1601":1505,"1602":1506,"1603":1507,"1604":1508,"1605":1509,"1606":1510,"1607":1511,"1608":1512,"1609":1513,"1610":1514,"1611":1515,"1612":1516,"1613":1517,"1614":1518,"1615":1519,"1616":1520,"1617":1521,"1618":1522,"1619":16778835,"1620":16778836,"1621":16778837,"1632":16778848,"1633":16778849,"1634":16778850,"1635":16778851,"1636":16778852,"1637":16778853,"1638":16778854,"1639":16778855,"1640":16778856,"1641":16778857,"1642":16778858,"1648":16778864,"1657":16778873,"1662":16778878,"1670":16778886,"1672":16778888,"1681":16778897,"1688":16778904,"1700":16778916,"1705":16778921,"1711":16778927,"1722":16778938,"1726":16778942,"1729":16778945,"1740":16778956,"1746":16778962,"1748":16778964,"1776":16778992,"1777":16778993,"1778":16778994,"1779":16778995,"1780":16778996,"1781":16778997,"1782":16778998,"1783":16778999,"1784":16779000,"1785":16779001,"3458":16780674,"3459":16780675,"3461":16780677,"3462":16780678,"3463":16780679,"3464":16780680,"3465":16780681,"3466":16780682,"3467":16780683,"3468":16780684,"3469":16780685,"3470":16780686,"3471":16780687,"3472":16780688,"3473":16780689,"3474":16780690,"3475":16780691,"3476":16780692,"3477":16780693,"3478":16780694,"3482":16780698,"3483":16780699,"3484":16780700,"3485":16780701,"3486":16780702,"3487":16780703,"3488":16780704,"3489":16780705,"3490":16780706,"3491":16780707,"3492":16780708,"3493":16780709,"3494":16780710,"3495":16780711,"3496":16780712,"3497":16780713,"3498":16780714,"3499":16780715,"3500":16780716,"3501":16780717,"3502":16780718,"3503":16780719,"3504":16780720,"3505":16780721,"3507":16780723,"3508":16780724,"3509":16780725,"3510":16780726,"3511":16780727,"3512":16780728,"3513":16780729,"3514":16780730,"3515":16780731,"3517":16780733,"3520":16780736,"3521":16780737,"3522":16780738,"3523":16780739,"3524":16780740,"3525":16780741,"3526":16780742,"3530":16780746,"3535":16780751,"3536":16780752,"3537":16780753,"3538":16780754,"3539":16780755,"3540":16780756,"3542":16780758,"3544":16780760,"3545":16780761,"3546":16780762,"3547":16780763,"3548":16780764,"3549":16780765,"3550":16780766,"3551":16780767,"3570":16780786,"3571":16780787,"3572":16780788,"3585":3489,"3586":3490,"3587":3491,"3588":3492,"3589":3493,"3590":3494,"3591":3495,"3592":3496,"3593":3497,"3594":3498,"3595":3499,"3596":3500,"3597":3501,"3598":3502,"3599":3503,"3600":3504,"3601":3505,"3602":3506,"3603":3507,"3604":3508,"3605":3509,"3606":3510,"3607":3511,"3608":3512,"3609":3513,"3610":3514,"3611":3515,"3612":3516,"3613":3517,"3614":3518,"3615":3519,"3616":3520,"3617":3521,"3618":3522,"3619":3523,"3620":3524,"3621":3525,"3622":3526,"3623":3527,"3624":3528,"3625":3529,"3626":3530,"3627":3531,"3628":3532,"3629":3533,"3630":3534,"3631":3535,"3632":3536,"3633":3537,"3634":3538,"3635":3539,"3636":3540,"3637":3541,"3638":3542,"3639":3543,"3640":3544,"3641":3545,"3642":3546,"3647":3551,"3648":3552,"3649":3553,"3650":3554,"3651":3555,"3652":3556,"3653":3557,"3654":3558,"3655":3559,"3656":3560,"3657":3561,"3658":3562,"3659":3563,"3660":3564,"3661":3565,"3664":3568,"3665":3569,"3666":3570,"3667":3571,"3668":3572,"3669":3573,"3670":3574,"3671":3575,"3672":3576,"3673":3577,"4304":16781520,"4305":16781521,"4306":16781522,"4307":16781523,"4308":16781524,"4309":16781525,"4310":16781526,"4311":16781527,"4312":16781528,"4313":16781529,"4314":16781530,"4315":16781531,"4316":16781532,"4317":16781533,"4318":16781534,"4319":16781535,"4320":16781536,"4321":16781537,"4322":16781538,"4323":16781539,"4324":16781540,"4325":16781541,"4326":16781542,"4327":16781543,"4328":16781544,"4329":16781545,"4330":16781546,"4331":16781547,"4332":16781548,"4333":16781549,"4334":16781550,"4335":16781551,"4336":16781552,"4337":16781553,"4338":16781554,"4339":16781555,"4340":16781556,"4341":16781557,"4342":16781558,"7682":16784898,"7683":16784899,"7690":16784906,"7691":16784907,"7710":16784926,"7711":16784927,"7734":16784950,"7735":16784951,"7744":16784960,"7745":16784961,"7766":16784982,"7767":16784983,"7776":16784992,"7777":16784993,"7786":16785002,"7787":16785003,"7808":16785024,"7809":16785025,"7810":16785026,"7811":16785027,"7812":16785028,"7813":16785029,"7818":16785034,"7819":16785035,"7840":16785056,"7841":16785057,"7842":16785058,"7843":16785059,"7844":16785060,"7845":16785061,"7846":16785062,"7847":16785063,"7848":16785064,"7849":16785065,"7850":16785066,"7851":16785067,"7852":16785068,"7853":16785069,"7854":16785070,"7855":16785071,"7856":16785072,"7857":16785073,"7858":16785074,"7859":16785075,"7860":16785076,"7861":16785077,"7862":16785078,"7863":16785079,"7864":16785080,"7865":16785081,"7866":16785082,"7867":16785083,"7868":16785084,"7869":16785085,"7870":16785086,"7871":16785087,"7872":16785088,"7873":16785089,"7874":16785090,"7875":16785091,"7876":16785092,"7877":16785093,"7878":16785094,"7879":16785095,"7880":16785096,"7881":16785097,"7882":16785098,"7883":16785099,"7884":16785100,"7885":16785101,"7886":16785102,"7887":16785103,"7888":16785104,"7889":16785105,"7890":16785106,"7891":16785107,"7892":16785108,"7893":16785109,"7894":16785110,"7895":16785111,"7896":16785112,"7897":16785113,"7898":16785114,"7899":16785115,"7900":16785116,"7901":16785117,"7902":16785118,"7903":16785119,"7904":16785120,"7905":16785121,"7906":16785122,"7907":16785123,"7908":16785124,"7909":16785125,"7910":16785126,"7911":16785127,"7912":16785128,"7913":16785129,"7914":16785130,"7915":16785131,"7916":16785132,"7917":16785133,"7918":16785134,"7919":16785135,"7920":16785136,"7921":16785137,"7922":16785138,"7923":16785139,"7924":16785140,"7925":16785141,"7926":16785142,"7927":16785143,"7928":16785144,"7929":16785145,"8194":2722,"8195":2721,"8196":2723,"8197":2724,"8199":2725,"8200":2726,"8201":2727,"8202":2728,"8210":2747,"8211":2730,"8212":2729,"8213":1967,"8215":3295,"8216":2768,"8217":2769,"8218":2813,"8220":2770,"8221":2771,"8222":2814,"8224":2801,"8225":2802,"8226":2790,"8229":2735,"8230":2734,"8240":2773,"8242":2774,"8243":2775,"8248":2812,"8254":1150,"8304":16785520,"8308":16785524,"8309":16785525,"8310":16785526,"8311":16785527,"8312":16785528,"8313":16785529,"8320":16785536,"8321":16785537,"8322":16785538,"8323":16785539,"8324":16785540,"8325":16785541,"8326":16785542,"8327":16785543,"8328":16785544,"8329":16785545,"8352":16785568,"8353":16785569,"8354":16785570,"8355":16785571,"8356":16785572,"8357":16785573,"8358":16785574,"8359":16785575,"8360":16785576,"8361":3839,"8362":16785578,"8363":16785579,"8364":8364,"8453":2744,"8470":1712,"8471":2811,"8478":2772,"8482":2761,"8531":2736,"8532":2737,"8533":2738,"8534":2739,"8535":2740,"8536":2741,"8537":2742,"8538":2743,"8539":2755,"8540":2756,"8541":2757,"8542":2758,"8592":2299,"8593":2300,"8594":2301,"8595":2302,"8658":2254,"8660":2253,"8706":2287,"8709":16785925,"8711":2245,"8712":16785928,"8713":16785929,"8715":16785931,"8728":3018,"8730":2262,"8731":16785947,"8732":16785948,"8733":2241,"8734":2242,"8743":2270,"8744":2271,"8745":2268,"8746":2269,"8747":2239,"8748":16785964,"8749":16785965,"8756":2240,"8757":16785973,"8764":2248,"8771":2249,"8773":16785992,"8775":16785991,"8800":2237,"8801":2255,"8802":16786018,"8803":16786019,"8804":2236,"8805":2238,"8834":2266,"8835":2267,"8866":3068,"8867":3036,"8868":3010,"8869":3022,"8968":3027,"8970":3012,"8981":2810,"8992":2212,"8993":2213,"9109":3020,"9115":2219,"9117":2220,"9118":2221,"9120":2222,"9121":2215,"9123":2216,"9124":2217,"9126":2218,"9128":2223,"9132":2224,"9143":2209,"9146":2543,"9147":2544,"9148":2546,"9149":2547,"9225":2530,"9226":2533,"9227":2537,"9228":2531,"9229":2532,"9251":2732,"9252":2536,"9472":2211,"9474":2214,"9484":2210,"9488":2539,"9492":2541,"9496":2538,"9500":2548,"9508":2549,"9516":2551,"9524":2550,"9532":2542,"9618":2529,"9642":2791,"9643":2785,"9644":2779,"9645":2786,"9646":2783,"9647":2767,"9650":2792,"9651":2787,"9654":2781,"9655":2765,"9660":2793,"9661":2788,"9664":2780,"9665":2764,"9670":2528,"9675":2766,"9679":2782,"9702":2784,"9734":2789,"9742":2809,"9747":2762,"9756":2794,"9758":2795,"9792":2808,"9794":2807,"9827":2796,"9829":2798,"9830":2797,"9837":2806,"9839":2805,"10003":2803,"10007":2804,"10013":2777,"10016":2800,"10216":2748,"10217":2750,"10240":16787456,"10241":16787457,"10242":16787458,"10243":16787459,"10244":16787460,"10245":16787461,"10246":16787462,"10247":16787463,"10248":16787464,"10249":16787465,"10250":16787466,"10251":16787467,"10252":16787468,"10253":16787469,"10254":16787470,"10255":16787471,"10256":16787472,"10257":16787473,"10258":16787474,"10259":16787475,"10260":16787476,"10261":16787477,"10262":16787478,"10263":16787479,"10264":16787480,"10265":16787481,"10266":16787482,"10267":16787483,"10268":16787484,"10269":16787485,"10270":16787486,"10271":16787487,"10272":16787488,"10273":16787489,"10274":16787490,"10275":16787491,"10276":16787492,"10277":16787493,"10278":16787494,"10279":16787495,"10280":16787496,"10281":16787497,"10282":16787498,"10283":16787499,"10284":16787500,"10285":16787501,"10286":16787502,"10287":16787503,"10288":16787504,"10289":16787505,"10290":16787506,"10291":16787507,"10292":16787508,"10293":16787509,"10294":16787510,"10295":16787511,"10296":16787512,"10297":16787513,"10298":16787514,"10299":16787515,"10300":16787516,"10301":16787517,"10302":16787518,"10303":16787519,"10304":16787520,"10305":16787521,"10306":16787522,"10307":16787523,"10308":16787524,"10309":16787525,"10310":16787526,"10311":16787527,"10312":16787528,"10313":16787529,"10314":16787530,"10315":16787531,"10316":16787532,"10317":16787533,"10318":16787534,"10319":16787535,"10320":16787536,"10321":16787537,"10322":16787538,"10323":16787539,"10324":16787540,"10325":16787541,"10326":16787542,"10327":16787543,"10328":16787544,"10329":16787545,"10330":16787546,"10331":16787547,"10332":16787548,"10333":16787549,"10334":16787550,"10335":16787551,"10336":16787552,"10337":16787553,"10338":16787554,"10339":16787555,"10340":16787556,"10341":16787557,"10342":16787558,"10343":16787559,"10344":16787560,"10345":16787561,"10346":16787562,"10347":16787563,"10348":16787564,"10349":16787565,"10350":16787566,"10351":16787567,"10352":16787568,"10353":16787569,"10354":16787570,"10355":16787571,"10356":16787572,"10357":16787573,"10358":16787574,"10359":16787575,"10360":16787576,"10361":16787577,"10362":16787578,"10363":16787579,"10364":16787580,"10365":16787581,"10366":16787582,"10367":16787583,"10368":16787584,"10369":16787585,"10370":16787586,"10371":16787587,"10372":16787588,"10373":16787589,"10374":16787590,"10375":16787591,"10376":16787592,"10377":16787593,"10378":16787594,"10379":16787595,"10380":16787596,"10381":16787597,"10382":16787598,"10383":16787599,"10384":16787600,"10385":16787601,"10386":16787602,"10387":16787603,"10388":16787604,"10389":16787605,"10390":16787606,"10391":16787607,"10392":16787608,"10393":16787609,"10394":16787610,"10395":16787611,"10396":16787612,"10397":16787613,"10398":16787614,"10399":16787615,"10400":16787616,"10401":16787617,"10402":16787618,"10403":16787619,"10404":16787620,"10405":16787621,"10406":16787622,"10407":16787623,"10408":16787624,"10409":16787625,"10410":16787626,"10411":16787627,"10412":16787628,"10413":16787629,"10414":16787630,"10415":16787631,"10416":16787632,"10417":16787633,"10418":16787634,"10419":16787635,"10420":16787636,"10421":16787637,"10422":16787638,"10423":16787639,"10424":16787640,"10425":16787641,"10426":16787642,"10427":16787643,"10428":16787644,"10429":16787645,"10430":16787646,"10431":16787647,"10432":16787648,"10433":16787649,"10434":16787650,"10435":16787651,"10436":16787652,"10437":16787653,"10438":16787654,"10439":16787655,"10440":16787656,"10441":16787657,"10442":16787658,"10443":16787659,"10444":16787660,"10445":16787661,"10446":16787662,"10447":16787663,"10448":16787664,"10449":16787665,"10450":16787666,"10451":16787667,"10452":16787668,"10453":16787669,"10454":16787670,"10455":16787671,"10456":16787672,"10457":16787673,"10458":16787674,"10459":16787675,"10460":16787676,"10461":16787677,"10462":16787678,"10463":16787679,"10464":16787680,"10465":16787681,"10466":16787682,"10467":16787683,"10468":16787684,"10469":16787685,"10470":16787686,"10471":16787687,"10472":16787688,"10473":16787689,"10474":16787690,"10475":16787691,"10476":16787692,"10477":16787693,"10478":16787694,"10479":16787695,"10480":16787696,"10481":16787697,"10482":16787698,"10483":16787699,"10484":16787700,"10485":16787701,"10486":16787702,"10487":16787703,"10488":16787704,"10489":16787705,"10490":16787706,"10491":16787707,"10492":16787708,"10493":16787709,"10494":16787710,"10495":16787711,"12289":1188,"12290":1185,"12300":1186,"12301":1187,"12443":1246,"12444":1247,"12449":1191,"12450":1201,"12451":1192,"12452":1202,"12453":1193,"12454":1203,"12455":1194,"12456":1204,"12457":1195,"12458":1205,"12459":1206,"12461":1207,"12463":1208,"12465":1209,"12467":1210,"12469":1211,"12471":1212,"12473":1213,"12475":1214,"12477":1215,"12479":1216,"12481":1217,"12483":1199,"12484":1218,"12486":1219,"12488":1220,"12490":1221,"12491":1222,"12492":1223,"12493":1224,"12494":1225,"12495":1226,"12498":1227,"12501":1228,"12504":1229,"12507":1230,"12510":1231,"12511":1232,"12512":1233,"12513":1234,"12514":1235,"12515":1196,"12516":1236,"12517":1197,"12518":1237,"12519":1198,"12520":1238,"12521":1239,"12522":1240,"12523":1241,"12524":1242,"12525":1243,"12527":1244,"12530":1190,"12531":1245,"12539":1189,"12540":1200}; + + function lookup(k) { return k ? {keysym: k, keyname: keynames ? keynames[k] : k} : undefined; } + return { + fromUnicode : function(u) { return lookup(codepoints[u]); }, + lookup : lookup + }; +})(); diff --git a/utils/parse.js b/utils/parse.js new file mode 100644 index 00000000..02ac66c2 --- /dev/null +++ b/utils/parse.js @@ -0,0 +1,97 @@ +// Utility to parse keysymdef.h to produce mappings from Unicode codepoints to keysyms +"use strict"; + +var fs = require('fs'); + +var show_help = process.argv.length === 2; +var use_keynames = false; +var filename; + +for (var i = 2; i < process.argv.length; ++i) { + switch (process.argv[i]) { + case "--help": + case "-h": + show_help = true; + break; + case "--debug-names": + case "-d": + use_keynames = true; + break; + case "--file": + case "-f": + default: + filename = process.argv[i]; + } +} + +if (!filename) { + show_help = true; + console.log("Error: No filename specified\n"); +} + +if (show_help) { + console.log("Parses a *nix keysymdef.h to generate Unicode code point mappings"); + console.log("Usage: node parse.js [options] filename:"); + console.log(" -h [ --help ] Produce this help message"); + console.log(" -d [ --debug-names ] Preserve keysym names for debugging (Increases file size by ~40KB)"); + console.log(" filename The keysymdef.h file to parse"); + return; +} + +// Set this to false to omit key names from the generated keysymdef.js +// This reduces the file size by around 40kb, but may hinder debugging + +var buf = fs.readFileSync(filename); +var str = buf.toString('utf8'); + +var re = /^\#define XK_([a-zA-Z_0-9]+)\s+0x([0-9a-fA-F]+)\s*(\/\*\s*(.*)\s*\*\/)?\s*$/m; + +var arr = str.split('\n'); + +var keysyms = {}; +var codepoints = {}; + +for (var i = 0; i < arr.length; ++i) { + var result = re.exec(arr[i]); + if (result){ + var keyname = result[1]; + var keysym = parseInt(result[2], 16); + var remainder = result[3]; + + keysyms[keysym] = keyname; + + var unicodeRes = /U\+([0-9a-fA-F]+)/.exec(remainder); + if (unicodeRes) { + var unicode = parseInt(unicodeRes[1], 16); + if (!codepoints[unicode]){ + codepoints[unicode] = keysym; + } + } + else { + console.log("no unicode codepoint found:", arr[i]); + } + } + else { + console.log("line is not a keysym:", arr[i]); + } +} + +var out = "// This file describes mappings from Unicode codepoints to the keysym values\n" + +"// (and optionally, key names) expected by the RFB protocol\n" + +"// How this file was generated:\n" + +"// " + process.argv.join(" ") + "\n" + +"var keysyms = (function(){\n" + +" \"use strict\";\n" + +" var keynames = {keysyms};\n" + +" var codepoints = {codepoints};\n" + +"\n" + +" function lookup(k) { return k ? {keysym: k, keyname: keynames ? keynames[k] : k} : undefined; }\n" + +" return {\n" + +" fromUnicode : function(u) { return lookup(codepoints[u]); },\n" + +" lookup : lookup\n" + +" };\n" + +"})();\n"; +out = out.replace('{keysyms}', use_keynames ? JSON.stringify(keysyms) : "null"); +out = out.replace('{codepoints}', JSON.stringify(codepoints)); + +fs.writeFileSync("keysymdef.js", out); From 4ef7566b10aca9a2c764ae86343dfee6932a83dd Mon Sep 17 00:00:00 2001 From: jalf Date: Wed, 27 Nov 2013 15:12:39 +0100 Subject: [PATCH 017/100] Keyboard Handling [2/8]: Core implementation of new keyboard handling Add keyboard.js, containing the actual keyboard event parsing code. --- include/keyboard.js | 511 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 511 insertions(+) create mode 100644 include/keyboard.js diff --git a/include/keyboard.js b/include/keyboard.js new file mode 100644 index 00000000..342f806e --- /dev/null +++ b/include/keyboard.js @@ -0,0 +1,511 @@ +var kbdUtil = (function() { + "use strict"; + + function isMac() { + return navigator && !!(/macintosh/i).exec(navigator.appVersion); + } + function isWindows() { + return navigator && !!(/windows/i).exec(navigator.appVersion); + } + function isLinux() { + return navigator && !!(/linux/i).exec(navigator.appVersion); + } + + // Return true if a modifier which is not the specified char modifier (and is not shift) is down + function hasShortcutModifier(charModifier, currentModifiers) { + var mods = {}; + for (var key in currentModifiers) { + if (key !== 0xffe1) { + mods[key] = currentModifiers[key]; + } + } + + var sum = 0; + for (var k in currentModifiers) { + if (mods[k]) { + ++sum; + } + } + if (hasCharModifier(charModifier, mods)) { + return sum > charModifier.length; + } + else { + return sum > 0; + } + } + + // Return true if the specified char modifier is currently down + function hasCharModifier(charModifier, currentModifiers) { + if (charModifier.length === 0) { return false; } + + for (var i = 0; i < charModifier.length; ++i) { + if (!currentModifiers[charModifier[i]]) { + return false; + } + } + return true; + } + + // Helper object tracking modifier key state + // and generates fake key events to compensate if it gets out of sync + function ModifierSync(charModifier) { + var ctrl = 0xffe3; + var alt = 0xffe9; + var altGr = 0xfe03; + var shift = 0xffe1; + var meta = 0xffe7; + + if (!charModifier) { + if (isMac()) { + // on Mac, Option (AKA Alt) is used as a char modifier + charModifier = [alt]; + } + else if (isWindows()) { + // on Windows, Ctrl+Alt is used as a char modifier + charModifier = [alt, ctrl]; + } + else if (isLinux()) { + // on Linux, AltGr is used as a char modifier + charModifier = [altGr]; + } + else { + charModifier = []; + } + } + + var state = {}; + state[ctrl] = false; + state[alt] = false; + state[altGr] = false; + state[shift] = false; + state[meta] = false; + + function sync(evt, keysym) { + var result = []; + function syncKey(keysym) { + return {keysym: keysyms.lookup(keysym), type: state[keysym] ? 'keydown' : 'keyup'}; + } + + if (evt.ctrlKey !== undefined && evt.ctrlKey !== state[ctrl] && keysym !== ctrl) { + state[ctrl] = evt.ctrlKey; + result.push(syncKey(ctrl)); + } + if (evt.altKey !== undefined && evt.altKey !== state[alt] && keysym !== alt) { + state[alt] = evt.altKey; + result.push(syncKey(alt)); + } + if (evt.altGraphKey !== undefined && evt.altGraphKey !== state[altGr] && keysym !== altGr) { + state[altGr] = evt.altGraphKey; + result.push(syncKey(altGr)); + } + if (evt.shiftKey !== undefined && evt.shiftKey !== state[shift] && keysym !== shift) { + state[shift] = evt.shiftKey; + result.push(syncKey(shift)); + } + if (evt.metaKey !== undefined && evt.metaKey !== state[meta] && keysym !== meta) { + state[meta] = evt.metaKey; + result.push(syncKey(meta)); + } + return result; + } + function syncKeyEvent(evt, down) { + var obj = getKeysym(evt); + var keysym = obj ? obj.keysym : null; + + // first, apply the event itself, if relevant + if (keysym !== null && state[keysym] !== undefined) { + state[keysym] = down; + } + return sync(evt, keysym); + } + + return { + // sync on the appropriate keyboard event + keydown: function(evt) { return syncKeyEvent(evt, true);}, + keyup: function(evt) { return syncKeyEvent(evt, false);}, + // Call this with a non-keyboard event (such as mouse events) to use its modifier state to synchronize anyway + syncAny: function(evt) { return sync(evt);}, + + // is a shortcut modifier down? + hasShortcutModifier: function() { return hasShortcutModifier(charModifier, state); }, + // if a char modifier is down, return the keys it consists of, otherwise return null + activeCharModifier: function() { return hasCharModifier(charModifier, state) ? charModifier : null; } + }; + } + + // Get a key ID from a keyboard event + // May be a string or an integer depending on the available properties + function getKey(evt){ + if (evt.key) { + return evt.key; + } + else { + return evt.keyCode; + } + } + + // Get the most reliable keysym value we can get from a key event + // if char/charCode is available, prefer those, otherwise fall back to key/keyCode/which + function getKeysym(evt){ + var codepoint; + if (evt.char && evt.char.length === 1) { + codepoint = evt.char.charCodeAt(); + } + else if (evt.charCode) { + codepoint = evt.charCode; + } + + if (codepoint) { + var res = keysyms.fromUnicode(codepoint); + if (res) { + return res; + } + } + // we could check evt.key here. + // Legal values are defined in http://www.w3.org/TR/DOM-Level-3-Events/#key-values-list, + // so we "just" need to map them to keysym, but AFAIK this is only available in IE10, which also provides evt.key + // so we don't *need* it yet + if (evt.keyCode) { + return keysyms.lookup(keysymFromKeyCode(evt.keyCode, evt.shiftKey)); + } + if (evt.which) { + return keysyms.lookup(keysymFromKeyCode(evt.which, evt.shiftKey)); + } + return null; + } + + // Given a keycode, try to predict which keysym it might be. + // If the keycode is unknown, null is returned. + function keysymFromKeyCode(keycode, shiftPressed) { + if (typeof(keycode) !== 'number') { + return null; + } + // won't be accurate for azerty + if (keycode >= 0x30 && keycode <= 0x39) { + return keycode; // digit + } + if (keycode >= 0x41 && keycode <= 0x5a) { + // remap to lowercase unless shift is down + return shiftPressed ? keycode : keycode + 32; // A-Z + } + if (keycode >= 0x60 && keycode <= 0x69) { + return 0xffb0 + (keycode - 0x60); // numpad 0-9 + } + + switch(keycode) { + case 0x20: return 0x20; // space + case 0x6a: return 0xffaa; // multiply + case 0x6b: return 0xffab; // add + case 0x6c: return 0xffac; // separator + case 0x6d: return 0xffad; // subtract + case 0x6e: return 0xffae; // decimal + case 0x6f: return 0xffaf; // divide + case 0xbb: return 0x2b; // + + case 0xbc: return 0x2c; // , + case 0xbd: return 0x2d; // - + case 0xbe: return 0x2e; // . + } + + return nonCharacterKey({keyCode: keycode}); + } + + // if the key is a known non-character key (any key which doesn't generate character data) + // return its keysym value. Otherwise return null + function nonCharacterKey(evt) { + // evt.key not implemented yet + if (!evt.keyCode) { return null; } + var keycode = evt.keyCode; + + if (keycode >= 0x70 && keycode <= 0x87) { + return 0xffbe + keycode - 0x70; // F1-F24 + } + switch (keycode) { + + case 8 : return 0xFF08; // BACKSPACE + case 13 : return 0xFF0D; // ENTER + + case 9 : return 0xFF09; // TAB + + case 27 : return 0xFF1B; // ESCAPE + case 46 : return 0xFFFF; // DELETE + + case 36 : return 0xFF50; // HOME + case 35 : return 0xFF57; // END + case 33 : return 0xFF55; // PAGE_UP + case 34 : return 0xFF56; // PAGE_DOWN + case 45 : return 0xFF63; // INSERT + + case 37 : return 0xFF51; // LEFT + case 38 : return 0xFF52; // UP + case 39 : return 0xFF53; // RIGHT + case 40 : return 0xFF54; // DOWN + case 16 : return 0xFFE1; // SHIFT + case 17 : return 0xFFE3; // CONTROL + case 18 : return 0xFFE9; // Left ALT (Mac Option) + + case 224 : return 0xFE07; // Meta + case 225 : return 0xFE03; // AltGr + case 91 : return 0xFFEC; // Super_L (Win Key) + case 92 : return 0xFFED; // Super_R (Win Key) + case 93 : return 0xFF67; // Menu (Win Menu), Mac Command + default: return null; + } + } + return { + hasShortcutModifier : hasShortcutModifier, + hasCharModifier : hasCharModifier, + ModifierSync : ModifierSync, + getKey : getKey, + getKeysym : getKeysym, + keysymFromKeyCode : keysymFromKeyCode, + nonCharacterKey : nonCharacterKey + }; +})(); + +// Takes a DOM keyboard event and: +// - determines which keysym it represents +// - determines a keyId identifying the key that was pressed (corresponding to the key/keyCode properties on the DOM event) +// - synthesizes events to synchronize modifier key state between which modifiers are actually down, and which we thought were down +// - marks each event with an 'escape' property if a modifier was down which should be "escaped" +// - generates a "stall" event in cases where it might be necessary to wait and see if a keypress event follows a keydown +// This information is collected into an object which is passed to the next() function. (one call per event) +function KeyEventDecoder(modifierState, next) { + "use strict"; + function sendAll(evts) { + for (var i = 0; i < evts.length; ++i) { + next(evts[i]); + } + } + function process(evt, type) { + var result = {type: type}; + var keyId = kbdUtil.getKey(evt); + if (keyId) { + result.keyId = keyId; + } + + var keysym = kbdUtil.getKeysym(evt); + + var hasModifier = modifierState.hasShortcutModifier() || !!modifierState.activeCharModifier(); + // Is this a case where we have to decide on the keysym right away, rather than waiting for the keypress? + // "special" keys like enter, tab or backspace don't send keypress events, + // and some browsers don't send keypresses at all if a modifier is down + if (keysym && (type !== 'keydown' || kbdUtil.nonCharacterKey(evt) || hasModifier)) { + result.keysym = keysym; + } + + var isShift = evt.keyCode === 0x10 || evt.key === 'Shift'; + + // Should we prevent the browser from handling the event? + // Doing so on a keydown (in most browsers) prevents keypress from being generated + // so only do that if we have to. + var suppress = !isShift && (type !== 'keydown' || modifierState.hasShortcutModifier() || !!kbdUtil.nonCharacterKey(evt)); + + // If a char modifier is down on a keydown, we need to insert a stall, + // so VerifyCharModifier knows to wait and see if a keypress is comnig + var stall = type === 'keydown' && modifierState.activeCharModifier() && !kbdUtil.nonCharacterKey(evt); + + // if a char modifier is pressed, get the keys it consists of (on Windows, AltGr is equivalent to Ctrl+Alt) + var active = modifierState.activeCharModifier(); + + // If we have a char modifier down, and we're able to determine a keysym reliably + // then (a) we know to treat the modifier as a char modifier, + // and (b) we'll have to "escape" the modifier to undo the modifier when sending the char. + if (active && keysym) { + var isCharModifier = false; + for (var i = 0; i < active.length; ++i) { + if (active[i] === keysym.keysym) { + isCharModifier = true; + } + } + if (type === 'keypress' && !isCharModifier) { + result.escape = modifierState.activeCharModifier(); + } + } + + if (stall) { + // insert a fake "stall" event + next({type: 'stall'}); + } + next(result); + + return suppress; + } + + return { + keydown: function(evt) { + sendAll(modifierState.keydown(evt)); + return process(evt, 'keydown'); + }, + keypress: function(evt) { + return process(evt, 'keypress'); + }, + keyup: function(evt) { + sendAll(modifierState.keyup(evt)); + return process(evt, 'keyup'); + }, + syncModifiers: function(evt) { + sendAll(modifierState.syncAny(evt)); + }, + releaseAll: function() { next({type: 'releaseall'}); } + }; +} + +// Combines keydown and keypress events where necessary to handle char modifiers. +// On some OS'es, a char modifier is sometimes used as a shortcut modifier. +// For example, on Windows, AltGr is synonymous with Ctrl-Alt. On a Danish keyboard layout, AltGr-2 yields a @, but Ctrl-Alt-D does nothing +// so when used with the '2' key, Ctrl-Alt counts as a char modifier (and should be escaped), but when used with 'D', it does not. +// The only way we can distinguish these cases is to wait and see if a keypress event arrives +// When we receive a "stall" event, wait a few ms before processing the next keydown. If a keypress has also arrived, merge the two +function VerifyCharModifier(next) { + "use strict"; + var queue = []; + var timer = null; + function process() { + if (timer) { + return; + } + while (queue.length !== 0) { + var cur = queue[0]; + queue = queue.splice(1); + switch (cur.type) { + case 'stall': + // insert a delay before processing available events. + timer = setTimeout(function() { + clearTimeout(timer); + timer = null; + process(); + }, 5); + return; + case 'keydown': + // is the next element a keypress? Then we should merge the two + if (queue.length !== 0 && queue[0].type === 'keypress') { + // Firefox sends keypress even when no char is generated. + // so, if keypress keysym is the same as we'd have guessed from keydown, + // the modifier didn't have any effect, and should not be escaped + if (queue[0].escape && (!cur.keysym || cur.keysym.keysym !== queue[0].keysym.keysym)) { + cur.escape = queue[0].escape; + } + cur.keysym = queue[0].keysym; + queue = queue.splice(1); + } + break; + } + + // swallow stall events, and pass all others to the next stage + if (cur.type !== 'stall') { + next(cur); + } + } + } + return function(evt) { + queue.push(evt); + process(); + }; +} + +// Keeps track of which keys we (and the server) believe are down +// When a keyup is received, match it against this list, to determine the corresponding keysym(s) +// in some cases, a single key may produce multiple keysyms, so the corresponding keyup event must release all of these chars +// key repeat events should be merged into a single entry. +// Because we can't always identify which entry a keydown or keyup event corresponds to, we sometimes have to guess +function TrackKeyState(next) { + "use strict"; + var state = []; + + return function (evt) { + var last = state.length !== 0 ? state[state.length-1] : null; + + switch (evt.type) { + case 'keydown': + // insert a new entry if last seen key was different. + if (!last || !evt.keyId || last.keyId !== evt.keyId) { + last = {keyId: evt.keyId, keysyms: {}}; + state.push(last); + } + if (evt.keysym) { + // make sure last event contains this keysym (a single "logical" keyevent + // can cause multiple key events to be sent to the VNC server) + last.keysyms[evt.keysym.keysym] = evt.keysym; + last.ignoreKeyPress = true; + next(evt); + } + break; + case 'keypress': + if (!last) { + last = {keyId: evt.keyId, keysyms: {}}; + state.push(last); + } + if (!evt.keysym) { + console.log('keypress with no keysym:', evt); + } + + // If we didn't expect a keypress, and already sent a keydown to the VNC server + // based on the keydown, make sure to skip this event. + if (evt.keysym && !last.ignoreKeyPress) { + last.keysyms[evt.keysym.keysym] = evt.keysym; + evt.type = 'keydown'; + next(evt); + } + break; + case 'keyup': + if (state.length === 0) { + return; + } + var idx = null; + // do we have a matching key tracked as being down? + for (var i = 0; i !== state.length; ++i) { + if (state[i].keyId === evt.keyId) { + idx = i; + break; + } + } + // if we couldn't find a match (it happens), assume it was the last key pressed + if (idx === null) { + idx = state.length - 1; + } + + var item = state.splice(idx, 1)[0]; + // for each keysym tracked by this key entry, clone the current event and override the keysym + for (var key in item.keysyms) { + var clone = (function(){ + function Clone(){} + return function (obj) { Clone.prototype=obj; return new Clone(); }; + }()); + var out = clone(evt); + out.keysym = item.keysyms[key]; + next(out); + } + break; + case 'releaseall': + for (var i = 0; i < state.length; ++i) { + for (var key in state[i].keysyms) { + var keysym = state[i].keysyms[key]; + next({keyId: 0, keysym: keysym, type: 'keyup'}); + } + } + state = []; + } + }; +} + +// Handles "escaping" of modifiers: if a char modifier is used to produce a keysym (such as AltGr-2 to generate an @), +// then the modifier must be "undone" before sending the @, and "redone" afterwards. +function EscapeModifiers(next) { + "use strict"; + return function(evt) { + if (evt.type !== 'keydown' || evt.escape === undefined) { + next(evt); + return; + } + // undo modifiers + for (var i = 0; i < evt.escape.length; ++i) { + next({type: 'keyup', keyId: 0, keysym: keysyms.lookup(evt.escape[i])}); + } + // send the character event + next(evt); + // redo modifiers + for (var i = 0; i < evt.escape.length; ++i) { + next({type: 'keydown', keyId: 0, keysym: keysyms.lookup(evt.escape[i])}); + } + }; +} From f00b6fb69a293cee2543e9910364c24d196484d1 Mon Sep 17 00:00:00 2001 From: jalf Date: Wed, 27 Nov 2013 15:14:41 +0100 Subject: [PATCH 018/100] Keyboard Handling [3/8]: Add unit tests for new keyboard handling Relies on the libraries chai and mocha (available via npm from Node.JS). Add anything installed via npm to the .gitignore file. --- .gitignore | 1 + tests/keyboard-tests.html | 29 ++ tests/test.helper.js | 237 +++++++++++ tests/test.keyboard.js | 841 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1108 insertions(+) create mode 100644 tests/keyboard-tests.html create mode 100644 tests/test.helper.js create mode 100644 tests/test.keyboard.js diff --git a/.gitignore b/.gitignore index 12271c8c..7cf2a2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.o tests/data_*.js utils/rebind.so +node_modules diff --git a/tests/keyboard-tests.html b/tests/keyboard-tests.html new file mode 100644 index 00000000..a30aa6e0 --- /dev/null +++ b/tests/keyboard-tests.html @@ -0,0 +1,29 @@ + + + + + Mocha Tests + + + + +
+ + + + + + + + + + diff --git a/tests/test.helper.js b/tests/test.helper.js new file mode 100644 index 00000000..cb6d88bc --- /dev/null +++ b/tests/test.helper.js @@ -0,0 +1,237 @@ +var assert = chai.assert; +var expect = chai.expect; + +describe('Helpers', function() { + "use strict"; + describe('keysymFromKeyCode', function() { + it('should map known keycodes to keysyms', function() { + expect(kbdUtil.keysymFromKeyCode(0x41, false), 'a').to.be.equal(0x61); + expect(kbdUtil.keysymFromKeyCode(0x41, true), 'A').to.be.equal(0x41); + expect(kbdUtil.keysymFromKeyCode(0xd, false), 'enter').to.be.equal(0xFF0D); + expect(kbdUtil.keysymFromKeyCode(0x11, false), 'ctrl').to.be.equal(0xFFE3); + expect(kbdUtil.keysymFromKeyCode(0x12, false), 'alt').to.be.equal(0xFFE9); + expect(kbdUtil.keysymFromKeyCode(0xe1, false), 'altgr').to.be.equal(0xFE03); + expect(kbdUtil.keysymFromKeyCode(0x1b, false), 'esc').to.be.equal(0xFF1B); + expect(kbdUtil.keysymFromKeyCode(0x26, false), 'up').to.be.equal(0xFF52); + }); + it('should return null for unknown keycodes', function() { + expect(kbdUtil.keysymFromKeyCode(0xc0, false), 'DK æ').to.be.null; + expect(kbdUtil.keysymFromKeyCode(0xde, false), 'DK ø').to.be.null; + }); + }); + + describe('keysyms.fromUnicode', function() { + it('should map ASCII characters to keysyms', function() { + expect(keysyms.fromUnicode('a'.charCodeAt())).to.have.property('keysym', 0x61); + expect(keysyms.fromUnicode('A'.charCodeAt())).to.have.property('keysym', 0x41); + }); + it('should map Latin-1 characters to keysyms', function() { + expect(keysyms.fromUnicode('ø'.charCodeAt())).to.have.property('keysym', 0xf8); + + expect(keysyms.fromUnicode('é'.charCodeAt())).to.have.property('keysym', 0xe9); + }); + it('should map characters that are in Windows-1252 but not in Latin-1 to keysyms', function() { + expect(keysyms.fromUnicode('Š'.charCodeAt())).to.have.property('keysym', 0x01a9); + }); + it('should map characters which aren\'t in Latin1 *or* Windows-1252 to keysyms', function() { + expect(keysyms.fromUnicode('ŵ'.charCodeAt())).to.have.property('keysym', 0x1000175); + }); + it('should return undefined for unknown codepoints', function() { + expect(keysyms.fromUnicode('\n'.charCodeAt())).to.be.undefined; + expect(keysyms.fromUnicode('\u1F686'.charCodeAt())).to.be.undefined; + }); + }); + + describe('nonCharacterKey', function() { + it('should recognize the right keys', function() { + expect(kbdUtil.nonCharacterKey({keyCode: 0xd}), 'enter').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0x08}), 'backspace').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0x09}), 'tab').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0x10}), 'shift').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0x11}), 'ctrl').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0x12}), 'alt').to.be.defined; + expect(kbdUtil.nonCharacterKey({keyCode: 0xe0}), 'meta').to.be.defined; + }); + it('should not recognize character keys', function() { + expect(kbdUtil.nonCharacterKey({keyCode: 'A'}), 'A').to.be.null; + expect(kbdUtil.nonCharacterKey({keyCode: '1'}), '1').to.be.null; + expect(kbdUtil.nonCharacterKey({keyCode: '.'}), '.').to.be.null; + expect(kbdUtil.nonCharacterKey({keyCode: ' '}), 'space').to.be.null; + }); + }); + + describe('getKeysym', function() { + it('should prefer char', function() { + expect(kbdUtil.getKeysym({char : 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x61); + }); + it('should use charCode if no char', function() { + expect(kbdUtil.getKeysym({char : '', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9); + expect(kbdUtil.getKeysym({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9); + expect(kbdUtil.getKeysym({char : 'hello', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9); + }); + it('should use keyCode if no charCode', function() { + expect(kbdUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: false})).to.have.property('keysym', 0x62); + expect(kbdUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: true})).to.have.property('keysym', 0x42); + }); + it('should use which if no keyCode', function() { + expect(kbdUtil.getKeysym({which: 0x43, shiftKey: false})).to.have.property('keysym', 0x63); + expect(kbdUtil.getKeysym({which: 0x43, shiftKey: true})).to.have.property('keysym', 0x43); + }); + }); + + describe('Modifier Sync', function() { // return a list of fake events necessary to fix modifier state + describe('Toggle all modifiers', function() { + var sync = kbdUtil.ModifierSync(); + it ('should do nothing if all modifiers are up as expected', function() { + expect(sync.keydown({ + keyCode: 0x41, + ctrlKey: false, + altKey: false, + altGraphKey: false, + shiftKey: false, + metaKey: false}) + ).to.have.lengthOf(0); + }); + it ('should synthesize events if all keys are unexpectedly down', function() { + var result = sync.keydown({ + keyCode: 0x41, + ctrlKey: true, + altKey: true, + altGraphKey: true, + shiftKey: true, + metaKey: true + }); + expect(result).to.have.lengthOf(5); + var keysyms = {}; + for (var i = 0; i < result.length; ++i) { + keysyms[result[i].keysym] = (result[i].type == 'keydown'); + } + expect(keysyms[0xffe3]); + expect(keysyms[0xffe9]); + expect(keysyms[0xfe03]); + expect(keysyms[0xffe1]); + expect(keysyms[0xffe7]); + }); + it ('should do nothing if all modifiers are down as expected', function() { + expect(sync.keydown({ + keyCode: 0x41, + ctrlKey: true, + altKey: true, + altGraphKey: true, + shiftKey: true, + metaKey: true + })).to.have.lengthOf(0); + }); + }); + describe('Toggle Ctrl', function() { + var sync = kbdUtil.ModifierSync(); + it('should sync if modifier is suddenly down', function() { + expect(sync.keydown({ + keyCode: 0x41, + ctrlKey: true, + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe3), type: 'keydown'}]); + }); + it('should sync if modifier is suddenly up', function() { + expect(sync.keydown({ + keyCode: 0x41, + ctrlKey: false + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe3), type: 'keyup'}]); + }); + }); + describe('Toggle Alt', function() { + var sync = kbdUtil.ModifierSync(); + it('should sync if modifier is suddenly down', function() { + expect(sync.keydown({ + keyCode: 0x41, + altKey: true, + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]); + }); + it('should sync if modifier is suddenly up', function() { + expect(sync.keydown({ + keyCode: 0x41, + altKey: false + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keyup'}]); + }); + }); + describe('Toggle AltGr', function() { + var sync = kbdUtil.ModifierSync(); + it('should sync if modifier is suddenly down', function() { + expect(sync.keydown({ + keyCode: 0x41, + altGraphKey: true, + })).to.be.deep.equal([{keysym: keysyms.lookup(0xfe03), type: 'keydown'}]); + }); + it('should sync if modifier is suddenly up', function() { + expect(sync.keydown({ + keyCode: 0x41, + altGraphKey: false + })).to.be.deep.equal([{keysym: keysyms.lookup(0xfe03), type: 'keyup'}]); + }); + }); + describe('Toggle Shift', function() { + var sync = kbdUtil.ModifierSync(); + it('should sync if modifier is suddenly down', function() { + expect(sync.keydown({ + keyCode: 0x41, + shiftKey: true, + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe1), type: 'keydown'}]); + }); + it('should sync if modifier is suddenly up', function() { + expect(sync.keydown({ + keyCode: 0x41, + shiftKey: false + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe1), type: 'keyup'}]); + }); + }); + describe('Toggle Meta', function() { + var sync = kbdUtil.ModifierSync(); + it('should sync if modifier is suddenly down', function() { + expect(sync.keydown({ + keyCode: 0x41, + metaKey: true, + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe7), type: 'keydown'}]); + }); + it('should sync if modifier is suddenly up', function() { + expect(sync.keydown({ + keyCode: 0x41, + metaKey: false + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe7), type: 'keyup'}]); + }); + }); + describe('Modifier keyevents', function() { + it('should not sync a modifier on its own events', function() { + expect(kbdUtil.ModifierSync().keydown({ + keyCode: 0x11, + ctrlKey: false + })).to.be.deep.equal([]); + expect(kbdUtil.ModifierSync().keydown({ + keyCode: 0x11, + ctrlKey: true + }), 'B').to.be.deep.equal([]); + }) + it('should update state on modifier keyevents', function() { + var sync = kbdUtil.ModifierSync(); + sync.keydown({ + keyCode: 0x11, + }); + expect(sync.keydown({ + keyCode: 0x41, + ctrlKey: true, + })).to.be.deep.equal([]); + }); + it('should sync other modifiers on ctrl events', function() { + expect(kbdUtil.ModifierSync().keydown({ + keyCode: 0x11, + altKey: true + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]); + }) + }); + describe('sync modifiers on non-key events', function() { + it('should generate sync events when receiving non-keyboard events', function() { + expect(kbdUtil.ModifierSync().syncAny({ + altKey: true + })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]); + }); + }); + }); +}); diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js new file mode 100644 index 00000000..80d1fee4 --- /dev/null +++ b/tests/test.keyboard.js @@ -0,0 +1,841 @@ +var assert = chai.assert; +var expect = chai.expect; + + +describe('Key Event Pipeline Stages', function() { + "use strict"; + describe('Decode Keyboard Events', function() { + it('should pass events to the next stage', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.an.object; + done(); + }).keydown({keyCode: 0x41}); + }); + it('should pass the right keysym through', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt.keysym).to.be.deep.equal(keysyms.lookup(0x61)); + done(); + }).keypress({keyCode: 0x41}); + }); + it('should pass the right keyid through', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.have.property('keyId', 0x41); + done(); + }).keydown({keyCode: 0x41}); + }); + it('should not sync modifiers on a keypress', function() { + // Firefox provides unreliable modifier state on keypress events + var count = 0; + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + ++count; + }).keypress({keyCode: 0x41, ctrlKey: true}); + expect(count).to.be.equal(1); + }); + it('should sync modifiers if necessary', function(done) { + var count = 0; + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + switch (count) { + case 0: // fake a ctrl keydown + expect(evt).to.be.deep.equal({keysym: keysyms.lookup(0xffe3), type: 'keydown'}); + ++count; + break; + case 1: + expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown', keysym: keysyms.lookup(0x61)}); + done(); + break; + } + }).keydown({keyCode: 0x41, ctrlKey: true}); + }); + it('should forward keydown events with the right type', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'}); + done(); + }).keydown({keyCode: 0x41}) + }); + it('should forward keyup events with the right type', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'}); + done(); + }).keyup({keyCode: 0x41}); + }); + it('should forward keypress events with the right type', function(done) { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'}); + done(); + }).keypress({keyCode: 0x41}); + }); + it('should generate stalls if a char modifier is down while a key is pressed', function(done) { + var count = 0; + KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) { + switch (count) { + case 0: // fake altgr + expect(evt).to.be.deep.equal({keysym: keysyms.lookup(0xfe03), type: 'keydown'}); + ++count; + break; + case 1: // stall before processing the 'a' keydown + expect(evt).to.be.deep.equal({type: 'stall'}); + ++count; + break; + case 2: // 'a' + expect(evt).to.be.deep.equal({ + type: 'keydown', + keyId: 0x41, + keysym: keysyms.lookup(0x61) + }); + + done(); + break; + } + }).keydown({keyCode: 0x41, altGraphKey: true}); + + }); + describe('suppress the right events at the right time', function() { + it('should suppress anything while a shortcut modifier is down', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {}); + + obj.keydown({keyCode: 0x11}); // press ctrl + expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.true; + expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.true; + expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.true; + expect(obj.keydown({keyCode: 0x3c})).to.be.true; // < key on DK Windows + expect(obj.keydown({keyCode: 0xde})).to.be.true; // Ø key on DK + }); + it('should suppress non-character keys', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {}); + + expect(obj.keydown({keyCode: 0x08}), 'a').to.be.true; + expect(obj.keydown({keyCode: 0x09}), 'b').to.be.true; + expect(obj.keydown({keyCode: 0x11}), 'd').to.be.true; + expect(obj.keydown({keyCode: 0x12}), 'e').to.be.true; + }); + it('should not suppress shift', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {}); + + expect(obj.keydown({keyCode: 0x10}), 'd').to.be.false; + }); + it('should generate event for shift keydown', function() { + var called = false; + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.have.property('keysym'); + called = true; + }).keydown({keyCode: 0x10}); + expect(called).to.be.true; + }); + it('should not suppress character keys', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {}); + + expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: 0x3c})).to.be.false; // < key on DK Windows + expect(obj.keydown({keyCode: 0xde})).to.be.false; // Ø key on DK + }); + it('should not suppress if a char modifier is down', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {}); + + obj.keydown({keyCode: 0xe1}); // press altgr + expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: '1'.charCodeAt()})).to.be.false; + expect(obj.keydown({keyCode: 0x3c})).to.be.false; // < key on DK Windows + expect(obj.keydown({keyCode: 0xde})).to.be.false; // Ø key on DK + }); + }); + describe('Keypress and keyup events', function() { + it('should always suppress event propagation', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {}); + + expect(obj.keypress({keyCode: 'A'.charCodeAt()})).to.be.true; + expect(obj.keypress({keyCode: 0x3c})).to.be.true; // < key on DK Windows + expect(obj.keypress({keyCode: 0x11})).to.be.true; + + expect(obj.keyup({keyCode: 'A'.charCodeAt()})).to.be.true; + expect(obj.keyup({keyCode: 0x3c})).to.be.true; // < key on DK Windows + expect(obj.keyup({keyCode: 0x11})).to.be.true; + }); + it('should never generate stalls', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt.type).to.not.be.equal('stall'); + }); + + obj.keypress({keyCode: 'A'.charCodeAt()}); + obj.keypress({keyCode: 0x3c}); + obj.keypress({keyCode: 0x11}); + + obj.keyup({keyCode: 'A'.charCodeAt()}); + obj.keyup({keyCode: 0x3c}); + obj.keyup({keyCode: 0x11}); + }); + }); + describe('mark events if a char modifier is down', function() { + it('should not mark modifiers on a keydown event', function() { + var times_called = 0; + var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) { + switch (times_called++) { + case 0: //altgr + break; + case 1: // 'a' + expect(evt).to.not.have.property('escape'); + break; + } + }); + + obj.keydown({keyCode: 0xe1}); // press altgr + obj.keydown({keyCode: 'A'.charCodeAt()}); + }); + + it('should indicate on events if a single-key char modifier is down', function(done) { + var times_called = 0; + var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) { + switch (times_called++) { + case 0: //altgr + break; + case 1: // 'a' + expect(evt).to.be.deep.equal({ + type: 'keypress', + keyId: 'A'.charCodeAt(), + keysym: keysyms.lookup('a'.charCodeAt()), + escape: [0xfe03] + }); + done(); + return; + } + }); + + obj.keydown({keyCode: 0xe1}); // press altgr + obj.keypress({keyCode: 'A'.charCodeAt()}); + }); + it('should indicate on events if a multi-key char modifier is down', function(done) { + var times_called = 0; + var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xffe9, 0xffe3]), function(evt) { + switch (times_called++) { + case 0: //ctrl + break; + case 1: //alt + break; + case 2: // 'a' + expect(evt).to.be.deep.equal({ + type: 'keypress', + keyId: 'A'.charCodeAt(), + keysym: keysyms.lookup('a'.charCodeAt()), + escape: [0xffe9, 0xffe3] + }); + done(); + return; + } + }); + + obj.keydown({keyCode: 0x11}); // press ctrl + obj.keydown({keyCode: 0x12}); // press alt + obj.keypress({keyCode: 'A'.charCodeAt()}); + }); + it('should not consider a char modifier to be down on the modifier key itself', function() { + var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) { + expect(evt).to.not.have.property('escape'); + }); + + obj.keydown({keyCode: 0xe1}); // press altgr + + }); + }); + describe('add/remove keysym', function() { + it('should remove keysym from keydown if a char key and no modifier', function() { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'}); + }).keydown({keyCode: 0x41}); + }); + it('should not remove keysym from keydown if a shortcut modifier is down', function() { + var times_called = 0; + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + switch (times_called++) { + case 1: + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'}); + break; + } + }).keydown({keyCode: 0x41, ctrlKey: true}); + expect(times_called).to.be.equal(2); + }); + it('should not remove keysym from keydown if a char modifier is down', function() { + var times_called = 0; + KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) { + switch (times_called++) { + case 2: + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'}); + break; + } + }).keydown({keyCode: 0x41, altGraphKey: true}); + expect(times_called).to.be.equal(3); + }); + it('should not remove keysym from keydown if key is noncharacter', function() { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt, 'bacobjpace').to.be.deep.equal({keyId: 0x09, keysym: keysyms.lookup(0xff09), type: 'keydown'}); + }).keydown({keyCode: 0x09}); + + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt, 'ctrl').to.be.deep.equal({keyId: 0x11, keysym: keysyms.lookup(0xffe3), type: 'keydown'}); + }).keydown({keyCode: 0x11}); + }); + it('should never remove keysym from keypress', function() { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'}); + }).keypress({keyCode: 0x41}); + }); + it('should never remove keysym from keyup', function() { + KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) { + expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'}); + }).keyup({keyCode: 0x41}); + }); + }); + // on keypress, keyup(?), always set keysym + // on keydown, only do it if we don't expect a keypress: if noncharacter OR modifier is down + }); + + describe('Verify that char modifiers are active', function() { + it('should pass keydown events through if there is no stall', function(done) { + var obj = VerifyCharModifier(function(evt){ + expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + done(); + })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + }); + it('should pass keyup events through if there is no stall', function(done) { + var obj = VerifyCharModifier(function(evt){ + expect(evt).to.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + done(); + })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + }); + it('should pass keypress events through if there is no stall', function(done) { + var obj = VerifyCharModifier(function(evt){ + expect(evt).to.deep.equal({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + done(); + })({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + }); + it('should not pass stall events through', function(done){ + var obj = VerifyCharModifier(function(evt){ + // should only be called once, for the keydown + expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + done(); + }); + + obj({type: 'stall'}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + }); + it('should merge keydown and keypress events if they come after a stall', function(done) { + var next_called = false; + var obj = VerifyCharModifier(function(evt){ + // should only be called once, for the keydown + expect(next_called).to.be.false; + next_called = true; + expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x44)}); + done(); + }); + + obj({type: 'stall'}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44)}); + expect(next_called).to.be.false; + }); + it('should preserve modifier attribute when merging if keysyms differ', function(done) { + var next_called = false; + var obj = VerifyCharModifier(function(evt){ + // should only be called once, for the keydown + expect(next_called).to.be.false; + next_called = true; + expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x44), escape: [0xffe3]}); + done(); + }); + + obj({type: 'stall'}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44), escape: [0xffe3]}); + expect(next_called).to.be.false; + }); + it('should not preserve modifier attribute when merging if keysyms are the same', function() { + var obj = VerifyCharModifier(function(evt){ + expect(evt).to.not.have.property('escape'); + }); + + obj({type: 'stall'}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x42), escape: [0xffe3]}); + }); + it('should not merge keydown and keypress events if there is no stall', function(done) { + var times_called = 0; + var obj = VerifyCharModifier(function(evt){ + switch(times_called) { + case 0: + expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + break; + case 1: + expect(evt).to.deep.equal({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44)}); + done(); + break; + } + + ++times_called; + }); + + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + obj({type: 'keypress', keyId: 0x43, keysym: keysyms.lookup(0x44)}); + }); + it('should not merge keydown and keypress events if separated by another event', function(done) { + var times_called = 0; + var obj = VerifyCharModifier(function(evt){ + switch(times_called) { + case 0: + expect(evt,1).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + break; + case 1: + expect(evt,2).to.deep.equal({type: 'keyup', keyId: 0x43, keysym: keysyms.lookup(0x44)}); + break; + case 2: + expect(evt,3).to.deep.equal({type: 'keypress', keyId: 0x45, keysym: keysyms.lookup(0x46)}); + done(); + break; + } + + ++times_called; + }); + + obj({type: 'stall'}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + obj({type: 'keyup', keyId: 0x43, keysym: keysyms.lookup(0x44)}); + obj({type: 'keypress', keyId: 0x45, keysym: keysyms.lookup(0x46)}); + }); + }); + + describe('Track Key State', function() { + it('should do nothing on keyup events if no keys are down', function() { + var obj = TrackKeyState(function(evt) { + expect(true).to.be.false; + }); + obj({type: 'keyup', keyId: 0x41}); + }); + it('should insert into the queue on keydown if no keys are down', function() { + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + } + elem = null; + }); + + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0x41}; + obj(elem); + expect(elem).to.be.null; + expect(times_called).to.be.equal(2); + }); + it('should insert into the queue on keypress if no keys are down', function() { + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + } + elem = null; + }); + + expect(elem).to.be.null; + elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0x41}; + obj(elem); + expect(elem).to.be.null; + expect(times_called).to.be.equal(2); + }); + it('should add keysym to last key entry if keyId matches', function() { + // this implies that a single keyup will release both keysyms + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x43)}; + keysymsdown[keysyms.lookup(0x43).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0x41}; + obj(elem); + expect(times_called).to.be.equal(4); + }); + it('should create new key entry if keyId matches and keysym does not', function() { + // this implies that a single keyup will release both keysyms + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x43)}; + keysymsdown[keysyms.lookup(0x43).keysym] = true; + obj(elem); + expect(times_called).to.be.equal(2); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0}; + obj(elem); + expect(times_called).to.be.equal(3); + elem = {type: 'keyup', keyId: 0}; + obj(elem); + expect(times_called).to.be.equal(4); + }); + it('should merge key entry if keyIds are zero and keysyms match', function() { + // this implies that a single keyup will release both keysyms + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(times_called).to.be.equal(2); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0}; + obj(elem); + expect(times_called).to.be.equal(3); + }); + it('should add keysym as separate entry if keyId does not match last event', function() { + // this implies that separate keyups are required + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keypress', keyId: 0x42, keysym: keysyms.lookup(0x43)}; + keysymsdown[keysyms.lookup(0x43).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0x41}; + obj(elem); + expect(times_called).to.be.equal(4); + elem = {type: 'keyup', keyId: 0x42}; + obj(elem); + expect(times_called).to.be.equal(4); + }); + it('should add keysym as separate entry if keyId does not match last event and first is zero', function() { + // this implies that separate keyups are required + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x43)}; + keysymsdown[keysyms.lookup(0x43).keysym] = true; + obj(elem); + expect(elem).to.be.null; + expect(times_called).to.be.equal(2); + elem = {type: 'keyup', keyId: 0}; + obj(elem); + expect(times_called).to.be.equal(3); + elem = {type: 'keyup', keyId: 0x42}; + obj(elem); + expect(times_called).to.be.equal(4); + }); + it('should add keysym as separate entry if keyId does not match last event and second is zero', function() { + // this implies that a separate keyups are required + var times_called = 0; + var elem = null; + var keysymsdown = {}; + var obj = TrackKeyState(function(evt) { + ++times_called; + if (elem.type == 'keyup') { + expect(evt).to.have.property('keysym'); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + delete keysymsdown[evt.keysym.keysym]; + } + else { + expect(evt).to.be.deep.equal(elem); + expect (keysymsdown[evt.keysym.keysym]).to.not.be.undefined; + elem = null; + } + }); + + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}; + keysymsdown[keysyms.lookup(0x42).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x43)}; + keysymsdown[keysyms.lookup(0x43).keysym] = true; + obj(elem); + expect(elem).to.be.null; + elem = {type: 'keyup', keyId: 0x41}; + obj(elem); + expect(times_called).to.be.equal(3); + elem = {type: 'keyup', keyId: 0}; + obj(elem); + expect(times_called).to.be.equal(4); + }); + it('should pop matching key event on keyup', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + switch (times_called++) { + case 0: + case 1: + case 2: + expect(evt.type).to.be.equal('keydown'); + break; + case 3: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x42, keysym: keysyms.lookup(0x62)}); + break; + } + }); + + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x61)}); + obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x62)}); + obj({type: 'keydown', keyId: 0x43, keysym: keysyms.lookup(0x63)}); + obj({type: 'keyup', keyId: 0x42}); + expect(times_called).to.equal(4); + }); + it('should pop the first zero keyevent on keyup with zero keyId', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + switch (times_called++) { + case 0: + case 1: + case 2: + expect(evt.type).to.be.equal('keydown'); + break; + case 3: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x61)}); + break; + } + }); + + obj({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x61)}); + obj({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0x62)}); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x63)}); + obj({type: 'keyup', keyId: 0x0}); + expect(times_called).to.equal(4); + }); + it('should pop the last keyevents keysym if no match is found for keyId', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + switch (times_called++) { + case 0: + case 1: + case 2: + expect(evt.type).to.be.equal('keydown'); + break; + case 3: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x44, keysym: keysyms.lookup(0x63)}); + break; + } + }); + + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x61)}); + obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x62)}); + obj({type: 'keydown', keyId: 0x43, keysym: keysyms.lookup(0x63)}); + obj({type: 'keyup', keyId: 0x44}); + expect(times_called).to.equal(4); + }); + describe('Firefox sends keypress even when keydown is suppressed', function() { + it('should discard the keypress', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + expect(times_called).to.be.equal(0); + ++times_called; + }); + + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + expect(times_called).to.be.equal(1); + obj({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x43)}); + }); + }); + describe('releaseAll', function() { + it('should do nothing if no keys have been pressed', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + ++times_called; + }); + obj({type: 'releaseall'}); + expect(times_called).to.be.equal(0); + }); + it('should release the keys that have been pressed', function() { + var times_called = 0; + var obj = TrackKeyState(function(evt) { + switch (times_called++) { + case 2: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x41)}); + break; + case 3: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x42)}); + break; + } + }); + obj({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)}); + obj({type: 'keydown', keyId: 0x42, keysym: keysyms.lookup(0x42)}); + expect(times_called).to.be.equal(2); + obj({type: 'releaseall'}); + expect(times_called).to.be.equal(4); + obj({type: 'releaseall'}); + expect(times_called).to.be.equal(4); + }); + }); + + }); + + describe('Escape Modifiers', function() { + describe('Keydown', function() { + it('should pass through when a char modifier is not down', function() { + var times_called = 0; + EscapeModifiers(function(evt) { + expect(times_called).to.be.equal(0); + ++times_called; + expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + expect(times_called).to.be.equal(1); + }); + it('should generate fake undo/redo events when a char modifier is down', function() { + var times_called = 0; + EscapeModifiers(function(evt) { + switch(times_called++) { + case 0: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0xffe9)}); + break; + case 1: + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0xffe3)}); + break; + case 2: + expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xffe9, 0xffe3]}); + break; + case 3: + expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0xffe9)}); + break; + case 4: + expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0, keysym: keysyms.lookup(0xffe3)}); + break; + } + })({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xffe9, 0xffe3]}); + expect(times_called).to.be.equal(5); + }); + }); + describe('Keyup', function() { + it('should pass through when a char modifier is down', function() { + var times_called = 0; + EscapeModifiers(function(evt) { + expect(times_called).to.be.equal(0); + ++times_called; + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xfe03]}); + })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xfe03]}); + expect(times_called).to.be.equal(1); + }); + it('should pass through when a char modifier is not down', function() { + var times_called = 0; + EscapeModifiers(function(evt) { + expect(times_called).to.be.equal(0); + ++times_called; + expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + })({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42)}); + expect(times_called).to.be.equal(1); + }); + }); + }); +}); From 9ceef041c6fc77af76c9b25cf4d287ee208cc072 Mon Sep 17 00:00:00 2001 From: jalf Date: Wed, 27 Nov 2013 15:17:32 +0100 Subject: [PATCH 019/100] Keyboard Handling [4/8]: Update input.html to work with new keyboard handling Plug new keyboard handling into input.js (which breaks everything else), and update input.html to work with this --- include/input.js | 1693 ++-------------------------------------------- tests/input.html | 19 +- 2 files changed, 73 insertions(+), 1639 deletions(-) diff --git a/include/input.js b/include/input.js index 8f0c650f..392b4107 100644 --- a/include/input.js +++ b/include/input.js @@ -35,305 +35,44 @@ Util.conf_defaults(conf, that, defaults, [ // Private functions // -// From the event keyCode return the keysym value for keys that need -// to be suppressed otherwise they may trigger unintended browser -// actions -function getKeysymSpecial(evt) { - var keysym = null; +/////// setup - switch ( evt.keyCode ) { - // These generate a keyDown and keyPress in Firefox and Opera - case 8 : keysym = 0xFF08; break; // BACKSPACE - case 13 : keysym = 0xFF0D; break; // ENTER - - // This generates a keyDown and keyPress in Opera - case 9 : keysym = 0xFF09; break; // TAB - default : break; +function onRfbEvent(evt) { + if (conf.onKeyPress) { + Util.Debug("onKeyPress " + (evt.type == 'keydown' ? "down" : "up") + + ", keysym: " + evt.keysym.keysym + "(" + evt.keysym.keyname + ")"); + conf.onKeyPress(evt.keysym.keysym, evt.type == 'keydown'); } - - if (evt.type === 'keydown') { - switch ( evt.keyCode ) { - case 27 : keysym = 0xFF1B; break; // ESCAPE - case 46 : keysym = 0xFFFF; break; // DELETE - - case 36 : keysym = 0xFF50; break; // HOME - case 35 : keysym = 0xFF57; break; // END - case 33 : keysym = 0xFF55; break; // PAGE_UP - case 34 : keysym = 0xFF56; break; // PAGE_DOWN - case 45 : keysym = 0xFF63; break; // INSERT - // '-' during keyPress - case 37 : keysym = 0xFF51; break; // LEFT - case 38 : keysym = 0xFF52; break; // UP - case 39 : keysym = 0xFF53; break; // RIGHT - case 40 : keysym = 0xFF54; break; // DOWN - case 16 : keysym = 0xFFE1; break; // SHIFT - case 17 : keysym = 0xFFE3; break; // CONTROL - //case 18 : keysym = 0xFFE7; break; // Left Meta (Mac Option) - case 18 : keysym = 0xFFE9; break; // Left ALT (Mac Command) - - case 112 : keysym = 0xFFBE; break; // F1 - case 113 : keysym = 0xFFBF; break; // F2 - case 114 : keysym = 0xFFC0; break; // F3 - case 115 : keysym = 0xFFC1; break; // F4 - case 116 : keysym = 0xFFC2; break; // F5 - case 117 : keysym = 0xFFC3; break; // F6 - case 118 : keysym = 0xFFC4; break; // F7 - case 119 : keysym = 0xFFC5; break; // F8 - case 120 : keysym = 0xFFC6; break; // F9 - case 121 : keysym = 0xFFC7; break; // F10 - case 122 : keysym = 0xFFC8; break; // F11 - case 123 : keysym = 0xFFC9; break; // F12 - - case 225 : keysym = 0xFE03; break; // AltGr - case 91 : keysym = 0xFFEC; break; // Super_R (Win Key) - case 93 : keysym = 0xFF67; break; // Menu (Win Menu) - - default : break; - } - } - - if ((!keysym) && (evt.ctrlKey || evt.altKey)) { - if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) { - keysym = evt.which; - } else { - // IE9 always - // Firefox and Opera when ctrl/alt + special - Util.Warn("which not set, using keyCode"); - keysym = evt.keyCode; - } - - /* Remap symbols */ - switch (keysym) { - case 186 : keysym = 59; break; // ; (IE) - case 187 : keysym = 61; break; // = (IE) - case 188 : keysym = 44; break; // , (Mozilla, IE) - case 109 : // - (Mozilla, Opera) - if (Util.Engine.gecko || Util.Engine.presto) { - keysym = 45; } - break; - case 173 : // - (Mozilla) - if (Util.Engine.gecko) { - keysym = 45; } - break; - case 189 : keysym = 45; break; // - (IE) - case 190 : keysym = 46; break; // . (Mozilla, IE) - case 191 : keysym = 47; break; // / (Mozilla, IE) - case 192 : keysym = 96; break; // ` (Mozilla, IE) - case 219 : keysym = 91; break; // [ (Mozilla, IE) - case 220 : keysym = 92; break; // \ (Mozilla, IE) - case 221 : keysym = 93; break; // ] (Mozilla, IE) - case 222 : keysym = 39; break; // ' (Mozilla, IE) - } - - /* Remap shifted and unshifted keys */ - if (!!evt.shiftKey) { - switch (keysym) { - case 48 : keysym = 41 ; break; // ) (shifted 0) - case 49 : keysym = 33 ; break; // ! (shifted 1) - case 50 : keysym = 64 ; break; // @ (shifted 2) - case 51 : keysym = 35 ; break; // # (shifted 3) - case 52 : keysym = 36 ; break; // $ (shifted 4) - case 53 : keysym = 37 ; break; // % (shifted 5) - case 54 : keysym = 94 ; break; // ^ (shifted 6) - case 55 : keysym = 38 ; break; // & (shifted 7) - case 56 : keysym = 42 ; break; // * (shifted 8) - case 57 : keysym = 40 ; break; // ( (shifted 9) - - case 59 : keysym = 58 ; break; // : (shifted `) - case 61 : keysym = 43 ; break; // + (shifted ;) - case 44 : keysym = 60 ; break; // < (shifted ,) - case 45 : keysym = 95 ; break; // _ (shifted -) - case 46 : keysym = 62 ; break; // > (shifted .) - case 47 : keysym = 63 ; break; // ? (shifted /) - case 96 : keysym = 126; break; // ~ (shifted `) - case 91 : keysym = 123; break; // { (shifted [) - case 92 : keysym = 124; break; // | (shifted \) - case 93 : keysym = 125; break; // } (shifted ]) - case 39 : keysym = 34 ; break; // " (shifted ') - } - } else if ((keysym >= 65) && (keysym <=90)) { - /* Remap unshifted A-Z */ - keysym += 32; - } else if (evt.keyLocation === 3) { - // numpad keys - switch (keysym) { - case 96 : keysym = 48; break; // 0 - case 97 : keysym = 49; break; // 1 - case 98 : keysym = 50; break; // 2 - case 99 : keysym = 51; break; // 3 - case 100: keysym = 52; break; // 4 - case 101: keysym = 53; break; // 5 - case 102: keysym = 54; break; // 6 - case 103: keysym = 55; break; // 7 - case 104: keysym = 56; break; // 8 - case 105: keysym = 57; break; // 9 - case 109: keysym = 45; break; // - - case 110: keysym = 46; break; // . - case 111: keysym = 47; break; // / - } - } - } - - return keysym; } -/* Translate DOM keyPress event to keysym value */ -function getKeysym(evt) { - var keysym, msg; - - if (typeof(evt.which) !== "undefined") { - // WebKit, Firefox, Opera - keysym = evt.which; - } else { - // IE9 - Util.Warn("which not set, using keyCode"); - keysym = evt.keyCode; - } - - if ((keysym > 255) && (keysym < 0xFF00)) { - msg = "Mapping character code " + keysym; - // Map Unicode outside Latin 1 to X11 keysyms - keysym = unicodeTable[keysym]; - if (typeof(keysym) === 'undefined') { - keysym = 0; - } - Util.Debug(msg + " to " + keysym); - } - - return keysym; -} - -function show_keyDownList(kind) { - var c; - var msg = "keyDownList (" + kind + "):\n"; - for (c = 0; c < keyDownList.length; c++) { - msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode + - " - which: " + keyDownList[c].which + "\n"; - } - Util.Debug(msg); -} - -function copyKeyEvent(evt) { - var members = ['type', 'keyCode', 'charCode', 'which', - 'altKey', 'ctrlKey', 'shiftKey', - 'keyLocation', 'keyIdentifier'], i, obj = {}; - for (i = 0; i < members.length; i++) { - if (typeof(evt[members[i]]) !== "undefined") { - obj[members[i]] = evt[members[i]]; - } - } - return obj; -} - -function pushKeyEvent(fevt) { - keyDownList.push(fevt); -} - -function getKeyEvent(keyCode, pop) { - var i, fevt = null; - for (i = keyDownList.length-1; i >= 0; i--) { - if (keyDownList[i].keyCode === keyCode) { - if ((typeof(pop) !== "undefined") && (pop)) { - fevt = keyDownList.splice(i, 1)[0]; - } else { - fevt = keyDownList[i]; - } - break; - } - } - return fevt; -} - -function ignoreKeyEvent(evt) { - // Blarg. Some keys have a different keyCode on keyDown vs keyUp - if (evt.keyCode === 229) { - // French AZERTY keyboard dead key. - // Lame thing is that the respective keyUp is 219 so we can't - // properly ignore the keyUp event - return true; - } - return false; -} - - -// -// Key Event Handling: -// -// There are several challenges when dealing with key events: -// - The meaning and use of keyCode, charCode and which depends on -// both the browser and the event type (keyDown/Up vs keyPress). -// - We cannot automatically determine the keyboard layout -// - The keyDown and keyUp events have a keyCode value that has not -// been translated by modifier keys. -// - The keyPress event has a translated (for layout and modifiers) -// character code but the attribute containing it differs. keyCode -// contains the translated value in WebKit (Chrome/Safari), Opera -// 11 and IE9. charCode contains the value in WebKit and Firefox. -// The which attribute contains the value on WebKit, Firefox and -// Opera 11. -// - The keyDown/Up keyCode value indicates (sort of) the physical -// key was pressed but only for standard US layout. On a US -// keyboard, the '-' and '_' characters are on the same key and -// generate a keyCode value of 189. But on an AZERTY keyboard even -// though they are different physical keys they both still -// generate a keyCode of 189! -// - To prevent a key event from propagating to the browser and -// causing unwanted default actions (such as closing a tab, -// opening a menu, shifting focus, etc) we must suppress this -// event in both keyDown and keyPress because not all key strokes -// generate on a keyPress event. Also, in WebKit and IE9 -// suppressing the keyDown prevents a keyPress but other browsers -// still generated a keyPress even if keyDown is suppressed. -// -// For safe key events, we wait until the keyPress event before -// reporting a key down event. For unsafe key events, we report a key -// down event when the keyDown event fires and we suppress any further -// actions (including keyPress). -// -// In order to report a key up event that matches what we reported -// for the key down event, we keep a list of keys that are currently -// down. When the keyDown event happens, we add the key event to the -// list. If it is a safe key event, then we update the which attribute -// in the most recent item on the list when we received a keyPress -// event (keyPress should immediately follow keyDown). When we -// received a keyUp event we search for the event on the list with -// a matching keyCode and we report the character code using the value -// in the 'which' attribute that was stored with that key. -// +// create the keyboard handler +var k = KeyEventDecoder(kbdUtil.ModifierSync(), + VerifyCharModifier( + TrackKeyState( + EscapeModifiers(onRfbEvent) + ) + ) +); function onKeyDown(e) { if (! conf.focused) { return true; } - var fevt = null, evt = (e ? e : window.event), - keysym = null, suppress = false; - //Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - fevt = copyKeyEvent(evt); - - keysym = getKeysymSpecial(evt); - // Save keysym decoding for use in keyUp - fevt.keysym = keysym; - if (keysym) { - // If it is a key or key combination that might trigger - // browser behaviors or it has no corresponding keyPress - // event, then send it immediately - if (conf.onKeyPress && !ignoreKeyEvent(evt)) { - Util.Debug("onKeyPress down, keysym: " + keysym + - " (onKeyDown key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 1, evt); - } - suppress = true; + if (k.keydown(e)) { + // Suppress bubbling/default actions + Util.stopEvent(e); + return false; + } else { + // Allow the event to bubble and become a keyPress event which + // will have the character code translated + return true; } - - if (! ignoreKeyEvent(evt)) { - // Add it to the list of depressed keys - pushKeyEvent(fevt); - //show_keyDownList('down'); +} +function onKeyPress(e) { + if (! conf.focused) { + return true; } - - if (suppress) { + if (k.keypress(e)) { // Suppress bubbling/default actions Util.stopEvent(e); return false; @@ -344,101 +83,30 @@ function onKeyDown(e) { } } -function onKeyPress(e) { - if (! conf.focused) { - return true; - } - var evt = (e ? e : window.event), - kdlen = keyDownList.length, keysym = null; - //Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - if (((evt.which !== "undefined") && (evt.which === 0)) || - (getKeysymSpecial(evt))) { - // Firefox and Opera generate a keyPress event even if keyDown - // is suppressed. But the keys we want to suppress will have - // either: - // - the which attribute set to 0 - // - getKeysymSpecial() will identify it - Util.Debug("Ignoring special key in keyPress"); - Util.stopEvent(e); - return false; - } - - keysym = getKeysym(evt); - - // Modify the the which attribute in the depressed keys list so - // that the keyUp event will be able to have the character code - // translation available. - if (kdlen > 0) { - keyDownList[kdlen-1].keysym = keysym; - } else { - Util.Warn("keyDownList empty when keyPress triggered"); - } - - //show_keyDownList('press'); - - // Send the translated keysym - if (conf.onKeyPress && (keysym > 0)) { - Util.Debug("onKeyPress down, keysym: " + keysym + - " (onKeyPress key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 1, evt); - } - - // Stop keypress events just in case - Util.stopEvent(e); - return false; -} - function onKeyUp(e) { if (! conf.focused) { return true; } - var fevt = null, evt = (e ? e : window.event), keysym; - //Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - fevt = getKeyEvent(evt.keyCode, true); - - if (fevt) { - keysym = fevt.keysym; + if (k.keyup(e)) { + // Suppress bubbling/default actions + Util.stopEvent(e); + return false; } else { - Util.Warn("Key event (keyCode = " + evt.keyCode + - ") not found on keyDownList"); - keysym = 0; + // Allow the event to bubble and become a keyPress event which + // will have the character code translated + return true; } +} - //show_keyDownList('up'); - - if (conf.onKeyPress && (keysym > 0)) { - //Util.Debug("keyPress up, keysym: " + keysym + - // " (key: " + evt.keyCode + ", which: " + evt.which + ")"); - Util.Debug("onKeyPress up, keysym: " + keysym + - " (onKeyPress key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 0, evt); - } - Util.stopEvent(e); - return false; +function onOther(e) { + k.syncModifiers(e); } function allKeysUp() { Util.Debug(">> Keyboard.allKeysUp"); - if (keyDownList.length > 0) { - Util.Info("Releasing pressed/down keys"); - } - var i, keysym, fevt = null; - for (i = keyDownList.length-1; i >= 0; i--) { - fevt = keyDownList.splice(i, 1)[0]; - keysym = fevt.keysym; - if (conf.onKeyPress && (keysym > 0)) { - Util.Debug("allKeysUp, keysym: " + keysym + - " (keyCode: " + fevt.keyCode + - ", which: " + fevt.which + ")"); - conf.onKeyPress(keysym, 0, fevt); - } - } + + k.releaseAll(); Util.Debug("<< Keyboard.allKeysUp"); - return; } // @@ -474,6 +142,10 @@ that.ungrab = function() { //Util.Debug(">> Keyboard.ungrab"); }; +that.sync = function(e) { + k.syncModifiers(e); +} + return that; // Return the public API interface } // End of Keyboard() @@ -496,6 +168,7 @@ var doubleClickTimer = null, // Configuration attributes Util.conf_defaults(conf, that, defaults, [ ['target', 'ro', 'dom', document, 'DOM element that captures mouse input'], + ['notify', 'ro', 'func', null, 'Function to call to notify whenever a mouse event is received'], ['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'], ['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'], @@ -534,6 +207,11 @@ function onMouseButton(e, down) { if (! conf.focused) { return true; } + + if (conf.notify) { + conf.notify(e); + } + evt = (e ? e : window.event); pos = Util.getEventPosition(e, conf.target, conf.scale); @@ -605,6 +283,10 @@ function onMouseWheel(e) { if (! conf.focused) { return true; } + if (conf.notify) { + conf.notify(e); + } + evt = (e ? e : window.event); pos = Util.getEventPosition(e, conf.target, conf.scale); wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40; @@ -627,6 +309,10 @@ function onMouseMove(e) { if (! conf.focused) { return true; } + if (conf.notify) { + conf.notify(e); + } + evt = (e ? e : window.event); pos = Util.getEventPosition(e, conf.target, conf.scale); //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y); @@ -713,1268 +399,3 @@ that.ungrab = function() { return that; // Return the public API interface } // End of Mouse() - - -/* - * Browser keypress to X11 keysym for Unicode characters > U+00FF - */ -unicodeTable = { - 0x0104 : 0x01a1, - 0x02D8 : 0x01a2, - 0x0141 : 0x01a3, - 0x013D : 0x01a5, - 0x015A : 0x01a6, - 0x0160 : 0x01a9, - 0x015E : 0x01aa, - 0x0164 : 0x01ab, - 0x0179 : 0x01ac, - 0x017D : 0x01ae, - 0x017B : 0x01af, - 0x0105 : 0x01b1, - 0x02DB : 0x01b2, - 0x0142 : 0x01b3, - 0x013E : 0x01b5, - 0x015B : 0x01b6, - 0x02C7 : 0x01b7, - 0x0161 : 0x01b9, - 0x015F : 0x01ba, - 0x0165 : 0x01bb, - 0x017A : 0x01bc, - 0x02DD : 0x01bd, - 0x017E : 0x01be, - 0x017C : 0x01bf, - 0x0154 : 0x01c0, - 0x0102 : 0x01c3, - 0x0139 : 0x01c5, - 0x0106 : 0x01c6, - 0x010C : 0x01c8, - 0x0118 : 0x01ca, - 0x011A : 0x01cc, - 0x010E : 0x01cf, - 0x0110 : 0x01d0, - 0x0143 : 0x01d1, - 0x0147 : 0x01d2, - 0x0150 : 0x01d5, - 0x0158 : 0x01d8, - 0x016E : 0x01d9, - 0x0170 : 0x01db, - 0x0162 : 0x01de, - 0x0155 : 0x01e0, - 0x0103 : 0x01e3, - 0x013A : 0x01e5, - 0x0107 : 0x01e6, - 0x010D : 0x01e8, - 0x0119 : 0x01ea, - 0x011B : 0x01ec, - 0x010F : 0x01ef, - 0x0111 : 0x01f0, - 0x0144 : 0x01f1, - 0x0148 : 0x01f2, - 0x0151 : 0x01f5, - 0x0171 : 0x01fb, - 0x0159 : 0x01f8, - 0x016F : 0x01f9, - 0x0163 : 0x01fe, - 0x02D9 : 0x01ff, - 0x0126 : 0x02a1, - 0x0124 : 0x02a6, - 0x0130 : 0x02a9, - 0x011E : 0x02ab, - 0x0134 : 0x02ac, - 0x0127 : 0x02b1, - 0x0125 : 0x02b6, - 0x0131 : 0x02b9, - 0x011F : 0x02bb, - 0x0135 : 0x02bc, - 0x010A : 0x02c5, - 0x0108 : 0x02c6, - 0x0120 : 0x02d5, - 0x011C : 0x02d8, - 0x016C : 0x02dd, - 0x015C : 0x02de, - 0x010B : 0x02e5, - 0x0109 : 0x02e6, - 0x0121 : 0x02f5, - 0x011D : 0x02f8, - 0x016D : 0x02fd, - 0x015D : 0x02fe, - 0x0138 : 0x03a2, - 0x0156 : 0x03a3, - 0x0128 : 0x03a5, - 0x013B : 0x03a6, - 0x0112 : 0x03aa, - 0x0122 : 0x03ab, - 0x0166 : 0x03ac, - 0x0157 : 0x03b3, - 0x0129 : 0x03b5, - 0x013C : 0x03b6, - 0x0113 : 0x03ba, - 0x0123 : 0x03bb, - 0x0167 : 0x03bc, - 0x014A : 0x03bd, - 0x014B : 0x03bf, - 0x0100 : 0x03c0, - 0x012E : 0x03c7, - 0x0116 : 0x03cc, - 0x012A : 0x03cf, - 0x0145 : 0x03d1, - 0x014C : 0x03d2, - 0x0136 : 0x03d3, - 0x0172 : 0x03d9, - 0x0168 : 0x03dd, - 0x016A : 0x03de, - 0x0101 : 0x03e0, - 0x012F : 0x03e7, - 0x0117 : 0x03ec, - 0x012B : 0x03ef, - 0x0146 : 0x03f1, - 0x014D : 0x03f2, - 0x0137 : 0x03f3, - 0x0173 : 0x03f9, - 0x0169 : 0x03fd, - 0x016B : 0x03fe, - 0x1E02 : 0x1001e02, - 0x1E03 : 0x1001e03, - 0x1E0A : 0x1001e0a, - 0x1E80 : 0x1001e80, - 0x1E82 : 0x1001e82, - 0x1E0B : 0x1001e0b, - 0x1EF2 : 0x1001ef2, - 0x1E1E : 0x1001e1e, - 0x1E1F : 0x1001e1f, - 0x1E40 : 0x1001e40, - 0x1E41 : 0x1001e41, - 0x1E56 : 0x1001e56, - 0x1E81 : 0x1001e81, - 0x1E57 : 0x1001e57, - 0x1E83 : 0x1001e83, - 0x1E60 : 0x1001e60, - 0x1EF3 : 0x1001ef3, - 0x1E84 : 0x1001e84, - 0x1E85 : 0x1001e85, - 0x1E61 : 0x1001e61, - 0x0174 : 0x1000174, - 0x1E6A : 0x1001e6a, - 0x0176 : 0x1000176, - 0x0175 : 0x1000175, - 0x1E6B : 0x1001e6b, - 0x0177 : 0x1000177, - 0x0152 : 0x13bc, - 0x0153 : 0x13bd, - 0x0178 : 0x13be, - 0x203E : 0x047e, - 0x3002 : 0x04a1, - 0x300C : 0x04a2, - 0x300D : 0x04a3, - 0x3001 : 0x04a4, - 0x30FB : 0x04a5, - 0x30F2 : 0x04a6, - 0x30A1 : 0x04a7, - 0x30A3 : 0x04a8, - 0x30A5 : 0x04a9, - 0x30A7 : 0x04aa, - 0x30A9 : 0x04ab, - 0x30E3 : 0x04ac, - 0x30E5 : 0x04ad, - 0x30E7 : 0x04ae, - 0x30C3 : 0x04af, - 0x30FC : 0x04b0, - 0x30A2 : 0x04b1, - 0x30A4 : 0x04b2, - 0x30A6 : 0x04b3, - 0x30A8 : 0x04b4, - 0x30AA : 0x04b5, - 0x30AB : 0x04b6, - 0x30AD : 0x04b7, - 0x30AF : 0x04b8, - 0x30B1 : 0x04b9, - 0x30B3 : 0x04ba, - 0x30B5 : 0x04bb, - 0x30B7 : 0x04bc, - 0x30B9 : 0x04bd, - 0x30BB : 0x04be, - 0x30BD : 0x04bf, - 0x30BF : 0x04c0, - 0x30C1 : 0x04c1, - 0x30C4 : 0x04c2, - 0x30C6 : 0x04c3, - 0x30C8 : 0x04c4, - 0x30CA : 0x04c5, - 0x30CB : 0x04c6, - 0x30CC : 0x04c7, - 0x30CD : 0x04c8, - 0x30CE : 0x04c9, - 0x30CF : 0x04ca, - 0x30D2 : 0x04cb, - 0x30D5 : 0x04cc, - 0x30D8 : 0x04cd, - 0x30DB : 0x04ce, - 0x30DE : 0x04cf, - 0x30DF : 0x04d0, - 0x30E0 : 0x04d1, - 0x30E1 : 0x04d2, - 0x30E2 : 0x04d3, - 0x30E4 : 0x04d4, - 0x30E6 : 0x04d5, - 0x30E8 : 0x04d6, - 0x30E9 : 0x04d7, - 0x30EA : 0x04d8, - 0x30EB : 0x04d9, - 0x30EC : 0x04da, - 0x30ED : 0x04db, - 0x30EF : 0x04dc, - 0x30F3 : 0x04dd, - 0x309B : 0x04de, - 0x309C : 0x04df, - 0x06F0 : 0x10006f0, - 0x06F1 : 0x10006f1, - 0x06F2 : 0x10006f2, - 0x06F3 : 0x10006f3, - 0x06F4 : 0x10006f4, - 0x06F5 : 0x10006f5, - 0x06F6 : 0x10006f6, - 0x06F7 : 0x10006f7, - 0x06F8 : 0x10006f8, - 0x06F9 : 0x10006f9, - 0x066A : 0x100066a, - 0x0670 : 0x1000670, - 0x0679 : 0x1000679, - 0x067E : 0x100067e, - 0x0686 : 0x1000686, - 0x0688 : 0x1000688, - 0x0691 : 0x1000691, - 0x060C : 0x05ac, - 0x06D4 : 0x10006d4, - 0x0660 : 0x1000660, - 0x0661 : 0x1000661, - 0x0662 : 0x1000662, - 0x0663 : 0x1000663, - 0x0664 : 0x1000664, - 0x0665 : 0x1000665, - 0x0666 : 0x1000666, - 0x0667 : 0x1000667, - 0x0668 : 0x1000668, - 0x0669 : 0x1000669, - 0x061B : 0x05bb, - 0x061F : 0x05bf, - 0x0621 : 0x05c1, - 0x0622 : 0x05c2, - 0x0623 : 0x05c3, - 0x0624 : 0x05c4, - 0x0625 : 0x05c5, - 0x0626 : 0x05c6, - 0x0627 : 0x05c7, - 0x0628 : 0x05c8, - 0x0629 : 0x05c9, - 0x062A : 0x05ca, - 0x062B : 0x05cb, - 0x062C : 0x05cc, - 0x062D : 0x05cd, - 0x062E : 0x05ce, - 0x062F : 0x05cf, - 0x0630 : 0x05d0, - 0x0631 : 0x05d1, - 0x0632 : 0x05d2, - 0x0633 : 0x05d3, - 0x0634 : 0x05d4, - 0x0635 : 0x05d5, - 0x0636 : 0x05d6, - 0x0637 : 0x05d7, - 0x0638 : 0x05d8, - 0x0639 : 0x05d9, - 0x063A : 0x05da, - 0x0640 : 0x05e0, - 0x0641 : 0x05e1, - 0x0642 : 0x05e2, - 0x0643 : 0x05e3, - 0x0644 : 0x05e4, - 0x0645 : 0x05e5, - 0x0646 : 0x05e6, - 0x0647 : 0x05e7, - 0x0648 : 0x05e8, - 0x0649 : 0x05e9, - 0x064A : 0x05ea, - 0x064B : 0x05eb, - 0x064C : 0x05ec, - 0x064D : 0x05ed, - 0x064E : 0x05ee, - 0x064F : 0x05ef, - 0x0650 : 0x05f0, - 0x0651 : 0x05f1, - 0x0652 : 0x05f2, - 0x0653 : 0x1000653, - 0x0654 : 0x1000654, - 0x0655 : 0x1000655, - 0x0698 : 0x1000698, - 0x06A4 : 0x10006a4, - 0x06A9 : 0x10006a9, - 0x06AF : 0x10006af, - 0x06BA : 0x10006ba, - 0x06BE : 0x10006be, - 0x06CC : 0x10006cc, - 0x06D2 : 0x10006d2, - 0x06C1 : 0x10006c1, - 0x0492 : 0x1000492, - 0x0493 : 0x1000493, - 0x0496 : 0x1000496, - 0x0497 : 0x1000497, - 0x049A : 0x100049a, - 0x049B : 0x100049b, - 0x049C : 0x100049c, - 0x049D : 0x100049d, - 0x04A2 : 0x10004a2, - 0x04A3 : 0x10004a3, - 0x04AE : 0x10004ae, - 0x04AF : 0x10004af, - 0x04B0 : 0x10004b0, - 0x04B1 : 0x10004b1, - 0x04B2 : 0x10004b2, - 0x04B3 : 0x10004b3, - 0x04B6 : 0x10004b6, - 0x04B7 : 0x10004b7, - 0x04B8 : 0x10004b8, - 0x04B9 : 0x10004b9, - 0x04BA : 0x10004ba, - 0x04BB : 0x10004bb, - 0x04D8 : 0x10004d8, - 0x04D9 : 0x10004d9, - 0x04E2 : 0x10004e2, - 0x04E3 : 0x10004e3, - 0x04E8 : 0x10004e8, - 0x04E9 : 0x10004e9, - 0x04EE : 0x10004ee, - 0x04EF : 0x10004ef, - 0x0452 : 0x06a1, - 0x0453 : 0x06a2, - 0x0451 : 0x06a3, - 0x0454 : 0x06a4, - 0x0455 : 0x06a5, - 0x0456 : 0x06a6, - 0x0457 : 0x06a7, - 0x0458 : 0x06a8, - 0x0459 : 0x06a9, - 0x045A : 0x06aa, - 0x045B : 0x06ab, - 0x045C : 0x06ac, - 0x0491 : 0x06ad, - 0x045E : 0x06ae, - 0x045F : 0x06af, - 0x2116 : 0x06b0, - 0x0402 : 0x06b1, - 0x0403 : 0x06b2, - 0x0401 : 0x06b3, - 0x0404 : 0x06b4, - 0x0405 : 0x06b5, - 0x0406 : 0x06b6, - 0x0407 : 0x06b7, - 0x0408 : 0x06b8, - 0x0409 : 0x06b9, - 0x040A : 0x06ba, - 0x040B : 0x06bb, - 0x040C : 0x06bc, - 0x0490 : 0x06bd, - 0x040E : 0x06be, - 0x040F : 0x06bf, - 0x044E : 0x06c0, - 0x0430 : 0x06c1, - 0x0431 : 0x06c2, - 0x0446 : 0x06c3, - 0x0434 : 0x06c4, - 0x0435 : 0x06c5, - 0x0444 : 0x06c6, - 0x0433 : 0x06c7, - 0x0445 : 0x06c8, - 0x0438 : 0x06c9, - 0x0439 : 0x06ca, - 0x043A : 0x06cb, - 0x043B : 0x06cc, - 0x043C : 0x06cd, - 0x043D : 0x06ce, - 0x043E : 0x06cf, - 0x043F : 0x06d0, - 0x044F : 0x06d1, - 0x0440 : 0x06d2, - 0x0441 : 0x06d3, - 0x0442 : 0x06d4, - 0x0443 : 0x06d5, - 0x0436 : 0x06d6, - 0x0432 : 0x06d7, - 0x044C : 0x06d8, - 0x044B : 0x06d9, - 0x0437 : 0x06da, - 0x0448 : 0x06db, - 0x044D : 0x06dc, - 0x0449 : 0x06dd, - 0x0447 : 0x06de, - 0x044A : 0x06df, - 0x042E : 0x06e0, - 0x0410 : 0x06e1, - 0x0411 : 0x06e2, - 0x0426 : 0x06e3, - 0x0414 : 0x06e4, - 0x0415 : 0x06e5, - 0x0424 : 0x06e6, - 0x0413 : 0x06e7, - 0x0425 : 0x06e8, - 0x0418 : 0x06e9, - 0x0419 : 0x06ea, - 0x041A : 0x06eb, - 0x041B : 0x06ec, - 0x041C : 0x06ed, - 0x041D : 0x06ee, - 0x041E : 0x06ef, - 0x041F : 0x06f0, - 0x042F : 0x06f1, - 0x0420 : 0x06f2, - 0x0421 : 0x06f3, - 0x0422 : 0x06f4, - 0x0423 : 0x06f5, - 0x0416 : 0x06f6, - 0x0412 : 0x06f7, - 0x042C : 0x06f8, - 0x042B : 0x06f9, - 0x0417 : 0x06fa, - 0x0428 : 0x06fb, - 0x042D : 0x06fc, - 0x0429 : 0x06fd, - 0x0427 : 0x06fe, - 0x042A : 0x06ff, - 0x0386 : 0x07a1, - 0x0388 : 0x07a2, - 0x0389 : 0x07a3, - 0x038A : 0x07a4, - 0x03AA : 0x07a5, - 0x038C : 0x07a7, - 0x038E : 0x07a8, - 0x03AB : 0x07a9, - 0x038F : 0x07ab, - 0x0385 : 0x07ae, - 0x2015 : 0x07af, - 0x03AC : 0x07b1, - 0x03AD : 0x07b2, - 0x03AE : 0x07b3, - 0x03AF : 0x07b4, - 0x03CA : 0x07b5, - 0x0390 : 0x07b6, - 0x03CC : 0x07b7, - 0x03CD : 0x07b8, - 0x03CB : 0x07b9, - 0x03B0 : 0x07ba, - 0x03CE : 0x07bb, - 0x0391 : 0x07c1, - 0x0392 : 0x07c2, - 0x0393 : 0x07c3, - 0x0394 : 0x07c4, - 0x0395 : 0x07c5, - 0x0396 : 0x07c6, - 0x0397 : 0x07c7, - 0x0398 : 0x07c8, - 0x0399 : 0x07c9, - 0x039A : 0x07ca, - 0x039B : 0x07cb, - 0x039C : 0x07cc, - 0x039D : 0x07cd, - 0x039E : 0x07ce, - 0x039F : 0x07cf, - 0x03A0 : 0x07d0, - 0x03A1 : 0x07d1, - 0x03A3 : 0x07d2, - 0x03A4 : 0x07d4, - 0x03A5 : 0x07d5, - 0x03A6 : 0x07d6, - 0x03A7 : 0x07d7, - 0x03A8 : 0x07d8, - 0x03A9 : 0x07d9, - 0x03B1 : 0x07e1, - 0x03B2 : 0x07e2, - 0x03B3 : 0x07e3, - 0x03B4 : 0x07e4, - 0x03B5 : 0x07e5, - 0x03B6 : 0x07e6, - 0x03B7 : 0x07e7, - 0x03B8 : 0x07e8, - 0x03B9 : 0x07e9, - 0x03BA : 0x07ea, - 0x03BB : 0x07eb, - 0x03BC : 0x07ec, - 0x03BD : 0x07ed, - 0x03BE : 0x07ee, - 0x03BF : 0x07ef, - 0x03C0 : 0x07f0, - 0x03C1 : 0x07f1, - 0x03C3 : 0x07f2, - 0x03C2 : 0x07f3, - 0x03C4 : 0x07f4, - 0x03C5 : 0x07f5, - 0x03C6 : 0x07f6, - 0x03C7 : 0x07f7, - 0x03C8 : 0x07f8, - 0x03C9 : 0x07f9, - 0x23B7 : 0x08a1, - 0x2320 : 0x08a4, - 0x2321 : 0x08a5, - 0x23A1 : 0x08a7, - 0x23A3 : 0x08a8, - 0x23A4 : 0x08a9, - 0x23A6 : 0x08aa, - 0x239B : 0x08ab, - 0x239D : 0x08ac, - 0x239E : 0x08ad, - 0x23A0 : 0x08ae, - 0x23A8 : 0x08af, - 0x23AC : 0x08b0, - 0x2264 : 0x08bc, - 0x2260 : 0x08bd, - 0x2265 : 0x08be, - 0x222B : 0x08bf, - 0x2234 : 0x08c0, - 0x221D : 0x08c1, - 0x221E : 0x08c2, - 0x2207 : 0x08c5, - 0x223C : 0x08c8, - 0x2243 : 0x08c9, - 0x21D4 : 0x08cd, - 0x21D2 : 0x08ce, - 0x2261 : 0x08cf, - //0x221A : 0x08d6, - 0x2282 : 0x08da, - 0x2283 : 0x08db, - 0x2229 : 0x08dc, - 0x222A : 0x08dd, - 0x2227 : 0x08de, - 0x2228 : 0x08df, - //0x2202 : 0x08ef, - 0x0192 : 0x08f6, - 0x2190 : 0x08fb, - 0x2191 : 0x08fc, - 0x2192 : 0x08fd, - 0x2193 : 0x08fe, - 0x25C6 : 0x09e0, - 0x2592 : 0x09e1, - 0x2409 : 0x09e2, - 0x240C : 0x09e3, - 0x240D : 0x09e4, - 0x240A : 0x09e5, - 0x2424 : 0x09e8, - 0x240B : 0x09e9, - 0x2518 : 0x09ea, - 0x2510 : 0x09eb, - 0x250C : 0x09ec, - 0x2514 : 0x09ed, - 0x253C : 0x09ee, - 0x23BA : 0x09ef, - 0x23BB : 0x09f0, - 0x2500 : 0x09f1, - 0x23BC : 0x09f2, - 0x23BD : 0x09f3, - 0x251C : 0x09f4, - 0x2524 : 0x09f5, - 0x2534 : 0x09f6, - 0x252C : 0x09f7, - 0x2502 : 0x09f8, - 0x2003 : 0x0aa1, - 0x2002 : 0x0aa2, - 0x2004 : 0x0aa3, - 0x2005 : 0x0aa4, - 0x2007 : 0x0aa5, - 0x2008 : 0x0aa6, - 0x2009 : 0x0aa7, - 0x200A : 0x0aa8, - 0x2014 : 0x0aa9, - 0x2013 : 0x0aaa, - 0x2026 : 0x0aae, - 0x2025 : 0x0aaf, - 0x2153 : 0x0ab0, - 0x2154 : 0x0ab1, - 0x2155 : 0x0ab2, - 0x2156 : 0x0ab3, - 0x2157 : 0x0ab4, - 0x2158 : 0x0ab5, - 0x2159 : 0x0ab6, - 0x215A : 0x0ab7, - 0x2105 : 0x0ab8, - 0x2012 : 0x0abb, - 0x215B : 0x0ac3, - 0x215C : 0x0ac4, - 0x215D : 0x0ac5, - 0x215E : 0x0ac6, - 0x2122 : 0x0ac9, - 0x2018 : 0x0ad0, - 0x2019 : 0x0ad1, - 0x201C : 0x0ad2, - 0x201D : 0x0ad3, - 0x211E : 0x0ad4, - 0x2032 : 0x0ad6, - 0x2033 : 0x0ad7, - 0x271D : 0x0ad9, - 0x2663 : 0x0aec, - 0x2666 : 0x0aed, - 0x2665 : 0x0aee, - 0x2720 : 0x0af0, - 0x2020 : 0x0af1, - 0x2021 : 0x0af2, - 0x2713 : 0x0af3, - 0x2717 : 0x0af4, - 0x266F : 0x0af5, - 0x266D : 0x0af6, - 0x2642 : 0x0af7, - 0x2640 : 0x0af8, - 0x260E : 0x0af9, - 0x2315 : 0x0afa, - 0x2117 : 0x0afb, - 0x2038 : 0x0afc, - 0x201A : 0x0afd, - 0x201E : 0x0afe, - 0x22A4 : 0x0bc2, - 0x230A : 0x0bc4, - 0x2218 : 0x0bca, - 0x2395 : 0x0bcc, - 0x22A5 : 0x0bce, - 0x25CB : 0x0bcf, - 0x2308 : 0x0bd3, - 0x22A3 : 0x0bdc, - 0x22A2 : 0x0bfc, - 0x2017 : 0x0cdf, - 0x05D0 : 0x0ce0, - 0x05D1 : 0x0ce1, - 0x05D2 : 0x0ce2, - 0x05D3 : 0x0ce3, - 0x05D4 : 0x0ce4, - 0x05D5 : 0x0ce5, - 0x05D6 : 0x0ce6, - 0x05D7 : 0x0ce7, - 0x05D8 : 0x0ce8, - 0x05D9 : 0x0ce9, - 0x05DA : 0x0cea, - 0x05DB : 0x0ceb, - 0x05DC : 0x0cec, - 0x05DD : 0x0ced, - 0x05DE : 0x0cee, - 0x05DF : 0x0cef, - 0x05E0 : 0x0cf0, - 0x05E1 : 0x0cf1, - 0x05E2 : 0x0cf2, - 0x05E3 : 0x0cf3, - 0x05E4 : 0x0cf4, - 0x05E5 : 0x0cf5, - 0x05E6 : 0x0cf6, - 0x05E7 : 0x0cf7, - 0x05E8 : 0x0cf8, - 0x05E9 : 0x0cf9, - 0x05EA : 0x0cfa, - 0x0E01 : 0x0da1, - 0x0E02 : 0x0da2, - 0x0E03 : 0x0da3, - 0x0E04 : 0x0da4, - 0x0E05 : 0x0da5, - 0x0E06 : 0x0da6, - 0x0E07 : 0x0da7, - 0x0E08 : 0x0da8, - 0x0E09 : 0x0da9, - 0x0E0A : 0x0daa, - 0x0E0B : 0x0dab, - 0x0E0C : 0x0dac, - 0x0E0D : 0x0dad, - 0x0E0E : 0x0dae, - 0x0E0F : 0x0daf, - 0x0E10 : 0x0db0, - 0x0E11 : 0x0db1, - 0x0E12 : 0x0db2, - 0x0E13 : 0x0db3, - 0x0E14 : 0x0db4, - 0x0E15 : 0x0db5, - 0x0E16 : 0x0db6, - 0x0E17 : 0x0db7, - 0x0E18 : 0x0db8, - 0x0E19 : 0x0db9, - 0x0E1A : 0x0dba, - 0x0E1B : 0x0dbb, - 0x0E1C : 0x0dbc, - 0x0E1D : 0x0dbd, - 0x0E1E : 0x0dbe, - 0x0E1F : 0x0dbf, - 0x0E20 : 0x0dc0, - 0x0E21 : 0x0dc1, - 0x0E22 : 0x0dc2, - 0x0E23 : 0x0dc3, - 0x0E24 : 0x0dc4, - 0x0E25 : 0x0dc5, - 0x0E26 : 0x0dc6, - 0x0E27 : 0x0dc7, - 0x0E28 : 0x0dc8, - 0x0E29 : 0x0dc9, - 0x0E2A : 0x0dca, - 0x0E2B : 0x0dcb, - 0x0E2C : 0x0dcc, - 0x0E2D : 0x0dcd, - 0x0E2E : 0x0dce, - 0x0E2F : 0x0dcf, - 0x0E30 : 0x0dd0, - 0x0E31 : 0x0dd1, - 0x0E32 : 0x0dd2, - 0x0E33 : 0x0dd3, - 0x0E34 : 0x0dd4, - 0x0E35 : 0x0dd5, - 0x0E36 : 0x0dd6, - 0x0E37 : 0x0dd7, - 0x0E38 : 0x0dd8, - 0x0E39 : 0x0dd9, - 0x0E3A : 0x0dda, - 0x0E3F : 0x0ddf, - 0x0E40 : 0x0de0, - 0x0E41 : 0x0de1, - 0x0E42 : 0x0de2, - 0x0E43 : 0x0de3, - 0x0E44 : 0x0de4, - 0x0E45 : 0x0de5, - 0x0E46 : 0x0de6, - 0x0E47 : 0x0de7, - 0x0E48 : 0x0de8, - 0x0E49 : 0x0de9, - 0x0E4A : 0x0dea, - 0x0E4B : 0x0deb, - 0x0E4C : 0x0dec, - 0x0E4D : 0x0ded, - 0x0E50 : 0x0df0, - 0x0E51 : 0x0df1, - 0x0E52 : 0x0df2, - 0x0E53 : 0x0df3, - 0x0E54 : 0x0df4, - 0x0E55 : 0x0df5, - 0x0E56 : 0x0df6, - 0x0E57 : 0x0df7, - 0x0E58 : 0x0df8, - 0x0E59 : 0x0df9, - 0x0587 : 0x1000587, - 0x0589 : 0x1000589, - 0x055D : 0x100055d, - 0x058A : 0x100058a, - 0x055C : 0x100055c, - 0x055B : 0x100055b, - 0x055E : 0x100055e, - 0x0531 : 0x1000531, - 0x0561 : 0x1000561, - 0x0532 : 0x1000532, - 0x0562 : 0x1000562, - 0x0533 : 0x1000533, - 0x0563 : 0x1000563, - 0x0534 : 0x1000534, - 0x0564 : 0x1000564, - 0x0535 : 0x1000535, - 0x0565 : 0x1000565, - 0x0536 : 0x1000536, - 0x0566 : 0x1000566, - 0x0537 : 0x1000537, - 0x0567 : 0x1000567, - 0x0538 : 0x1000538, - 0x0568 : 0x1000568, - 0x0539 : 0x1000539, - 0x0569 : 0x1000569, - 0x053A : 0x100053a, - 0x056A : 0x100056a, - 0x053B : 0x100053b, - 0x056B : 0x100056b, - 0x053C : 0x100053c, - 0x056C : 0x100056c, - 0x053D : 0x100053d, - 0x056D : 0x100056d, - 0x053E : 0x100053e, - 0x056E : 0x100056e, - 0x053F : 0x100053f, - 0x056F : 0x100056f, - 0x0540 : 0x1000540, - 0x0570 : 0x1000570, - 0x0541 : 0x1000541, - 0x0571 : 0x1000571, - 0x0542 : 0x1000542, - 0x0572 : 0x1000572, - 0x0543 : 0x1000543, - 0x0573 : 0x1000573, - 0x0544 : 0x1000544, - 0x0574 : 0x1000574, - 0x0545 : 0x1000545, - 0x0575 : 0x1000575, - 0x0546 : 0x1000546, - 0x0576 : 0x1000576, - 0x0547 : 0x1000547, - 0x0577 : 0x1000577, - 0x0548 : 0x1000548, - 0x0578 : 0x1000578, - 0x0549 : 0x1000549, - 0x0579 : 0x1000579, - 0x054A : 0x100054a, - 0x057A : 0x100057a, - 0x054B : 0x100054b, - 0x057B : 0x100057b, - 0x054C : 0x100054c, - 0x057C : 0x100057c, - 0x054D : 0x100054d, - 0x057D : 0x100057d, - 0x054E : 0x100054e, - 0x057E : 0x100057e, - 0x054F : 0x100054f, - 0x057F : 0x100057f, - 0x0550 : 0x1000550, - 0x0580 : 0x1000580, - 0x0551 : 0x1000551, - 0x0581 : 0x1000581, - 0x0552 : 0x1000552, - 0x0582 : 0x1000582, - 0x0553 : 0x1000553, - 0x0583 : 0x1000583, - 0x0554 : 0x1000554, - 0x0584 : 0x1000584, - 0x0555 : 0x1000555, - 0x0585 : 0x1000585, - 0x0556 : 0x1000556, - 0x0586 : 0x1000586, - 0x055A : 0x100055a, - 0x10D0 : 0x10010d0, - 0x10D1 : 0x10010d1, - 0x10D2 : 0x10010d2, - 0x10D3 : 0x10010d3, - 0x10D4 : 0x10010d4, - 0x10D5 : 0x10010d5, - 0x10D6 : 0x10010d6, - 0x10D7 : 0x10010d7, - 0x10D8 : 0x10010d8, - 0x10D9 : 0x10010d9, - 0x10DA : 0x10010da, - 0x10DB : 0x10010db, - 0x10DC : 0x10010dc, - 0x10DD : 0x10010dd, - 0x10DE : 0x10010de, - 0x10DF : 0x10010df, - 0x10E0 : 0x10010e0, - 0x10E1 : 0x10010e1, - 0x10E2 : 0x10010e2, - 0x10E3 : 0x10010e3, - 0x10E4 : 0x10010e4, - 0x10E5 : 0x10010e5, - 0x10E6 : 0x10010e6, - 0x10E7 : 0x10010e7, - 0x10E8 : 0x10010e8, - 0x10E9 : 0x10010e9, - 0x10EA : 0x10010ea, - 0x10EB : 0x10010eb, - 0x10EC : 0x10010ec, - 0x10ED : 0x10010ed, - 0x10EE : 0x10010ee, - 0x10EF : 0x10010ef, - 0x10F0 : 0x10010f0, - 0x10F1 : 0x10010f1, - 0x10F2 : 0x10010f2, - 0x10F3 : 0x10010f3, - 0x10F4 : 0x10010f4, - 0x10F5 : 0x10010f5, - 0x10F6 : 0x10010f6, - 0x1E8A : 0x1001e8a, - 0x012C : 0x100012c, - 0x01B5 : 0x10001b5, - 0x01E6 : 0x10001e6, - 0x01D2 : 0x10001d1, - 0x019F : 0x100019f, - 0x1E8B : 0x1001e8b, - 0x012D : 0x100012d, - 0x01B6 : 0x10001b6, - 0x01E7 : 0x10001e7, - //0x01D2 : 0x10001d2, - 0x0275 : 0x1000275, - 0x018F : 0x100018f, - 0x0259 : 0x1000259, - 0x1E36 : 0x1001e36, - 0x1E37 : 0x1001e37, - 0x1EA0 : 0x1001ea0, - 0x1EA1 : 0x1001ea1, - 0x1EA2 : 0x1001ea2, - 0x1EA3 : 0x1001ea3, - 0x1EA4 : 0x1001ea4, - 0x1EA5 : 0x1001ea5, - 0x1EA6 : 0x1001ea6, - 0x1EA7 : 0x1001ea7, - 0x1EA8 : 0x1001ea8, - 0x1EA9 : 0x1001ea9, - 0x1EAA : 0x1001eaa, - 0x1EAB : 0x1001eab, - 0x1EAC : 0x1001eac, - 0x1EAD : 0x1001ead, - 0x1EAE : 0x1001eae, - 0x1EAF : 0x1001eaf, - 0x1EB0 : 0x1001eb0, - 0x1EB1 : 0x1001eb1, - 0x1EB2 : 0x1001eb2, - 0x1EB3 : 0x1001eb3, - 0x1EB4 : 0x1001eb4, - 0x1EB5 : 0x1001eb5, - 0x1EB6 : 0x1001eb6, - 0x1EB7 : 0x1001eb7, - 0x1EB8 : 0x1001eb8, - 0x1EB9 : 0x1001eb9, - 0x1EBA : 0x1001eba, - 0x1EBB : 0x1001ebb, - 0x1EBC : 0x1001ebc, - 0x1EBD : 0x1001ebd, - 0x1EBE : 0x1001ebe, - 0x1EBF : 0x1001ebf, - 0x1EC0 : 0x1001ec0, - 0x1EC1 : 0x1001ec1, - 0x1EC2 : 0x1001ec2, - 0x1EC3 : 0x1001ec3, - 0x1EC4 : 0x1001ec4, - 0x1EC5 : 0x1001ec5, - 0x1EC6 : 0x1001ec6, - 0x1EC7 : 0x1001ec7, - 0x1EC8 : 0x1001ec8, - 0x1EC9 : 0x1001ec9, - 0x1ECA : 0x1001eca, - 0x1ECB : 0x1001ecb, - 0x1ECC : 0x1001ecc, - 0x1ECD : 0x1001ecd, - 0x1ECE : 0x1001ece, - 0x1ECF : 0x1001ecf, - 0x1ED0 : 0x1001ed0, - 0x1ED1 : 0x1001ed1, - 0x1ED2 : 0x1001ed2, - 0x1ED3 : 0x1001ed3, - 0x1ED4 : 0x1001ed4, - 0x1ED5 : 0x1001ed5, - 0x1ED6 : 0x1001ed6, - 0x1ED7 : 0x1001ed7, - 0x1ED8 : 0x1001ed8, - 0x1ED9 : 0x1001ed9, - 0x1EDA : 0x1001eda, - 0x1EDB : 0x1001edb, - 0x1EDC : 0x1001edc, - 0x1EDD : 0x1001edd, - 0x1EDE : 0x1001ede, - 0x1EDF : 0x1001edf, - 0x1EE0 : 0x1001ee0, - 0x1EE1 : 0x1001ee1, - 0x1EE2 : 0x1001ee2, - 0x1EE3 : 0x1001ee3, - 0x1EE4 : 0x1001ee4, - 0x1EE5 : 0x1001ee5, - 0x1EE6 : 0x1001ee6, - 0x1EE7 : 0x1001ee7, - 0x1EE8 : 0x1001ee8, - 0x1EE9 : 0x1001ee9, - 0x1EEA : 0x1001eea, - 0x1EEB : 0x1001eeb, - 0x1EEC : 0x1001eec, - 0x1EED : 0x1001eed, - 0x1EEE : 0x1001eee, - 0x1EEF : 0x1001eef, - 0x1EF0 : 0x1001ef0, - 0x1EF1 : 0x1001ef1, - 0x1EF4 : 0x1001ef4, - 0x1EF5 : 0x1001ef5, - 0x1EF6 : 0x1001ef6, - 0x1EF7 : 0x1001ef7, - 0x1EF8 : 0x1001ef8, - 0x1EF9 : 0x1001ef9, - 0x01A0 : 0x10001a0, - 0x01A1 : 0x10001a1, - 0x01AF : 0x10001af, - 0x01B0 : 0x10001b0, - 0x20A0 : 0x10020a0, - 0x20A1 : 0x10020a1, - 0x20A2 : 0x10020a2, - 0x20A3 : 0x10020a3, - 0x20A4 : 0x10020a4, - 0x20A5 : 0x10020a5, - 0x20A6 : 0x10020a6, - 0x20A7 : 0x10020a7, - 0x20A8 : 0x10020a8, - 0x20A9 : 0x10020a9, - 0x20AA : 0x10020aa, - 0x20AB : 0x10020ab, - 0x20AC : 0x20ac, - 0x2070 : 0x1002070, - 0x2074 : 0x1002074, - 0x2075 : 0x1002075, - 0x2076 : 0x1002076, - 0x2077 : 0x1002077, - 0x2078 : 0x1002078, - 0x2079 : 0x1002079, - 0x2080 : 0x1002080, - 0x2081 : 0x1002081, - 0x2082 : 0x1002082, - 0x2083 : 0x1002083, - 0x2084 : 0x1002084, - 0x2085 : 0x1002085, - 0x2086 : 0x1002086, - 0x2087 : 0x1002087, - 0x2088 : 0x1002088, - 0x2089 : 0x1002089, - 0x2202 : 0x1002202, - 0x2205 : 0x1002205, - 0x2208 : 0x1002208, - 0x2209 : 0x1002209, - 0x220B : 0x100220B, - 0x221A : 0x100221A, - 0x221B : 0x100221B, - 0x221C : 0x100221C, - 0x222C : 0x100222C, - 0x222D : 0x100222D, - 0x2235 : 0x1002235, - 0x2245 : 0x1002248, - 0x2247 : 0x1002247, - 0x2262 : 0x1002262, - 0x2263 : 0x1002263, - 0x2800 : 0x1002800, - 0x2801 : 0x1002801, - 0x2802 : 0x1002802, - 0x2803 : 0x1002803, - 0x2804 : 0x1002804, - 0x2805 : 0x1002805, - 0x2806 : 0x1002806, - 0x2807 : 0x1002807, - 0x2808 : 0x1002808, - 0x2809 : 0x1002809, - 0x280a : 0x100280a, - 0x280b : 0x100280b, - 0x280c : 0x100280c, - 0x280d : 0x100280d, - 0x280e : 0x100280e, - 0x280f : 0x100280f, - 0x2810 : 0x1002810, - 0x2811 : 0x1002811, - 0x2812 : 0x1002812, - 0x2813 : 0x1002813, - 0x2814 : 0x1002814, - 0x2815 : 0x1002815, - 0x2816 : 0x1002816, - 0x2817 : 0x1002817, - 0x2818 : 0x1002818, - 0x2819 : 0x1002819, - 0x281a : 0x100281a, - 0x281b : 0x100281b, - 0x281c : 0x100281c, - 0x281d : 0x100281d, - 0x281e : 0x100281e, - 0x281f : 0x100281f, - 0x2820 : 0x1002820, - 0x2821 : 0x1002821, - 0x2822 : 0x1002822, - 0x2823 : 0x1002823, - 0x2824 : 0x1002824, - 0x2825 : 0x1002825, - 0x2826 : 0x1002826, - 0x2827 : 0x1002827, - 0x2828 : 0x1002828, - 0x2829 : 0x1002829, - 0x282a : 0x100282a, - 0x282b : 0x100282b, - 0x282c : 0x100282c, - 0x282d : 0x100282d, - 0x282e : 0x100282e, - 0x282f : 0x100282f, - 0x2830 : 0x1002830, - 0x2831 : 0x1002831, - 0x2832 : 0x1002832, - 0x2833 : 0x1002833, - 0x2834 : 0x1002834, - 0x2835 : 0x1002835, - 0x2836 : 0x1002836, - 0x2837 : 0x1002837, - 0x2838 : 0x1002838, - 0x2839 : 0x1002839, - 0x283a : 0x100283a, - 0x283b : 0x100283b, - 0x283c : 0x100283c, - 0x283d : 0x100283d, - 0x283e : 0x100283e, - 0x283f : 0x100283f, - 0x2840 : 0x1002840, - 0x2841 : 0x1002841, - 0x2842 : 0x1002842, - 0x2843 : 0x1002843, - 0x2844 : 0x1002844, - 0x2845 : 0x1002845, - 0x2846 : 0x1002846, - 0x2847 : 0x1002847, - 0x2848 : 0x1002848, - 0x2849 : 0x1002849, - 0x284a : 0x100284a, - 0x284b : 0x100284b, - 0x284c : 0x100284c, - 0x284d : 0x100284d, - 0x284e : 0x100284e, - 0x284f : 0x100284f, - 0x2850 : 0x1002850, - 0x2851 : 0x1002851, - 0x2852 : 0x1002852, - 0x2853 : 0x1002853, - 0x2854 : 0x1002854, - 0x2855 : 0x1002855, - 0x2856 : 0x1002856, - 0x2857 : 0x1002857, - 0x2858 : 0x1002858, - 0x2859 : 0x1002859, - 0x285a : 0x100285a, - 0x285b : 0x100285b, - 0x285c : 0x100285c, - 0x285d : 0x100285d, - 0x285e : 0x100285e, - 0x285f : 0x100285f, - 0x2860 : 0x1002860, - 0x2861 : 0x1002861, - 0x2862 : 0x1002862, - 0x2863 : 0x1002863, - 0x2864 : 0x1002864, - 0x2865 : 0x1002865, - 0x2866 : 0x1002866, - 0x2867 : 0x1002867, - 0x2868 : 0x1002868, - 0x2869 : 0x1002869, - 0x286a : 0x100286a, - 0x286b : 0x100286b, - 0x286c : 0x100286c, - 0x286d : 0x100286d, - 0x286e : 0x100286e, - 0x286f : 0x100286f, - 0x2870 : 0x1002870, - 0x2871 : 0x1002871, - 0x2872 : 0x1002872, - 0x2873 : 0x1002873, - 0x2874 : 0x1002874, - 0x2875 : 0x1002875, - 0x2876 : 0x1002876, - 0x2877 : 0x1002877, - 0x2878 : 0x1002878, - 0x2879 : 0x1002879, - 0x287a : 0x100287a, - 0x287b : 0x100287b, - 0x287c : 0x100287c, - 0x287d : 0x100287d, - 0x287e : 0x100287e, - 0x287f : 0x100287f, - 0x2880 : 0x1002880, - 0x2881 : 0x1002881, - 0x2882 : 0x1002882, - 0x2883 : 0x1002883, - 0x2884 : 0x1002884, - 0x2885 : 0x1002885, - 0x2886 : 0x1002886, - 0x2887 : 0x1002887, - 0x2888 : 0x1002888, - 0x2889 : 0x1002889, - 0x288a : 0x100288a, - 0x288b : 0x100288b, - 0x288c : 0x100288c, - 0x288d : 0x100288d, - 0x288e : 0x100288e, - 0x288f : 0x100288f, - 0x2890 : 0x1002890, - 0x2891 : 0x1002891, - 0x2892 : 0x1002892, - 0x2893 : 0x1002893, - 0x2894 : 0x1002894, - 0x2895 : 0x1002895, - 0x2896 : 0x1002896, - 0x2897 : 0x1002897, - 0x2898 : 0x1002898, - 0x2899 : 0x1002899, - 0x289a : 0x100289a, - 0x289b : 0x100289b, - 0x289c : 0x100289c, - 0x289d : 0x100289d, - 0x289e : 0x100289e, - 0x289f : 0x100289f, - 0x28a0 : 0x10028a0, - 0x28a1 : 0x10028a1, - 0x28a2 : 0x10028a2, - 0x28a3 : 0x10028a3, - 0x28a4 : 0x10028a4, - 0x28a5 : 0x10028a5, - 0x28a6 : 0x10028a6, - 0x28a7 : 0x10028a7, - 0x28a8 : 0x10028a8, - 0x28a9 : 0x10028a9, - 0x28aa : 0x10028aa, - 0x28ab : 0x10028ab, - 0x28ac : 0x10028ac, - 0x28ad : 0x10028ad, - 0x28ae : 0x10028ae, - 0x28af : 0x10028af, - 0x28b0 : 0x10028b0, - 0x28b1 : 0x10028b1, - 0x28b2 : 0x10028b2, - 0x28b3 : 0x10028b3, - 0x28b4 : 0x10028b4, - 0x28b5 : 0x10028b5, - 0x28b6 : 0x10028b6, - 0x28b7 : 0x10028b7, - 0x28b8 : 0x10028b8, - 0x28b9 : 0x10028b9, - 0x28ba : 0x10028ba, - 0x28bb : 0x10028bb, - 0x28bc : 0x10028bc, - 0x28bd : 0x10028bd, - 0x28be : 0x10028be, - 0x28bf : 0x10028bf, - 0x28c0 : 0x10028c0, - 0x28c1 : 0x10028c1, - 0x28c2 : 0x10028c2, - 0x28c3 : 0x10028c3, - 0x28c4 : 0x10028c4, - 0x28c5 : 0x10028c5, - 0x28c6 : 0x10028c6, - 0x28c7 : 0x10028c7, - 0x28c8 : 0x10028c8, - 0x28c9 : 0x10028c9, - 0x28ca : 0x10028ca, - 0x28cb : 0x10028cb, - 0x28cc : 0x10028cc, - 0x28cd : 0x10028cd, - 0x28ce : 0x10028ce, - 0x28cf : 0x10028cf, - 0x28d0 : 0x10028d0, - 0x28d1 : 0x10028d1, - 0x28d2 : 0x10028d2, - 0x28d3 : 0x10028d3, - 0x28d4 : 0x10028d4, - 0x28d5 : 0x10028d5, - 0x28d6 : 0x10028d6, - 0x28d7 : 0x10028d7, - 0x28d8 : 0x10028d8, - 0x28d9 : 0x10028d9, - 0x28da : 0x10028da, - 0x28db : 0x10028db, - 0x28dc : 0x10028dc, - 0x28dd : 0x10028dd, - 0x28de : 0x10028de, - 0x28df : 0x10028df, - 0x28e0 : 0x10028e0, - 0x28e1 : 0x10028e1, - 0x28e2 : 0x10028e2, - 0x28e3 : 0x10028e3, - 0x28e4 : 0x10028e4, - 0x28e5 : 0x10028e5, - 0x28e6 : 0x10028e6, - 0x28e7 : 0x10028e7, - 0x28e8 : 0x10028e8, - 0x28e9 : 0x10028e9, - 0x28ea : 0x10028ea, - 0x28eb : 0x10028eb, - 0x28ec : 0x10028ec, - 0x28ed : 0x10028ed, - 0x28ee : 0x10028ee, - 0x28ef : 0x10028ef, - 0x28f0 : 0x10028f0, - 0x28f1 : 0x10028f1, - 0x28f2 : 0x10028f2, - 0x28f3 : 0x10028f3, - 0x28f4 : 0x10028f4, - 0x28f5 : 0x10028f5, - 0x28f6 : 0x10028f6, - 0x28f7 : 0x10028f7, - 0x28f8 : 0x10028f8, - 0x28f9 : 0x10028f9, - 0x28fa : 0x10028fa, - 0x28fb : 0x10028fb, - 0x28fc : 0x10028fc, - 0x28fd : 0x10028fd, - 0x28fe : 0x10028fe, - 0x28ff : 0x10028ff -}; diff --git a/tests/input.html b/tests/input.html index 248d24e7..bc5d2e15 100644 --- a/tests/input.html +++ b/tests/input.html @@ -26,6 +26,8 @@ + + + + " }, + header: "\n\n\n\n\n
", + script_tag: function(p) { return ""; }, footer: "\n\n" }; template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/chai/chai.js')); template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/mocha/mocha.js')); + template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/sinon/pkg/sinon.js')); + template.header += "\n" + template.script_tag(path.resolve(__dirname, 'node_modules/sinon-chai/lib/sinon-chai.js')); template.header += "\n"; @@ -74,7 +77,7 @@ if (program.outputHtml) { console.warn(error.stack); return; } - + cursor .bold() .write(program.tests[path_ind]) @@ -137,8 +140,8 @@ if (!program.outputHtml && !program.generateHtml) { console.log(''); - cursor.write(''+test_json.num_tests+' tests run, ') cursor + .write(''+test_json.num_tests+' tests run, ') .green() .write(''+test_json.num_passes+' passed'); if (test_json.num_slow > 0) { @@ -157,9 +160,16 @@ if (!program.outputHtml && !program.generateHtml) { cursor .red() .write(''+test_json.num_fails+' failed'); + if (test_json.num_skipped > 0) { + cursor + .reset() + .write(', ') + .grey() + .write(''+test_json.num_skipped+' skipped'); + } cursor .reset() - .write(' -- duration: '+test_json.duration+"\n"); + .write(' -- duration: '+test_json.duration+"s\n"); console.log(''); @@ -168,7 +178,7 @@ if (!program.outputHtml && !program.generateHtml) { if (node.type == 'suite') { if (!node.has_subfailures && !program.printAll) return; - if (indentation == 0) { + if (indentation === 0) { cursor.bold(); console.log(node.name); console.log(Array(node.name.length+1).join('-')); @@ -195,17 +205,25 @@ if (!program.outputHtml && !program.generateHtml) { cursor.magenta(); console.log('- failed: '+node.text+test_json.replay); cursor.red(); - console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS, we get a stack trace too + console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too cursor.reset(); console.log(''); } else if (program.printAll) { - if (node.slow) cursor.yellow(); - else cursor.green(); - cursor - .write('- pass: '+node.text) - .grey() - .write(' ('+node.duration+') '); + if (node.skipped) { + cursor + .grey() + .write('- skipped: '+node.text); + } + else { + if (node.slow) cursor.yellow(); + else cursor.green(); + + cursor + .write('- pass: '+node.text) + .grey() + .write(' ('+node.duration+') '); + } /*if (node.slow) cursor.yellow(); else cursor.green();*/ cursor @@ -215,23 +233,25 @@ if (!program.outputHtml && !program.generateHtml) { console.log(''); } } - } + }; for (var i = 0; i < test_json.suites.length; i++) { traverse_tree(0, test_json.suites[i]); } } - if (test_json.num_fails == 0) { + if (test_json.num_fails === 0) { cursor.fg.green(); console.log('all tests passed :-)'); cursor.reset(); } }); - /*provider.on('console', function(line) { - //console.log(line); - });*/ + if (program.debug) { + provider.on('console', function(line) { + console.log(line); + }); + } /*gprom.finally(function(ph) { ph.exit(); diff --git a/tests/run_from_console.zombie.js b/tests/run_from_console.zombie.js index 5ae51846..7280f75d 100644 --- a/tests/run_from_console.zombie.js +++ b/tests/run_from_console.zombie.js @@ -18,16 +18,18 @@ var provide_emitter = function(file_paths) { res_json.num_fails = browser.querySelectorAll('li.test.fail').length; res_json.num_passes = browser.querySelectorAll('li.test.pass').length; res_json.num_slow = browser.querySelectorAll('li.test.pass:not(.fast)').length; + res_json.num_skipped = browser.querySelectorAll('li.test.pending').length; res_json.duration = browser.text('li.duration em'); var traverse_node = function(elem) { var classList = elem.className.split(' '); + var res; if (classList.indexOf('suite') > -1) { - var res = { + res = { type: 'suite', name: elem.querySelector('h1').textContent, has_subfailures: elem.querySelectorAll('li.test.fail').length > 0 - } + }; var child_elems = elem.querySelector('ul').children; res.children = Array.prototype.map.call(child_elems, traverse_node); @@ -35,15 +37,22 @@ var provide_emitter = function(file_paths) { } else { var h2_content = elem.querySelector('h2').childNodes; - var res = { + res = { type: 'test', text: h2_content[0].textContent - } + }; if (classList.indexOf('pass') > -1) { res.pass = true; - res.slow = classList.indexOf('fast') < 0; - res.duration = h2_content[1].textContent; + if (classList.indexOf('pending') > -1) { + res.slow = false; + res.skipped = true; + } + else { + res.slow = classList.indexOf('fast') < 0; + res.skipped = false; + res.duration = h2_content[1].textContent; + } } else { res.error = elem.querySelector('pre.error').textContent; @@ -51,7 +60,7 @@ var provide_emitter = function(file_paths) { return res; } - } + }; var top_suites = browser.querySelectorAll('#mocha-report > li.suite'); res_json.suites = Array.prototype.map.call(top_suites, traverse_node); @@ -65,9 +74,9 @@ var provide_emitter = function(file_paths) { }, Q(new Browser())); return emitter; -} +}; module.exports = { provide_emitter: provide_emitter, name: 'ZombieJS' -} +}; From d823e8956ecfb6110c82a5bb2e1fe324d51cd380 Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Tue, 17 Dec 2013 18:00:45 -0500 Subject: [PATCH 025/100] Support Running All Tests Now, if the '-t' option is passed but no tests are listed, all tests in the same directory as the launcher will be run. A file is considered a test if it matches the RegEx /^test\.(\w|\.|-)+\.js$/ (for those who cannot read PCRE, that's roughly 'test.*.js'). --- tests/run_from_console.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/run_from_console.js b/tests/run_from_console.js index bafdebcf..4d0cae4a 100755 --- a/tests/run_from_console.js +++ b/tests/run_from_console.js @@ -2,6 +2,7 @@ var ansi = require('ansi'); var program = require('commander'); var path = require('path'); +var fs = require('fs'); var make_list = function(val) { return val.split(','); @@ -19,11 +20,15 @@ program .option('-d, --debug', 'Show debug output (the "console" event) from the provider') .parse(process.argv); +if (program.tests.length === 0) { + program.tests = fs.readdirSync(__dirname).filter(function(f) { return (/^test\.(\w|\.|-)+\.js$/).test(f); }); + console.log('using files %s', program.tests); +} + var file_paths = []; if (program.autoInject) { var temp = require('temp'); - var fs = require('fs'); temp.track(); var template = { @@ -70,7 +75,6 @@ else if (process.stdout.isTTY) use_ansi = true; var cursor = ansi(process.stdout, { enabled: use_ansi }); if (program.outputHtml) { - var fs = require('fs'); file_paths.forEach(function(path, path_ind) { fs.readFile(path, function(err, data) { if (err) { From 85e899166447866fc2fd9e51a565efbc8308673e Mon Sep 17 00:00:00 2001 From: Solly Ross Date: Tue, 17 Dec 2013 18:00:57 -0500 Subject: [PATCH 026/100] Support 'requires' Line in Test Runner If the files passed to the '-t' option are all '.js' files (or the 'run all tests' option is used) and the '-i' option is not passed, all tests will be search for the string 'require local modules: '. Only the first instance of this string will be used. Following the colon should be a list of either local modules (i.e. files in the '../include/' folder relative to the test runner's directory, without the '.js' extension) or paths to other Javascript files. The list of modules and/or files should be comma-separated. These files will then be included in the generated HTML file for the appropriate tests as if the '-i' option had been used. --- tests/run_from_console.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/run_from_console.js b/tests/run_from_console.js index 4d0cae4a..7525c8b4 100755 --- a/tests/run_from_console.js +++ b/tests/run_from_console.js @@ -15,8 +15,8 @@ program .option('-c, --color', 'Explicitly enable color (default is to use color when not outputting to a pipe)') .option('-i, --auto-inject ', 'Treat the test list as a set of mocha JS files, and automatically generate HTML files with which to test test. \'includefiles\' should be a comma-separated list of paths to javascript files to include in each of the generated HTML files', make_list, null) .option('-p, --provider ', 'Use the given provider (defaults to "casper"). Currently, may be "casper" or "zombie"', 'casper') - .option('-g, --generate-html', 'Instead of running the tests, just return the path to the generated HTML file, then wait for user interaction to exit (should be used with -i)') - .option('-o, --output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with -i)') + .option('-g, --generate-html', 'Instead of running the tests, just return the path to the generated HTML file, then wait for user interaction to exit (should be used with .js tests)') + .option('-o, --output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with .js tests)') .option('-d, --debug', 'Show debug output (the "console" event) from the provider') .parse(process.argv); @@ -27,6 +27,29 @@ if (program.tests.length === 0) { var file_paths = []; +var all_js = program.tests.reduce(function(a,e) { return a && e.slice(-3) == '.js'; }, true); + +if (all_js && !program.autoInject) { + var all_modules = {}; + + // uses the first instance of the string 'requires local modules: ' + program.tests.forEach(function (testname) { + var full_path = path.resolve(process.cwd(), testname); + var content = fs.readFileSync(full_path).toString(); + var ind = content.indexOf('requires local modules: '); + if (ind > -1) { + ind += 'requires local modules: '.length; + var eol = content.indexOf('\n', ind); + var modules = content.slice(ind, eol).split(/,\s*/); + modules.forEach(function (mod) { + all_modules[path.resolve(__dirname, '../include/', mod)+'.js'] = 1; + }); + } + }); + + program.autoInject = Object.keys(all_modules); +} + if (program.autoInject) { var temp = require('temp'); temp.track(); From f6a1d98a3a40a9f37c337d06420d277899a0a269 Mon Sep 17 00:00:00 2001 From: Jesper Dam Date: Mon, 6 Jan 2014 13:59:25 +0100 Subject: [PATCH 027/100] Fix issue #326: correct handling of shift key When shortcut modifiers (modifier keys such as CTRL, which do not participate in composing character input) are pressed, we try to suppress the keypress event, as browsers do not reliably generate it. This means that subsequent key events are decoded only based on the keydown event. Due to a type error (comparing a string to a number), shift was mistakenly treated as a shortcut modifier, preventing text input which relied on shift, such as _ and %, from being generated. --- include/keyboard.js | 2 +- tests/test.helper.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/keyboard.js b/include/keyboard.js index 623d5b29..f21f9767 100644 --- a/include/keyboard.js +++ b/include/keyboard.js @@ -31,7 +31,7 @@ var kbdUtil = (function() { function hasShortcutModifier(charModifier, currentModifiers) { var mods = {}; for (var key in currentModifiers) { - if (key !== 0xffe1) { + if (parseInt(key) !== 0xffe1) { mods[key] = currentModifiers[key]; } } diff --git a/tests/test.helper.js b/tests/test.helper.js index d6a68cd9..d9e8e144 100644 --- a/tests/test.helper.js +++ b/tests/test.helper.js @@ -248,5 +248,13 @@ describe('Helpers', function() { })).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]); }); }); + describe('do not treat shift as a modifier key', function() { + it('should not treat shift as a shortcut modifier', function() { + expect(kbdUtil.hasShortcutModifier([], {0xffe1 : true})).to.be.false; + }); + it('should not treat shift as a char modifier', function() { + expect(kbdUtil.hasCharModifier([], {0xffe1 : true})).to.be.false; + }); + }); }); }); From d86cc2d911a0d2d5aa51c3ff654e2fbcd650d934 Mon Sep 17 00:00:00 2001 From: Brian Rak Date: Thu, 30 Jan 2014 19:20:41 -0500 Subject: [PATCH 028/100] Add support for TightVNC auth type --- include/rfb.js | 93 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/include/rfb.js b/include/rfb.js index 55d38c08..b0719357 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -45,6 +45,7 @@ var that = {}, // Public API methods rfb_version = 0, rfb_max_version= 3.8, rfb_auth_scheme= '', + rfb_tightvnc = false, // In preference order @@ -709,7 +710,7 @@ init_msg = function() { types = ws.rQshiftBytes(num_types); Util.Debug("Server security types: " + types); for (i=0; i < types.length; i+=1) { - if ((types[i] > rfb_auth_scheme) && (types[i] < 3)) { + if ((types[i] > rfb_auth_scheme) && (types[i] <= 16)) { rfb_auth_scheme = types[i]; } } @@ -764,6 +765,68 @@ init_msg = function() { //Util.Debug("Sending DES encrypted auth response"); ws.send(response); updateState('SecurityResult'); + return; + case 16: // TightVNC Security Type + if (ws.rQwait("num tunnels", 4)) { return false; } + var numTunnels = ws.rQshift32(); + //console.log("Number of tunnels: "+numTunnels); + + rfb_tightvnc = true; + + if (numTunnels != 0) + { + fail("Protocol requested tunnels, not currently supported. numTunnels: " + numTunnels); + return; + } + + var clientSupportedTypes = { + 'STDVNOAUTH__': 1, + 'STDVVNCAUTH_': 2 + }; + + var serverSupportedTypes = []; + + if (ws.rQwait("sub auth count", 4)) { return false; } + var subAuthCount = ws.rQshift32(); + //console.log("Sub auth count: "+subAuthCount); + for (var i=0;i Date: Thu, 6 Feb 2014 16:08:00 +0100 Subject: [PATCH 029/100] Removes the connection timeouts to enable slower clients, connections or servers. --- include/base.css | 3 --- include/rfb.js | 15 --------------- include/ui.js | 5 ----- vnc.html | 1 - 4 files changed, 24 deletions(-) diff --git a/include/base.css b/include/base.css index f57d20e3..295b1321 100644 --- a/include/base.css +++ b/include/base.css @@ -41,9 +41,6 @@ html { } #noVNC_encrypt { } -#noVNC_connectTimeout { - width: 30px; -} #noVNC_path { width: 100px; } diff --git a/include/rfb.js b/include/rfb.js index 55d38c08..90b18dcd 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -76,7 +76,6 @@ var that = {}, // Public API methods keyboard = null, // Keyboard input handler object mouse = null, // Mouse input handler object sendTimer = null, // Send Queue check timer - connTimer = null, // connection timer disconnTimer = null, // disconnection timer msgTimer = null, // queued handle_message timer @@ -120,8 +119,6 @@ var that = {}, // Public API methods test_mode = false, - def_con_timeout = Websock_native ? 2 : 5, - /* Mouse state */ mouse_buttonMask = 0, mouse_arr = [], @@ -138,8 +135,6 @@ Util.conf_defaults(conf, that, defaults, [ ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'], ['shared', 'rw', 'bool', true, 'Request shared mode'], ['view_only', 'rw', 'bool', false, 'Disable client mouse/keyboard'], - - ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'], ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], // UltraVNC repeater ID to connect to @@ -439,12 +434,6 @@ updateState = function(state, statusMsg) { rfb_state = state; } - if (connTimer && (rfb_state !== 'connect')) { - Util.Debug("Clearing connect timer"); - clearTimeout(connTimer); - connTimer = null; - } - if (disconnTimer && (rfb_state !== 'disconnect')) { Util.Debug("Clearing disconnect timer"); clearTimeout(disconnTimer); @@ -461,10 +450,6 @@ updateState = function(state, statusMsg) { case 'connect': - - connTimer = setTimeout(function () { - fail("Connect timeout"); - }, conf.connectTimeout * 1000); init_vars(); connect(); diff --git a/include/ui.js b/include/ui.js index 9d2f1c4d..3ea8c884 100644 --- a/include/ui.js +++ b/include/ui.js @@ -86,7 +86,6 @@ start: function(callback) { UI.initSetting('cursor', !UI.isTouchDevice); UI.initSetting('shared', true); UI.initSetting('view_only', false); - UI.initSetting('connectTimeout', 2); UI.initSetting('path', 'websockify'); UI.initSetting('repeaterID', ''); @@ -388,7 +387,6 @@ toggleSettingsPanel: function() { UI.updateSetting('clip'); UI.updateSetting('shared'); UI.updateSetting('view_only'); - UI.updateSetting('connectTimeout'); UI.updateSetting('path'); UI.updateSetting('repeaterID'); UI.updateSetting('stylesheet'); @@ -437,7 +435,6 @@ settingsApply: function() { UI.saveSetting('clip'); UI.saveSetting('shared'); UI.saveSetting('view_only'); - UI.saveSetting('connectTimeout'); UI.saveSetting('path'); UI.saveSetting('repeaterID'); UI.saveSetting('stylesheet'); @@ -549,7 +546,6 @@ updateVisualState: function() { } $D('noVNC_shared').disabled = connected; $D('noVNC_view_only').disabled = connected; - $D('noVNC_connectTimeout').disabled = connected; $D('noVNC_path').disabled = connected; $D('noVNC_repeaterID').disabled = connected; @@ -622,7 +618,6 @@ connect: function() { UI.rfb.set_local_cursor(UI.getSetting('cursor')); UI.rfb.set_shared(UI.getSetting('shared')); UI.rfb.set_view_only(UI.getSetting('view_only')); - UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout')); UI.rfb.set_repeaterID(UI.getSetting('repeaterID')); UI.rfb.connect(host, port, password, path); diff --git a/vnc.html b/vnc.html index 8b8847cc..174a12f3 100644 --- a/vnc.html +++ b/vnc.html @@ -148,7 +148,6 @@
  • Clip to Window
  • Shared Mode
  • View Only
  • -
  • Connect Timeout (s)
  • Path
  • Repeater ID

  • From 03ab251587f60f8a2516171f16f9899075bc82b4 Mon Sep 17 00:00:00 2001 From: Malcolm Scott Date: Sat, 28 Sep 2013 17:32:37 +0100 Subject: [PATCH 030/100] Implement XVP auth --- include/rfb.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index 0ca3f40b..83fe0318 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -136,6 +136,7 @@ Util.conf_defaults(conf, that, defaults, [ ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'], ['shared', 'rw', 'bool', true, 'Request shared mode'], ['view_only', 'rw', 'bool', false, 'Disable client mouse/keyboard'], + ['xvp_password_sep', 'rw', 'str', '@', 'Separator for XVP password fields'], ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], // UltraVNC repeater ID to connect to @@ -630,7 +631,8 @@ init_msg = function() { var strlen, reason, length, sversion, cversion, repeaterID, i, types, num_types, challenge, response, bpp, depth, big_endian, red_max, green_max, blue_max, red_shift, - green_shift, blue_shift, true_color, name_length, is_repeater; + green_shift, blue_shift, true_color, name_length, is_repeater, + xvp_sep, xvp_auth, xvp_auth_str; //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0)); switch (rfb_state) { @@ -695,7 +697,7 @@ init_msg = function() { types = ws.rQshiftBytes(num_types); Util.Debug("Server security types: " + types); for (i=0; i < types.length; i+=1) { - if ((types[i] > rfb_auth_scheme) && (types[i] <= 16)) { + if ((types[i] > rfb_auth_scheme) && (types[i] <= 16 || types[i] == 22)) { rfb_auth_scheme = types[i]; } } @@ -730,6 +732,23 @@ init_msg = function() { } // Fall through to ClientInitialisation break; + case 22: // XVP authentication + xvp_sep = conf.xvp_password_sep; + xvp_auth = rfb_password.split(xvp_sep); + if (xvp_auth.length < 3) { + updateState('password', "XVP credentials required (user" + xvp_sep + + "target" + xvp_sep + "password) -- got only " + rfb_password); + conf.onPasswordRequired(that); + return; + } + xvp_auth_str = String.fromCharCode(xvp_auth[0].length) + + String.fromCharCode(xvp_auth[1].length) + + xvp_auth[0] + + xvp_auth[1]; + ws.send_string(xvp_auth_str); + rfb_password = xvp_auth.slice(2).join(xvp_sep); + rfb_auth_scheme = 2; + // Fall through to standard VNC authentication with remaining part of password case 2: // VNC authentication if (rfb_password.length === 0) { // Notify via both callbacks since it is kind of From a856a051da78f637d0d01d71b09a1c0f117a56c7 Mon Sep 17 00:00:00 2001 From: Malcolm Scott Date: Sat, 28 Sep 2013 19:24:54 +0100 Subject: [PATCH 031/100] Implement XVP extension (shutdown/reboot/reset) --- include/rfb.js | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index 83fe0318..700e5a8a 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -47,6 +47,8 @@ var that = {}, // Public API methods rfb_auth_scheme= '', rfb_tightvnc = false, + rfb_xvp_ver = 0, + // In preference order encodings = [ @@ -65,7 +67,8 @@ var that = {}, // Public API methods //['JPEG_quality_hi', -23 ], //['compress_lo', -255 ], ['compress_hi', -247 ], - ['last_rect', -224 ] + ['last_rect', -224 ], + ['xvp', -309 ] ], encHandlers = {}, @@ -161,6 +164,8 @@ Util.conf_defaults(conf, that, defaults, [ 'onFBResize(rfb, width, height): frame buffer resized'], ['onDesktopName', 'rw', 'func', function() { }, 'onDesktopName(rfb, name): desktop name received'], + ['onXvpInit', 'rw', 'func', function() { }, + 'onXvpInit(version): XVP extensions active for this connection'], // These callback names are deprecated ['updateState', 'rw', 'func', function() { }, @@ -991,7 +996,8 @@ normal_msg = function() { //Util.Debug(">> normal_msg"); var ret = true, msg_type, length, text, - c, first_colour, num_colours, red, green, blue; + c, first_colour, num_colours, red, green, blue, + xvp_ver, xvp_msg; if (FBU.rects > 0) { msg_type = 0; @@ -1041,6 +1047,24 @@ normal_msg = function() { conf.clipboardReceive(that, text); // Obsolete conf.onClipboard(that, text); break; + case 250: // XVP + ws.rQshift8(); // Padding + xvp_ver = ws.rQshift8(); + xvp_msg = ws.rQshift8(); + switch (xvp_msg) { + case 0: // XVP_FAIL + updateState(rfb_state, "Operation failed"); + break; + case 1: // XVP_INIT + rfb_xvp_ver = xvp_ver; + Util.Info("XVP extensions enabled (version " + rfb_xvp_ver + ")"); + conf.onXvpInit(rfb_xvp_ver); + break; + default: + fail("Disconnected: illegal server XVP message " + xvp_msg); + break; + } + break; default: fail("Disconnected: illegal server message type " + msg_type); Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30)); @@ -1895,6 +1919,25 @@ that.sendCtrlAltDel = function() { ws.send(arr); }; +that.xvpOp = function(ver, op) { + if (rfb_xvp_ver < ver) { return false; } + Util.Info("Sending XVP operation " + op + " (version " + ver + ")") + ws.send_string("\xFA\x00" + String.fromCharCode(ver) + String.fromCharCode(op)); + return true; +}; + +that.xvpShutdown = function() { + return that.xvpOp(1, 2); +}; + +that.xvpReboot = function() { + return that.xvpOp(1, 3); +}; + +that.xvpReset = function() { + return that.xvpOp(1, 4); +}; + // Send a key press. If 'down' is not specified then send a down key // followed by an up key. that.sendKey = function(code, down) { From fb35d50f6a9ba28c03f6e5d75b778cb9189655d3 Mon Sep 17 00:00:00 2001 From: Malcolm Scott Date: Sat, 28 Sep 2013 19:25:15 +0100 Subject: [PATCH 032/100] Implement XVP UI in HTML --- images/power.png | Bin 0 -> 390 bytes include/base.css | 17 +++++++++++ include/ui.js | 76 +++++++++++++++++++++++++++++++++++++++++++++++ vnc.html | 12 ++++++++ vnc_auto.html | 42 ++++++++++++++++++++++++-- 5 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 images/power.png diff --git a/images/power.png b/images/power.png new file mode 100644 index 0000000000000000000000000000000000000000..f68fd0813c02a625f3fb5097353b7825f287939f GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)r;MP5p&nmUBLf4Yu&0Y-h{y4#VS!wS40wF6uK&wz zeJ1b0dp`q-xCQJ1W&L*#{jK6yZ}@>J>(2+?q>Rf`4Fzff;%=K%nq(i6F}{53M#?;U zLBZzq!>RXNprLZ*hUsB!Gewso}{}^ zyS5zqsqt+q$3eS=bG3syL}aJxswlO({ZMz^<8@I+aHiGz+=bUm8NM^#j@;<7{?FO# zrb}1(?6I-+nz%_ndc~vpE9T2SE8eKOh+S~6fqC~wzI*9n-{OAGRx&S`su`qNAN+(V z&&XBkX?|VBYQH4q-F|DjwzF)~vb(lB%jUA~j<{R9onkH8Tw^2Zl+T|DXQ^pge?vdW h@Q(gJk3Tz4NXMlvaGP>8%>o!=44$rjF6*2UngBV_o1g#y literal 0 HcmV?d00001 diff --git a/include/base.css b/include/base.css index 295b1321..e2c9a96d 100644 --- a/include/base.css +++ b/include/base.css @@ -49,12 +49,19 @@ html { float:right; } +#noVNC_buttons { + white-space: nowrap; +} + #noVNC_view_drag_button { display: none; } #sendCtrlAltDelButton { display: none; } +#noVNC_xvp_buttons { + display: none; +} #noVNC_mobile_buttons { display: none; } @@ -196,6 +203,16 @@ html { border-radius:10px; } +#noVNC_xvp { + display:none; + margin-top:73px; + right:30px; + position:fixed; +} +#noVNC_xvp.top:after { + right:125px; +} + #noVNC_clipboard { display:none; margin-top:73px; diff --git a/include/ui.js b/include/ui.js index 3ea8c884..f8524632 100644 --- a/include/ui.js +++ b/include/ui.js @@ -91,6 +91,7 @@ start: function(callback) { UI.rfb = RFB({'target': $D('noVNC_canvas'), 'onUpdateState': UI.updateState, + 'onXvpInit': UI.updateXvpVisualState, 'onClipboard': UI.clipReceive, 'onDesktopName': UI.updateDocumentTitle}); @@ -184,8 +185,12 @@ addMouseHandlers: function() { $D("sendEscButton").onclick = UI.sendEsc; $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel; + $D("xvpShutdownButton").onclick = UI.xvpShutdown; + $D("xvpRebootButton").onclick = UI.xvpReboot; + $D("xvpResetButton").onclick = UI.xvpReset; $D("noVNC_status").onclick = UI.togglePopupStatusPanel; $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel; + $D("xvpButton").onclick = UI.toggleXvpPanel; $D("clipboardButton").onclick = UI.toggleClipboardPanel; $D("settingsButton").onclick = UI.toggleSettingsPanel; $D("connectButton").onclick = UI.toggleConnectPanel; @@ -302,6 +307,39 @@ togglePopupStatusPanel: function() { } }, +// Show the XVP panel +toggleXvpPanel: function() { + // Close the description panel + $D('noVNC_description').style.display = "none"; + // Close settings if open + if (UI.settingsOpen === true) { + UI.settingsApply(); + UI.closeSettingsMenu(); + } + // Close connection settings if open + if (UI.connSettingsOpen === true) { + UI.toggleConnectPanel(); + } + // Close popup status panel if open + if (UI.popupStatusOpen === true) { + UI.togglePopupStatusPanel(); + } + // Close clipboard panel if open + if (UI.clipboardOpen === true) { + UI.toggleClipboardPanel(); + } + // Toggle XVP panel + if (UI.xvpOpen === true) { + $D('noVNC_xvp').style.display = "none"; + $D('xvpButton').className = "noVNC_status_button"; + UI.xvpOpen = false; + } else { + $D('noVNC_xvp').style.display = "block"; + $D('xvpButton').className = "noVNC_status_button_selected"; + UI.xvpOpen = true; + } +}, + // Show the clipboard panel toggleClipboardPanel: function() { // Close the description panel @@ -319,6 +357,10 @@ toggleClipboardPanel: function() { if (UI.popupStatusOpen === true) { UI.togglePopupStatusPanel(); } + // Close XVP panel if open + if (UI.xvpOpen === true) { + UI.toggleXvpPanel(); + } // Toggle Clipboard Panel if (UI.clipboardOpen === true) { $D('noVNC_clipboard').style.display = "none"; @@ -349,6 +391,10 @@ toggleConnectPanel: function() { if (UI.popupStatusOpen === true) { UI.togglePopupStatusPanel(); } + // Close XVP panel if open + if (UI.xvpOpen === true) { + UI.toggleXvpPanel(); + } // Toggle Connection Panel if (UI.connSettingsOpen === true) { @@ -412,6 +458,10 @@ openSettingsMenu: function() { if (UI.popupStatusOpen === true) { UI.togglePopupStatusPanel(); } + // Close XVP panel if open + if (UI.xvpOpen === true) { + UI.toggleXvpPanel(); + } $D('noVNC_settings').style.display = "block"; $D('settingsButton').className = "noVNC_status_button_selected"; UI.settingsOpen = true; @@ -464,6 +514,18 @@ sendCtrlAltDel: function() { UI.rfb.sendCtrlAltDel(); }, +xvpShutdown: function() { + UI.rfb.xvpShutdown(); +}, + +xvpReboot: function() { + UI.rfb.xvpReboot(); +}, + +xvpReset: function() { + UI.rfb.xvpReset(); +}, + setMouseButton: function(num) { var b, blist = [0, 1,2,4], button; @@ -562,6 +624,7 @@ updateVisualState: function() { $D('showKeyboard').style.display = "none"; $D('noVNC_extra_keys').style.display = "none"; $D('sendCtrlAltDelButton').style.display = "none"; + UI.updateXvpVisualState(0); } // State change disables viewport dragging. @@ -585,6 +648,19 @@ updateVisualState: function() { //Util.Debug("<< updateVisualState"); }, +// Disable/enable XVP button +updateXvpVisualState: function(ver) { + if (ver >= 1) { + $D('xvpButton').style.display = 'inline'; + } else { + $D('xvpButton').style.display = 'none'; + // Close XVP panel if open + if (UI.xvpOpen === true) { + UI.toggleXvpPanel(); + } + } +}, + // Display the desktop name in the document title updateDocumentTitle: function(rfb, name) { diff --git a/vnc.html b/vnc.html index 174a12f3..2aa9fe34 100644 --- a/vnc.html +++ b/vnc.html @@ -95,6 +95,9 @@ + @@ -138,6 +141,15 @@ value="Clear"> + +
    + + + + + +
    +
    diff --git a/vnc_auto.html b/vnc_auto.html index aa6a9363..53b8220c 100644 --- a/vnc_auto.html +++ b/vnc_auto.html @@ -53,6 +53,14 @@
    + + + + +
    @@ -91,6 +99,18 @@ rfb.sendCtrlAltDel(); return false; } + function xvpShutdown() { + rfb.xvpShutdown(); + return false; + } + function xvpReboot() { + rfb.xvpReboot(); + return false; + } + function xvpReset() { + rfb.xvpReset(); + return false; + } function updateState(rfb, state, oldstate, msg) { var s, sb, cad, level; s = $D('noVNC_status'); @@ -105,8 +125,12 @@ default: level = "warn"; break; } - if (state === "normal") { cad.disabled = false; } - else { cad.disabled = true; } + if (state === "normal") { + cad.disabled = false; + } else { + cad.disabled = true; + xvpInit(0); + } if (typeof(msg) !== 'undefined') { sb.setAttribute("class", "noVNC_status_" + level); @@ -114,11 +138,24 @@ } } + function xvpInit(ver) { + var xvpbuttons; + xvpbuttons = $D('noVNC_xvp_buttons'); + if (ver >= 1) { + xvpbuttons.style.display = 'inline'; + } else { + xvpbuttons.style.display = 'none'; + } + } + window.onscriptsload = function () { var host, port, password, path, token; $D('sendCtrlAltDelButton').style.display = "inline"; $D('sendCtrlAltDelButton').onclick = sendCtrlAltDel; + $D('xvpShutdownButton').onclick = xvpShutdown; + $D('xvpRebootButton').onclick = xvpReboot; + $D('xvpResetButton').onclick = xvpReset; WebUtil.init_logging(WebUtil.getQueryVar('logging', 'warn')); document.title = unescape(WebUtil.getQueryVar('title', 'noVNC')); @@ -162,6 +199,7 @@ 'shared': WebUtil.getQueryVar('shared', true), 'view_only': WebUtil.getQueryVar('view_only', false), 'updateState': updateState, + 'onXvpInit': xvpInit, 'onPasswordRequired': passwordRequired}); rfb.connect(host, port, password, path); }; From c7fc3c082fb4afee9fea77cdc9a78c5ac31c935a Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 19 Feb 2014 19:29:06 +0100 Subject: [PATCH 033/100] WebSocket protocols are now configurable. --- include/rfb.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/rfb.js b/include/rfb.js index 700e5a8a..c9fd92a9 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -142,6 +142,9 @@ Util.conf_defaults(conf, that, defaults, [ ['xvp_password_sep', 'rw', 'str', '@', 'Separator for XVP password fields'], ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], + ['wsProtocols', 'rw', 'arr', ['binary', 'base64'], + 'Protocols to use in the WebSocket connection'], + // UltraVNC repeater ID to connect to ['repeaterID', 'rw', 'str', '', 'RepeaterID to connect to'], @@ -304,7 +307,7 @@ function connect() { } Util.Info("connecting to " + uri); // TODO: make protocols a configurable - ws.open(uri, ['binary', 'base64']); + ws.open(uri, conf.wsProtocols); Util.Debug("<< RFB.connect"); } From 97362c39804f07bdfa11c73b07189b1949eb5e97 Mon Sep 17 00:00:00 2001 From: Dominic Luechinger Date: Tue, 11 Mar 2014 14:29:58 +0100 Subject: [PATCH 034/100] Improved websocket binary support detection A facke connection to 'wss://localhost:17523' (randomly chosen) to detect the WebSocket binary support is not the best solution. First of all, check of prototype has the property 'binaryType'. If not, perform a dummy connection to 'wss://.' instead of 'wss://localhost:17523'. This patch was inspired by the discussion and implementation of Modernizr: https://github.com/Modernizr/Modernizr/issues/370 https://github.com/Modernizr/Modernizr/blob/master/feature-detects/websockets/binary.js --- include/rfb.js | 12 ++++-------- include/websock.js | 16 ++++++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index c9fd92a9..4cacca16 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -296,17 +296,13 @@ function connect() { var uri; if (typeof UsingSocketIO !== "undefined") { - uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path; + uri = "http"; } else { - if (conf.encrypt) { - uri = "wss://"; - } else { - uri = "ws://"; - } - uri += rfb_host + ":" + rfb_port + "/" + rfb_path; + uri = conf.encrypt ? "wss" : "ws"; } + uri += "://" + rfb_host + ":" + rfb_port + "/" + rfb_path; Util.Info("connecting to " + uri); - // TODO: make protocols a configurable + ws.open(uri, conf.wsProtocols); Util.Debug("<< RFB.connect"); diff --git a/include/websock.js b/include/websock.js index b8cc46f6..d3790fea 100644 --- a/include/websock.js +++ b/include/websock.js @@ -262,7 +262,7 @@ function on(evt, handler) { eventHandlers[evt] = handler; } -function init(protocols) { +function init(protocols, ws_schema) { rQ = []; rQi = 0; sQ = []; @@ -278,11 +278,14 @@ function init(protocols) { bt = true; } - // Check for full binary type support in WebSockets - // TODO: this sucks, the property should exist on the prototype - // but it does not. + // Check for full binary type support in WebSocket + // Inspired by: + // https://github.com/Modernizr/Modernizr/issues/370 + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/websockets/binary.js try { - if (bt && ('binaryType' in (new WebSocket("wss://localhost:17523")))) { + if (bt && + ('binaryType' in WebSocket.prototype || + !!(new WebSocket(ws_schema + '://.').binaryType))) { Util.Info("Detected binaryType support in WebSockets"); wsbt = true; } @@ -325,7 +328,8 @@ function init(protocols) { } function open(uri, protocols) { - protocols = init(protocols); + var ws_schema = uri.match(/^([a-z]+):\/\//)[1]; + protocols = init(protocols, ws_schema); if (test_mode) { websocket = {}; From c3f6052435249033a36b807bc95e03942aba664f Mon Sep 17 00:00:00 2001 From: Jesper Dam Date: Wed, 12 Mar 2014 10:08:14 +0100 Subject: [PATCH 035/100] Better key identifiers Previously we identified keys in keyboard events by the 'key' property if it was set, and 'keyCode' otherwise. This turns out to be problematic as Firefox no longer leaves 'key' undefined (so we fall back to using 'keyCode'), but instead sets 'key' to 'MozPrintableKey' for all printable keys. This meant that when (printable) keys are released, we can't match it against the corresponding keydown event, and instead just send a keyup event for the last keydown received. Now, if both 'key' and 'keyCode' are set, use the concatenation of both. Otherwise prefer 'keyCode', as that is at least unique for every key. This should let us release the right keys on keyup events. --- include/keyboard.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/keyboard.js b/include/keyboard.js index f21f9767..3fde55bb 100644 --- a/include/keyboard.js +++ b/include/keyboard.js @@ -152,11 +152,14 @@ var kbdUtil = (function() { // Get a key ID from a keyboard event // May be a string or an integer depending on the available properties function getKey(evt){ - if (evt.key) { - return evt.key; + if ('keyCode' in evt && 'key' in evt) { + return evt.key + ':' + evt.keyCode; + } + else if ('keyCode' in evt) { + return evt.keyCode; } else { - return evt.keyCode; + return evt.key; } } From 230784066c7950316b8267a508406eb571e0ff79 Mon Sep 17 00:00:00 2001 From: Jesper Dam Date: Wed, 12 Mar 2014 11:11:52 +0100 Subject: [PATCH 036/100] Better browser OS detection. Apparently Firefox on Linux changed the value of navigator.appVersion, causing our OS detection (used to determine how to interpret different modifier keys) to fail. Use navigator.platform instead, which should be more stable. http://stackoverflow.com/a/19883965/33213 --- include/keyboard.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/keyboard.js b/include/keyboard.js index 3fde55bb..6bea9b53 100644 --- a/include/keyboard.js +++ b/include/keyboard.js @@ -18,13 +18,13 @@ var kbdUtil = (function() { }; function isMac() { - return navigator && !!(/macintosh/i).exec(navigator.appVersion); + return navigator && !!(/mac/i).exec(navigator.platform); } function isWindows() { - return navigator && !!(/windows/i).exec(navigator.appVersion); + return navigator && !!(/win/i).exec(navigator.platform); } function isLinux() { - return navigator && !!(/linux/i).exec(navigator.appVersion); + return navigator && !!(/linux/i).exec(navigator.platform); } // Return true if a modifier which is not the specified char modifier (and is not shift) is down From 6227a91c017f2d8e3deb03ece1eca082b336ef52 Mon Sep 17 00:00:00 2001 From: samhed Date: Fri, 14 Mar 2014 13:44:10 +0100 Subject: [PATCH 037/100] Decode from UTF-8 to allow unicode characters in the connection name --- include/rfb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rfb.js b/include/rfb.js index c9fd92a9..9dad36aa 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -923,7 +923,7 @@ init_msg = function() { /* Connection name/title */ name_length = ws.rQshift32(); - fb_name = ws.rQshiftStr(name_length); + fb_name = decodeURIComponent(escape(ws.rQshiftStr(name_length))); conf.onDesktopName(that, fb_name); if (conf.true_color && fb_name === "Intel(r) AMT KVM") From b7996b048bd9d47504899d88973d7fff1dc8af60 Mon Sep 17 00:00:00 2001 From: samhed Date: Fri, 14 Mar 2014 15:18:05 +0100 Subject: [PATCH 038/100] Added a wrapper for the UTF-8 decoding. --- include/rfb.js | 2 +- include/util.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/rfb.js b/include/rfb.js index 9dad36aa..173f6997 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -923,7 +923,7 @@ init_msg = function() { /* Connection name/title */ name_length = ws.rQshift32(); - fb_name = decodeURIComponent(escape(ws.rQshiftStr(name_length))); + fb_name = Util.decodeUTF8(ws.rQshiftStr(name_length)); conf.onDesktopName(that, fb_name); if (conf.true_color && fb_name === "Intel(r) AMT KVM") diff --git a/include/util.js b/include/util.js index 8893591c..1c02676c 100644 --- a/include/util.js +++ b/include/util.js @@ -202,6 +202,14 @@ Util.conf_defaults = function(cfg, api, defaults, arr) { } }; +/* + * Decode from UTF-8 + */ +Util.decodeUTF8 = function(utf8string) { + return decodeURIComponent(escape(utf8string)); +} + + /* * Cross-browser routines From 2db62a95289d05155be32900ec5f7f3b3cc6f42c Mon Sep 17 00:00:00 2001 From: samhed Date: Mon, 17 Mar 2014 14:24:42 +0100 Subject: [PATCH 039/100] Fixed typo in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53d14402..d547267d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ discussion group Bugs and feature requests can be submitted via [github issues](https://github.com/kanaka/noVNC/issues). If you are looking for a place to start contributing to noVNC, a good place to start -would be the issues that are have marked as +would be the issues that are marked as ["patchwelcome"](https://github.com/kanaka/noVNC/issues?labels=patchwelcome). If you want to show appreciation for noVNC you could donate to a great From 2fa1c0988a964f6856328a92958c632d41a6f2a6 Mon Sep 17 00:00:00 2001 From: samhed Date: Wed, 26 Mar 2014 11:18:48 +0100 Subject: [PATCH 040/100] Removed unused code. --- vnc.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vnc.html b/vnc.html index 2aa9fe34..d5b08cb7 100644 --- a/vnc.html +++ b/vnc.html @@ -47,8 +47,6 @@
    -
    -