init
							
								
								
									
										79
									
								
								app/error-handler.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,79 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | // Fallback for all uncought errors | ||||||
|  | function handleError(event, err) { | ||||||
|  |     try { | ||||||
|  |         const msg = document.getElementById('noVNC_fallback_errormsg'); | ||||||
|  |  | ||||||
|  |         // Work around Firefox bug: | ||||||
|  |         // https://bugzilla.mozilla.org/show_bug.cgi?id=1685038 | ||||||
|  |         if (event.message === "ResizeObserver loop completed with undelivered notifications.") { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Only show the initial error | ||||||
|  |         if (msg.hasChildNodes()) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let div = document.createElement("div"); | ||||||
|  |         div.classList.add('noVNC_message'); | ||||||
|  |         div.appendChild(document.createTextNode(event.message)); | ||||||
|  |         msg.appendChild(div); | ||||||
|  |  | ||||||
|  |         if (event.filename) { | ||||||
|  |             div = document.createElement("div"); | ||||||
|  |             div.className = 'noVNC_location'; | ||||||
|  |             let text = event.filename; | ||||||
|  |             if (event.lineno !== undefined) { | ||||||
|  |                 text += ":" + event.lineno; | ||||||
|  |                 if (event.colno !== undefined) { | ||||||
|  |                     text += ":" + event.colno; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             div.appendChild(document.createTextNode(text)); | ||||||
|  |             msg.appendChild(div); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (err && err.stack) { | ||||||
|  |             div = document.createElement("div"); | ||||||
|  |             div.className = 'noVNC_stack'; | ||||||
|  |             div.appendChild(document.createTextNode(err.stack)); | ||||||
|  |             msg.appendChild(div); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         document.getElementById('noVNC_fallback_error') | ||||||
|  |             .classList.add("noVNC_open"); | ||||||
|  |  | ||||||
|  |     } catch (exc) { | ||||||
|  |         document.write("noVNC encountered an error."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Try to disable keyboard interaction, best effort | ||||||
|  |     try { | ||||||
|  |         // Remove focus from the currently focused element in order to | ||||||
|  |         // prevent keyboard interaction from continuing | ||||||
|  |         if (document.activeElement) { document.activeElement.blur(); } | ||||||
|  |  | ||||||
|  |         // Don't let any element be focusable when showing the error | ||||||
|  |         let keyboardFocusable = 'a[href], button, input, textarea, select, details, [tabindex]'; | ||||||
|  |         document.querySelectorAll(keyboardFocusable).forEach((elem) => { | ||||||
|  |             elem.setAttribute("tabindex", "-1"); | ||||||
|  |         }); | ||||||
|  |     } catch (exc) { | ||||||
|  |         // Do nothing | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Don't return true since this would prevent the error | ||||||
|  |     // from being printed to the browser console. | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | window.addEventListener('error', evt => handleError(evt, evt.error)); | ||||||
|  | window.addEventListener('unhandledrejection', evt => handleError(evt.reason, evt.reason)); | ||||||
							
								
								
									
										92
									
								
								app/images/alt.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,92 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="alt.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="18.205425" | ||||||
|  |      inkscape:cy="17.531398" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <g | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        id="text5290"> | ||||||
|  |       <path | ||||||
|  |          d="m 9.9560547,1042.3329 -2.9394531,0 -0.4638672,1.3281 -1.8896485,0 2.7001953,-7.29 2.241211,0 2.7001958,7.29 -1.889649,0 -0.4589843,-1.3281 z m -2.4707031,-1.3526 1.9970703,0 -0.9960938,-2.9003 -1.0009765,2.9003 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5340" /> | ||||||
|  |       <path | ||||||
|  |          d="m 13.188477,1036.0634 1.748046,0 0,7.5976 -1.748046,0 0,-7.5976 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5342" /> | ||||||
|  |       <path | ||||||
|  |          d="m 18.535156,1036.6395 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151367,0.5176 0.151368,0.1318 0.600586,0.1318 l 0.898438,0 0,1.25 -1.499024,0 q -1.035156,0 -1.469726,-0.4297 -0.429688,-0.4345 -0.429688,-1.4697 l 0,-2.3193 -0.86914,0 0,-1.25 0.86914,0 0,-1.5528 1.748047,0 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5344" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										106
									
								
								app/images/clipboard.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,106 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="clipboard.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="15.366606" | ||||||
|  |      inkscape:cy="16.42981" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="M 9,6 6,6 C 5.4459889,6 5,6.4459889 5,7 l 0,13 c 0,0.554011 0.4459889,1 1,1 l 13,0 c 0.554011,0 1,-0.445989 1,-1 L 20,7 C 20,6.4459889 19.554011,6 19,6 l -3,0" | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="rect6083" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="cssssssssc" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect6085" | ||||||
|  |        width="7" | ||||||
|  |        height="4" | ||||||
|  |        x="9" | ||||||
|  |        y="1031.3622" | ||||||
|  |        ry="1.00002" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081" | ||||||
|  |        d="m 8.5071212,1038.8622 7.9999998,0" | ||||||
|  |        id="path6087" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081" | ||||||
|  |        d="m 8.5071212,1041.8622 3.9999998,0" | ||||||
|  |        id="path6089" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081" | ||||||
|  |        d="m 8.5071212,1044.8622 5.9999998,0" | ||||||
|  |        id="path6091" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										96
									
								
								app/images/connect.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,96 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="connect.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="37.14834" | ||||||
|  |      inkscape:cy="1.9525926" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <g | ||||||
|  |        id="g5103" | ||||||
|  |        transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,-729.15757,315.8823)"> | ||||||
|  |       <path | ||||||
|  |          sodipodi:nodetypes="cssssc" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="rect5096" | ||||||
|  |          d="m 11,1040.3622 -5,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-4 c 0,-1.108 0.892,-2 2,-2 l 5,0" | ||||||
|  |          style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |       <path | ||||||
|  |          style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |          d="m 14,1032.3622 5,0 c 1.108,0 2,0.892 2,2 l 0,4 c 0,1.108 -0.892,2 -2,2 l -5,0" | ||||||
|  |          id="path5099" | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          sodipodi:nodetypes="cssssc" /> | ||||||
|  |       <path | ||||||
|  |          inkscape:connector-curvature="0" | ||||||
|  |          id="path5101" | ||||||
|  |          d="m 9,1036.3622 7,0" | ||||||
|  |          style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										96
									
								
								app/images/ctrl.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,96 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="ctrl.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="18.205425" | ||||||
|  |      inkscape:cy="17.531398" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <g | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        id="text5290"> | ||||||
|  |       <path | ||||||
|  |          d="m 9.1210938,1043.1898 q -0.5175782,0.2686 -1.0791016,0.4053 -0.5615235,0.1367 -1.171875,0.1367 -1.8212891,0 -2.8857422,-1.0156 -1.0644531,-1.0205 -1.0644531,-2.7637 0,-1.748 1.0644531,-2.7637 1.0644531,-1.0205 2.8857422,-1.0205 0.6103515,0 1.171875,0.1368 0.5615234,0.1367 1.0791016,0.4052 l 0,1.5088 q -0.522461,-0.3564 -1.0302735,-0.5224 -0.5078125,-0.1661 -1.0693359,-0.1661 -1.0058594,0 -1.5820313,0.6446 -0.5761719,0.6445 -0.5761719,1.7773 0,1.1279 0.5761719,1.7725 0.5761719,0.6445 1.5820313,0.6445 0.5615234,0 1.0693359,-0.166 0.5078125,-0.166 1.0302735,-0.5225 l 0,1.5088 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5370" /> | ||||||
|  |       <path | ||||||
|  |          d="m 12.514648,1036.5687 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151368,0.5176 0.151367,0.1318 0.600586,0.1318 l 0.898437,0 0,1.25 -1.499023,0 q -1.035157,0 -1.469727,-0.4297 -0.429687,-0.4345 -0.429687,-1.4697 l 0,-2.3193 -0.8691411,0 0,-1.25 0.8691411,0 0,-1.5528 1.748046,0 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5372" /> | ||||||
|  |       <path | ||||||
|  |          d="m 19.453125,1039.6107 q -0.229492,-0.1074 -0.458984,-0.1562 -0.22461,-0.054 -0.454102,-0.054 -0.673828,0 -1.040039,0.4345 -0.361328,0.4297 -0.361328,1.2354 l 0,2.5195 -1.748047,0 0,-5.4687 1.748047,0 0,0.8984 q 0.336914,-0.5371 0.771484,-0.7813 0.439453,-0.249 1.049805,-0.249 0.08789,0 0.19043,0.01 0.102539,0 0.297851,0.029 l 0.0049,1.582 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5374" /> | ||||||
|  |       <path | ||||||
|  |          d="m 20.332031,1035.9926 1.748047,0 0,7.5976 -1.748047,0 0,-7.5976 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5376" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 4.3 KiB | 
							
								
								
									
										100
									
								
								app/images/ctrlaltdel.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,100 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="ctrlaltdel.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="8" | ||||||
|  |      inkscape:cx="11.135667" | ||||||
|  |      inkscape:cy="16.407428" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect5253" | ||||||
|  |        width="5" | ||||||
|  |        height="5.0000172" | ||||||
|  |        x="16" | ||||||
|  |        y="1031.3622" | ||||||
|  |        ry="1.0000174" /> | ||||||
|  |     <rect | ||||||
|  |        y="1043.3622" | ||||||
|  |        x="4" | ||||||
|  |        height="5.0000172" | ||||||
|  |        width="5" | ||||||
|  |        id="rect5255" | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        ry="1.0000174" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect5257" | ||||||
|  |        width="5" | ||||||
|  |        height="5.0000172" | ||||||
|  |        x="13" | ||||||
|  |        y="1043.3622" | ||||||
|  |        ry="1.0000174" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.2 KiB | 
							
								
								
									
										94
									
								
								app/images/disconnect.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,94 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="disconnect.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="25.05707" | ||||||
|  |      inkscape:cy="11.594858" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="false"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <g | ||||||
|  |        id="g5171" | ||||||
|  |        transform="translate(-24.062499,-6.15775e-4)"> | ||||||
|  |       <path | ||||||
|  |          id="path5110" | ||||||
|  |          transform="translate(0,1027.3622)" | ||||||
|  |          d="m 39.744141,3.4960938 c -0.769923,0 -1.539607,0.2915468 -2.121094,0.8730468 l -2.566406,2.5664063 1.414062,1.4140625 2.566406,-2.5664063 c 0.403974,-0.404 1.010089,-0.404 1.414063,0 l 2.828125,2.828125 c 0.40398,0.4039 0.403907,1.0101621 0,1.4140629 l -2.566406,2.566406 1.414062,1.414062 2.566406,-2.566406 c 1.163041,-1.1629 1.162968,-3.0791874 0,-4.2421874 L 41.865234,4.3691406 C 41.283747,3.7876406 40.514063,3.4960937 39.744141,3.4960938 Z M 39.017578,9.015625 a 1.0001,1.0001 0 0 0 -0.6875,0.3027344 l -0.445312,0.4453125 1.414062,1.4140621 0.445313,-0.445312 A 1.0001,1.0001 0 0 0 39.017578,9.015625 Z m -6.363281,0.7070312 a 1.0001,1.0001 0 0 0 -0.6875,0.3027348 L 28.431641,13.5625 c -1.163042,1.163 -1.16297,3.079187 0,4.242188 l 2.828125,2.828124 c 1.162974,1.163101 3.079213,1.163101 4.242187,0 l 3.535156,-3.535156 a 1.0001,1.0001 0 1 0 -1.414062,-1.414062 l -3.535156,3.535156 c -0.403974,0.404 -1.010089,0.404 -1.414063,0 l -2.828125,-2.828125 c -0.403981,-0.404 -0.403908,-1.010162 0,-1.414063 l 3.535156,-3.537109 A 1.0001,1.0001 0 0 0 32.654297,9.7226562 Z m 3.109375,2.1621098 -2.382813,2.384765 a 1.0001,1.0001 0 1 0 1.414063,1.414063 l 2.382812,-2.384766 -1.414062,-1.414062 z" | ||||||
|  |          style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |       <rect | ||||||
|  |          transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,0,0)" | ||||||
|  |          y="752.29541" | ||||||
|  |          x="-712.31262" | ||||||
|  |          height="18.000017" | ||||||
|  |          width="3" | ||||||
|  |          id="rect5116" | ||||||
|  |          style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 4.9 KiB | 
							
								
								
									
										76
									
								
								app/images/drag.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,76 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="drag.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="22.627417" | ||||||
|  |      inkscape:cx="9.8789407" | ||||||
|  |      inkscape:cy="9.5008608" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="m 7.039733,1049.3037 c -0.4309106,-0.1233 -0.7932634,-0.4631 -0.9705434,-0.9103 -0.04922,-0.1241 -0.057118,-0.2988 -0.071321,-1.5771 l -0.015972,-1.4375 -0.328125,-0.082 c -0.7668138,-0.1927 -1.1897046,-0.4275 -1.7031253,-0.9457 -0.4586773,-0.4629 -0.6804297,-0.8433 -0.867034,-1.4875 -0.067215,-0.232 -0.068001,-0.2642 -0.078682,-3.2188 -0.012078,-3.341 -0.020337,-3.2012 0.2099452,-3.5555 0.2246623,-0.3458 0.5798271,-0.5892 0.9667343,-0.6626 0.092506,-0.017 0.531898,-0.032 0.9764271,-0.032 l 0.8082347,0 1.157e-4,1.336 c 1.125e-4,1.2779 0.00281,1.3403 0.062214,1.4378 0.091785,0.1505 0.2357707,0.226 0.4314082,0.2261 0.285389,2e-4 0.454884,-0.1352 0.5058962,-0.4042 0.019355,-0.102 0.031616,-0.982 0.031616,-2.269 0,-1.9756 0.00357,-2.1138 0.059205,-2.2926 0.1645475,-0.5287 0.6307616,-0.9246 1.19078,-1.0113 0.8000572,-0.1238 1.5711277,0.4446 1.6860387,1.2429 0.01732,0.1203 0.03177,0.8248 0.03211,1.5657 6.19e-4,1.3449 7.22e-4,1.347 0.07093,1.4499 0.108355,0.1587 0.255268,0.2248 0.46917,0.2108 0.204069,-0.013 0.316116,-0.08 0.413642,-0.2453 0.06028,-0.1024 0.06307,-0.1778 0.07862,-2.1218 0.01462,-1.8283 0.02124,-2.0285 0.07121,-2.1549 0.260673,-0.659 0.934894,-1.0527 1.621129,-0.9465 0.640523,0.099 1.152269,0.6104 1.243187,1.2421 0.01827,0.1269 0.03175,0.9943 0.03211,2.0657 l 6.19e-4,1.8469 0.07031,0.103 c 0.108355,0.1587 0.255267,0.2248 0.46917,0.2108 0.204069,-0.013 0.316115,-0.08 0.413642,-0.2453 0.05951,-0.1011 0.06329,-0.1786 0.07907,-1.6218 0.01469,-1.3438 0.02277,-1.5314 0.07121,-1.6549 0.257975,-0.6576 0.934425,-1.0527 1.620676,-0.9465 0.640522,0.099 1.152269,0.6104 1.243186,1.2421 0.0186,0.1292 0.03179,1.0759 0.03222,2.3125 7.15e-4,2.0335 0.0025,2.0966 0.06283,2.1956 0.09178,0.1505 0.235771,0.226 0.431409,0.2261 0.285388,2e-4 0.454884,-0.1352 0.505897,-0.4042 0.01874,-0.099 0.03161,-0.8192 0.03161,-1.769 0,-1.4848 0.0043,-1.6163 0.0592,-1.7926 0.164548,-0.5287 0.630762,-0.9246 1.19078,-1.0113 0.800057,-0.1238 1.571128,0.4446 1.686039,1.2429 0.04318,0.2999 0.04372,9.1764 5.78e-4,9.4531 -0.04431,0.2841 -0.217814,0.6241 -0.420069,0.8232 -0.320102,0.315 -0.63307,0.4268 -1.194973,0.4268 l -0.35281,0 -2.51e-4,1.2734 c -1.25e-4,0.7046 -0.01439,1.3642 -0.03191,1.4766 -0.06665,0.4274 -0.372966,0.8704 -0.740031,1.0702 -0.349999,0.1905 0.01748,0.18 -6.242199,0.1776 -5.3622439,0 -5.7320152,-0.01 -5.9121592,-0.057 l 1.4e-5,0 z" | ||||||
|  |        id="path4379" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										81
									
								
								app/images/error.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,81 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="error.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="14.00357" | ||||||
|  |      inkscape:cy="12.443398" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="M 7 3 C 4.7839905 3 3 4.7839905 3 7 L 3 18 C 3 20.21601 4.7839905 22 7 22 L 18 22 C 20.21601 22 22 20.21601 22 18 L 22 7 C 22 4.7839905 20.21601 3 18 3 L 7 3 z M 7.6992188 6 A 1.6916875 1.6924297 0 0 1 8.9121094 6.5117188 L 12.5 10.101562 L 16.087891 6.5117188 A 1.6916875 1.6924297 0 0 1 17.251953 6 A 1.6916875 1.6924297 0 0 1 18.480469 8.90625 L 14.892578 12.496094 L 18.480469 16.085938 A 1.6916875 1.6924297 0 1 1 16.087891 18.478516 L 12.5 14.888672 L 8.9121094 18.478516 A 1.6916875 1.6924297 0 1 1 6.5214844 16.085938 L 10.109375 12.496094 L 6.5214844 8.90625 A 1.6916875 1.6924297 0 0 1 7.6992188 6 z " | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="rect4135" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.0 KiB | 
							
								
								
									
										92
									
								
								app/images/esc.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,92 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="esc.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="18.205425" | ||||||
|  |      inkscape:cy="17.531398" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="text5290" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <g | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        id="text5290"> | ||||||
|  |       <path | ||||||
|  |          d="m 3.9331055,1036.1464 5.0732422,0 0,1.4209 -3.1933594,0 0,1.3574 3.0029297,0 0,1.4209 -3.0029297,0 0,1.6699 3.3007812,0 0,1.4209 -5.180664,0 0,-7.29 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5314" /> | ||||||
|  |       <path | ||||||
|  |          d="m 14.963379,1038.1385 0,1.3282 q -0.561524,-0.2344 -1.083984,-0.3516 -0.522461,-0.1172 -0.986329,-0.1172 -0.498046,0 -0.742187,0.127 -0.239258,0.122 -0.239258,0.3808 0,0.21 0.180664,0.3223 0.185547,0.1123 0.65918,0.166 l 0.307617,0.044 q 1.342773,0.1709 1.806641,0.5615 0.463867,0.3906 0.463867,1.2256 0,0.874 -0.644531,1.3134 -0.644532,0.4395 -1.923829,0.4395 -0.541992,0 -1.123046,-0.088 -0.576172,-0.083 -1.186524,-0.2539 l 0,-1.3281 q 0.522461,0.2539 1.069336,0.3808 0.551758,0.127 1.118164,0.127 0.512695,0 0.771485,-0.1416 0.258789,-0.1416 0.258789,-0.4199 0,-0.2344 -0.180664,-0.3467 -0.175782,-0.1172 -0.708008,-0.1807 l -0.307617,-0.039 q -1.166993,-0.1465 -1.635743,-0.542 -0.46875,-0.3955 -0.46875,-1.2012 0,-0.8691 0.595703,-1.2891 0.595704,-0.4199 1.826172,-0.4199 0.483399,0 1.015625,0.073 0.532227,0.073 1.157227,0.2294 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5316" /> | ||||||
|  |       <path | ||||||
|  |          d="m 21.066895,1038.1385 0,1.4258 q -0.356446,-0.2441 -0.717774,-0.3613 -0.356445,-0.1172 -0.742187,-0.1172 -0.732422,0 -1.142579,0.4297 -0.405273,0.4248 -0.405273,1.1914 0,0.7666 0.405273,1.1963 0.410157,0.4248 1.142579,0.4248 0.410156,0 0.776367,-0.1221 0.371094,-0.122 0.683594,-0.3613 l 0,1.4307 q -0.410157,0.1513 -0.834961,0.2246 -0.419922,0.078 -0.844727,0.078 -1.479492,0 -2.314453,-0.7568 -0.834961,-0.7618 -0.834961,-2.1143 0,-1.3525 0.834961,-2.1094 0.834961,-0.7617 2.314453,-0.7617 0.429688,0 0.844727,0.078 0.419921,0.073 0.834961,0.2246 z" | ||||||
|  |          style="font-size:10px;fill:#ffffff;fill-opacity:1" | ||||||
|  |          id="path5318" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 4.4 KiB | 
							
								
								
									
										69
									
								
								app/images/expander.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="9" | ||||||
|  |    height="10" | ||||||
|  |    viewBox="0 0 9 10" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="expander.svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="45.254834" | ||||||
|  |      inkscape:cx="9.8737281" | ||||||
|  |      inkscape:cy="6.4583132" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-object-midpoints="false" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1042.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |        d="M 2.0800781,1042.3633 A 2.0002,2.0002 0 0 0 0,1044.3613 l 0,6 a 2.0002,2.0002 0 0 0 3.0292969,1.7168 l 5,-3 a 2.0002,2.0002 0 0 0 0,-3.4316 l -5,-3 a 2.0002,2.0002 0 0 0 -0.9492188,-0.2832 z" | ||||||
|  |        id="path4138" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.0 KiB | 
							
								
								
									
										93
									
								
								app/images/fullscreen.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,93 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="fullscreen.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="16.400723" | ||||||
|  |      inkscape:cy="15.083758" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="false"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect5006" | ||||||
|  |        width="17" | ||||||
|  |        height="17.000017" | ||||||
|  |        x="4" | ||||||
|  |        y="1031.3622" | ||||||
|  |        ry="3.0000174" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" | ||||||
|  |        d="m 7.5,1044.8622 4,0 -1.5,-1.5 1.5,-1.5 -1,-1 -1.5,1.5 -1.5,-1.5 0,4 z" | ||||||
|  |        id="path5017" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <path | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        id="path5025" | ||||||
|  |        d="m 17.5,1034.8622 -4,0 1.5,1.5 -1.5,1.5 1,1 1.5,-1.5 1.5,1.5 0,-4 z" | ||||||
|  |        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										82
									
								
								app/images/handle.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,82 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="5" | ||||||
|  |    height="6" | ||||||
|  |    viewBox="0 0 5 6" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="handle.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="32" | ||||||
|  |      inkscape:cx="1.3551778" | ||||||
|  |      inkscape:cy="8.7800329" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1046.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||||
|  |        d="m 4.0000803,1049.3622 -3,-2 0,4 z" | ||||||
|  |        id="path4247" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="cccc" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 2.5 KiB | 
							
								
								
									
										172
									
								
								app/images/handle_bg.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,172 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="15" | ||||||
|  |    height="50" | ||||||
|  |    viewBox="0 0 15 50" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="handle_bg.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="-10.001409" | ||||||
|  |      inkscape:cy="24.512566" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1002.3622)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4249" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="9.5" | ||||||
|  |        y="1008.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1013.8622" | ||||||
|  |        x="9.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4255" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1008.8622" | ||||||
|  |        x="4.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4261" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4263" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="4.5" | ||||||
|  |        y="1013.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1039.8622" | ||||||
|  |        x="9.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4265" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4267" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="9.5" | ||||||
|  |        y="1044.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4269" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="4.5" | ||||||
|  |        y="1039.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1044.8622" | ||||||
|  |        x="4.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4271" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4273" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="9.5" | ||||||
|  |        y="1018.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1018.8622" | ||||||
|  |        x="4.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4275" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4277" | ||||||
|  |        width="1" | ||||||
|  |        height="1.0000174" | ||||||
|  |        x="9.5" | ||||||
|  |        y="1034.8622" | ||||||
|  |        ry="1.7382812e-05" /> | ||||||
|  |     <rect | ||||||
|  |        ry="1.7382812e-05" | ||||||
|  |        y="1034.8622" | ||||||
|  |        x="4.5" | ||||||
|  |        height="1.0000174" | ||||||
|  |        width="1" | ||||||
|  |        id="rect4279" | ||||||
|  |        style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 6.2 KiB | 
							
								
								
									
										42
									
								
								app/images/icons/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,42 @@ | |||||||
|  | BROWSER_SIZES := 16 24 32 48 64 | ||||||
|  | #ANDROID_SIZES := 72 96 144 192 | ||||||
|  | # FIXME: The ICO is limited to 8 icons due to a Chrome bug: | ||||||
|  | #        https://bugs.chromium.org/p/chromium/issues/detail?id=1381393 | ||||||
|  | ANDROID_SIZES := 96 144 192 | ||||||
|  | WEB_ICON_SIZES := $(BROWSER_SIZES) $(ANDROID_SIZES) | ||||||
|  |  | ||||||
|  | #IOS_1X_SIZES := 20 29 40 76 # No such devices exist anymore | ||||||
|  | IOS_2X_SIZES := 40 58 80 120 152 167 | ||||||
|  | IOS_3X_SIZES := 60 87 120 180 | ||||||
|  | ALL_IOS_SIZES := $(IOS_1X_SIZES) $(IOS_2X_SIZES) $(IOS_3X_SIZES) | ||||||
|  |  | ||||||
|  | ALL_ICONS := \ | ||||||
|  | 	$(ALL_IOS_SIZES:%=novnc-ios-%.png) \ | ||||||
|  | 	novnc.ico | ||||||
|  |  | ||||||
|  | all: $(ALL_ICONS) | ||||||
|  |  | ||||||
|  | # Our testing shows that the ICO file need to be sorted in largest to | ||||||
|  | # smallest to get the apporpriate behviour | ||||||
|  | WEB_ICON_SIZES_REVERSE := $(shell echo $(WEB_ICON_SIZES) | tr ' ' '\n' | sort -nr | tr '\n' ' ') | ||||||
|  | WEB_BASE_ICONS := $(WEB_ICON_SIZES_REVERSE:%=novnc-%.png) | ||||||
|  | .INTERMEDIATE: $(WEB_BASE_ICONS) | ||||||
|  |  | ||||||
|  | novnc.ico: $(WEB_BASE_ICONS) | ||||||
|  | 	convert $(WEB_BASE_ICONS) "$@" | ||||||
|  |  | ||||||
|  | # General conversion | ||||||
|  | novnc-%.png: novnc-icon.svg | ||||||
|  | 	convert -depth 8 -background transparent \ | ||||||
|  | 		-size $*x$* "$(lastword $^)" "$@" | ||||||
|  |  | ||||||
|  | # iOS icons use their own SVG | ||||||
|  | novnc-ios-%.png: novnc-ios-icon.svg | ||||||
|  | 	convert -depth 8 -background transparent \ | ||||||
|  | 		-size $*x$* "$(lastword $^)" "$@" | ||||||
|  |  | ||||||
|  | # The smallest sizes are generated using a different SVG | ||||||
|  | novnc-16.png novnc-24.png novnc-32.png: novnc-icon-sm.svg | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	rm -f *.png | ||||||
							
								
								
									
										163
									
								
								app/images/icons/novnc-icon-sm.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,163 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="16" | ||||||
|  |    height="16" | ||||||
|  |    viewBox="0 0 16 16" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="novnc-icon-sm.svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="45.254834" | ||||||
|  |      inkscape:cx="9.722703" | ||||||
|  |      inkscape:cy="5.5311896" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:snap-midpoints="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4169" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1036.3621)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4167" | ||||||
|  |        width="16" | ||||||
|  |        height="15.999992" | ||||||
|  |        x="0" | ||||||
|  |        y="1036.3622" | ||||||
|  |        ry="2.6666584" /> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="M 2.6666667,1036.3621 C 1.1893373,1036.3621 0,1037.5515 0,1039.0288 l 0,10.6666 c 0,1.4774 1.1893373,2.6667 2.6666667,2.6667 l 4,0 C 11.837333,1052.3621 16,1046.7128 16,1039.6955 l 0,-0.6667 c 0,-1.4773 -1.189337,-2.6667 -2.666667,-2.6667 l -10.6666663,0 z" | ||||||
|  |        id="rect4173" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <g | ||||||
|  |        id="g4381"> | ||||||
|  |       <g | ||||||
|  |          transform="translate(0.25,0.25)" | ||||||
|  |          style="fill:#000000;fill-opacity:1" | ||||||
|  |          id="g4365"> | ||||||
|  |         <g | ||||||
|  |            style="fill:#000000;fill-opacity:1" | ||||||
|  |            id="g4367"> | ||||||
|  |           <path | ||||||
|  |              inkscape:connector-curvature="0" | ||||||
|  |              id="path4369" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 C 2.011349,1040.3621 2,1040.3741 2,1040.3981 l 0,2.964 -1,0 0,-4 z" | ||||||
|  |              sodipodi:nodetypes="scsccsssscccs" /> | ||||||
|  |           <path | ||||||
|  |              inkscape:connector-curvature="0" | ||||||
|  |              id="path4371" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z" | ||||||
|  |              sodipodi:nodetypes="sscsscsscsscssssssssss" /> | ||||||
|  |         </g> | ||||||
|  |         <g | ||||||
|  |            style="fill:#000000;fill-opacity:1" | ||||||
|  |            id="g4373"> | ||||||
|  |           <path | ||||||
|  |              inkscape:connector-curvature="0" | ||||||
|  |              id="path4375" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z" | ||||||
|  |              sodipodi:nodetypes="cccccccc" /> | ||||||
|  |           <path | ||||||
|  |              inkscape:connector-curvature="0" | ||||||
|  |              id="path4377" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z" | ||||||
|  |              sodipodi:nodetypes="ccccccccccc" /> | ||||||
|  |           <path | ||||||
|  |              inkscape:connector-curvature="0" | ||||||
|  |              id="path4379" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z" | ||||||
|  |              sodipodi:nodetypes="cssssccscsscscc" /> | ||||||
|  |         </g> | ||||||
|  |       </g> | ||||||
|  |       <g | ||||||
|  |          id="g4356"> | ||||||
|  |         <g | ||||||
|  |            id="g4347"> | ||||||
|  |           <path | ||||||
|  |              sodipodi:nodetypes="scsccsssscccs" | ||||||
|  |              d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 c -0.022689,0 -0.034038,0.012 -0.034038,0.036 l 0,2.964 -1,0 0,-4 z" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              id="path4143" | ||||||
|  |              inkscape:connector-curvature="0" /> | ||||||
|  |           <path | ||||||
|  |              sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||||
|  |              d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              id="path4145" | ||||||
|  |              inkscape:connector-curvature="0" /> | ||||||
|  |         </g> | ||||||
|  |         <g | ||||||
|  |            id="g4351"> | ||||||
|  |           <path | ||||||
|  |              sodipodi:nodetypes="cccccccc" | ||||||
|  |              d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              id="path4147" | ||||||
|  |              inkscape:connector-curvature="0" /> | ||||||
|  |           <path | ||||||
|  |              sodipodi:nodetypes="ccccccccccc" | ||||||
|  |              d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              id="path4149" | ||||||
|  |              inkscape:connector-curvature="0" /> | ||||||
|  |           <path | ||||||
|  |              sodipodi:nodetypes="cssssccscsscscc" | ||||||
|  |              d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z" | ||||||
|  |              style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |              id="path4151" | ||||||
|  |              inkscape:connector-curvature="0" /> | ||||||
|  |         </g> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										163
									
								
								app/images/icons/novnc-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,163 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="48" | ||||||
|  |    height="48" | ||||||
|  |    viewBox="0 0 48 48.000001" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="novnc-icon.svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="11.313708" | ||||||
|  |      inkscape:cx="27.187245" | ||||||
|  |      inkscape:cy="17.700974" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:snap-midpoints="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4169" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1004.3621)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4167" | ||||||
|  |        width="48" | ||||||
|  |        height="48" | ||||||
|  |        x="0" | ||||||
|  |        y="1004.3621" | ||||||
|  |        ry="7.9999785" /> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="m 8,1004.3621 c -4.4319881,0 -8,3.568 -8,8 l 0,32 c 0,4.432 3.5680119,8 8,8 l 12,0 c 15.512,0 28,-16.948 28,-38 l 0,-2 c 0,-4.432 -3.568012,-8 -8,-8 l -32,0 z" | ||||||
|  |        id="rect4173" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <g | ||||||
|  |        id="g4300" | ||||||
|  |        style="fill:#000000;fill-opacity:1;stroke:none" | ||||||
|  |        transform="translate(0.5,0.5)"> | ||||||
|  |       <g | ||||||
|  |          id="g4302" | ||||||
|  |          style="fill:#000000;fill-opacity:1;stroke:none"> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="scsccsssscccs" | ||||||
|  |            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4304" | ||||||
|  |            inkscape:connector-curvature="0" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||||
|  |            d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4306" | ||||||
|  |            inkscape:connector-curvature="0" /> | ||||||
|  |       </g> | ||||||
|  |       <g | ||||||
|  |          id="g4308" | ||||||
|  |          style="fill:#000000;fill-opacity:1;stroke:none"> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="cccccccc" | ||||||
|  |            d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4310" | ||||||
|  |            inkscape:connector-curvature="0" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="ccccccccccc" | ||||||
|  |            d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4312" | ||||||
|  |            inkscape:connector-curvature="0" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="cssssccscsscscc" | ||||||
|  |            d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4314" | ||||||
|  |            inkscape:connector-curvature="0" /> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        id="g4291" | ||||||
|  |        style="stroke:none"> | ||||||
|  |       <g | ||||||
|  |          id="g4282" | ||||||
|  |          style="stroke:none"> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4143" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z" | ||||||
|  |            sodipodi:nodetypes="scsccsssscccs" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4145" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||||
|  |            sodipodi:nodetypes="sscsscsscsscssssssssss" /> | ||||||
|  |       </g> | ||||||
|  |       <g | ||||||
|  |          id="g4286" | ||||||
|  |          style="stroke:none"> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4147" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z" | ||||||
|  |            sodipodi:nodetypes="cccccccc" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4149" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z" | ||||||
|  |            sodipodi:nodetypes="ccccccccccc" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4151" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z" | ||||||
|  |            sodipodi:nodetypes="cssssccscsscscc" /> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-120.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-152.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-167.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-180.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-40.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-58.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-60.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-80.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc-ios-87.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.6 KiB | 
							
								
								
									
										183
									
								
								app/images/icons/novnc-ios-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,183 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    width="48" | ||||||
|  |    height="48" | ||||||
|  |    viewBox="0 0 48 48.000001" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" | ||||||
|  |    sodipodi:docname="novnc-ios-icon.svg" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0.0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="11.313708" | ||||||
|  |      inkscape:cx="27.356195" | ||||||
|  |      inkscape:cy="17.810253" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:snap-midpoints="true" | ||||||
|  |      inkscape:window-width="2560" | ||||||
|  |      inkscape:window-height="1371" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="0" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:showpageshadow="2" | ||||||
|  |      inkscape:pagecheckerboard="0" | ||||||
|  |      inkscape:deskcolor="#d1d1d1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4169" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1004.3621)"> | ||||||
|  |     <rect | ||||||
|  |        style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        id="rect4167" | ||||||
|  |        width="48" | ||||||
|  |        height="48" | ||||||
|  |        x="0" | ||||||
|  |        y="1004.3621" | ||||||
|  |        inkscape:label="background" /> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="m 0,1004.3621 v 48 h 20 c 15.512,0 28,-16.948 28,-38 v -10 z" | ||||||
|  |        id="rect4173" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="cccccc" | ||||||
|  |        inkscape:label="darker_grey_plate" /> | ||||||
|  |     <g | ||||||
|  |        id="g4300" | ||||||
|  |        style="display:inline;fill:#000000;fill-opacity:1;stroke:none" | ||||||
|  |        transform="translate(0.5,0.5)" | ||||||
|  |        inkscape:label="shadows"> | ||||||
|  |       <g | ||||||
|  |          id="g4302" | ||||||
|  |          style="fill:#000000;fill-opacity:1;stroke:none" | ||||||
|  |          inkscape:label="no"> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="scsccsssscccs" | ||||||
|  |            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 v 6.8586 h -2 v -6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 H 7.1021125 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 v 6.8914 H 5 v -9 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4304" | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            inkscape:label="n" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||||
|  |            d="m 17.013073,1016.3621 h 4.973854 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 v 4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 h -4.973854 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 v -4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 h -4.795776 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 v 4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 h 4.795776 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 v -4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4306" | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            inkscape:label="o" /> | ||||||
|  |       </g> | ||||||
|  |       <g | ||||||
|  |          id="g4308" | ||||||
|  |          style="fill:#000000;fill-opacity:1;stroke:none" | ||||||
|  |          inkscape:label="VNC"> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="cccccccc" | ||||||
|  |            d="m 12,1036.9177 4.768114,-8.5556 H 19 l -6,11 h -2 l -6,-11 h 2.2318854 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4310" | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            inkscape:label="V" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="ccccccccccc" | ||||||
|  |            d="m 29,1036.3621 v -8 h 2 v 11 h -2 l -7,-8 v 8 h -2 v -11 h 2 z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4312" | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            inkscape:label="N" /> | ||||||
|  |         <path | ||||||
|  |            sodipodi:nodetypes="cssssccscsscscc" | ||||||
|  |            d="m 43,1030.3621 h -8.897887 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 v 6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 H 43 v 2 h -8.972339 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 v -6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 H 43 Z" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            id="path4314" | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            inkscape:label="C" /> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |     <g | ||||||
|  |        id="g4291" | ||||||
|  |        style="stroke:none" | ||||||
|  |        inkscape:label="noVNC"> | ||||||
|  |       <g | ||||||
|  |          id="g4282" | ||||||
|  |          style="stroke:none" | ||||||
|  |          inkscape:label="no"> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4143" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z" | ||||||
|  |            sodipodi:nodetypes="scsccsssscccs" | ||||||
|  |            inkscape:label="n" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4145" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z" | ||||||
|  |            sodipodi:nodetypes="sscsscsscsscssssssssss" | ||||||
|  |            inkscape:label="o" /> | ||||||
|  |       </g> | ||||||
|  |       <g | ||||||
|  |          id="g4286" | ||||||
|  |          style="stroke:none" | ||||||
|  |          inkscape:label="VNC"> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4147" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z" | ||||||
|  |            sodipodi:nodetypes="cccccccc" | ||||||
|  |            inkscape:label="V" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4149" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z" | ||||||
|  |            sodipodi:nodetypes="ccccccccccc" | ||||||
|  |            inkscape:label="N" /> | ||||||
|  |         <path | ||||||
|  |            inkscape:connector-curvature="0" | ||||||
|  |            id="path4151" | ||||||
|  |            style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |            d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z" | ||||||
|  |            sodipodi:nodetypes="cssssccscsscscc" | ||||||
|  |            inkscape:label="C" /> | ||||||
|  |       </g> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/images/icons/novnc.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 303 KiB | 
							
								
								
									
										81
									
								
								app/images/info.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,81 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="info.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="15.720838" | ||||||
|  |      inkscape:cy="8.9111233" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="M 12.5 3 A 9.5 9.4999914 0 0 0 3 12.5 A 9.5 9.4999914 0 0 0 12.5 22 A 9.5 9.4999914 0 0 0 22 12.5 A 9.5 9.4999914 0 0 0 12.5 3 z M 12.5 5 A 1.5 1.5000087 0 0 1 14 6.5 A 1.5 1.5000087 0 0 1 12.5 8 A 1.5 1.5000087 0 0 1 11 6.5 A 1.5 1.5000087 0 0 1 12.5 5 z M 10.521484 8.9785156 L 12.521484 8.9785156 A 1.50015 1.50015 0 0 1 14.021484 10.478516 L 14.021484 15.972656 A 1.50015 1.50015 0 0 1 14.498047 18.894531 C 14.498047 18.894531 13.74301 19.228309 12.789062 18.912109 C 12.312092 18.754109 11.776235 18.366625 11.458984 17.828125 C 11.141734 17.289525 11.021484 16.668469 11.021484 15.980469 L 11.021484 11.980469 L 10.521484 11.980469 A 1.50015 1.50015 0 1 1 10.521484 8.9804688 L 10.521484 8.9785156 z " | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="path4136" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										88
									
								
								app/images/keyboard.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,88 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="keyboard.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/keyboard.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#717171" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="31.285341" | ||||||
|  |      inkscape:cy="8.8028469" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:snap-bbox-midpoints="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-midpoints="true" | ||||||
|  |      inkscape:snap-smooth-nodes="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |        d="M 7,3 C 4.8012876,3 3,4.8013 3,7 3,11.166667 3,15.333333 3,19.5 3,20.8764 4.1236413,22 5.5,22 l 14,0 C 20.876358,22 22,20.8764 22,19.5 22,15.333333 22,11.166667 22,7 22,4.8013 20.198712,3 18,3 Z m 0,2 11,0 c 1.125307,0 2,0.8747 2,2 L 20,12 5,12 5,7 C 5,5.8747 5.8746931,5 7,5 Z M 6.5,14 C 6.777,14 7,14.223 7,14.5 7,14.777 6.777,15 6.5,15 6.223,15 6,14.777 6,14.5 6,14.223 6.223,14 6.5,14 Z m 2,0 C 8.777,14 9,14.223 9,14.5 9,14.777 8.777,15 8.5,15 8.223,15 8,14.777 8,14.5 8,14.223 8.223,14 8.5,14 Z m 2,0 C 10.777,14 11,14.223 11,14.5 11,14.777 10.777,15 10.5,15 10.223,15 10,14.777 10,14.5 10,14.223 10.223,14 10.5,14 Z m 2,0 C 12.777,14 13,14.223 13,14.5 13,14.777 12.777,15 12.5,15 12.223,15 12,14.777 12,14.5 12,14.223 12.223,14 12.5,14 Z m 2,0 C 14.777,14 15,14.223 15,14.5 15,14.777 14.777,15 14.5,15 14.223,15 14,14.777 14,14.5 14,14.223 14.223,14 14.5,14 Z m 2,0 C 16.777,14 17,14.223 17,14.5 17,14.777 16.777,15 16.5,15 16.223,15 16,14.777 16,14.5 16,14.223 16.223,14 16.5,14 Z m 2,0 C 18.777,14 19,14.223 19,14.5 19,14.777 18.777,15 18.5,15 18.223,15 18,14.777 18,14.5 18,14.223 18.223,14 18.5,14 Z m -13,2 C 5.777,16 6,16.223 6,16.5 6,16.777 5.777,17 5.5,17 5.223,17 5,16.777 5,16.5 5,16.223 5.223,16 5.5,16 Z m 2,0 C 7.777,16 8,16.223 8,16.5 8,16.777 7.777,17 7.5,17 7.223,17 7,16.777 7,16.5 7,16.223 7.223,16 7.5,16 Z m 2,0 C 9.777,16 10,16.223 10,16.5 10,16.777 9.777,17 9.5,17 9.223,17 9,16.777 9,16.5 9,16.223 9.223,16 9.5,16 Z m 2,0 C 11.777,16 12,16.223 12,16.5 12,16.777 11.777,17 11.5,17 11.223,17 11,16.777 11,16.5 11,16.223 11.223,16 11.5,16 Z m 2,0 C 13.777,16 14,16.223 14,16.5 14,16.777 13.777,17 13.5,17 13.223,17 13,16.777 13,16.5 13,16.223 13.223,16 13.5,16 Z m 2,0 C 15.777,16 16,16.223 16,16.5 16,16.777 15.777,17 15.5,17 15.223,17 15,16.777 15,16.5 15,16.223 15.223,16 15.5,16 Z m 2,0 C 17.777,16 18,16.223 18,16.5 18,16.777 17.777,17 17.5,17 17.223,17 17,16.777 17,16.5 17,16.223 17.223,16 17.5,16 Z m 2,0 C 19.777,16 20,16.223 20,16.5 20,16.777 19.777,17 19.5,17 19.223,17 19,16.777 19,16.5 19,16.223 19.223,16 19.5,16 Z M 6,18 c 0.554,0 1,0.446 1,1 0,0.554 -0.446,1 -1,1 -0.554,0 -1,-0.446 -1,-1 0,-0.554 0.446,-1 1,-1 z m 2.8261719,0 7.3476561,0 C 16.631643,18 17,18.368372 17,18.826172 l 0,0.347656 C 17,19.631628 16.631643,20 16.173828,20 L 8.8261719,20 C 8.3683573,20 8,19.631628 8,19.173828 L 8,18.826172 C 8,18.368372 8.3683573,18 8.8261719,18 Z m 10.1113281,0 0.125,0 C 19.581551,18 20,18.4184 20,18.9375 l 0,0.125 C 20,19.5816 19.581551,20 19.0625,20 l -0.125,0 C 18.418449,20 18,19.5816 18,19.0625 l 0,-0.125 C 18,18.4184 18.418449,18 18.9375,18 Z" | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="rect4160" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="sccssccsssssccssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" | ||||||
|  |        d="m 12.499929,1033.8622 -2,2 1.500071,0 0,2 1,0 0,-2 1.499929,0 z" | ||||||
|  |        id="path4150" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="cccccccc" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 6.3 KiB | 
							
								
								
									
										87
									
								
								app/images/power.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,87 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="power.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="9.3159849" | ||||||
|  |      inkscape:cy="13.436208" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |        d="M 9 6.8183594 C 6.3418164 8.1213032 4.5 10.849161 4.5 14 C 4.5 18.4065 8.0935666 22 12.5 22 C 16.906433 22 20.5 18.4065 20.5 14 C 20.5 10.849161 18.658184 8.1213032 16 6.8183594 L 16 9.125 C 17.514327 10.211757 18.5 11.984508 18.5 14 C 18.5 17.3256 15.825553 20 12.5 20 C 9.1744469 20 6.5 17.3256 6.5 14 C 6.5 11.984508 7.4856727 10.211757 9 9.125 L 9 6.8183594 z " | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="path6140" /> | ||||||
|  |     <path | ||||||
|  |        style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||||
|  |        d="m 12.5,1031.8836 0,6.4786" | ||||||
|  |        id="path6142" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="cc" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										76
									
								
								app/images/settings.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,76 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="settings.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="22.627417" | ||||||
|  |      inkscape:cx="14.69683" | ||||||
|  |      inkscape:cy="8.8039511" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="true" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="M 11 3 L 11 5.1601562 A 7.5 7.5 0 0 0 8.3671875 6.2460938 L 6.84375 4.7226562 L 4.7226562 6.84375 L 6.2480469 8.3691406 A 7.5 7.5 0 0 0 5.1523438 11 L 3 11 L 3 14 L 5.1601562 14 A 7.5 7.5 0 0 0 6.2460938 16.632812 L 4.7226562 18.15625 L 6.84375 20.277344 L 8.3691406 18.751953 A 7.5 7.5 0 0 0 11 19.847656 L 11 22 L 14 22 L 14 19.839844 A 7.5 7.5 0 0 0 16.632812 18.753906 L 18.15625 20.277344 L 20.277344 18.15625 L 18.751953 16.630859 A 7.5 7.5 0 0 0 19.847656 14 L 22 14 L 22 11 L 19.839844 11 A 7.5 7.5 0 0 0 18.753906 8.3671875 L 20.277344 6.84375 L 18.15625 4.7226562 L 16.630859 6.2480469 A 7.5 7.5 0 0 0 14 5.1523438 L 14 3 L 11 3 z M 12.5 10 A 2.5 2.5 0 0 1 15 12.5 A 2.5 2.5 0 0 1 12.5 15 A 2.5 2.5 0 0 1 10 12.5 A 2.5 2.5 0 0 1 12.5 10 z " | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="rect4967" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.0 KiB | 
							
								
								
									
										86
									
								
								app/images/tab.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,86 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="tab.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="16" | ||||||
|  |      inkscape:cx="11.67335" | ||||||
|  |      inkscape:cy="17.881696" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="true" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        d="m 3,1031.3622 0,8 2,0 0,-4 0,-4 -2,0 z m 2,4 4,4 0,-3 13,0 0,-2 -13,0 0,-3 -4,4 z" | ||||||
|  |        id="rect5194" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |     <path | ||||||
|  |        id="path5211" | ||||||
|  |        d="m 22,1048.3622 0,-8 -2,0 0,4 0,4 2,0 z m -2,-4 -4,-4 0,3 -13,0 0,2 13,0 0,3 4,-4 z" | ||||||
|  |        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | ||||||
|  |        inkscape:connector-curvature="0" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 2.9 KiB | 
							
								
								
									
										90
									
								
								app/images/toggleextrakeys.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,90 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="extrakeys.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="15.234555" | ||||||
|  |      inkscape:cy="9.9710826" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="false"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |        d="m 8,1031.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,8.9996 c 0,2.1987 1.8012876,4 4,4 l 9,0 c 2.198712,0 4,-1.8013 4,-4 l 0,-8.9996 c 0,-2.1987 -1.801288,-4 -4,-4 z m 0,2 9,0 c 1.125307,0 2,0.8747 2,2 l 0,7.0005 c 0,1.1253 -0.874693,2 -2,2 l -9,0 c -1.1253069,0 -2,-0.8747 -2,-2 l 0,-7.0005 c 0,-1.1253 0.8746931,-2 2,-2 z" | ||||||
|  |        id="rect5006" | ||||||
|  |        inkscape:connector-curvature="0" | ||||||
|  |        sodipodi:nodetypes="ssssssssssssssssss" /> | ||||||
|  |     <g | ||||||
|  |        style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |        id="text4167" | ||||||
|  |        transform="matrix(0.96021948,0,0,0.96021948,0.18921715,41.80659)"> | ||||||
|  |       <path | ||||||
|  |          d="m 14.292969,1040.6791 -2.939453,0 -0.463868,1.3281 -1.889648,0 2.700195,-7.29 2.241211,0 2.700196,7.29 -1.889649,0 -0.458984,-1.3281 z m -2.470703,-1.3526 1.99707,0 -0.996094,-2.9004 -1.000976,2.9004 z" | ||||||
|  |          id="path4172" | ||||||
|  |          inkscape:connector-curvature="0" /> | ||||||
|  |     </g> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 4.3 KiB | 
							
								
								
									
										81
									
								
								app/images/warning.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,81 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    width="25" | ||||||
|  |    height="25" | ||||||
|  |    viewBox="0 0 25 25" | ||||||
|  |    id="svg2" | ||||||
|  |    version="1.1" | ||||||
|  |    inkscape:version="0.91 r13725" | ||||||
|  |    sodipodi:docname="warning.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    inkscape:export-ydpi="90"> | ||||||
|  |   <defs | ||||||
|  |      id="defs4" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="base" | ||||||
|  |      pagecolor="#959595" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1.0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:zoom="1" | ||||||
|  |      inkscape:cx="16.457343" | ||||||
|  |      inkscape:cy="12.179552" | ||||||
|  |      inkscape:document-units="px" | ||||||
|  |      inkscape:current-layer="layer1" | ||||||
|  |      showgrid="false" | ||||||
|  |      units="px" | ||||||
|  |      inkscape:snap-bbox="true" | ||||||
|  |      inkscape:bbox-paths="true" | ||||||
|  |      inkscape:bbox-nodes="true" | ||||||
|  |      inkscape:snap-bbox-edge-midpoints="true" | ||||||
|  |      inkscape:object-paths="true" | ||||||
|  |      showguides="false" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1136" | ||||||
|  |      inkscape:window-x="1920" | ||||||
|  |      inkscape:window-y="27" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:snap-smooth-nodes="true" | ||||||
|  |      inkscape:object-nodes="true" | ||||||
|  |      inkscape:snap-intersection-paths="true" | ||||||
|  |      inkscape:snap-nodes="true" | ||||||
|  |      inkscape:snap-global="true"> | ||||||
|  |     <inkscape:grid | ||||||
|  |        type="xygrid" | ||||||
|  |        id="grid4136" /> | ||||||
|  |   </sodipodi:namedview> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata7"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |         <dc:title></dc:title> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <g | ||||||
|  |      inkscape:label="Layer 1" | ||||||
|  |      inkscape:groupmode="layer" | ||||||
|  |      id="layer1" | ||||||
|  |      transform="translate(0,-1027.3622)"> | ||||||
|  |     <path | ||||||
|  |        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" | ||||||
|  |        d="M 12.513672 3.0019531 C 11.751609 2.9919531 11.052563 3.4242687 10.710938 4.1054688 L 3.2109375 19.105469 C 2.5461937 20.435369 3.5132277 21.9999 5 22 L 20 22 C 21.486772 21.9999 22.453806 20.435369 21.789062 19.105469 L 14.289062 4.1054688 C 13.951849 3.4330688 13.265888 3.0066531 12.513672 3.0019531 z M 12.478516 6.9804688 A 1.50015 1.50015 0 0 1 14 8.5 L 14 14.5 A 1.50015 1.50015 0 1 1 11 14.5 L 11 8.5 A 1.50015 1.50015 0 0 1 12.478516 6.9804688 z M 12.5 17 A 1.5 1.5 0 0 1 14 18.5 A 1.5 1.5 0 0 1 12.5 20 A 1.5 1.5 0 0 1 11 18.5 A 1.5 1.5 0 0 1 12.5 17 z " | ||||||
|  |        transform="translate(0,1027.3622)" | ||||||
|  |        id="path4208" /> | ||||||
|  |   </g> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 3.8 KiB | 
							
								
								
									
										65
									
								
								app/images/windows.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,65 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||||
|  |  | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    version="1.1" | ||||||
|  |    id="svg2" | ||||||
|  |    inkscape:export-ydpi="90" | ||||||
|  |    inkscape:export-xdpi="90" | ||||||
|  |    sodipodi:docname="windows.svg" | ||||||
|  |    inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png" | ||||||
|  |    inkscape:version="0.92.4 (unknown)" | ||||||
|  |    x="0px" | ||||||
|  |    y="0px" | ||||||
|  |    viewBox="-293 384 25 25" | ||||||
|  |    xml:space="preserve" | ||||||
|  |    width="25" | ||||||
|  |    height="25"><metadata | ||||||
|  |    id="metadata21"><rdf:RDF><cc:Work | ||||||
|  |        rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | ||||||
|  |          rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs | ||||||
|  |    id="defs19" /><sodipodi:namedview | ||||||
|  |    pagecolor="#959595" | ||||||
|  |    bordercolor="#666666" | ||||||
|  |    borderopacity="1" | ||||||
|  |    objecttolerance="10" | ||||||
|  |    gridtolerance="10" | ||||||
|  |    guidetolerance="10" | ||||||
|  |    inkscape:pageopacity="0" | ||||||
|  |    inkscape:pageshadow="2" | ||||||
|  |    inkscape:window-width="1920" | ||||||
|  |    inkscape:window-height="1136" | ||||||
|  |    id="namedview17" | ||||||
|  |    showgrid="true" | ||||||
|  |    inkscape:pagecheckerboard="false" | ||||||
|  |    inkscape:zoom="32" | ||||||
|  |    inkscape:cx="3.926913" | ||||||
|  |    inkscape:cy="13.255959" | ||||||
|  |    inkscape:window-x="1920" | ||||||
|  |    inkscape:window-y="27" | ||||||
|  |    inkscape:window-maximized="1" | ||||||
|  |    inkscape:current-layer="svg2"><inkscape:grid | ||||||
|  |      type="xygrid" | ||||||
|  |      id="grid818" /></sodipodi:namedview> | ||||||
|  | <style | ||||||
|  |    type="text/css" | ||||||
|  |    id="style2"> | ||||||
|  | 	.st0{fill:#FFFFFF;} | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  | <path | ||||||
|  |    style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" | ||||||
|  |    d="M 21 4 L 11 5.1757812 L 11 12 L 21 12 L 21 4 z M 10 5.2949219 L 4 6 L 4 12 L 10 12 L 10 5.2949219 z " | ||||||
|  |    transform="translate(-293,384)" | ||||||
|  |    id="path853" /><path | ||||||
|  |    id="path858" | ||||||
|  |    d="m -272,405 -10,-1.17578 V 397 h 10 z M -283,403.70508 -289,403 v -6 h 6 z" | ||||||
|  |    style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" | ||||||
|  |    inkscape:connector-curvature="0" /></svg> | ||||||
| After Width: | Height: | Size: 2.4 KiB | 
							
								
								
									
										1
									
								
								app/locale/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | DO NOT MODIFY THE FILES IN THIS FOLDER, THEY ARE AUTOMATICALLY GENERATED FROM THE PO-FILES. | ||||||
							
								
								
									
										71
									
								
								app/locale/cs.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,71 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Připojení...", | ||||||
|  |     "Disconnecting...": "Odpojení...", | ||||||
|  |     "Reconnecting...": "Obnova připojení...", | ||||||
|  |     "Internal error": "Vnitřní chyba", | ||||||
|  |     "Must set host": "Hostitel musí být nastavení", | ||||||
|  |     "Connected (encrypted) to ": "Připojení (šifrované) k ", | ||||||
|  |     "Connected (unencrypted) to ": "Připojení (nešifrované) k ", | ||||||
|  |     "Something went wrong, connection is closed": "Něco se pokazilo, odpojeno", | ||||||
|  |     "Failed to connect to server": "Chyba připojení k serveru", | ||||||
|  |     "Disconnected": "Odpojeno", | ||||||
|  |     "New connection has been rejected with reason: ": "Nové připojení bylo odmítnuto s odůvodněním: ", | ||||||
|  |     "New connection has been rejected": "Nové připojení bylo odmítnuto", | ||||||
|  |     "Password is required": "Je vyžadováno heslo", | ||||||
|  |     "noVNC encountered an error:": "noVNC narazilo na chybu:", | ||||||
|  |     "Hide/Show the control bar": "Skrýt/zobrazit ovládací panel", | ||||||
|  |     "Move/Drag Viewport": "Přesunout/přetáhnout výřez", | ||||||
|  |     "viewport drag": "přesun výřezu", | ||||||
|  |     "Active Mouse Button": "Aktivní tlačítka myši", | ||||||
|  |     "No mousebutton": "Žádné", | ||||||
|  |     "Left mousebutton": "Levé tlačítko myši", | ||||||
|  |     "Middle mousebutton": "Prostřední tlačítko myši", | ||||||
|  |     "Right mousebutton": "Pravé tlačítko myši", | ||||||
|  |     "Keyboard": "Klávesnice", | ||||||
|  |     "Show Keyboard": "Zobrazit klávesnici", | ||||||
|  |     "Extra keys": "Extra klávesy", | ||||||
|  |     "Show Extra Keys": "Zobrazit extra klávesy", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Přepnout Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Přepnout Alt", | ||||||
|  |     "Send Tab": "Odeslat tabulátor", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Odeslat Esc", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Poslat Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Vypnutí/Restart", | ||||||
|  |     "Shutdown/Reboot...": "Vypnutí/Restart...", | ||||||
|  |     "Power": "Napájení", | ||||||
|  |     "Shutdown": "Vypnout", | ||||||
|  |     "Reboot": "Restart", | ||||||
|  |     "Reset": "Reset", | ||||||
|  |     "Clipboard": "Schránka", | ||||||
|  |     "Clear": "Vymazat", | ||||||
|  |     "Fullscreen": "Celá obrazovka", | ||||||
|  |     "Settings": "Nastavení", | ||||||
|  |     "Shared Mode": "Sdílený režim", | ||||||
|  |     "View Only": "Pouze prohlížení", | ||||||
|  |     "Clip to Window": "Přizpůsobit oknu", | ||||||
|  |     "Scaling Mode:": "Přizpůsobení velikosti", | ||||||
|  |     "None": "Žádné", | ||||||
|  |     "Local Scaling": "Místní", | ||||||
|  |     "Remote Resizing": "Vzdálené", | ||||||
|  |     "Advanced": "Pokročilé", | ||||||
|  |     "Repeater ID:": "ID opakovače", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Šifrování:", | ||||||
|  |     "Host:": "Hostitel:", | ||||||
|  |     "Port:": "Port:", | ||||||
|  |     "Path:": "Cesta", | ||||||
|  |     "Automatic Reconnect": "Automatická obnova připojení", | ||||||
|  |     "Reconnect Delay (ms):": "Zpoždění připojení (ms)", | ||||||
|  |     "Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši", | ||||||
|  |     "Logging:": "Logování:", | ||||||
|  |     "Disconnect": "Odpojit", | ||||||
|  |     "Connect": "Připojit", | ||||||
|  |     "Password:": "Heslo", | ||||||
|  |     "Send Password": "Odeslat heslo", | ||||||
|  |     "Cancel": "Zrušit" | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								app/locale/de.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Verbinden...", | ||||||
|  |     "Disconnecting...": "Verbindung trennen...", | ||||||
|  |     "Reconnecting...": "Verbindung wiederherstellen...", | ||||||
|  |     "Internal error": "Interner Fehler", | ||||||
|  |     "Must set host": "Richten Sie den Server ein", | ||||||
|  |     "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", | ||||||
|  |     "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", | ||||||
|  |     "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt", | ||||||
|  |     "Disconnected": "Verbindung zum Server getrennt", | ||||||
|  |     "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ", | ||||||
|  |     "New connection has been rejected": "Verbindung wurde abgelehnt", | ||||||
|  |     "Password is required": "Passwort ist erforderlich", | ||||||
|  |     "noVNC encountered an error:": "Ein Fehler ist aufgetreten:", | ||||||
|  |     "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", | ||||||
|  |     "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", | ||||||
|  |     "viewport drag": "Ansichtsfenster ziehen", | ||||||
|  |     "Active Mouse Button": "Aktive Maustaste", | ||||||
|  |     "No mousebutton": "Keine Maustaste", | ||||||
|  |     "Left mousebutton": "Linke Maustaste", | ||||||
|  |     "Middle mousebutton": "Mittlere Maustaste", | ||||||
|  |     "Right mousebutton": "Rechte Maustaste", | ||||||
|  |     "Keyboard": "Tastatur", | ||||||
|  |     "Show Keyboard": "Tastatur anzeigen", | ||||||
|  |     "Extra keys": "Zusatztasten", | ||||||
|  |     "Show Extra Keys": "Zusatztasten anzeigen", | ||||||
|  |     "Ctrl": "Strg", | ||||||
|  |     "Toggle Ctrl": "Strg umschalten", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Alt umschalten", | ||||||
|  |     "Send Tab": "Tab senden", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Escape senden", | ||||||
|  |     "Ctrl+Alt+Del": "Strg+Alt+Entf", | ||||||
|  |     "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden", | ||||||
|  |     "Shutdown/Reboot": "Herunterfahren/Neustarten", | ||||||
|  |     "Shutdown/Reboot...": "Herunterfahren/Neustarten...", | ||||||
|  |     "Power": "Energie", | ||||||
|  |     "Shutdown": "Herunterfahren", | ||||||
|  |     "Reboot": "Neustarten", | ||||||
|  |     "Reset": "Zurücksetzen", | ||||||
|  |     "Clipboard": "Zwischenablage", | ||||||
|  |     "Clear": "Löschen", | ||||||
|  |     "Fullscreen": "Vollbild", | ||||||
|  |     "Settings": "Einstellungen", | ||||||
|  |     "Shared Mode": "Geteilter Modus", | ||||||
|  |     "View Only": "Nur betrachten", | ||||||
|  |     "Clip to Window": "Auf Fenster begrenzen", | ||||||
|  |     "Scaling Mode:": "Skalierungsmodus:", | ||||||
|  |     "None": "Keiner", | ||||||
|  |     "Local Scaling": "Lokales skalieren", | ||||||
|  |     "Remote Resizing": "Serverseitiges skalieren", | ||||||
|  |     "Advanced": "Erweitert", | ||||||
|  |     "Repeater ID:": "Repeater ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Verschlüsselt", | ||||||
|  |     "Host:": "Server:", | ||||||
|  |     "Port:": "Port:", | ||||||
|  |     "Path:": "Pfad:", | ||||||
|  |     "Automatic Reconnect": "Automatisch wiederverbinden", | ||||||
|  |     "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", | ||||||
|  |     "Logging:": "Protokollierung:", | ||||||
|  |     "Disconnect": "Verbindung trennen", | ||||||
|  |     "Connect": "Verbinden", | ||||||
|  |     "Password:": "Passwort:", | ||||||
|  |     "Cancel": "Abbrechen", | ||||||
|  |     "Canvas not supported.": "Canvas nicht unterstützt." | ||||||
|  | } | ||||||
							
								
								
									
										79
									
								
								app/locale/el.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,79 @@ | |||||||
|  | { | ||||||
|  |     "HTTPS is required for full functionality": "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα", | ||||||
|  |     "Connecting...": "Συνδέεται...", | ||||||
|  |     "Disconnecting...": "Aποσυνδέεται...", | ||||||
|  |     "Reconnecting...": "Επανασυνδέεται...", | ||||||
|  |     "Internal error": "Εσωτερικό σφάλμα", | ||||||
|  |     "Must set host": "Πρέπει να οριστεί ο διακομιστής", | ||||||
|  |     "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ", | ||||||
|  |     "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ", | ||||||
|  |     "Something went wrong, connection is closed": "Κάτι πήγε στραβά, η σύνδεση διακόπηκε", | ||||||
|  |     "Failed to connect to server": "Αποτυχία στη σύνδεση με το διακομιστή", | ||||||
|  |     "Disconnected": "Αποσυνδέθηκε", | ||||||
|  |     "New connection has been rejected with reason: ": "Η νέα σύνδεση απορρίφθηκε διότι: ", | ||||||
|  |     "New connection has been rejected": "Η νέα σύνδεση απορρίφθηκε ", | ||||||
|  |     "Credentials are required": "Απαιτούνται διαπιστευτήρια", | ||||||
|  |     "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:", | ||||||
|  |     "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου", | ||||||
|  |     "Drag": "Σύρσιμο", | ||||||
|  |     "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου", | ||||||
|  |     "Keyboard": "Πληκτρολόγιο", | ||||||
|  |     "Show Keyboard": "Εμφάνιση Πληκτρολογίου", | ||||||
|  |     "Extra keys": "Επιπλέον πλήκτρα", | ||||||
|  |     "Show Extra Keys": "Εμφάνιση Επιπλέον Πλήκτρων", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Εναλλαγή Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Εναλλαγή Alt", | ||||||
|  |     "Toggle Windows": "Εναλλαγή Παράθυρων", | ||||||
|  |     "Windows": "Παράθυρα", | ||||||
|  |     "Send Tab": "Αποστολή Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Αποστολή Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Αποστολή Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Κλείσιμο/Επανεκκίνηση", | ||||||
|  |     "Shutdown/Reboot...": "Κλείσιμο/Επανεκκίνηση...", | ||||||
|  |     "Power": "Απενεργοποίηση", | ||||||
|  |     "Shutdown": "Κλείσιμο", | ||||||
|  |     "Reboot": "Επανεκκίνηση", | ||||||
|  |     "Reset": "Επαναφορά", | ||||||
|  |     "Clipboard": "Πρόχειρο", | ||||||
|  |     "Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.", | ||||||
|  |     "Settings": "Ρυθμίσεις", | ||||||
|  |     "Shared Mode": "Κοινόχρηστη Λειτουργία", | ||||||
|  |     "View Only": "Μόνο Θέαση", | ||||||
|  |     "Clip to Window": "Αποκοπή στο όριο του Παράθυρου", | ||||||
|  |     "Scaling Mode:": "Λειτουργία Κλιμάκωσης:", | ||||||
|  |     "None": "Καμία", | ||||||
|  |     "Local Scaling": "Τοπική Κλιμάκωση", | ||||||
|  |     "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους", | ||||||
|  |     "Advanced": "Για προχωρημένους", | ||||||
|  |     "Quality:": "Ποιότητα:", | ||||||
|  |     "Compression level:": "Επίπεδο συμπίεσης:", | ||||||
|  |     "Repeater ID:": "Repeater ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Κρυπτογράφηση", | ||||||
|  |     "Host:": "Όνομα διακομιστή:", | ||||||
|  |     "Port:": "Πόρτα διακομιστή:", | ||||||
|  |     "Path:": "Διαδρομή:", | ||||||
|  |     "Automatic Reconnect": "Αυτόματη επανασύνδεση", | ||||||
|  |     "Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):", | ||||||
|  |     "Show Dot when No Cursor": "Εμφάνιση Τελείας όταν δεν υπάρχει Δρομέας", | ||||||
|  |     "Logging:": "Καταγραφή:", | ||||||
|  |     "Version:": "Έκδοση:", | ||||||
|  |     "Disconnect": "Αποσύνδεση", | ||||||
|  |     "Connect": "Σύνδεση", | ||||||
|  |     "Server identity": "Ταυτότητα Διακομιστή", | ||||||
|  |     "The server has provided the following identifying information:": "Ο διακομιστής παρείχε την ακόλουθη πληροφορία ταυτοποίησης:", | ||||||
|  |     "Fingerprint:": "Δακτυλικό αποτύπωμα:", | ||||||
|  |     "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Παρακαλώ επαληθεύσετε ότι η πληροφορία είναι σωστή και πιέστε \"Αποδοχή\". Αλλιώς πιέστε \"Απόρριψη\".", | ||||||
|  |     "Approve": "Αποδοχή", | ||||||
|  |     "Reject": "Απόρριψη", | ||||||
|  |     "Credentials": "Διαπιστευτήρια", | ||||||
|  |     "Username:": "Κωδικός Χρήστη:", | ||||||
|  |     "Password:": "Κωδικός Πρόσβασης:", | ||||||
|  |     "Send Credentials": "Αποστολή Διαπιστευτηρίων", | ||||||
|  |     "Cancel": "Ακύρωση" | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								app/locale/es.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,68 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Conectando...", | ||||||
|  |     "Connected (encrypted) to ": "Conectado (con encriptación) a", | ||||||
|  |     "Connected (unencrypted) to ": "Conectado (sin encriptación) a", | ||||||
|  |     "Disconnecting...": "Desconectando...", | ||||||
|  |     "Disconnected": "Desconectado", | ||||||
|  |     "Must set host": "Se debe configurar el host", | ||||||
|  |     "Reconnecting...": "Reconectando...", | ||||||
|  |     "Password is required": "La contraseña es obligatoria", | ||||||
|  |     "Disconnect timeout": "Tiempo de desconexión agotado", | ||||||
|  |     "noVNC encountered an error:": "noVNC ha encontrado un error:", | ||||||
|  |     "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", | ||||||
|  |     "Move/Drag Viewport": "Mover/Arrastrar la ventana", | ||||||
|  |     "viewport drag": "Arrastrar la ventana", | ||||||
|  |     "Active Mouse Button": "Botón activo del ratón", | ||||||
|  |     "No mousebutton": "Ningún botón del ratón", | ||||||
|  |     "Left mousebutton": "Botón izquierdo del ratón", | ||||||
|  |     "Middle mousebutton": "Botón central del ratón", | ||||||
|  |     "Right mousebutton": "Botón derecho del ratón", | ||||||
|  |     "Keyboard": "Teclado", | ||||||
|  |     "Show Keyboard": "Mostrar teclado", | ||||||
|  |     "Extra keys": "Teclas adicionales", | ||||||
|  |     "Show Extra Keys": "Mostrar Teclas Adicionales", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Pulsar/Soltar Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Pulsar/Soltar Alt", | ||||||
|  |     "Send Tab": "Enviar Tabulación", | ||||||
|  |     "Tab": "Tabulación", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Enviar Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", | ||||||
|  |     "Shutdown/Reboot": "Apagar/Reiniciar", | ||||||
|  |     "Shutdown/Reboot...": "Apagar/Reiniciar...", | ||||||
|  |     "Power": "Encender", | ||||||
|  |     "Shutdown": "Apagar", | ||||||
|  |     "Reboot": "Reiniciar", | ||||||
|  |     "Reset": "Restablecer", | ||||||
|  |     "Clipboard": "Portapapeles", | ||||||
|  |     "Clear": "Vaciar", | ||||||
|  |     "Fullscreen": "Pantalla Completa", | ||||||
|  |     "Settings": "Configuraciones", | ||||||
|  |     "Encrypt": "Encriptar", | ||||||
|  |     "Shared Mode": "Modo Compartido", | ||||||
|  |     "View Only": "Solo visualización", | ||||||
|  |     "Clip to Window": "Recortar al tamaño de la ventana", | ||||||
|  |     "Scaling Mode:": "Modo de escalado:", | ||||||
|  |     "None": "Ninguno", | ||||||
|  |     "Local Scaling": "Escalado Local", | ||||||
|  |     "Local Downscaling": "Reducción de escala local", | ||||||
|  |     "Remote Resizing": "Cambio de tamaño remoto", | ||||||
|  |     "Advanced": "Avanzado", | ||||||
|  |     "Local Cursor": "Cursor Local", | ||||||
|  |     "Repeater ID:": "ID del Repetidor:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Host:": "Host:", | ||||||
|  |     "Port:": "Puerto:", | ||||||
|  |     "Path:": "Ruta:", | ||||||
|  |     "Automatic Reconnect": "Reconexión automática", | ||||||
|  |     "Reconnect Delay (ms):": "Retraso en la reconexión (ms):", | ||||||
|  |     "Logging:": "Registrando:", | ||||||
|  |     "Disconnect": "Desconectar", | ||||||
|  |     "Connect": "Conectar", | ||||||
|  |     "Password:": "Contraseña:", | ||||||
|  |     "Cancel": "Cancelar", | ||||||
|  |     "Canvas not supported.": "Canvas no soportado." | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								app/locale/fr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,72 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "En cours de connexion...", | ||||||
|  |     "Disconnecting...": "Déconnexion en cours...", | ||||||
|  |     "Reconnecting...": "Reconnexion en cours...", | ||||||
|  |     "Internal error": "Erreur interne", | ||||||
|  |     "Must set host": "Doit définir l'hôte", | ||||||
|  |     "Connected (encrypted) to ": "Connecté (chiffré) à ", | ||||||
|  |     "Connected (unencrypted) to ": "Connecté (non chiffré) à ", | ||||||
|  |     "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion a été fermée", | ||||||
|  |     "Failed to connect to server": "Échec de connexion au serveur", | ||||||
|  |     "Disconnected": "Déconnecté", | ||||||
|  |     "New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec motif : ", | ||||||
|  |     "New connection has been rejected": "Une nouvelle connexion a été rejetée", | ||||||
|  |     "Credentials are required": "Les identifiants sont requis", | ||||||
|  |     "noVNC encountered an error:": "noVNC a rencontré une erreur :", | ||||||
|  |     "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", | ||||||
|  |     "Drag": "Faire glisser", | ||||||
|  |     "Move/Drag Viewport": "Déplacer/faire glisser le Viewport", | ||||||
|  |     "Keyboard": "Clavier", | ||||||
|  |     "Show Keyboard": "Afficher le clavier", | ||||||
|  |     "Extra keys": "Touches supplémentaires", | ||||||
|  |     "Show Extra Keys": "Afficher les touches supplémentaires", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Basculer Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Basculer Alt", | ||||||
|  |     "Toggle Windows": "Basculer Windows", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Envoyer l'onglet", | ||||||
|  |     "Tab": "l'onglet", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Envoyer Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Arrêter/Redémarrer", | ||||||
|  |     "Shutdown/Reboot...": "Arrêter/Redémarrer...", | ||||||
|  |     "Power": "Alimentation", | ||||||
|  |     "Shutdown": "Arrêter", | ||||||
|  |     "Reboot": "Redémarrer", | ||||||
|  |     "Reset": "Réinitialiser", | ||||||
|  |     "Clipboard": "Presse-papiers", | ||||||
|  |     "Clear": "Effacer", | ||||||
|  |     "Fullscreen": "Plein écran", | ||||||
|  |     "Settings": "Paramètres", | ||||||
|  |     "Shared Mode": "Mode partagé", | ||||||
|  |     "View Only": "Afficher uniquement", | ||||||
|  |     "Clip to Window": "Clip à fenêtre", | ||||||
|  |     "Scaling Mode:": "Mode mise à l'échelle :", | ||||||
|  |     "None": "Aucun", | ||||||
|  |     "Local Scaling": "Mise à l'échelle locale", | ||||||
|  |     "Remote Resizing": "Redimensionnement à distance", | ||||||
|  |     "Advanced": "Avancé", | ||||||
|  |     "Quality:": "Qualité :", | ||||||
|  |     "Compression level:": "Niveau de compression :", | ||||||
|  |     "Repeater ID:": "ID Répéteur :", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Chiffrer", | ||||||
|  |     "Host:": "Hôte :", | ||||||
|  |     "Port:": "Port :", | ||||||
|  |     "Path:": "Chemin :", | ||||||
|  |     "Automatic Reconnect": "Reconnecter automatiquemen", | ||||||
|  |     "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", | ||||||
|  |     "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", | ||||||
|  |     "Logging:": "Se connecter :", | ||||||
|  |     "Version:": "Version :", | ||||||
|  |     "Disconnect": "Déconnecter", | ||||||
|  |     "Connect": "Connecter", | ||||||
|  |     "Username:": "Nom d'utilisateur :", | ||||||
|  |     "Password:": "Mot de passe :", | ||||||
|  |     "Send Credentials": "Envoyer les identifiants", | ||||||
|  |     "Cancel": "Annuler" | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								app/locale/it.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,68 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Connessione in corso...", | ||||||
|  |     "Disconnecting...": "Disconnessione...", | ||||||
|  |     "Reconnecting...": "Riconnessione...", | ||||||
|  |     "Internal error": "Errore interno", | ||||||
|  |     "Must set host": "Devi impostare l'host", | ||||||
|  |     "Connected (encrypted) to ": "Connesso (crittografato) a ", | ||||||
|  |     "Connected (unencrypted) to ": "Connesso (non crittografato) a", | ||||||
|  |     "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è stata chiusa", | ||||||
|  |     "Failed to connect to server": "Impossibile connettersi al server", | ||||||
|  |     "Disconnected": "Disconnesso", | ||||||
|  |     "New connection has been rejected with reason: ": "La nuova connessione è stata rifiutata con motivo: ", | ||||||
|  |     "New connection has been rejected": "La nuova connessione è stata rifiutata", | ||||||
|  |     "Credentials are required": "Le credenziali sono obbligatorie", | ||||||
|  |     "noVNC encountered an error:": "noVNC ha riscontrato un errore:", | ||||||
|  |     "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", | ||||||
|  |     "Keyboard": "Tastiera", | ||||||
|  |     "Show Keyboard": "Mostra tastiera", | ||||||
|  |     "Extra keys": "Tasti Aggiuntivi", | ||||||
|  |     "Show Extra Keys": "Mostra Tasti Aggiuntivi", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Tieni premuto Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Tieni premuto Alt", | ||||||
|  |     "Toggle Windows": "Tieni premuto Windows", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Invia Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Invia Esc", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Canc", | ||||||
|  |     "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", | ||||||
|  |     "Shutdown/Reboot": "Spegnimento/Riavvio", | ||||||
|  |     "Shutdown/Reboot...": "Spegnimento/Riavvio...", | ||||||
|  |     "Power": "Alimentazione", | ||||||
|  |     "Shutdown": "Spegnimento", | ||||||
|  |     "Reboot": "Riavvio", | ||||||
|  |     "Reset": "Reset", | ||||||
|  |     "Clipboard": "Clipboard", | ||||||
|  |     "Clear": "Pulisci", | ||||||
|  |     "Fullscreen": "Schermo intero", | ||||||
|  |     "Settings": "Impostazioni", | ||||||
|  |     "Shared Mode": "Modalità condivisa", | ||||||
|  |     "View Only": "Sola Visualizzazione", | ||||||
|  |     "Scaling Mode:": "Modalità di ridimensionamento:", | ||||||
|  |     "None": "Nessuna", | ||||||
|  |     "Local Scaling": "Ridimensionamento Locale", | ||||||
|  |     "Remote Resizing": "Ridimensionamento Remoto", | ||||||
|  |     "Advanced": "Avanzate", | ||||||
|  |     "Quality:": "Qualità:", | ||||||
|  |     "Compression level:": "Livello Compressione:", | ||||||
|  |     "Repeater ID:": "ID Ripetitore:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Crittografa", | ||||||
|  |     "Host:": "Host:", | ||||||
|  |     "Port:": "Porta:", | ||||||
|  |     "Path:": "Percorso:", | ||||||
|  |     "Automatic Reconnect": "Riconnessione Automatica", | ||||||
|  |     "Reconnect Delay (ms):": "Ritardo Riconnessione (ms):", | ||||||
|  |     "Show Dot when No Cursor": "Mostra Punto quando Nessun Cursore", | ||||||
|  |     "Version:": "Versione:", | ||||||
|  |     "Disconnect": "Disconnetti", | ||||||
|  |     "Connect": "Connetti", | ||||||
|  |     "Username:": "Utente:", | ||||||
|  |     "Password:": "Password:", | ||||||
|  |     "Send Credentials": "Invia Credenziale", | ||||||
|  |     "Cancel": "Annulla" | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								app/locale/ja.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,80 @@ | |||||||
|  | { | ||||||
|  |     "HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です", | ||||||
|  |     "Connecting...": "接続しています...", | ||||||
|  |     "Disconnecting...": "切断しています...", | ||||||
|  |     "Reconnecting...": "再接続しています...", | ||||||
|  |     "Internal error": "内部エラー", | ||||||
|  |     "Must set host": "ホストを設定する必要があります", | ||||||
|  |     "Connected (encrypted) to ": "接続しました (暗号化済み): ", | ||||||
|  |     "Connected (unencrypted) to ": "接続しました (暗号化されていません): ", | ||||||
|  |     "Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました", | ||||||
|  |     "Failed to connect to server": "サーバーへの接続に失敗しました", | ||||||
|  |     "Disconnected": "切断しました", | ||||||
|  |     "New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ", | ||||||
|  |     "New connection has been rejected": "新規接続は拒否されました", | ||||||
|  |     "Credentials are required": "資格情報が必要です", | ||||||
|  |     "noVNC encountered an error:": "noVNC でエラーが発生しました:", | ||||||
|  |     "Hide/Show the control bar": "コントロールバーを隠す/表示する", | ||||||
|  |     "Drag": "ドラッグ", | ||||||
|  |     "Move/Drag Viewport": "ビューポートを移動/ドラッグ", | ||||||
|  |     "Keyboard": "キーボード", | ||||||
|  |     "Show Keyboard": "キーボードを表示", | ||||||
|  |     "Extra keys": "追加キー", | ||||||
|  |     "Show Extra Keys": "追加キーを表示", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Ctrl キーをトグル", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Alt キーをトグル", | ||||||
|  |     "Toggle Windows": "Windows キーをトグル", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Tab キーを送信", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Escape キーを送信", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Ctrl-Alt-Del を送信", | ||||||
|  |     "Shutdown/Reboot": "シャットダウン/再起動", | ||||||
|  |     "Shutdown/Reboot...": "シャットダウン/再起動...", | ||||||
|  |     "Power": "電源", | ||||||
|  |     "Shutdown": "シャットダウン", | ||||||
|  |     "Reboot": "再起動", | ||||||
|  |     "Reset": "リセット", | ||||||
|  |     "Clipboard": "クリップボード", | ||||||
|  |     "Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。", | ||||||
|  |     "Full Screen": "全画面表示", | ||||||
|  |     "Settings": "設定", | ||||||
|  |     "Shared Mode": "共有モード", | ||||||
|  |     "View Only": "表示専用", | ||||||
|  |     "Clip to Window": "ウィンドウにクリップ", | ||||||
|  |     "Scaling Mode:": "スケーリングモード:", | ||||||
|  |     "None": "なし", | ||||||
|  |     "Local Scaling": "ローカルスケーリング", | ||||||
|  |     "Remote Resizing": "リモートでリサイズ", | ||||||
|  |     "Advanced": "高度", | ||||||
|  |     "Quality:": "品質:", | ||||||
|  |     "Compression level:": "圧縮レベル:", | ||||||
|  |     "Repeater ID:": "リピーター ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "暗号化", | ||||||
|  |     "Host:": "ホスト:", | ||||||
|  |     "Port:": "ポート:", | ||||||
|  |     "Path:": "パス:", | ||||||
|  |     "Automatic Reconnect": "自動再接続", | ||||||
|  |     "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", | ||||||
|  |     "Show Dot when No Cursor": "カーソルがないときにドットを表示する", | ||||||
|  |     "Logging:": "ロギング:", | ||||||
|  |     "Version:": "バージョン:", | ||||||
|  |     "Disconnect": "切断", | ||||||
|  |     "Connect": "接続", | ||||||
|  |     "Server identity": "サーバーの識別情報", | ||||||
|  |     "The server has provided the following identifying information:": "サーバーは以下の識別情報を提供しています:", | ||||||
|  |     "Fingerprint:": "フィンガープリント:", | ||||||
|  |     "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してください。", | ||||||
|  |     "Approve": "承認", | ||||||
|  |     "Reject": "拒否", | ||||||
|  |     "Credentials": "資格情報", | ||||||
|  |     "Username:": "ユーザー名:", | ||||||
|  |     "Password:": "パスワード:", | ||||||
|  |     "Send Credentials": "資格情報を送信", | ||||||
|  |     "Cancel": "キャンセル" | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								app/locale/ko.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,70 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "연결중...", | ||||||
|  |     "Disconnecting...": "연결 해제중...", | ||||||
|  |     "Reconnecting...": "재연결중...", | ||||||
|  |     "Internal error": "내부 오류", | ||||||
|  |     "Must set host": "호스트는 설정되어야 합니다.", | ||||||
|  |     "Connected (encrypted) to ": "다음과 (암호화되어) 연결되었습니다:", | ||||||
|  |     "Connected (unencrypted) to ": "다음과 (암호화 없이) 연결되었습니다:", | ||||||
|  |     "Something went wrong, connection is closed": "무언가 잘못되었습니다, 연결이 닫혔습니다.", | ||||||
|  |     "Failed to connect to server": "서버에 연결하지 못했습니다.", | ||||||
|  |     "Disconnected": "연결이 해제되었습니다.", | ||||||
|  |     "New connection has been rejected with reason: ": "새 연결이 다음 이유로 거부되었습니다:", | ||||||
|  |     "New connection has been rejected": "새 연결이 거부되었습니다.", | ||||||
|  |     "Password is required": "비밀번호가 필요합니다.", | ||||||
|  |     "noVNC encountered an error:": "noVNC에 오류가 발생했습니다:", | ||||||
|  |     "Hide/Show the control bar": "컨트롤 바 숨기기/보이기", | ||||||
|  |     "Move/Drag Viewport": "움직이기/드래그 뷰포트", | ||||||
|  |     "viewport drag": "뷰포트 드래그", | ||||||
|  |     "Active Mouse Button": "마우스 버튼 활성화", | ||||||
|  |     "No mousebutton": "마우스 버튼 없음", | ||||||
|  |     "Left mousebutton": "왼쪽 마우스 버튼", | ||||||
|  |     "Middle mousebutton": "중간 마우스 버튼", | ||||||
|  |     "Right mousebutton": "오른쪽 마우스 버튼", | ||||||
|  |     "Keyboard": "키보드", | ||||||
|  |     "Show Keyboard": "키보드 보이기", | ||||||
|  |     "Extra keys": "기타 키들", | ||||||
|  |     "Show Extra Keys": "기타 키들 보이기", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Ctrl 켜기/끄기", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Alt 켜기/끄기", | ||||||
|  |     "Send Tab": "Tab 보내기", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Esc 보내기", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Ctrl+Alt+Del 보내기", | ||||||
|  |     "Shutdown/Reboot": "셧다운/리붓", | ||||||
|  |     "Shutdown/Reboot...": "셧다운/리붓...", | ||||||
|  |     "Power": "전원", | ||||||
|  |     "Shutdown": "셧다운", | ||||||
|  |     "Reboot": "리붓", | ||||||
|  |     "Reset": "리셋", | ||||||
|  |     "Clipboard": "클립보드", | ||||||
|  |     "Clear": "지우기", | ||||||
|  |     "Fullscreen": "전체화면", | ||||||
|  |     "Settings": "설정", | ||||||
|  |     "Shared Mode": "공유 모드", | ||||||
|  |     "View Only": "보기 전용", | ||||||
|  |     "Clip to Window": "창에 클립", | ||||||
|  |     "Scaling Mode:": "스케일링 모드:", | ||||||
|  |     "None": "없음", | ||||||
|  |     "Local Scaling": "로컬 스케일링", | ||||||
|  |     "Remote Resizing": "원격 크기 조절", | ||||||
|  |     "Advanced": "고급", | ||||||
|  |     "Repeater ID:": "중계 ID", | ||||||
|  |     "WebSocket": "웹소켓", | ||||||
|  |     "Encrypt": "암호화", | ||||||
|  |     "Host:": "호스트:", | ||||||
|  |     "Port:": "포트:", | ||||||
|  |     "Path:": "위치:", | ||||||
|  |     "Automatic Reconnect": "자동 재연결", | ||||||
|  |     "Reconnect Delay (ms):": "재연결 지연 시간 (ms)", | ||||||
|  |     "Logging:": "로깅", | ||||||
|  |     "Disconnect": "연결 해제", | ||||||
|  |     "Connect": "연결", | ||||||
|  |     "Password:": "비밀번호:", | ||||||
|  |     "Send Password": "비밀번호 전송", | ||||||
|  |     "Cancel": "취소" | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								app/locale/nl.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,73 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Verbinden...", | ||||||
|  |     "Disconnecting...": "Verbinding verbreken...", | ||||||
|  |     "Reconnecting...": "Opnieuw verbinding maken...", | ||||||
|  |     "Internal error": "Interne fout", | ||||||
|  |     "Must set host": "Host moeten worden ingesteld", | ||||||
|  |     "Connected (encrypted) to ": "Verbonden (versleuteld) met ", | ||||||
|  |     "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", | ||||||
|  |     "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", | ||||||
|  |     "Failed to connect to server": "Verbinding maken met server is mislukt", | ||||||
|  |     "Disconnected": "Verbinding verbroken", | ||||||
|  |     "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", | ||||||
|  |     "New connection has been rejected": "Nieuwe verbinding is geweigerd", | ||||||
|  |     "Password is required": "Wachtwoord is vereist", | ||||||
|  |     "noVNC encountered an error:": "noVNC heeft een fout bemerkt:", | ||||||
|  |     "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", | ||||||
|  |     "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", | ||||||
|  |     "viewport drag": "kijkvenster slepen", | ||||||
|  |     "Active Mouse Button": "Actieve Muisknop", | ||||||
|  |     "No mousebutton": "Geen muisknop", | ||||||
|  |     "Left mousebutton": "Linker muisknop", | ||||||
|  |     "Middle mousebutton": "Middelste muisknop", | ||||||
|  |     "Right mousebutton": "Rechter muisknop", | ||||||
|  |     "Keyboard": "Toetsenbord", | ||||||
|  |     "Show Keyboard": "Toon Toetsenbord", | ||||||
|  |     "Extra keys": "Extra toetsen", | ||||||
|  |     "Show Extra Keys": "Toon Extra Toetsen", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Ctrl omschakelen", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Alt omschakelen", | ||||||
|  |     "Toggle Windows": "Windows omschakelen", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Tab Sturen", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Escape Sturen", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl-Alt-Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen", | ||||||
|  |     "Shutdown/Reboot": "Uitschakelen/Herstarten", | ||||||
|  |     "Shutdown/Reboot...": "Uitschakelen/Herstarten...", | ||||||
|  |     "Power": "Systeem", | ||||||
|  |     "Shutdown": "Uitschakelen", | ||||||
|  |     "Reboot": "Herstarten", | ||||||
|  |     "Reset": "Resetten", | ||||||
|  |     "Clipboard": "Klembord", | ||||||
|  |     "Clear": "Wissen", | ||||||
|  |     "Fullscreen": "Volledig Scherm", | ||||||
|  |     "Settings": "Instellingen", | ||||||
|  |     "Shared Mode": "Gedeelde Modus", | ||||||
|  |     "View Only": "Alleen Kijken", | ||||||
|  |     "Clip to Window": "Randen buiten venster afsnijden", | ||||||
|  |     "Scaling Mode:": "Schaalmodus:", | ||||||
|  |     "None": "Geen", | ||||||
|  |     "Local Scaling": "Lokaal Schalen", | ||||||
|  |     "Remote Resizing": "Op Afstand Formaat Wijzigen", | ||||||
|  |     "Advanced": "Geavanceerd", | ||||||
|  |     "Repeater ID:": "Repeater ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Versleutelen", | ||||||
|  |     "Host:": "Host:", | ||||||
|  |     "Port:": "Poort:", | ||||||
|  |     "Path:": "Pad:", | ||||||
|  |     "Automatic Reconnect": "Automatisch Opnieuw Verbinden", | ||||||
|  |     "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", | ||||||
|  |     "Show Dot when No Cursor": "Geef stip weer indien geen cursor", | ||||||
|  |     "Logging:": "Logmeldingen:", | ||||||
|  |     "Disconnect": "Verbinding verbreken", | ||||||
|  |     "Connect": "Verbinden", | ||||||
|  |     "Password:": "Wachtwoord:", | ||||||
|  |     "Send Password": "Verzend Wachtwoord:", | ||||||
|  |     "Cancel": "Annuleren" | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								app/locale/pl.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Łączenie...", | ||||||
|  |     "Disconnecting...": "Rozłączanie...", | ||||||
|  |     "Reconnecting...": "Łączenie...", | ||||||
|  |     "Internal error": "Błąd wewnętrzny", | ||||||
|  |     "Must set host": "Host i port są wymagane", | ||||||
|  |     "Connected (encrypted) to ": "Połączenie (szyfrowane) z ", | ||||||
|  |     "Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ", | ||||||
|  |     "Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte", | ||||||
|  |     "Disconnected": "Rozłączony", | ||||||
|  |     "New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ", | ||||||
|  |     "New connection has been rejected": "Nowe połączenie zostało odrzucone", | ||||||
|  |     "Password is required": "Hasło jest wymagane", | ||||||
|  |     "noVNC encountered an error:": "noVNC napotkało błąd:", | ||||||
|  |     "Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień", | ||||||
|  |     "Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport", | ||||||
|  |     "viewport drag": "przeciągnij viewport", | ||||||
|  |     "Active Mouse Button": "Aktywny Przycisk Myszy", | ||||||
|  |     "No mousebutton": "Brak przycisku myszy", | ||||||
|  |     "Left mousebutton": "Lewy przycisk myszy", | ||||||
|  |     "Middle mousebutton": "Środkowy przycisk myszy", | ||||||
|  |     "Right mousebutton": "Prawy przycisk myszy", | ||||||
|  |     "Keyboard": "Klawiatura", | ||||||
|  |     "Show Keyboard": "Pokaż klawiaturę", | ||||||
|  |     "Extra keys": "Przyciski dodatkowe", | ||||||
|  |     "Show Extra Keys": "Pokaż przyciski dodatkowe", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Przełącz Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Przełącz Alt", | ||||||
|  |     "Send Tab": "Wyślij Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Wyślij Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Wyłącz/Uruchom ponownie", | ||||||
|  |     "Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...", | ||||||
|  |     "Power": "Włączony", | ||||||
|  |     "Shutdown": "Wyłącz", | ||||||
|  |     "Reboot": "Uruchom ponownie", | ||||||
|  |     "Reset": "Resetuj", | ||||||
|  |     "Clipboard": "Schowek", | ||||||
|  |     "Clear": "Wyczyść", | ||||||
|  |     "Fullscreen": "Pełny ekran", | ||||||
|  |     "Settings": "Ustawienia", | ||||||
|  |     "Shared Mode": "Tryb Współdzielenia", | ||||||
|  |     "View Only": "Tylko Podgląd", | ||||||
|  |     "Clip to Window": "Przytnij do Okna", | ||||||
|  |     "Scaling Mode:": "Tryb Skalowania:", | ||||||
|  |     "None": "Brak", | ||||||
|  |     "Local Scaling": "Skalowanie lokalne", | ||||||
|  |     "Remote Resizing": "Skalowanie zdalne", | ||||||
|  |     "Advanced": "Zaawansowane", | ||||||
|  |     "Repeater ID:": "ID Repeatera:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Szyfrowanie", | ||||||
|  |     "Host:": "Host:", | ||||||
|  |     "Port:": "Port:", | ||||||
|  |     "Path:": "Ścieżka:", | ||||||
|  |     "Automatic Reconnect": "Automatycznie wznawiaj połączenie", | ||||||
|  |     "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):", | ||||||
|  |     "Logging:": "Poziom logowania:", | ||||||
|  |     "Disconnect": "Rozłącz", | ||||||
|  |     "Connect": "Połącz", | ||||||
|  |     "Password:": "Hasło:", | ||||||
|  |     "Cancel": "Anuluj", | ||||||
|  |     "Canvas not supported.": "Element Canvas nie jest wspierany." | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								app/locale/pt_BR.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,72 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Conectando...", | ||||||
|  |     "Disconnecting...": "Desconectando...", | ||||||
|  |     "Reconnecting...": "Reconectando...", | ||||||
|  |     "Internal error": "Erro interno", | ||||||
|  |     "Must set host": "É necessário definir o host", | ||||||
|  |     "Connected (encrypted) to ": "Conectado (com criptografia) a ", | ||||||
|  |     "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", | ||||||
|  |     "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", | ||||||
|  |     "Failed to connect to server": "Falha ao conectar-se ao servidor", | ||||||
|  |     "Disconnected": "Desconectado", | ||||||
|  |     "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", | ||||||
|  |     "New connection has been rejected": "A nova conexão foi rejeitada", | ||||||
|  |     "Credentials are required": "Credenciais são obrigatórias", | ||||||
|  |     "noVNC encountered an error:": "O noVNC encontrou um erro:", | ||||||
|  |     "Hide/Show the control bar": "Esconder/mostrar a barra de controles", | ||||||
|  |     "Drag": "Arrastar", | ||||||
|  |     "Move/Drag Viewport": "Mover/arrastar a janela", | ||||||
|  |     "Keyboard": "Teclado", | ||||||
|  |     "Show Keyboard": "Mostrar teclado", | ||||||
|  |     "Extra keys": "Teclas adicionais", | ||||||
|  |     "Show Extra Keys": "Mostar teclas adicionais", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Pressionar/soltar Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Pressionar/soltar Alt", | ||||||
|  |     "Toggle Windows": "Pressionar/soltar Windows", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Enviar Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Enviar Esc", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Desligar/reiniciar", | ||||||
|  |     "Shutdown/Reboot...": "Desligar/reiniciar...", | ||||||
|  |     "Power": "Ligar", | ||||||
|  |     "Shutdown": "Desligar", | ||||||
|  |     "Reboot": "Reiniciar", | ||||||
|  |     "Reset": "Reiniciar (forçado)", | ||||||
|  |     "Clipboard": "Área de transferência", | ||||||
|  |     "Clear": "Limpar", | ||||||
|  |     "Fullscreen": "Tela cheia", | ||||||
|  |     "Settings": "Configurações", | ||||||
|  |     "Shared Mode": "Modo compartilhado", | ||||||
|  |     "View Only": "Apenas visualizar", | ||||||
|  |     "Clip to Window": "Recortar à janela", | ||||||
|  |     "Scaling Mode:": "Modo de dimensionamento:", | ||||||
|  |     "None": "Nenhum", | ||||||
|  |     "Local Scaling": "Local", | ||||||
|  |     "Remote Resizing": "Remoto", | ||||||
|  |     "Advanced": "Avançado", | ||||||
|  |     "Quality:": "Qualidade:", | ||||||
|  |     "Compression level:": "Nível de compressão:", | ||||||
|  |     "Repeater ID:": "ID do repetidor:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Criptografar", | ||||||
|  |     "Host:": "Host:", | ||||||
|  |     "Port:": "Porta:", | ||||||
|  |     "Path:": "Caminho:", | ||||||
|  |     "Automatic Reconnect": "Reconexão automática", | ||||||
|  |     "Reconnect Delay (ms):": "Atraso da reconexão (ms)", | ||||||
|  |     "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", | ||||||
|  |     "Logging:": "Registros:", | ||||||
|  |     "Version:": "Versão:", | ||||||
|  |     "Disconnect": "Desconectar", | ||||||
|  |     "Connect": "Conectar", | ||||||
|  |     "Username:": "Nome de usuário:", | ||||||
|  |     "Password:": "Senha:", | ||||||
|  |     "Send Credentials": "Enviar credenciais", | ||||||
|  |     "Cancel": "Cancelar" | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								app/locale/ru.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,72 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Подключение...", | ||||||
|  |     "Disconnecting...": "Отключение...", | ||||||
|  |     "Reconnecting...": "Переподключение...", | ||||||
|  |     "Internal error": "Внутренняя ошибка", | ||||||
|  |     "Must set host": "Задайте имя сервера или IP", | ||||||
|  |     "Connected (encrypted) to ": "Подключено (с шифрованием) к ", | ||||||
|  |     "Connected (unencrypted) to ": "Подключено (без шифрования) к ", | ||||||
|  |     "Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано", | ||||||
|  |     "Failed to connect to server": "Ошибка подключения к серверу", | ||||||
|  |     "Disconnected": "Отключено", | ||||||
|  |     "New connection has been rejected with reason: ": "Новое соединение отклонено по причине: ", | ||||||
|  |     "New connection has been rejected": "Новое соединение отклонено", | ||||||
|  |     "Credentials are required": "Требуются учетные данные", | ||||||
|  |     "noVNC encountered an error:": "Ошибка noVNC: ", | ||||||
|  |     "Hide/Show the control bar": "Скрыть/Показать контрольную панель", | ||||||
|  |     "Drag": "Переместить", | ||||||
|  |     "Move/Drag Viewport": "Переместить окно", | ||||||
|  |     "Keyboard": "Клавиатура", | ||||||
|  |     "Show Keyboard": "Показать клавиатуру", | ||||||
|  |     "Extra keys": "Дополнительные Кнопки", | ||||||
|  |     "Show Extra Keys": "Показать Дополнительные Кнопки", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Переключение нажатия Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Переключение нажатия Alt", | ||||||
|  |     "Toggle Windows": "Переключение вкладок", | ||||||
|  |     "Windows": "Вкладка", | ||||||
|  |     "Send Tab": "Передать нажатие Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Передать нажатие Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Выключить/Перезагрузить", | ||||||
|  |     "Shutdown/Reboot...": "Выключить/Перезагрузить...", | ||||||
|  |     "Power": "Питание", | ||||||
|  |     "Shutdown": "Выключить", | ||||||
|  |     "Reboot": "Перезагрузить", | ||||||
|  |     "Reset": "Сброс", | ||||||
|  |     "Clipboard": "Буфер обмена", | ||||||
|  |     "Clear": "Очистить", | ||||||
|  |     "Fullscreen": "Во весь экран", | ||||||
|  |     "Settings": "Настройки", | ||||||
|  |     "Shared Mode": "Общий режим", | ||||||
|  |     "View Only": "Только Просмотр", | ||||||
|  |     "Clip to Window": "В окно", | ||||||
|  |     "Scaling Mode:": "Масштаб:", | ||||||
|  |     "None": "Нет", | ||||||
|  |     "Local Scaling": "Локльный масштаб", | ||||||
|  |     "Remote Resizing": "Удаленная перенастройка размера", | ||||||
|  |     "Advanced": "Дополнительно", | ||||||
|  |     "Quality:": "Качество", | ||||||
|  |     "Compression level:": "Уровень Сжатия", | ||||||
|  |     "Repeater ID:": "Идентификатор ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Шифрование", | ||||||
|  |     "Host:": "Сервер:", | ||||||
|  |     "Port:": "Порт:", | ||||||
|  |     "Path:": "Путь:", | ||||||
|  |     "Automatic Reconnect": "Автоматическое переподключение", | ||||||
|  |     "Reconnect Delay (ms):": "Задержка переподключения (мс):", | ||||||
|  |     "Show Dot when No Cursor": "Показать точку вместо курсора", | ||||||
|  |     "Logging:": "Лог:", | ||||||
|  |     "Version:": "Версия", | ||||||
|  |     "Disconnect": "Отключение", | ||||||
|  |     "Connect": "Подключение", | ||||||
|  |     "Username:": "Имя Пользователя", | ||||||
|  |     "Password:": "Пароль:", | ||||||
|  |     "Send Credentials": "Передача Учетных Данных", | ||||||
|  |     "Cancel": "Выход" | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								app/locale/sv.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,81 @@ | |||||||
|  | { | ||||||
|  |     "Running without HTTPS is not recommended, crashes or other issues are likely.": "Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är troliga.", | ||||||
|  |     "Connecting...": "Ansluter...", | ||||||
|  |     "Disconnecting...": "Kopplar ner...", | ||||||
|  |     "Reconnecting...": "Återansluter...", | ||||||
|  |     "Internal error": "Internt fel", | ||||||
|  |     "Must set host": "Du måste specifiera en värd", | ||||||
|  |     "Failed to connect to server: ": "Misslyckades att ansluta till servern: ", | ||||||
|  |     "Connected (encrypted) to ": "Ansluten (krypterat) till ", | ||||||
|  |     "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", | ||||||
|  |     "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", | ||||||
|  |     "Failed to connect to server": "Misslyckades att ansluta till servern", | ||||||
|  |     "Disconnected": "Frånkopplad", | ||||||
|  |     "New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ", | ||||||
|  |     "New connection has been rejected": "Ny anslutning har blivit nekad", | ||||||
|  |     "Credentials are required": "Användaruppgifter krävs", | ||||||
|  |     "noVNC encountered an error:": "noVNC stötte på ett problem:", | ||||||
|  |     "Hide/Show the control bar": "Göm/Visa kontrollbaren", | ||||||
|  |     "Drag": "Dra", | ||||||
|  |     "Move/Drag Viewport": "Flytta/Dra Vyn", | ||||||
|  |     "Keyboard": "Tangentbord", | ||||||
|  |     "Show Keyboard": "Visa Tangentbord", | ||||||
|  |     "Extra keys": "Extraknappar", | ||||||
|  |     "Show Extra Keys": "Visa Extraknappar", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Växla Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Växla Alt", | ||||||
|  |     "Toggle Windows": "Växla Windows", | ||||||
|  |     "Windows": "Windows", | ||||||
|  |     "Send Tab": "Skicka Tab", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Skicka Escape", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del", | ||||||
|  |     "Shutdown/Reboot": "Stäng av/Boota om", | ||||||
|  |     "Shutdown/Reboot...": "Stäng av/Boota om...", | ||||||
|  |     "Power": "Ström", | ||||||
|  |     "Shutdown": "Stäng av", | ||||||
|  |     "Reboot": "Boota om", | ||||||
|  |     "Reset": "Återställ", | ||||||
|  |     "Clipboard": "Urklipp", | ||||||
|  |     "Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.", | ||||||
|  |     "Full Screen": "Fullskärm", | ||||||
|  |     "Settings": "Inställningar", | ||||||
|  |     "Shared Mode": "Delat Läge", | ||||||
|  |     "View Only": "Endast Visning", | ||||||
|  |     "Clip to Window": "Begränsa till Fönster", | ||||||
|  |     "Scaling Mode:": "Skalningsläge:", | ||||||
|  |     "None": "Ingen", | ||||||
|  |     "Local Scaling": "Lokal Skalning", | ||||||
|  |     "Remote Resizing": "Ändra Storlek", | ||||||
|  |     "Advanced": "Avancerat", | ||||||
|  |     "Quality:": "Kvalitet:", | ||||||
|  |     "Compression level:": "Kompressionsnivå:", | ||||||
|  |     "Repeater ID:": "Repeater-ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Kryptera", | ||||||
|  |     "Host:": "Värd:", | ||||||
|  |     "Port:": "Port:", | ||||||
|  |     "Path:": "Sökväg:", | ||||||
|  |     "Automatic Reconnect": "Automatisk Återanslutning", | ||||||
|  |     "Reconnect Delay (ms):": "Fördröjning (ms):", | ||||||
|  |     "Show Dot when No Cursor": "Visa prick när ingen muspekare finns", | ||||||
|  |     "Logging:": "Loggning:", | ||||||
|  |     "Version:": "Version:", | ||||||
|  |     "Disconnect": "Koppla från", | ||||||
|  |     "Connect": "Anslut", | ||||||
|  |     "Server identity": "Server-identitet", | ||||||
|  |     "The server has provided the following identifying information:": "Servern har gett följande identifierande information:", | ||||||
|  |     "Fingerprint:": "Fingeravtryck:", | ||||||
|  |     "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck annars \"Neka\".", | ||||||
|  |     "Approve": "Godkänn", | ||||||
|  |     "Reject": "Neka", | ||||||
|  |     "Credentials": "Användaruppgifter", | ||||||
|  |     "Username:": "Användarnamn:", | ||||||
|  |     "Password:": "Lösenord:", | ||||||
|  |     "Send Credentials": "Skicka Användaruppgifter", | ||||||
|  |     "Cancel": "Avbryt" | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								app/locale/tr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "Bağlanıyor...", | ||||||
|  |     "Disconnecting...": "Bağlantı kesiliyor...", | ||||||
|  |     "Reconnecting...": "Yeniden bağlantı kuruluyor...", | ||||||
|  |     "Internal error": "İç hata", | ||||||
|  |     "Must set host": "Sunucuyu kur", | ||||||
|  |     "Connected (encrypted) to ": "Bağlı (şifrelenmiş)", | ||||||
|  |     "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)", | ||||||
|  |     "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi", | ||||||
|  |     "Disconnected": "Bağlantı kesildi", | ||||||
|  |     "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ", | ||||||
|  |     "New connection has been rejected": "Bağlantı reddedildi", | ||||||
|  |     "Password is required": "Şifre gerekli", | ||||||
|  |     "noVNC encountered an error:": "Bir hata oluştu:", | ||||||
|  |     "Hide/Show the control bar": "Denetim masasını Gizle/Göster", | ||||||
|  |     "Move/Drag Viewport": "Görünümü Taşı/Sürükle", | ||||||
|  |     "viewport drag": "Görüntü penceresini sürükle", | ||||||
|  |     "Active Mouse Button": "Aktif Fare Düğmesi", | ||||||
|  |     "No mousebutton": "Fare düğmesi yok", | ||||||
|  |     "Left mousebutton": "Farenin sol düğmesi", | ||||||
|  |     "Middle mousebutton": "Farenin orta düğmesi", | ||||||
|  |     "Right mousebutton": "Farenin sağ düğmesi", | ||||||
|  |     "Keyboard": "Klavye", | ||||||
|  |     "Show Keyboard": "Klavye Düzenini Göster", | ||||||
|  |     "Extra keys": "Ekstra tuşlar", | ||||||
|  |     "Show Extra Keys": "Ekstra tuşları göster", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "Ctrl Değiştir ", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "Alt Değiştir", | ||||||
|  |     "Send Tab": "Sekme Gönder", | ||||||
|  |     "Tab": "Sekme", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "Boşluk Gönder", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl + Alt + Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder", | ||||||
|  |     "Shutdown/Reboot": "Kapat/Yeniden Başlat", | ||||||
|  |     "Shutdown/Reboot...": "Kapat/Yeniden Başlat...", | ||||||
|  |     "Power": "Güç", | ||||||
|  |     "Shutdown": "Kapat", | ||||||
|  |     "Reboot": "Yeniden Başlat", | ||||||
|  |     "Reset": "Sıfırla", | ||||||
|  |     "Clipboard": "Pano", | ||||||
|  |     "Clear": "Temizle", | ||||||
|  |     "Fullscreen": "Tam Ekran", | ||||||
|  |     "Settings": "Ayarlar", | ||||||
|  |     "Shared Mode": "Paylaşım Modu", | ||||||
|  |     "View Only": "Sadece Görüntüle", | ||||||
|  |     "Clip to Window": "Pencereye Tıkla", | ||||||
|  |     "Scaling Mode:": "Ölçekleme Modu:", | ||||||
|  |     "None": "Bilinmeyen", | ||||||
|  |     "Local Scaling": "Yerel Ölçeklendirme", | ||||||
|  |     "Remote Resizing": "Uzaktan Yeniden Boyutlandırma", | ||||||
|  |     "Advanced": "Gelişmiş", | ||||||
|  |     "Repeater ID:": "Tekralayıcı ID:", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "Şifrele", | ||||||
|  |     "Host:": "Ana makine:", | ||||||
|  |     "Port:": "Port:", | ||||||
|  |     "Path:": "Yol:", | ||||||
|  |     "Automatic Reconnect": "Otomatik Yeniden Bağlan", | ||||||
|  |     "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):", | ||||||
|  |     "Logging:": "Giriş yapılıyor:", | ||||||
|  |     "Disconnect": "Bağlantıyı Kes", | ||||||
|  |     "Connect": "Bağlan", | ||||||
|  |     "Password:": "Parola:", | ||||||
|  |     "Cancel": "Vazgeç", | ||||||
|  |     "Canvas not supported.": "Tuval desteklenmiyor." | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								app/locale/zh_CN.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "连接中...", | ||||||
|  |     "Connected (encrypted) to ": "已连接(已加密)到", | ||||||
|  |     "Connected (unencrypted) to ": "已连接(未加密)到", | ||||||
|  |     "Disconnecting...": "正在断开连接...", | ||||||
|  |     "Disconnected": "已断开连接", | ||||||
|  |     "Must set host": "必须设置主机", | ||||||
|  |     "Reconnecting...": "重新连接中...", | ||||||
|  |     "Password is required": "请提供密码", | ||||||
|  |     "Disconnect timeout": "超时断开", | ||||||
|  |     "noVNC encountered an error:": "noVNC 遇到一个错误:", | ||||||
|  |     "Hide/Show the control bar": "显示/隐藏控制栏", | ||||||
|  |     "Move/Drag Viewport": "移动/拖动窗口", | ||||||
|  |     "viewport drag": "窗口拖动", | ||||||
|  |     "Active Mouse Button": "启动鼠标按键", | ||||||
|  |     "No mousebutton": "禁用鼠标按键", | ||||||
|  |     "Left mousebutton": "鼠标左键", | ||||||
|  |     "Middle mousebutton": "鼠标中键", | ||||||
|  |     "Right mousebutton": "鼠标右键", | ||||||
|  |     "Keyboard": "键盘", | ||||||
|  |     "Show Keyboard": "显示键盘", | ||||||
|  |     "Extra keys": "额外按键", | ||||||
|  |     "Show Extra Keys": "显示额外按键", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "切换 Ctrl", | ||||||
|  |     "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "切换 Alt", | ||||||
|  |     "Send Tab": "发送 Tab 键", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "发送 Escape 键", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl+Alt+Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "发送 Ctrl+Alt+Del 键", | ||||||
|  |     "Shutdown/Reboot": "关机/重启", | ||||||
|  |     "Shutdown/Reboot...": "关机/重启...", | ||||||
|  |     "Power": "电源", | ||||||
|  |     "Shutdown": "关机", | ||||||
|  |     "Reboot": "重启", | ||||||
|  |     "Reset": "重置", | ||||||
|  |     "Clipboard": "剪贴板", | ||||||
|  |     "Clear": "清除", | ||||||
|  |     "Fullscreen": "全屏", | ||||||
|  |     "Settings": "设置", | ||||||
|  |     "Encrypt": "加密", | ||||||
|  |     "Shared Mode": "分享模式", | ||||||
|  |     "View Only": "仅查看", | ||||||
|  |     "Clip to Window": "限制/裁切窗口大小", | ||||||
|  |     "Scaling Mode:": "缩放模式:", | ||||||
|  |     "None": "无", | ||||||
|  |     "Local Scaling": "本地缩放", | ||||||
|  |     "Local Downscaling": "降低本地尺寸", | ||||||
|  |     "Remote Resizing": "远程调整大小", | ||||||
|  |     "Advanced": "高级", | ||||||
|  |     "Local Cursor": "本地光标", | ||||||
|  |     "Repeater ID:": "中继站 ID", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Host:": "主机:", | ||||||
|  |     "Port:": "端口:", | ||||||
|  |     "Path:": "路径:", | ||||||
|  |     "Automatic Reconnect": "自动重新连接", | ||||||
|  |     "Reconnect Delay (ms):": "重新连接间隔 (ms):", | ||||||
|  |     "Logging:": "日志级别:", | ||||||
|  |     "Disconnect": "断开连接", | ||||||
|  |     "Connect": "连接", | ||||||
|  |     "Password:": "密码:", | ||||||
|  |     "Cancel": "取消", | ||||||
|  |     "Canvas not supported.": "不支持 Canvas。" | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								app/locale/zh_TW.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,69 @@ | |||||||
|  | { | ||||||
|  |     "Connecting...": "連線中...", | ||||||
|  |     "Disconnecting...": "正在中斷連線...", | ||||||
|  |     "Reconnecting...": "重新連線中...", | ||||||
|  |     "Internal error": "內部錯誤", | ||||||
|  |     "Must set host": "請提供主機資訊", | ||||||
|  |     "Connected (encrypted) to ": "已加密連線到", | ||||||
|  |     "Connected (unencrypted) to ": "未加密連線到", | ||||||
|  |     "Something went wrong, connection is closed": "發生錯誤,連線已關閉", | ||||||
|  |     "Failed to connect to server": "無法連線到伺服器", | ||||||
|  |     "Disconnected": "連線已中斷", | ||||||
|  |     "New connection has been rejected with reason: ": "連線被拒絕,原因:", | ||||||
|  |     "New connection has been rejected": "連線被拒絕", | ||||||
|  |     "Password is required": "請提供密碼", | ||||||
|  |     "noVNC encountered an error:": "noVNC 遇到一個錯誤:", | ||||||
|  |     "Hide/Show the control bar": "顯示/隱藏控制列", | ||||||
|  |     "Move/Drag Viewport": "拖放顯示範圍", | ||||||
|  |     "viewport drag": "顯示範圍拖放", | ||||||
|  |     "Active Mouse Button": "啟用滑鼠按鍵", | ||||||
|  |     "No mousebutton": "無滑鼠按鍵", | ||||||
|  |     "Left mousebutton": "滑鼠左鍵", | ||||||
|  |     "Middle mousebutton": "滑鼠中鍵", | ||||||
|  |     "Right mousebutton": "滑鼠右鍵", | ||||||
|  |     "Keyboard": "鍵盤", | ||||||
|  |     "Show Keyboard": "顯示鍵盤", | ||||||
|  |     "Extra keys": "額外按鍵", | ||||||
|  |     "Show Extra Keys": "顯示額外按鍵", | ||||||
|  |     "Ctrl": "Ctrl", | ||||||
|  |     "Toggle Ctrl": "切換 Ctrl", | ||||||
|  |     "Alt": "Alt", | ||||||
|  |     "Toggle Alt": "切換 Alt", | ||||||
|  |     "Send Tab": "送出 Tab 鍵", | ||||||
|  |     "Tab": "Tab", | ||||||
|  |     "Esc": "Esc", | ||||||
|  |     "Send Escape": "送出 Escape 鍵", | ||||||
|  |     "Ctrl+Alt+Del": "Ctrl-Alt-Del", | ||||||
|  |     "Send Ctrl-Alt-Del": "送出 Ctrl-Alt-Del 快捷鍵", | ||||||
|  |     "Shutdown/Reboot": "關機/重新啟動", | ||||||
|  |     "Shutdown/Reboot...": "關機/重新啟動...", | ||||||
|  |     "Power": "電源", | ||||||
|  |     "Shutdown": "關機", | ||||||
|  |     "Reboot": "重新啟動", | ||||||
|  |     "Reset": "重設", | ||||||
|  |     "Clipboard": "剪貼簿", | ||||||
|  |     "Clear": "清除", | ||||||
|  |     "Fullscreen": "全螢幕", | ||||||
|  |     "Settings": "設定", | ||||||
|  |     "Shared Mode": "分享模式", | ||||||
|  |     "View Only": "僅檢視", | ||||||
|  |     "Clip to Window": "限制/裁切視窗大小", | ||||||
|  |     "Scaling Mode:": "縮放模式:", | ||||||
|  |     "None": "無", | ||||||
|  |     "Local Scaling": "本機縮放", | ||||||
|  |     "Remote Resizing": "遠端調整大小", | ||||||
|  |     "Advanced": "進階", | ||||||
|  |     "Repeater ID:": "中繼站 ID", | ||||||
|  |     "WebSocket": "WebSocket", | ||||||
|  |     "Encrypt": "加密", | ||||||
|  |     "Host:": "主機:", | ||||||
|  |     "Port:": "連接埠:", | ||||||
|  |     "Path:": "路徑:", | ||||||
|  |     "Automatic Reconnect": "自動重新連線", | ||||||
|  |     "Reconnect Delay (ms):": "重新連線間隔 (ms):", | ||||||
|  |     "Logging:": "日誌級別:", | ||||||
|  |     "Disconnect": "中斷連線", | ||||||
|  |     "Connect": "連線", | ||||||
|  |     "Password:": "密碼:", | ||||||
|  |     "Cancel": "取消" | ||||||
|  | } | ||||||
							
								
								
									
										206
									
								
								app/localization.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,206 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2018 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Localization Utilities | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export class Localizer { | ||||||
|  |     constructor() { | ||||||
|  |         // Currently configured language | ||||||
|  |         this.language = 'en'; | ||||||
|  |  | ||||||
|  |         // Current dictionary of translations | ||||||
|  |         this._dictionary = undefined; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Configure suitable language based on user preferences | ||||||
|  |     async setup(supportedLanguages, baseURL) { | ||||||
|  |         this.language = 'en'; // Default: US English | ||||||
|  |         this._dictionary = undefined; | ||||||
|  |  | ||||||
|  |         this._setupLanguage(supportedLanguages); | ||||||
|  |         await this._setupDictionary(baseURL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _setupLanguage(supportedLanguages) { | ||||||
|  |         /* | ||||||
|  |          * Navigator.languages only available in Chrome (32+) and FireFox (32+) | ||||||
|  |          * Fall back to navigator.language for other browsers | ||||||
|  |          */ | ||||||
|  |         let userLanguages; | ||||||
|  |         if (typeof window.navigator.languages == 'object') { | ||||||
|  |             userLanguages = window.navigator.languages; | ||||||
|  |         } else { | ||||||
|  |             userLanguages = [navigator.language || navigator.userLanguage]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (let i = 0;i < userLanguages.length;i++) { | ||||||
|  |             const userLang = userLanguages[i] | ||||||
|  |                 .toLowerCase() | ||||||
|  |                 .replace("_", "-") | ||||||
|  |                 .split("-"); | ||||||
|  |  | ||||||
|  |             // First pass: perfect match | ||||||
|  |             for (let j = 0; j < supportedLanguages.length; j++) { | ||||||
|  |                 const supLang = supportedLanguages[j] | ||||||
|  |                     .toLowerCase() | ||||||
|  |                     .replace("_", "-") | ||||||
|  |                     .split("-"); | ||||||
|  |  | ||||||
|  |                 if (userLang[0] !== supLang[0]) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 if (userLang[1] !== supLang[1]) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 this.language = supportedLanguages[j]; | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Second pass: English fallback | ||||||
|  |             if (userLang[0] === 'en') { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Third pass pass: other fallback | ||||||
|  |             for (let j = 0;j < supportedLanguages.length;j++) { | ||||||
|  |                 const supLang = supportedLanguages[j] | ||||||
|  |                     .toLowerCase() | ||||||
|  |                     .replace("_", "-") | ||||||
|  |                     .split("-"); | ||||||
|  |  | ||||||
|  |                 if (userLang[0] !== supLang[0]) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 if (supLang[1] !== undefined) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 this.language = supportedLanguages[j]; | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _setupDictionary(baseURL) { | ||||||
|  |         if (baseURL) { | ||||||
|  |             if (!baseURL.endsWith("/")) { | ||||||
|  |                 baseURL = baseURL + "/"; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             baseURL = ""; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.language === "en") { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let response = await fetch(baseURL + this.language + ".json"); | ||||||
|  |         if (!response.ok) { | ||||||
|  |             throw Error("" + response.status + " " + response.statusText); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._dictionary = await response.json(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Retrieve localised text | ||||||
|  |     get(id) { | ||||||
|  |         if (typeof this._dictionary !== 'undefined' && | ||||||
|  |             this._dictionary[id]) { | ||||||
|  |             return this._dictionary[id]; | ||||||
|  |         } else { | ||||||
|  |             return id; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Traverses the DOM and translates relevant fields | ||||||
|  |     // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate | ||||||
|  |     translateDOM() { | ||||||
|  |         const self = this; | ||||||
|  |  | ||||||
|  |         function process(elem, enabled) { | ||||||
|  |             function isAnyOf(searchElement, items) { | ||||||
|  |                 return items.indexOf(searchElement) !== -1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             function translateString(str) { | ||||||
|  |                 // We assume surrounding whitespace, and whitespace around line | ||||||
|  |                 // breaks is just for source formatting | ||||||
|  |                 str = str.split("\n").map(s => s.trim()).join(" ").trim(); | ||||||
|  |                 return self.get(str); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             function translateAttribute(elem, attr) { | ||||||
|  |                 const str = translateString(elem.getAttribute(attr)); | ||||||
|  |                 elem.setAttribute(attr, str); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             function translateTextNode(node) { | ||||||
|  |                 const str = translateString(node.data); | ||||||
|  |                 node.data = str; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (elem.hasAttribute("translate")) { | ||||||
|  |                 if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) { | ||||||
|  |                     enabled = true; | ||||||
|  |                 } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) { | ||||||
|  |                     enabled = false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (enabled) { | ||||||
|  |                 if (elem.hasAttribute("abbr") && | ||||||
|  |                     elem.tagName === "TH") { | ||||||
|  |                     translateAttribute(elem, "abbr"); | ||||||
|  |                 } | ||||||
|  |                 if (elem.hasAttribute("alt") && | ||||||
|  |                     isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) { | ||||||
|  |                     translateAttribute(elem, "alt"); | ||||||
|  |                 } | ||||||
|  |                 if (elem.hasAttribute("download") && | ||||||
|  |                     isAnyOf(elem.tagName, ["A", "AREA"])) { | ||||||
|  |                     translateAttribute(elem, "download"); | ||||||
|  |                 } | ||||||
|  |                 if (elem.hasAttribute("label") && | ||||||
|  |                     isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP", | ||||||
|  |                                            "OPTION", "TRACK"])) { | ||||||
|  |                     translateAttribute(elem, "label"); | ||||||
|  |                 } | ||||||
|  |                 // FIXME: Should update "lang" | ||||||
|  |                 if (elem.hasAttribute("placeholder") && | ||||||
|  |                     isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) { | ||||||
|  |                     translateAttribute(elem, "placeholder"); | ||||||
|  |                 } | ||||||
|  |                 if (elem.hasAttribute("title")) { | ||||||
|  |                     translateAttribute(elem, "title"); | ||||||
|  |                 } | ||||||
|  |                 if (elem.hasAttribute("value") && | ||||||
|  |                     elem.tagName === "INPUT" && | ||||||
|  |                     isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) { | ||||||
|  |                     translateAttribute(elem, "value"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for (let i = 0; i < elem.childNodes.length; i++) { | ||||||
|  |                 const node = elem.childNodes[i]; | ||||||
|  |                 if (node.nodeType === node.ELEMENT_NODE) { | ||||||
|  |                     process(node, enabled); | ||||||
|  |                 } else if (node.nodeType === node.TEXT_NODE && enabled) { | ||||||
|  |                     translateTextNode(node); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         process(document.body, true); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const l10n = new Localizer(); | ||||||
|  | export default l10n.get.bind(l10n); | ||||||
							
								
								
									
										4
									
								
								app/sounds/CREDITS
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,4 @@ | |||||||
|  | bell | ||||||
|  |         Copyright: Dr. Richard Boulanger et al | ||||||
|  |         URL: http://www.archive.org/details/Berklee44v12 | ||||||
|  |         License: CC-BY Attribution 3.0 Unported | ||||||
							
								
								
									
										
											BIN
										
									
								
								app/sounds/bell.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/sounds/bell.oga
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/styles/Orbitron700.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								app/styles/Orbitron700.woff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										922
									
								
								app/styles/base.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,922 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC base CSS | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Z index layers: | ||||||
|  |  * | ||||||
|  |  * 0: Main screen | ||||||
|  |  * 10: Control bar | ||||||
|  |  * 50: Transition blocker | ||||||
|  |  * 60: Connection popups | ||||||
|  |  * 100: Status bar | ||||||
|  |  * ... | ||||||
|  |  * 1000: Javascript crash | ||||||
|  |  * ... | ||||||
|  |  * 10000: Max (used for polyfills) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * State variables (set on :root): | ||||||
|  |  * | ||||||
|  |  * noVNC_loading: Page is still loading | ||||||
|  |  * noVNC_connecting: Connecting to server | ||||||
|  |  * noVNC_reconnecting: Re-establishing a connection | ||||||
|  |  * noVNC_connected: Connected to server (most common state) | ||||||
|  |  * noVNC_disconnecting: Disconnecting from server | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | :root { | ||||||
|  |   font-family: sans-serif; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | body { | ||||||
|  |   margin:0; | ||||||
|  |   padding:0; | ||||||
|  |   /*Background image with light grey curve.*/ | ||||||
|  |   background-color:#494949; | ||||||
|  |   background-repeat:no-repeat; | ||||||
|  |   background-position:right bottom; | ||||||
|  |   height:100%; | ||||||
|  |   touch-action: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | html { | ||||||
|  |   height:100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_only_touch.noVNC_hidden { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_disabled { | ||||||
|  |   color: rgb(128, 128, 128); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Spinner | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | .noVNC_spinner { | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  | .noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after { | ||||||
|  |   width: 10px; | ||||||
|  |   height: 10px; | ||||||
|  |   border-radius: 2px; | ||||||
|  |   box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); | ||||||
|  |   animation: noVNC_spinner 1.0s linear infinite; | ||||||
|  | } | ||||||
|  | .noVNC_spinner::before { | ||||||
|  |   content: ""; | ||||||
|  |   position: absolute; | ||||||
|  |   left: 0px; | ||||||
|  |   top: 0px; | ||||||
|  |   animation-delay: -0.1s; | ||||||
|  | } | ||||||
|  | .noVNC_spinner::after { | ||||||
|  |   content: ""; | ||||||
|  |   position: absolute; | ||||||
|  |   top: 0px; | ||||||
|  |   left: 0px; | ||||||
|  |   animation-delay: 0.1s; | ||||||
|  | } | ||||||
|  | @keyframes noVNC_spinner { | ||||||
|  |   0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } | ||||||
|  |   25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } | ||||||
|  |   50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * WebKit centering hacks | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | .noVNC_center { | ||||||
|  |   /* | ||||||
|  |    * This is a workaround because webkit misrenders transforms and | ||||||
|  |    * uses non-integer coordinates, resulting in blurry content. | ||||||
|  |    * Ideally we'd use "top: 50%; transform: translateY(-50%);" on | ||||||
|  |    * the objects instead. | ||||||
|  |    */ | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   position: fixed; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |   pointer-events: none; | ||||||
|  | } | ||||||
|  | .noVNC_center > * { | ||||||
|  |   pointer-events: auto; | ||||||
|  | } | ||||||
|  | .noVNC_vcenter { | ||||||
|  |   display: flex !important; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: center; | ||||||
|  |   position: fixed; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   height: 100%; | ||||||
|  |   margin: 0 !important; | ||||||
|  |   padding: 0 !important; | ||||||
|  |   pointer-events: none; | ||||||
|  | } | ||||||
|  | .noVNC_vcenter > * { | ||||||
|  |   pointer-events: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Layering | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | .noVNC_connect_layer { | ||||||
|  |   z-index: 60; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Fallback error | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_fallback_error { | ||||||
|  |   z-index: 1000; | ||||||
|  |   visibility: hidden; | ||||||
|  |   /* Put a dark background in front of everything but the error, | ||||||
|  |      and don't let mouse events pass through */ | ||||||
|  |   background: rgba(0, 0, 0, 0.8); | ||||||
|  |   pointer-events: all; | ||||||
|  | } | ||||||
|  | #noVNC_fallback_error.noVNC_open { | ||||||
|  |   visibility: visible; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_fallback_error > div { | ||||||
|  |   max-width: calc(100vw - 30px - 30px); | ||||||
|  |   max-height: calc(100vh - 30px - 30px); | ||||||
|  |   overflow: auto; | ||||||
|  |  | ||||||
|  |   padding: 15px; | ||||||
|  |  | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   transform: translateY(-50px); | ||||||
|  |   opacity: 0; | ||||||
|  |  | ||||||
|  |   text-align: center; | ||||||
|  |   font-weight: bold; | ||||||
|  |   color: #fff; | ||||||
|  |  | ||||||
|  |   border-radius: 10px; | ||||||
|  |   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||||
|  |   background: rgba(200,55,55,0.8); | ||||||
|  | } | ||||||
|  | #noVNC_fallback_error.noVNC_open > div { | ||||||
|  |   transform: translateY(0); | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_fallback_errormsg { | ||||||
|  |   font-weight: normal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_fallback_errormsg .noVNC_message { | ||||||
|  |   display: inline-block; | ||||||
|  |   text-align: left; | ||||||
|  |   font-family: monospace; | ||||||
|  |   white-space: pre-wrap; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_fallback_error .noVNC_location { | ||||||
|  |   font-style: italic; | ||||||
|  |   font-size: 0.8em; | ||||||
|  |   color: rgba(255, 255, 255, 0.8); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_fallback_error .noVNC_stack { | ||||||
|  |   padding: 10px; | ||||||
|  |   margin: 10px; | ||||||
|  |   font-size: 0.8em; | ||||||
|  |   text-align: left; | ||||||
|  |   font-family: monospace; | ||||||
|  |   white-space: pre; | ||||||
|  |   border: 1px solid rgba(0, 0, 0, 0.5); | ||||||
|  |   background: rgba(0, 0, 0, 0.2); | ||||||
|  |   overflow: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Control Bar | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_control_bar_anchor { | ||||||
|  |   /* The anchor is needed to get z-stacking to work */ | ||||||
|  |   position: fixed; | ||||||
|  |   z-index: 10; | ||||||
|  |  | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   /* Edge misrenders animations wihthout this */ | ||||||
|  |   transform: translateX(0); | ||||||
|  | } | ||||||
|  | :root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle { | ||||||
|  |   opacity: 0.8; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_anchor.noVNC_right { | ||||||
|  |   left: auto; | ||||||
|  |   right: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_control_bar { | ||||||
|  |   position: relative; | ||||||
|  |   left: -100%; | ||||||
|  |  | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   border-radius: 0 10px 10px 0; | ||||||
|  |  | ||||||
|  |   user-select: none; | ||||||
|  |   -webkit-user-select: none; | ||||||
|  |   -webkit-touch-callout: none; /* Disable iOS image long-press popup */ | ||||||
|  | } | ||||||
|  | #noVNC_control_bar.noVNC_open { | ||||||
|  |   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||||
|  |   left: 0; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar::before { | ||||||
|  |   /* This extra element is to get a proper shadow */ | ||||||
|  |   content: ""; | ||||||
|  |   position: absolute; | ||||||
|  |   z-index: -1; | ||||||
|  |   height: 100%; | ||||||
|  |   width: 30px; | ||||||
|  |   left: -30px; | ||||||
|  |   transition: box-shadow 0.5s ease-in-out; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar.noVNC_open::before { | ||||||
|  |   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar { | ||||||
|  |   left: 100%; | ||||||
|  |   border-radius: 10px 0 0 10px; | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar.noVNC_open { | ||||||
|  |   left: 0; | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar::before { | ||||||
|  |   visibility: hidden; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_control_bar_handle { | ||||||
|  |   position: absolute; | ||||||
|  |   left: -15px; | ||||||
|  |   top: 0; | ||||||
|  |   transform: translateY(35px); | ||||||
|  |   width: calc(100% + 30px); | ||||||
|  |   height: 50px; | ||||||
|  |   z-index: -1; | ||||||
|  |   cursor: pointer; | ||||||
|  |   border-radius: 5px; | ||||||
|  |   background-color: rgb(83, 99, 122); | ||||||
|  |   background-image: url("../images/handle_bg.svg"); | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   background-position: right; | ||||||
|  |   box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_handle:after { | ||||||
|  |   content: ""; | ||||||
|  |   transition: transform 0.5s ease-in-out; | ||||||
|  |   background: url("../images/handle.svg"); | ||||||
|  |   position: absolute; | ||||||
|  |   top: 22px; /* (50px-6px)/2 */ | ||||||
|  |   right: 5px; | ||||||
|  |   width: 5px; | ||||||
|  |   height: 6px; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { | ||||||
|  |   transform: translateX(1px) rotate(180deg); | ||||||
|  | } | ||||||
|  | :root:not(.noVNC_connected) #noVNC_control_bar_handle { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar_handle { | ||||||
|  |   background-position: left; | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar_handle:after { | ||||||
|  |   left: 5px; | ||||||
|  |   right: 0; | ||||||
|  |   transform: translateX(1px) rotate(180deg); | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { | ||||||
|  |   transform: none; | ||||||
|  | } | ||||||
|  | /* Larger touch area for the handle, used when a touch screen is available */ | ||||||
|  | #noVNC_control_bar_handle div { | ||||||
|  |   position: absolute; | ||||||
|  |   right: -35px; | ||||||
|  |   top: 0; | ||||||
|  |   width: 50px; | ||||||
|  |   height: 100%; | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | @media (any-pointer: coarse) { | ||||||
|  |   #noVNC_control_bar_handle div { | ||||||
|  |     display: initial; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | .noVNC_right #noVNC_control_bar_handle div { | ||||||
|  |   left: -35px; | ||||||
|  |   right: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_control_bar > .noVNC_scroll { | ||||||
|  |   max-height: 100vh; /* Chrome is buggy with 100% */ | ||||||
|  |   overflow-x: hidden; | ||||||
|  |   overflow-y: auto; | ||||||
|  |   padding: 0 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_control_bar > .noVNC_scroll > * { | ||||||
|  |   display: block; | ||||||
|  |   margin: 10px auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Control bar hint */ | ||||||
|  | #noVNC_hint_anchor { | ||||||
|  |   position: fixed; | ||||||
|  |   right: -50px; | ||||||
|  |   left: auto; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { | ||||||
|  |   left: -50px; | ||||||
|  |   right: auto; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_hint { | ||||||
|  |   position: relative; | ||||||
|  |   transform: scale(0); | ||||||
|  |   width: 100px; | ||||||
|  |   height: 50%; | ||||||
|  |   max-height: 600px; | ||||||
|  |  | ||||||
|  |   visibility: hidden; | ||||||
|  |   opacity: 0; | ||||||
|  |   transition: 0.2s ease-in-out; | ||||||
|  |   background: transparent; | ||||||
|  |   box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); | ||||||
|  |   border-radius: 10px; | ||||||
|  |   transition-delay: 0s; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_hint.noVNC_active { | ||||||
|  |   visibility: visible; | ||||||
|  |   opacity: 1; | ||||||
|  |   transition-delay: 0.2s; | ||||||
|  |   transform: scale(1); | ||||||
|  | } | ||||||
|  | #noVNC_control_bar_hint.noVNC_notransition { | ||||||
|  |   transition: none !important; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Control bar buttons */ | ||||||
|  | #noVNC_control_bar .noVNC_button { | ||||||
|  |   padding: 4px 4px; | ||||||
|  |   vertical-align: middle; | ||||||
|  |   border:1px solid rgba(255, 255, 255, 0.2); | ||||||
|  |   border-radius: 6px; | ||||||
|  |   background-color: transparent; | ||||||
|  |   background-image: unset; /* we don't want the gradiant from input.css */ | ||||||
|  | } | ||||||
|  | #noVNC_control_bar .noVNC_button.noVNC_selected { | ||||||
|  |   border-color: rgba(0, 0, 0, 0.8); | ||||||
|  |   background-color: rgba(0, 0, 0, 0.5); | ||||||
|  | } | ||||||
|  | #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { | ||||||
|  |   border-color: rgba(0, 0, 0, 0.4); | ||||||
|  |   background-color: rgba(0, 0, 0, 0.2); | ||||||
|  | } | ||||||
|  | #noVNC_control_bar .noVNC_button:not(:disabled):hover { | ||||||
|  |   background-color: rgba(255, 255, 255, 0.2); | ||||||
|  | } | ||||||
|  | #noVNC_control_bar .noVNC_button:not(:disabled):active { | ||||||
|  |   padding-top: 5px; | ||||||
|  |   padding-bottom: 3px; | ||||||
|  | } | ||||||
|  | #noVNC_control_bar .noVNC_button.noVNC_hidden { | ||||||
|  |   display: none !important; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Android browsers don't properly update hover state if touch events are | ||||||
|  |  * intercepted, like they are when clicking on the remote screen. */ | ||||||
|  | @media (any-pointer: coarse) { | ||||||
|  |   #noVNC_control_bar .noVNC_button:not(:disabled):hover { | ||||||
|  |     background-color: transparent; | ||||||
|  |   } | ||||||
|  |   #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { | ||||||
|  |     border-color: rgba(0, 0, 0, 0.8); | ||||||
|  |     background-color: rgba(0, 0, 0, 0.5); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Panels */ | ||||||
|  | .noVNC_panel { | ||||||
|  |   transform: translateX(25px); | ||||||
|  |  | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   box-sizing: border-box; /* so max-width don't have to care about padding */ | ||||||
|  |   max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ | ||||||
|  |   max-height: 100vh; /* Chrome is buggy with 100% */ | ||||||
|  |   overflow-x: hidden; | ||||||
|  |   overflow-y: auto; | ||||||
|  |  | ||||||
|  |   visibility: hidden; | ||||||
|  |   opacity: 0; | ||||||
|  |  | ||||||
|  |   padding: 15px; | ||||||
|  |  | ||||||
|  |   background: #fff; | ||||||
|  |   border-radius: 10px; | ||||||
|  |   color: #000; | ||||||
|  |   border: 2px solid #E0E0E0; | ||||||
|  |   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||||
|  | } | ||||||
|  | .noVNC_panel.noVNC_open { | ||||||
|  |   visibility: visible; | ||||||
|  |   opacity: 1; | ||||||
|  |   transform: translateX(75px); | ||||||
|  | } | ||||||
|  | .noVNC_right .noVNC_vcenter { | ||||||
|  |   left: auto; | ||||||
|  |   right: 0; | ||||||
|  | } | ||||||
|  | .noVNC_right .noVNC_panel { | ||||||
|  |   transform: translateX(-25px); | ||||||
|  | } | ||||||
|  | .noVNC_right .noVNC_panel.noVNC_open { | ||||||
|  |   transform: translateX(-75px); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_panel > * { | ||||||
|  |   display: block; | ||||||
|  |   margin: 10px auto; | ||||||
|  | } | ||||||
|  | .noVNC_panel > *:first-child { | ||||||
|  |   margin-top: 0 !important; | ||||||
|  | } | ||||||
|  | .noVNC_panel > *:last-child { | ||||||
|  |   margin-bottom: 0 !important; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_panel hr { | ||||||
|  |   border: none; | ||||||
|  |   border-top: 1px solid rgb(192, 192, 192); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_panel label { | ||||||
|  |   display: block; | ||||||
|  |   white-space: nowrap; | ||||||
|  |   margin: 5px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_panel li { | ||||||
|  |   margin: 5px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_panel .noVNC_heading { | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   border-radius: 5px; | ||||||
|  |   padding: 5px; | ||||||
|  |   /* Compensate for padding in image */ | ||||||
|  |   padding-right: 8px; | ||||||
|  |   color: white; | ||||||
|  |   font-size: 20px; | ||||||
|  |   white-space: nowrap; | ||||||
|  | } | ||||||
|  | .noVNC_panel .noVNC_heading img { | ||||||
|  |   vertical-align: bottom; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_submit { | ||||||
|  |   float: right; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Expanders */ | ||||||
|  | .noVNC_expander { | ||||||
|  |   cursor: pointer; | ||||||
|  | } | ||||||
|  | .noVNC_expander::before { | ||||||
|  |   content: url("../images/expander.svg"); | ||||||
|  |   display: inline-block; | ||||||
|  |   margin-right: 5px; | ||||||
|  |   transition: 0.2s ease-in-out; | ||||||
|  | } | ||||||
|  | .noVNC_expander.noVNC_open::before { | ||||||
|  |   transform: rotateZ(90deg); | ||||||
|  | } | ||||||
|  | .noVNC_expander ~ * { | ||||||
|  |   margin: 5px; | ||||||
|  |   margin-left: 10px; | ||||||
|  |   padding: 5px; | ||||||
|  |   background: rgba(0, 0, 0, 0.05); | ||||||
|  |   border-radius: 5px; | ||||||
|  | } | ||||||
|  | .noVNC_expander:not(.noVNC_open) ~ * { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Control bar content */ | ||||||
|  |  | ||||||
|  | #noVNC_control_bar .noVNC_logo { | ||||||
|  |   font-size: 13px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_logo + hr { | ||||||
|  |     /* Remove all but top border */ | ||||||
|  |     border: none; | ||||||
|  |     border-top: 1px solid rgba(255, 255, 255, 0.2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | :root:not(.noVNC_connected) #noVNC_view_drag_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* noVNC Touch Device only buttons */ | ||||||
|  | :root:not(.noVNC_connected) #noVNC_mobile_buttons { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | @media not all and (any-pointer: coarse) { | ||||||
|  |   /* FIXME: The button for the virtual keyboard is the only button in this | ||||||
|  |             group of "mobile buttons". It is bad to assume that no touch | ||||||
|  |             devices have physical keyboards available. Hopefully we can get | ||||||
|  |             a media query for this: | ||||||
|  |             https://github.com/w3c/csswg-drafts/issues/3871 */ | ||||||
|  |   :root.noVNC_connected #noVNC_mobile_buttons { | ||||||
|  |     display: none; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Extra manual keys */ | ||||||
|  | :root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_modifiers { | ||||||
|  |   background-color: rgb(92, 92, 92); | ||||||
|  |   border: none; | ||||||
|  |   padding: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Shutdown/Reboot */ | ||||||
|  | :root:not(.noVNC_connected) #noVNC_power_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | #noVNC_power { | ||||||
|  | } | ||||||
|  | #noVNC_power_buttons { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_power input[type=button] { | ||||||
|  |   width: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Clipboard */ | ||||||
|  | :root:not(.noVNC_connected) #noVNC_clipboard_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | #noVNC_clipboard_text { | ||||||
|  |   width: 360px; | ||||||
|  |   min-width: 150px; | ||||||
|  |   height: 160px; | ||||||
|  |   min-height: 70px; | ||||||
|  |  | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   max-width: 100%; | ||||||
|  |   /* minus approximate height of title, height of subtitle, and margin */ | ||||||
|  |   max-height: calc(100vh - 10em - 25px); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Settings */ | ||||||
|  | #noVNC_settings { | ||||||
|  | } | ||||||
|  | #noVNC_settings ul { | ||||||
|  |   list-style: none; | ||||||
|  |   padding: 0px; | ||||||
|  | } | ||||||
|  | #noVNC_setting_port { | ||||||
|  |   width: 80px; | ||||||
|  | } | ||||||
|  | #noVNC_setting_path { | ||||||
|  |   width: 100px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Version */ | ||||||
|  |  | ||||||
|  | .noVNC_version_wrapper { | ||||||
|  |   font-size: small; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_version { | ||||||
|  |   margin-left: 1rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Connection Controls */ | ||||||
|  | :root:not(.noVNC_connected) #noVNC_disconnect_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Status Dialog | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_status { | ||||||
|  |   position: fixed; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   width: 100%; | ||||||
|  |   z-index: 100; | ||||||
|  |   transform: translateY(-100%); | ||||||
|  |  | ||||||
|  |   cursor: pointer; | ||||||
|  |  | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   visibility: hidden; | ||||||
|  |   opacity: 0; | ||||||
|  |  | ||||||
|  |   padding: 5px; | ||||||
|  |  | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: row; | ||||||
|  |   justify-content: center; | ||||||
|  |   align-content: center; | ||||||
|  |  | ||||||
|  |   line-height: 1.6; | ||||||
|  |   word-wrap: break-word; | ||||||
|  |   color: #fff; | ||||||
|  |  | ||||||
|  |   border-bottom: 1px solid rgba(0, 0, 0, 0.9); | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_open { | ||||||
|  |   transform: translateY(0); | ||||||
|  |   visibility: visible; | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_status::before { | ||||||
|  |   content: ""; | ||||||
|  |   display: inline-block; | ||||||
|  |   width: 25px; | ||||||
|  |   height: 25px; | ||||||
|  |   margin-right: 5px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_status.noVNC_status_normal { | ||||||
|  |   background: rgba(128,128,128,0.9); | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_status_normal::before { | ||||||
|  |   content: url("../images/info.svg") " "; | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_status_error { | ||||||
|  |   background: rgba(200,55,55,0.9); | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_status_error::before { | ||||||
|  |   content: url("../images/error.svg") " "; | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_status_warn { | ||||||
|  |   background: rgba(180,180,30,0.9); | ||||||
|  | } | ||||||
|  | #noVNC_status.noVNC_status_warn::before { | ||||||
|  |   content: url("../images/warning.svg") " "; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Connect Dialog | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_connect_dlg { | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   transform: scale(0, 0); | ||||||
|  |   visibility: hidden; | ||||||
|  |   opacity: 0; | ||||||
|  | } | ||||||
|  | #noVNC_connect_dlg.noVNC_open { | ||||||
|  |   transform: scale(1, 1); | ||||||
|  |   visibility: visible; | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  | #noVNC_connect_dlg .noVNC_logo { | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |   padding: 10px; | ||||||
|  |   margin-bottom: 10px; | ||||||
|  |  | ||||||
|  |   font-size: 80px; | ||||||
|  |   text-align: center; | ||||||
|  |  | ||||||
|  |   border-radius: 5px; | ||||||
|  | } | ||||||
|  | @media (max-width: 440px) { | ||||||
|  |   #noVNC_connect_dlg { | ||||||
|  |     max-width: calc(100vw - 100px); | ||||||
|  |   } | ||||||
|  |   #noVNC_connect_dlg .noVNC_logo { | ||||||
|  |     font-size: calc(25vw - 30px); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | #noVNC_connect_dlg div { | ||||||
|  |   padding: 12px; | ||||||
|  |  | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   border-radius: 12px; | ||||||
|  |   text-align: center; | ||||||
|  |   font-size: 20px; | ||||||
|  |  | ||||||
|  |   box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); | ||||||
|  | } | ||||||
|  | #noVNC_connect_button { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 5px 30px; | ||||||
|  |  | ||||||
|  |   cursor: pointer; | ||||||
|  |  | ||||||
|  |   border-color: rgb(83, 99, 122); | ||||||
|  |   border-radius: 5px; | ||||||
|  |  | ||||||
|  |   background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); | ||||||
|  |   color: white; | ||||||
|  |  | ||||||
|  |   /* This avoids it jumping around when :active */ | ||||||
|  |   vertical-align: middle; | ||||||
|  | } | ||||||
|  | #noVNC_connect_button:hover { | ||||||
|  |   background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_connect_button img { | ||||||
|  |   vertical-align: bottom; | ||||||
|  |   height: 1.3em; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Server verification Dialog | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_verify_server_dlg { | ||||||
|  |   position: relative; | ||||||
|  |  | ||||||
|  |   transform: translateY(-50px); | ||||||
|  | } | ||||||
|  | #noVNC_verify_server_dlg.noVNC_open { | ||||||
|  |   transform: translateY(0); | ||||||
|  | } | ||||||
|  | #noVNC_fingerprint_block { | ||||||
|  |   margin: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Password Dialog | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #noVNC_credentials_dlg { | ||||||
|  |   position: relative; | ||||||
|  |  | ||||||
|  |   transform: translateY(-50px); | ||||||
|  | } | ||||||
|  | #noVNC_credentials_dlg.noVNC_open { | ||||||
|  |   transform: translateY(0); | ||||||
|  | } | ||||||
|  | #noVNC_username_block.noVNC_hidden, | ||||||
|  | #noVNC_password_block.noVNC_hidden { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Main Area | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* Transition screen */ | ||||||
|  | #noVNC_transition { | ||||||
|  |   transition: 0.5s ease-in-out; | ||||||
|  |  | ||||||
|  |   display: flex; | ||||||
|  |   opacity: 0; | ||||||
|  |   visibility: hidden; | ||||||
|  |  | ||||||
|  |   position: fixed; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   bottom: 0; | ||||||
|  |   right: 0; | ||||||
|  |  | ||||||
|  |   color: white; | ||||||
|  |   background: rgba(0, 0, 0, 0.5); | ||||||
|  |   z-index: 50; | ||||||
|  |  | ||||||
|  |   /*display: flex;*/ | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   flex-direction: column; | ||||||
|  | } | ||||||
|  | :root.noVNC_loading #noVNC_transition, | ||||||
|  | :root.noVNC_connecting #noVNC_transition, | ||||||
|  | :root.noVNC_disconnecting #noVNC_transition, | ||||||
|  | :root.noVNC_reconnecting #noVNC_transition { | ||||||
|  |   opacity: 1; | ||||||
|  |   visibility: visible; | ||||||
|  | } | ||||||
|  | :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | #noVNC_transition_text { | ||||||
|  |   font-size: 1.5em; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Main container */ | ||||||
|  | #noVNC_container { | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |   background-color: #313131; | ||||||
|  |   border-bottom-right-radius: 800px 600px; | ||||||
|  |   /*border-top-left-radius: 800px 600px;*/ | ||||||
|  |  | ||||||
|  |   /* If selection isn't disabled, long-pressing stuff in the sidebar | ||||||
|  |      can accidentally select the container or the canvas. This can | ||||||
|  |      happen when attempting to move the handle. */ | ||||||
|  |   user-select: none; | ||||||
|  |   -webkit-user-select: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_keyboardinput { | ||||||
|  |   width: 1px; | ||||||
|  |   height: 1px; | ||||||
|  |   background-color: #fff; | ||||||
|  |   color: #fff; | ||||||
|  |   border: 0; | ||||||
|  |   position: absolute; | ||||||
|  |   left: -40px; | ||||||
|  |   z-index: -1; | ||||||
|  |   ime-mode: disabled; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*Default noVNC logo.*/ | ||||||
|  | /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ | ||||||
|  | @font-face { | ||||||
|  |   font-family: 'Orbitron'; | ||||||
|  |   font-style: normal; | ||||||
|  |   font-weight: 700; | ||||||
|  |   src: local('?'), url('Orbitron700.woff') format('woff'), | ||||||
|  |                    url('Orbitron700.ttf') format('truetype'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .noVNC_logo { | ||||||
|  |   color:yellow; | ||||||
|  |   font-family: 'Orbitron', 'OrbitronTTF', sans-serif; | ||||||
|  |   line-height: 0.9; | ||||||
|  |   text-shadow: 0.1em 0.1em 0 black; | ||||||
|  | } | ||||||
|  | .noVNC_logo span{ | ||||||
|  |   color:green; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #noVNC_bell { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ---------------------------------------- | ||||||
|  |  * Media sizing | ||||||
|  |  * ---------------------------------------- | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | @media screen and (max-width: 640px){ | ||||||
|  |   #noVNC_logo { | ||||||
|  |     font-size: 150px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media screen and (min-width: 321px) and (max-width: 480px) { | ||||||
|  |   #noVNC_logo { | ||||||
|  |     font-size: 110px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media screen and (max-width: 320px) { | ||||||
|  |   #noVNC_logo { | ||||||
|  |     font-size: 90px; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										281
									
								
								app/styles/input.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,281 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC general input element CSS | ||||||
|  |  * Copyright (C) 2022 The noVNC Authors | ||||||
|  |  * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Common for all inputs | ||||||
|  |  */ | ||||||
|  | input, input::file-selector-button, button, select, textarea { | ||||||
|  |   /* Respect standard font settings */ | ||||||
|  |   font: inherit; | ||||||
|  |  | ||||||
|  |   /* Disable default rendering */ | ||||||
|  |   appearance: none; | ||||||
|  |   background: none; | ||||||
|  |  | ||||||
|  |   padding: 5px; | ||||||
|  |   border: 1px solid rgb(192, 192, 192); | ||||||
|  |   border-radius: 5px; | ||||||
|  |   color: black; | ||||||
|  |   --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); | ||||||
|  |   background-image: var(--bg-gradient); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Buttons | ||||||
|  |  */ | ||||||
|  | input[type=button], | ||||||
|  | input[type=color], | ||||||
|  | input[type=image], | ||||||
|  | input[type=reset], | ||||||
|  | input[type=submit], | ||||||
|  | input::file-selector-button, | ||||||
|  | button, | ||||||
|  | select { | ||||||
|  |   border-bottom-width: 2px; | ||||||
|  |  | ||||||
|  |   /* This avoids it jumping around when :active */ | ||||||
|  |   vertical-align: middle; | ||||||
|  |   margin-top: 0; | ||||||
|  |  | ||||||
|  |   padding-left: 20px; | ||||||
|  |   padding-right: 20px; | ||||||
|  |  | ||||||
|  |   /* Disable Chrome's touch tap highlight */ | ||||||
|  |   -webkit-tap-highlight-color: transparent; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Select dropdowns | ||||||
|  |  */ | ||||||
|  | select { | ||||||
|  |   --select-arrow: url('data:image/svg+xml;utf8, \ | ||||||
|  |       <svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \ | ||||||
|  |            xmlns="http://www.w3.org/2000/svg"> \ | ||||||
|  |           <path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \ | ||||||
|  |                 stroke="rgb(31,31,31)" fill="none" \ | ||||||
|  |                 stroke-linecap="round" stroke-linejoin="round" /> \ | ||||||
|  |       </svg>'); | ||||||
|  |   background-image: var(--select-arrow), var(--bg-gradient); | ||||||
|  |   background-position: calc(100% - 7px), left top; | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   padding-right: calc(2*7px + 8px); | ||||||
|  |   padding-left: 7px; | ||||||
|  | } | ||||||
|  | /* FIXME: :active isn't set when the <select> is opened in Firefox: | ||||||
|  |           https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */ | ||||||
|  | select:active { | ||||||
|  |   /* Rotated arrow */ | ||||||
|  |   background-image: url('data:image/svg+xml;utf8, \ | ||||||
|  |       <svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \ | ||||||
|  |            xmlns="http://www.w3.org/2000/svg" transform="rotate(180)" > \ | ||||||
|  |           <path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \ | ||||||
|  |                 stroke="rgb(31,31,31)" fill="none" \ | ||||||
|  |                 stroke-linecap="round" stroke-linejoin="round" /> \ | ||||||
|  |       </svg>'), var(--bg-gradient); | ||||||
|  | } | ||||||
|  | option { | ||||||
|  |   color: black; | ||||||
|  |   background: white; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Checkboxes | ||||||
|  |  */ | ||||||
|  | input[type=checkbox] { | ||||||
|  |   display: inline-flex; | ||||||
|  |   justify-content: center; | ||||||
|  |   align-items: center; | ||||||
|  |   background-color: white; | ||||||
|  |   background-image: unset; | ||||||
|  |   border: 1px solid dimgrey; | ||||||
|  |   border-radius: 3px; | ||||||
|  |   width: 13px; | ||||||
|  |   height: 13px; | ||||||
|  |   padding: 0; | ||||||
|  |   margin-right: 6px; | ||||||
|  |   vertical-align: bottom; | ||||||
|  |   transition: 0.2s background-color linear; | ||||||
|  | } | ||||||
|  | input[type=checkbox]:checked { | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   border-color: rgb(110, 132, 163); | ||||||
|  | } | ||||||
|  | input[type=checkbox]:checked::after { | ||||||
|  |   content: ""; | ||||||
|  |   display: block; /* width & height doesn't work on inline elements */ | ||||||
|  |   width: 3px; | ||||||
|  |   height: 7px; | ||||||
|  |   border: 1px solid white; | ||||||
|  |   border-width: 0 2px 2px 0; | ||||||
|  |   transform: rotate(40deg) translateY(-1px); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Radiobuttons | ||||||
|  |  */ | ||||||
|  | input[type=radio] { | ||||||
|  |   border-radius: 50%; | ||||||
|  |   border: 1px solid dimgrey; | ||||||
|  |   width: 12px; | ||||||
|  |   height: 12px; | ||||||
|  |   padding: 0; | ||||||
|  |   margin-right: 6px; | ||||||
|  |   transition: 0.2s border linear; | ||||||
|  | } | ||||||
|  | input[type=radio]:checked { | ||||||
|  |   border: 6px solid rgb(110, 132, 163); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Range sliders | ||||||
|  |  */ | ||||||
|  | input[type=range] { | ||||||
|  |   border: unset; | ||||||
|  |   border-radius: 3px; | ||||||
|  |   height: 20px; | ||||||
|  |   padding: 0; | ||||||
|  |   background: transparent; | ||||||
|  | } | ||||||
|  | /* -webkit-slider.. & -moz-range.. cant be in selector lists: | ||||||
|  |    https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */ | ||||||
|  | input[type=range]::-webkit-slider-runnable-track { | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   height: 6px; | ||||||
|  |   border-radius: 3px; | ||||||
|  | } | ||||||
|  | input[type=range]::-moz-range-track { | ||||||
|  |   background-color: rgb(110, 132, 163); | ||||||
|  |   height: 6px; | ||||||
|  |   border-radius: 3px; | ||||||
|  | } | ||||||
|  | input[type=range]::-webkit-slider-thumb { | ||||||
|  |   appearance: none; | ||||||
|  |   width: 18px; | ||||||
|  |   height: 20px; | ||||||
|  |   border-radius: 5px; | ||||||
|  |   background-color: white; | ||||||
|  |   border: 1px solid dimgray; | ||||||
|  |   margin-top: -7px; | ||||||
|  | } | ||||||
|  | input[type=range]::-moz-range-thumb { | ||||||
|  |   appearance: none; | ||||||
|  |   width: 18px; | ||||||
|  |   height: 20px; | ||||||
|  |   border-radius: 5px; | ||||||
|  |   background-color: white; | ||||||
|  |   border: 1px solid dimgray; | ||||||
|  |   margin-top: -7px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * File choosers | ||||||
|  |  */ | ||||||
|  | input[type=file] { | ||||||
|  |   background-image: none; | ||||||
|  |   border: none; | ||||||
|  | } | ||||||
|  | input::file-selector-button { | ||||||
|  |   margin-right: 6px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Hover | ||||||
|  |  */ | ||||||
|  | input[type=button]:hover, | ||||||
|  | input[type=color]:hover, | ||||||
|  | input[type=image]:hover, | ||||||
|  | input[type=reset]:hover, | ||||||
|  | input[type=submit]:hover, | ||||||
|  | input::file-selector-button:hover, | ||||||
|  | button:hover { | ||||||
|  |   background-image: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); | ||||||
|  | } | ||||||
|  | select:hover { | ||||||
|  |   background-image: var(--select-arrow), | ||||||
|  |     linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); | ||||||
|  |   background-position: calc(100% - 7px), left top; | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  | } | ||||||
|  | @media (any-pointer: coarse) { | ||||||
|  |   /* We don't want a hover style after touch input */ | ||||||
|  |   input[type=button]:hover, | ||||||
|  |   input[type=color]:hover, | ||||||
|  |   input[type=image]:hover, | ||||||
|  |   input[type=reset]:hover, | ||||||
|  |   input[type=submit]:hover, | ||||||
|  |   input::file-selector-button:hover, | ||||||
|  |   button:hover { | ||||||
|  |     background-image: var(--bg-gradient); | ||||||
|  |   } | ||||||
|  |   select:hover { | ||||||
|  |     background-image: var(--select-arrow), var(--bg-gradient); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Active (clicked) | ||||||
|  |  */ | ||||||
|  | input[type=button]:active, | ||||||
|  | input[type=color]:active, | ||||||
|  | input[type=image]:active, | ||||||
|  | input[type=reset]:active, | ||||||
|  | input[type=submit]:active, | ||||||
|  | input::file-selector-button:active, | ||||||
|  | button:active, | ||||||
|  | select:active { | ||||||
|  |   border-bottom-width: 1px; | ||||||
|  |   margin-top: 1px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Focus (tab) | ||||||
|  |  */ | ||||||
|  | input:focus-visible, | ||||||
|  | input:focus-visible::file-selector-button, | ||||||
|  | button:focus-visible, | ||||||
|  | select:focus-visible, | ||||||
|  | textarea:focus-visible { | ||||||
|  |   outline: 2px solid rgb(74, 144, 217); | ||||||
|  |   outline-offset: 1px; | ||||||
|  | } | ||||||
|  | input[type=file]:focus-visible { | ||||||
|  |   outline: none; /* We outline the button instead of the entire element */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Disabled | ||||||
|  |  */ | ||||||
|  | input:disabled, | ||||||
|  | input:disabled::file-selector-button, | ||||||
|  | button:disabled, | ||||||
|  | select:disabled, | ||||||
|  | textarea:disabled { | ||||||
|  |   opacity: 0.4; | ||||||
|  | } | ||||||
|  | input[type=button]:disabled, | ||||||
|  | input[type=color]:disabled, | ||||||
|  | input[type=image]:disabled, | ||||||
|  | input[type=reset]:disabled, | ||||||
|  | input[type=submit]:disabled, | ||||||
|  | input:disabled::file-selector-button, | ||||||
|  | button:disabled, | ||||||
|  | select:disabled { | ||||||
|  |   background-image: var(--bg-gradient); | ||||||
|  |   border-bottom-width: 2px; | ||||||
|  |   margin-top: 0; | ||||||
|  | } | ||||||
|  | input[type=file]:disabled { | ||||||
|  |   background-image: none; | ||||||
|  | } | ||||||
|  | select:disabled { | ||||||
|  |   background-image: var(--select-arrow), var(--bg-gradient); | ||||||
|  | } | ||||||
|  | input[type=image]:disabled { | ||||||
|  |   /* See Firefox bug: | ||||||
|  |      https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */ | ||||||
|  |   cursor: default; | ||||||
|  | } | ||||||
							
								
								
									
										250
									
								
								app/webutil.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,250 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from '../core/util/logging.js'; | ||||||
|  |  | ||||||
|  | // init log level reading the logging HTTP param | ||||||
|  | export function initLogging(level) { | ||||||
|  |     "use strict"; | ||||||
|  |     if (typeof level !== "undefined") { | ||||||
|  |         Log.initLogging(level); | ||||||
|  |     } else { | ||||||
|  |         const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/); | ||||||
|  |         Log.initLogging(param || undefined); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read a query string variable | ||||||
|  | // A URL with a query parameter can look like this (But will most probably get logged on the http server): | ||||||
|  | // https://www.example.com?myqueryparam=myvalue | ||||||
|  | // | ||||||
|  | // For privacy (Using a hastag #, the parameters will not be sent to the server) | ||||||
|  | // the url can be requested in the following way: | ||||||
|  | // https://www.example.com#myqueryparam=myvalue&password=secretvalue | ||||||
|  | // | ||||||
|  | // Even Mixing public and non public parameters will work: | ||||||
|  | // https://www.example.com?nonsecretparam=example.com#password=secretvalue | ||||||
|  | export function getQueryVar(name, defVal) { | ||||||
|  |     "use strict"; | ||||||
|  |     const re = new RegExp('.*[?&]' + name + '=([^&#]*)'), | ||||||
|  |           match = document.location.href.match(re); | ||||||
|  |     if (typeof defVal === 'undefined') { defVal = null; } | ||||||
|  |  | ||||||
|  |     if (match) { | ||||||
|  |         return decodeURIComponent(match[1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return defVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read a hash fragment variable | ||||||
|  | export function getHashVar(name, defVal) { | ||||||
|  |     "use strict"; | ||||||
|  |     const re = new RegExp('.*[&#]' + name + '=([^&]*)'), | ||||||
|  |           match = document.location.hash.match(re); | ||||||
|  |     if (typeof defVal === 'undefined') { defVal = null; } | ||||||
|  |  | ||||||
|  |     if (match) { | ||||||
|  |         return decodeURIComponent(match[1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return defVal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read a variable from the fragment or the query string | ||||||
|  | // Fragment takes precedence | ||||||
|  | export function getConfigVar(name, defVal) { | ||||||
|  |     "use strict"; | ||||||
|  |     const val = getHashVar(name); | ||||||
|  |  | ||||||
|  |     if (val === null) { | ||||||
|  |         return getQueryVar(name, defVal); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | // No days means only for this browser session | ||||||
|  | export function createCookie(name, value, days) { | ||||||
|  |     "use strict"; | ||||||
|  |     let date, expires; | ||||||
|  |     if (days) { | ||||||
|  |         date = new Date(); | ||||||
|  |         date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); | ||||||
|  |         expires = "; expires=" + date.toGMTString(); | ||||||
|  |     } else { | ||||||
|  |         expires = ""; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let secure; | ||||||
|  |     if (document.location.protocol === "https:") { | ||||||
|  |         secure = "; secure"; | ||||||
|  |     } else { | ||||||
|  |         secure = ""; | ||||||
|  |     } | ||||||
|  |     document.cookie = name + "=" + value + expires + "; path=/" + secure; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function readCookie(name, defaultValue) { | ||||||
|  |     "use strict"; | ||||||
|  |     const nameEQ = name + "="; | ||||||
|  |     const ca = document.cookie.split(';'); | ||||||
|  |  | ||||||
|  |     for (let i = 0; i < ca.length; i += 1) { | ||||||
|  |         let c = ca[i]; | ||||||
|  |         while (c.charAt(0) === ' ') { | ||||||
|  |             c = c.substring(1, c.length); | ||||||
|  |         } | ||||||
|  |         if (c.indexOf(nameEQ) === 0) { | ||||||
|  |             return c.substring(nameEQ.length, c.length); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return (typeof defaultValue !== 'undefined') ? defaultValue : null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function eraseCookie(name) { | ||||||
|  |     "use strict"; | ||||||
|  |     createCookie(name, "", -1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Setting handling. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | let settings = {}; | ||||||
|  |  | ||||||
|  | export function initSettings() { | ||||||
|  |     if (!window.chrome || !window.chrome.storage) { | ||||||
|  |         settings = {}; | ||||||
|  |         return Promise.resolve(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return new Promise(resolve => window.chrome.storage.sync.get(resolve)) | ||||||
|  |         .then((cfg) => { settings = cfg; }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Update the settings cache, but do not write to permanent storage | ||||||
|  | export function setSetting(name, value) { | ||||||
|  |     settings[name] = value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // No days means only for this browser session | ||||||
|  | export function writeSetting(name, value) { | ||||||
|  |     "use strict"; | ||||||
|  |     if (settings[name] === value) return; | ||||||
|  |     settings[name] = value; | ||||||
|  |     if (window.chrome && window.chrome.storage) { | ||||||
|  |         window.chrome.storage.sync.set(settings); | ||||||
|  |     } else { | ||||||
|  |         localStorageSet(name, value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function readSetting(name, defaultValue) { | ||||||
|  |     "use strict"; | ||||||
|  |     let value; | ||||||
|  |     if ((name in settings) || (window.chrome && window.chrome.storage)) { | ||||||
|  |         value = settings[name]; | ||||||
|  |     } else { | ||||||
|  |         value = localStorageGet(name); | ||||||
|  |         settings[name] = value; | ||||||
|  |     } | ||||||
|  |     if (typeof value === "undefined") { | ||||||
|  |         value = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (value === null && typeof defaultValue !== "undefined") { | ||||||
|  |         return defaultValue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function eraseSetting(name) { | ||||||
|  |     "use strict"; | ||||||
|  |     // Deleting here means that next time the setting is read when using local | ||||||
|  |     // storage, it will be pulled from local storage again. | ||||||
|  |     // If the setting in local storage is changed (e.g. in another tab) | ||||||
|  |     // between this delete and the next read, it could lead to an unexpected | ||||||
|  |     // value change. | ||||||
|  |     delete settings[name]; | ||||||
|  |     if (window.chrome && window.chrome.storage) { | ||||||
|  |         window.chrome.storage.sync.remove(name); | ||||||
|  |     } else { | ||||||
|  |         localStorageRemove(name); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let loggedMsgs = []; | ||||||
|  | function logOnce(msg, level = "warn") { | ||||||
|  |     if (!loggedMsgs.includes(msg)) { | ||||||
|  |         switch (level) { | ||||||
|  |             case "error": | ||||||
|  |                 Log.Error(msg); | ||||||
|  |                 break; | ||||||
|  |             case "warn": | ||||||
|  |                 Log.Warn(msg); | ||||||
|  |                 break; | ||||||
|  |             case "debug": | ||||||
|  |                 Log.Debug(msg); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 Log.Info(msg); | ||||||
|  |         } | ||||||
|  |         loggedMsgs.push(msg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let cookiesMsg = "Couldn't access noVNC settings, are cookies disabled?"; | ||||||
|  |  | ||||||
|  | function localStorageGet(name) { | ||||||
|  |     let r; | ||||||
|  |     try { | ||||||
|  |         r = localStorage.getItem(name); | ||||||
|  |     } catch (e) { | ||||||
|  |         if (e instanceof DOMException) { | ||||||
|  |             logOnce(cookiesMsg); | ||||||
|  |             logOnce("'localStorage.getItem(" + name + ")' failed: " + e, | ||||||
|  |                     "debug"); | ||||||
|  |         } else { | ||||||
|  |             throw e; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  | function localStorageSet(name, value) { | ||||||
|  |     try { | ||||||
|  |         localStorage.setItem(name, value); | ||||||
|  |     } catch (e) { | ||||||
|  |         if (e instanceof DOMException) { | ||||||
|  |             logOnce(cookiesMsg); | ||||||
|  |             logOnce("'localStorage.setItem(" + name + "," + value + | ||||||
|  |                     ")' failed: " + e, "debug"); | ||||||
|  |         } else { | ||||||
|  |             throw e; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | function localStorageRemove(name) { | ||||||
|  |     try { | ||||||
|  |         localStorage.removeItem(name); | ||||||
|  |     } catch (e) { | ||||||
|  |         if (e instanceof DOMException) { | ||||||
|  |             logOnce(cookiesMsg); | ||||||
|  |             logOnce("'localStorage.removeItem(" + name + ")' failed: " + e, | ||||||
|  |                     "debug"); | ||||||
|  |         } else { | ||||||
|  |             throw e; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								core/base64.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,104 @@ | |||||||
|  | /* This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||||
|  |  | ||||||
|  | // From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js | ||||||
|  |  | ||||||
|  | import * as Log from './util/logging.js'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |     /* Convert data (an array of integers) to a Base64 string. */ | ||||||
|  |     toBase64Table: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''), | ||||||
|  |     base64Pad: '=', | ||||||
|  |  | ||||||
|  |     encode(data) { | ||||||
|  |         "use strict"; | ||||||
|  |         let result = ''; | ||||||
|  |         const length = data.length; | ||||||
|  |         const lengthpad = (length % 3); | ||||||
|  |         // Convert every three bytes to 4 ascii characters. | ||||||
|  |  | ||||||
|  |         for (let i = 0; i < (length - 2); i += 3) { | ||||||
|  |             result += this.toBase64Table[data[i] >> 2]; | ||||||
|  |             result += this.toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)]; | ||||||
|  |             result += this.toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)]; | ||||||
|  |             result += this.toBase64Table[data[i + 2] & 0x3f]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Convert the remaining 1 or 2 bytes, pad out to 4 characters. | ||||||
|  |         const j = length - lengthpad; | ||||||
|  |         if (lengthpad === 2) { | ||||||
|  |             result += this.toBase64Table[data[j] >> 2]; | ||||||
|  |             result += this.toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)]; | ||||||
|  |             result += this.toBase64Table[(data[j + 1] & 0x0f) << 2]; | ||||||
|  |             result += this.toBase64Table[64]; | ||||||
|  |         } else if (lengthpad === 1) { | ||||||
|  |             result += this.toBase64Table[data[j] >> 2]; | ||||||
|  |             result += this.toBase64Table[(data[j] & 0x03) << 4]; | ||||||
|  |             result += this.toBase64Table[64]; | ||||||
|  |             result += this.toBase64Table[64]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     /* Convert Base64 data to a string */ | ||||||
|  |     /* eslint-disable comma-spacing */ | ||||||
|  |     toBinaryTable: [ | ||||||
|  |         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | ||||||
|  |         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | ||||||
|  |         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, | ||||||
|  |         52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, | ||||||
|  |         -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14, | ||||||
|  |         15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, | ||||||
|  |         -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, | ||||||
|  |         41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 | ||||||
|  |     ], | ||||||
|  |     /* eslint-enable comma-spacing */ | ||||||
|  |  | ||||||
|  |     decode(data, offset = 0) { | ||||||
|  |         let dataLength = data.indexOf('=') - offset; | ||||||
|  |         if (dataLength < 0) { dataLength = data.length - offset; } | ||||||
|  |  | ||||||
|  |         /* Every four characters is 3 resulting numbers */ | ||||||
|  |         const resultLength = (dataLength >> 2) * 3 + Math.floor((dataLength % 4) / 1.5); | ||||||
|  |         const result = new Array(resultLength); | ||||||
|  |  | ||||||
|  |         // Convert one by one. | ||||||
|  |  | ||||||
|  |         let leftbits = 0; // number of bits decoded, but yet to be appended | ||||||
|  |         let leftdata = 0; // bits decoded, but yet to be appended | ||||||
|  |         for (let idx = 0, i = offset; i < data.length; i++) { | ||||||
|  |             const c = this.toBinaryTable[data.charCodeAt(i) & 0x7f]; | ||||||
|  |             const padding = (data.charAt(i) === this.base64Pad); | ||||||
|  |             // Skip illegal characters and whitespace | ||||||
|  |             if (c === -1) { | ||||||
|  |                 Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Collect data into leftdata, update bitcount | ||||||
|  |             leftdata = (leftdata << 6) | c; | ||||||
|  |             leftbits += 6; | ||||||
|  |  | ||||||
|  |             // If we have 8 or more bits, append 8 bits to the result | ||||||
|  |             if (leftbits >= 8) { | ||||||
|  |                 leftbits -= 8; | ||||||
|  |                 // Append if not padding. | ||||||
|  |                 if (!padding) { | ||||||
|  |                     result[idx++] = (leftdata >> leftbits) & 0xff; | ||||||
|  |                 } | ||||||
|  |                 leftdata &= (1 << leftbits) - 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // If there are any bits left, the base64 string was corrupted | ||||||
|  |         if (leftbits) { | ||||||
|  |             const err = new Error('Corrupted base64 string'); | ||||||
|  |             err.name = 'Base64-Error'; | ||||||
|  |             throw err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | }; /* End of Base64 namespace */ | ||||||
							
								
								
									
										178
									
								
								core/crypto/aes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,178 @@ | |||||||
|  | export class AESECBCipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._key = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "AES-ECB" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static async importKey(key, _algorithm, extractable, keyUsages) { | ||||||
|  |         const cipher = new AESECBCipher; | ||||||
|  |         await cipher._importKey(key, extractable, keyUsages); | ||||||
|  |         return cipher; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _importKey(key, extractable, keyUsages) { | ||||||
|  |         this._key = await window.crypto.subtle.importKey( | ||||||
|  |             "raw", key, {name: "AES-CBC"}, extractable, keyUsages); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async encrypt(_algorithm, plaintext) { | ||||||
|  |         const x = new Uint8Array(plaintext); | ||||||
|  |         if (x.length % 16 !== 0 || this._key === null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const n = x.length / 16; | ||||||
|  |         for (let i = 0; i < n; i++) { | ||||||
|  |             const y = new Uint8Array(await window.crypto.subtle.encrypt({ | ||||||
|  |                 name: "AES-CBC", | ||||||
|  |                 iv: new Uint8Array(16), | ||||||
|  |             }, this._key, x.slice(i * 16, i * 16 + 16))).slice(0, 16); | ||||||
|  |             x.set(y, i * 16); | ||||||
|  |         } | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class AESEAXCipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._rawKey = null; | ||||||
|  |         this._ctrKey = null; | ||||||
|  |         this._cbcKey = null; | ||||||
|  |         this._zeroBlock = new Uint8Array(16); | ||||||
|  |         this._prefixBlock0 = this._zeroBlock; | ||||||
|  |         this._prefixBlock1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); | ||||||
|  |         this._prefixBlock2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "AES-EAX" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _encryptBlock(block) { | ||||||
|  |         const encrypted = await window.crypto.subtle.encrypt({ | ||||||
|  |             name: "AES-CBC", | ||||||
|  |             iv: this._zeroBlock, | ||||||
|  |         }, this._cbcKey, block); | ||||||
|  |         return new Uint8Array(encrypted).slice(0, 16); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _initCMAC() { | ||||||
|  |         const k1 = await this._encryptBlock(this._zeroBlock); | ||||||
|  |         const k2 = new Uint8Array(16); | ||||||
|  |         const v = k1[0] >>> 6; | ||||||
|  |         for (let i = 0; i < 15; i++) { | ||||||
|  |             k2[i] = (k1[i + 1] >> 6) | (k1[i] << 2); | ||||||
|  |             k1[i] = (k1[i + 1] >> 7) | (k1[i] << 1); | ||||||
|  |         } | ||||||
|  |         const lut = [0x0, 0x87, 0x0e, 0x89]; | ||||||
|  |         k2[14] ^= v >>> 1; | ||||||
|  |         k2[15] = (k1[15] << 2) ^ lut[v]; | ||||||
|  |         k1[15] = (k1[15] << 1) ^ lut[v >> 1]; | ||||||
|  |         this._k1 = k1; | ||||||
|  |         this._k2 = k2; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _encryptCTR(data, counter) { | ||||||
|  |         const encrypted = await window.crypto.subtle.encrypt({ | ||||||
|  |             name: "AES-CTR", | ||||||
|  |             counter: counter, | ||||||
|  |             length: 128 | ||||||
|  |         }, this._ctrKey, data); | ||||||
|  |         return new Uint8Array(encrypted); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _decryptCTR(data, counter) { | ||||||
|  |         const decrypted = await window.crypto.subtle.decrypt({ | ||||||
|  |             name: "AES-CTR", | ||||||
|  |             counter: counter, | ||||||
|  |             length: 128 | ||||||
|  |         }, this._ctrKey, data); | ||||||
|  |         return new Uint8Array(decrypted); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _computeCMAC(data, prefixBlock) { | ||||||
|  |         if (prefixBlock.length !== 16) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const n = Math.floor(data.length / 16); | ||||||
|  |         const m = Math.ceil(data.length / 16); | ||||||
|  |         const r = data.length - n * 16; | ||||||
|  |         const cbcData = new Uint8Array((m + 1) * 16); | ||||||
|  |         cbcData.set(prefixBlock); | ||||||
|  |         cbcData.set(data, 16); | ||||||
|  |         if (r === 0) { | ||||||
|  |             for (let i = 0; i < 16; i++) { | ||||||
|  |                 cbcData[n * 16 + i] ^= this._k1[i]; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             cbcData[(n + 1) * 16 + r] = 0x80; | ||||||
|  |             for (let i = 0; i < 16; i++) { | ||||||
|  |                 cbcData[(n + 1) * 16 + i] ^= this._k2[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         let cbcEncrypted = await window.crypto.subtle.encrypt({ | ||||||
|  |             name: "AES-CBC", | ||||||
|  |             iv: this._zeroBlock, | ||||||
|  |         }, this._cbcKey, cbcData); | ||||||
|  |  | ||||||
|  |         cbcEncrypted = new Uint8Array(cbcEncrypted); | ||||||
|  |         const mac = cbcEncrypted.slice(cbcEncrypted.length - 32, cbcEncrypted.length - 16); | ||||||
|  |         return mac; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static async importKey(key, _algorithm, _extractable, _keyUsages) { | ||||||
|  |         const cipher = new AESEAXCipher; | ||||||
|  |         await cipher._importKey(key); | ||||||
|  |         return cipher; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _importKey(key) { | ||||||
|  |         this._rawKey = key; | ||||||
|  |         this._ctrKey = await window.crypto.subtle.importKey( | ||||||
|  |             "raw", key, {name: "AES-CTR"}, false, ["encrypt", "decrypt"]); | ||||||
|  |         this._cbcKey = await window.crypto.subtle.importKey( | ||||||
|  |             "raw", key, {name: "AES-CBC"}, false, ["encrypt"]); | ||||||
|  |         await this._initCMAC(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async encrypt(algorithm, message) { | ||||||
|  |         const ad = algorithm.additionalData; | ||||||
|  |         const nonce = algorithm.iv; | ||||||
|  |         const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0); | ||||||
|  |         const encrypted = await this._encryptCTR(message, nCMAC); | ||||||
|  |         const adCMAC = await this._computeCMAC(ad, this._prefixBlock1); | ||||||
|  |         const mac = await this._computeCMAC(encrypted, this._prefixBlock2); | ||||||
|  |         for (let i = 0; i < 16; i++) { | ||||||
|  |             mac[i] ^= nCMAC[i] ^ adCMAC[i]; | ||||||
|  |         } | ||||||
|  |         const res = new Uint8Array(16 + encrypted.length); | ||||||
|  |         res.set(encrypted); | ||||||
|  |         res.set(mac, encrypted.length); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async decrypt(algorithm, data) { | ||||||
|  |         const encrypted = data.slice(0, data.length - 16); | ||||||
|  |         const ad = algorithm.additionalData; | ||||||
|  |         const nonce = algorithm.iv; | ||||||
|  |         const mac = data.slice(data.length - 16); | ||||||
|  |         const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0); | ||||||
|  |         const adCMAC = await this._computeCMAC(ad, this._prefixBlock1); | ||||||
|  |         const computedMac = await this._computeCMAC(encrypted, this._prefixBlock2); | ||||||
|  |         for (let i = 0; i < 16; i++) { | ||||||
|  |             computedMac[i] ^= nCMAC[i] ^ adCMAC[i]; | ||||||
|  |         } | ||||||
|  |         if (computedMac.length !== mac.length) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         for (let i = 0; i < mac.length; i++) { | ||||||
|  |             if (computedMac[i] !== mac[i]) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         const res = await this._decryptCTR(encrypted, nCMAC); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								core/crypto/bigint.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,34 @@ | |||||||
|  | export function modPow(b, e, m) { | ||||||
|  |     let r = 1n; | ||||||
|  |     b = b % m; | ||||||
|  |     while (e > 0n) { | ||||||
|  |         if ((e & 1n) === 1n) { | ||||||
|  |             r = (r * b) % m; | ||||||
|  |         } | ||||||
|  |         e = e >> 1n; | ||||||
|  |         b = (b * b) % m; | ||||||
|  |     } | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function bigIntToU8Array(bigint, padLength=0) { | ||||||
|  |     let hex = bigint.toString(16); | ||||||
|  |     if (padLength === 0) { | ||||||
|  |         padLength = Math.ceil(hex.length / 2); | ||||||
|  |     } | ||||||
|  |     hex = hex.padStart(padLength * 2, '0'); | ||||||
|  |     const length = hex.length / 2; | ||||||
|  |     const arr = new Uint8Array(length); | ||||||
|  |     for (let i = 0; i < length; i++) { | ||||||
|  |         arr[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); | ||||||
|  |     } | ||||||
|  |     return arr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function u8ArrayToBigInt(arr) { | ||||||
|  |     let hex = '0x'; | ||||||
|  |     for (let i = 0; i < arr.length; i++) { | ||||||
|  |         hex += arr[i].toString(16).padStart(2, '0'); | ||||||
|  |     } | ||||||
|  |     return BigInt(hex); | ||||||
|  | } | ||||||
							
								
								
									
										90
									
								
								core/crypto/crypto.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,90 @@ | |||||||
|  | import { AESECBCipher, AESEAXCipher } from "./aes.js"; | ||||||
|  | import { DESCBCCipher, DESECBCipher } from "./des.js"; | ||||||
|  | import { RSACipher } from "./rsa.js"; | ||||||
|  | import { DHCipher } from "./dh.js"; | ||||||
|  | import { MD5 } from "./md5.js"; | ||||||
|  |  | ||||||
|  | // A single interface for the cryptographic algorithms not supported by SubtleCrypto. | ||||||
|  | // Both synchronous and asynchronous implmentations are allowed. | ||||||
|  | class LegacyCrypto { | ||||||
|  |     constructor() { | ||||||
|  |         this._algorithms = { | ||||||
|  |             "AES-ECB": AESECBCipher, | ||||||
|  |             "AES-EAX": AESEAXCipher, | ||||||
|  |             "DES-ECB": DESECBCipher, | ||||||
|  |             "DES-CBC": DESCBCCipher, | ||||||
|  |             "RSA-PKCS1-v1_5": RSACipher, | ||||||
|  |             "DH": DHCipher, | ||||||
|  |             "MD5": MD5, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     encrypt(algorithm, key, data) { | ||||||
|  |         if (key.algorithm.name !== algorithm.name) { | ||||||
|  |             throw new Error("algorithm does not match"); | ||||||
|  |         } | ||||||
|  |         if (typeof key.encrypt !== "function") { | ||||||
|  |             throw new Error("key does not support encryption"); | ||||||
|  |         } | ||||||
|  |         return key.encrypt(algorithm, data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decrypt(algorithm, key, data) { | ||||||
|  |         if (key.algorithm.name !== algorithm.name) { | ||||||
|  |             throw new Error("algorithm does not match"); | ||||||
|  |         } | ||||||
|  |         if (typeof key.decrypt !== "function") { | ||||||
|  |             throw new Error("key does not support encryption"); | ||||||
|  |         } | ||||||
|  |         return key.decrypt(algorithm, data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     importKey(format, keyData, algorithm, extractable, keyUsages) { | ||||||
|  |         if (format !== "raw") { | ||||||
|  |             throw new Error("key format is not supported"); | ||||||
|  |         } | ||||||
|  |         const alg = this._algorithms[algorithm.name]; | ||||||
|  |         if (typeof alg === "undefined" || typeof alg.importKey !== "function") { | ||||||
|  |             throw new Error("algorithm is not supported"); | ||||||
|  |         } | ||||||
|  |         return alg.importKey(keyData, algorithm, extractable, keyUsages); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     generateKey(algorithm, extractable, keyUsages) { | ||||||
|  |         const alg = this._algorithms[algorithm.name]; | ||||||
|  |         if (typeof alg === "undefined" || typeof alg.generateKey !== "function") { | ||||||
|  |             throw new Error("algorithm is not supported"); | ||||||
|  |         } | ||||||
|  |         return alg.generateKey(algorithm, extractable, keyUsages); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     exportKey(format, key) { | ||||||
|  |         if (format !== "raw") { | ||||||
|  |             throw new Error("key format is not supported"); | ||||||
|  |         } | ||||||
|  |         if (typeof key.exportKey !== "function") { | ||||||
|  |             throw new Error("key does not support exportKey"); | ||||||
|  |         } | ||||||
|  |         return key.exportKey(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     digest(algorithm, data) { | ||||||
|  |         const alg = this._algorithms[algorithm]; | ||||||
|  |         if (typeof alg !== "function") { | ||||||
|  |             throw new Error("algorithm is not supported"); | ||||||
|  |         } | ||||||
|  |         return alg(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     deriveBits(algorithm, key, length) { | ||||||
|  |         if (key.algorithm.name !== algorithm.name) { | ||||||
|  |             throw new Error("algorithm does not match"); | ||||||
|  |         } | ||||||
|  |         if (typeof key.deriveBits !== "function") { | ||||||
|  |             throw new Error("key does not support deriveBits"); | ||||||
|  |         } | ||||||
|  |         return key.deriveBits(algorithm, length); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default new LegacyCrypto; | ||||||
							
								
								
									
										330
									
								
								core/crypto/des.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,330 @@ | |||||||
|  | /* | ||||||
|  |  * Ported from Flashlight VNC ActionScript implementation: | ||||||
|  |  *     http://www.wizhelp.com/flashlight-vnc/ | ||||||
|  |  * | ||||||
|  |  * Full attribution follows: | ||||||
|  |  * | ||||||
|  |  * ------------------------------------------------------------------------- | ||||||
|  |  * | ||||||
|  |  * This DES class has been extracted from package Acme.Crypto for use in VNC. | ||||||
|  |  * The unnecessary odd parity code has been removed. | ||||||
|  |  * | ||||||
|  |  * These changes are: | ||||||
|  |  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * This software is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||||
|  |  * | ||||||
|  |  | ||||||
|  |  * DesCipher - the DES encryption method | ||||||
|  |  * | ||||||
|  |  * The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is: | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * Permission to use, copy, modify, and distribute this software | ||||||
|  |  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and | ||||||
|  |  * without fee is hereby granted, provided that this copyright notice is kept | ||||||
|  |  * intact. | ||||||
|  |  * | ||||||
|  |  * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY | ||||||
|  |  * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||||||
|  |  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||||||
|  |  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE | ||||||
|  |  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | ||||||
|  |  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE | ||||||
|  |  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE | ||||||
|  |  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT | ||||||
|  |  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE | ||||||
|  |  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE | ||||||
|  |  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE | ||||||
|  |  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  WIDGET WORKSHOP | ||||||
|  |  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR | ||||||
|  |  * HIGH RISK ACTIVITIES. | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * The rest is: | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions | ||||||
|  |  * are met: | ||||||
|  |  * 1. Redistributions of source code must retain the above copyright | ||||||
|  |  *    notice, this list of conditions and the following disclaimer. | ||||||
|  |  * 2. Redistributions in binary form must reproduce the above copyright | ||||||
|  |  *    notice, this list of conditions and the following disclaimer in the | ||||||
|  |  *    documentation and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||||||
|  |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
|  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
|  |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||||||
|  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
|  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||||
|  |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||||
|  |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||||
|  |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||||
|  |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||||
|  |  * SUCH DAMAGE. | ||||||
|  |  * | ||||||
|  |  * Visit the ACME Labs Java page for up-to-date versions of this and other | ||||||
|  |  * fine Java utilities: http://www.acme.com/java/ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* eslint-disable comma-spacing */ | ||||||
|  |  | ||||||
|  | // Tables, permutations, S-boxes, etc. | ||||||
|  | const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3, | ||||||
|  |              25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39, | ||||||
|  |              50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ], | ||||||
|  |       totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28]; | ||||||
|  |  | ||||||
|  | const z = 0x0; | ||||||
|  | let a,b,c,d,e,f; | ||||||
|  | a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e; | ||||||
|  | const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d, | ||||||
|  |              z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z, | ||||||
|  |              a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f, | ||||||
|  |              c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d]; | ||||||
|  | a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e; | ||||||
|  | const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d, | ||||||
|  |              a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f, | ||||||
|  |              z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z, | ||||||
|  |              z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e]; | ||||||
|  | a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e; | ||||||
|  | const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f, | ||||||
|  |              b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z, | ||||||
|  |              c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d, | ||||||
|  |              b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e]; | ||||||
|  | a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e; | ||||||
|  | const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d, | ||||||
|  |              z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f, | ||||||
|  |              b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e, | ||||||
|  |              c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e]; | ||||||
|  | a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e; | ||||||
|  | const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z, | ||||||
|  |              a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f, | ||||||
|  |              z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e, | ||||||
|  |              c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d]; | ||||||
|  | a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e; | ||||||
|  | const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f, | ||||||
|  |              z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z, | ||||||
|  |              b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z, | ||||||
|  |              a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f]; | ||||||
|  | a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e; | ||||||
|  | const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f, | ||||||
|  |              b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e, | ||||||
|  |              b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e, | ||||||
|  |              z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d]; | ||||||
|  | a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e; | ||||||
|  | const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d, | ||||||
|  |              c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z, | ||||||
|  |              a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f, | ||||||
|  |              z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e]; | ||||||
|  |  | ||||||
|  | /* eslint-enable comma-spacing */ | ||||||
|  |  | ||||||
|  | class DES { | ||||||
|  |     constructor(password) { | ||||||
|  |         this.keys = []; | ||||||
|  |  | ||||||
|  |         // Set the key. | ||||||
|  |         const pc1m = [], pcr = [], kn = []; | ||||||
|  |  | ||||||
|  |         for (let j = 0, l = 56; j < 56; ++j, l -= 8) { | ||||||
|  |             l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1 | ||||||
|  |             const m = l & 0x7; | ||||||
|  |             pc1m[j] = ((password[l >>> 3] & (1<<m)) !== 0) ? 1: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (let i = 0; i < 16; ++i) { | ||||||
|  |             const m = i << 1; | ||||||
|  |             const n = m + 1; | ||||||
|  |             kn[m] = kn[n] = 0; | ||||||
|  |             for (let o = 28; o < 59; o += 28) { | ||||||
|  |                 for (let j = o - 28; j < o; ++j) { | ||||||
|  |                     const l = j + totrot[i]; | ||||||
|  |                     pcr[j] = l < o ? pc1m[l] : pc1m[l - 28]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             for (let j = 0; j < 24; ++j) { | ||||||
|  |                 if (pcr[PC2[j]] !== 0) { | ||||||
|  |                     kn[m] |= 1 << (23 - j); | ||||||
|  |                 } | ||||||
|  |                 if (pcr[PC2[j + 24]] !== 0) { | ||||||
|  |                     kn[n] |= 1 << (23 - j); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // cookey | ||||||
|  |         for (let i = 0, rawi = 0, KnLi = 0; i < 16; ++i) { | ||||||
|  |             const raw0 = kn[rawi++]; | ||||||
|  |             const raw1 = kn[rawi++]; | ||||||
|  |             this.keys[KnLi] = (raw0 & 0x00fc0000) << 6; | ||||||
|  |             this.keys[KnLi] |= (raw0 & 0x00000fc0) << 10; | ||||||
|  |             this.keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10; | ||||||
|  |             this.keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6; | ||||||
|  |             ++KnLi; | ||||||
|  |             this.keys[KnLi] = (raw0 & 0x0003f000) << 12; | ||||||
|  |             this.keys[KnLi] |= (raw0 & 0x0000003f) << 16; | ||||||
|  |             this.keys[KnLi] |= (raw1 & 0x0003f000) >>> 4; | ||||||
|  |             this.keys[KnLi] |= (raw1 & 0x0000003f); | ||||||
|  |             ++KnLi; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Encrypt 8 bytes of text | ||||||
|  |     enc8(text) { | ||||||
|  |         const b = text.slice(); | ||||||
|  |         let i = 0, l, r, x; // left, right, accumulator | ||||||
|  |  | ||||||
|  |         // Squash 8 bytes to 2 ints | ||||||
|  |         l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; | ||||||
|  |         r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; | ||||||
|  |  | ||||||
|  |         x = ((l >>> 4) ^ r) & 0x0f0f0f0f; | ||||||
|  |         r ^= x; | ||||||
|  |         l ^= (x << 4); | ||||||
|  |         x = ((l >>> 16) ^ r) & 0x0000ffff; | ||||||
|  |         r ^= x; | ||||||
|  |         l ^= (x << 16); | ||||||
|  |         x = ((r >>> 2) ^ l) & 0x33333333; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= (x << 2); | ||||||
|  |         x = ((r >>> 8) ^ l) & 0x00ff00ff; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= (x << 8); | ||||||
|  |         r = (r << 1) | ((r >>> 31) & 1); | ||||||
|  |         x = (l ^ r) & 0xaaaaaaaa; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= x; | ||||||
|  |         l = (l << 1) | ((l >>> 31) & 1); | ||||||
|  |  | ||||||
|  |         for (let i = 0, keysi = 0; i < 8; ++i) { | ||||||
|  |             x = (r << 28) | (r >>> 4); | ||||||
|  |             x ^= this.keys[keysi++]; | ||||||
|  |             let fval =  SP7[x & 0x3f]; | ||||||
|  |             fval |= SP5[(x >>> 8) & 0x3f]; | ||||||
|  |             fval |= SP3[(x >>> 16) & 0x3f]; | ||||||
|  |             fval |= SP1[(x >>> 24) & 0x3f]; | ||||||
|  |             x = r ^ this.keys[keysi++]; | ||||||
|  |             fval |= SP8[x & 0x3f]; | ||||||
|  |             fval |= SP6[(x >>> 8) & 0x3f]; | ||||||
|  |             fval |= SP4[(x >>> 16) & 0x3f]; | ||||||
|  |             fval |= SP2[(x >>> 24) & 0x3f]; | ||||||
|  |             l ^= fval; | ||||||
|  |             x = (l << 28) | (l >>> 4); | ||||||
|  |             x ^= this.keys[keysi++]; | ||||||
|  |             fval =  SP7[x & 0x3f]; | ||||||
|  |             fval |= SP5[(x >>> 8) & 0x3f]; | ||||||
|  |             fval |= SP3[(x >>> 16) & 0x3f]; | ||||||
|  |             fval |= SP1[(x >>> 24) & 0x3f]; | ||||||
|  |             x = l ^ this.keys[keysi++]; | ||||||
|  |             fval |= SP8[x & 0x0000003f]; | ||||||
|  |             fval |= SP6[(x >>> 8) & 0x3f]; | ||||||
|  |             fval |= SP4[(x >>> 16) & 0x3f]; | ||||||
|  |             fval |= SP2[(x >>> 24) & 0x3f]; | ||||||
|  |             r ^= fval; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         r = (r << 31) | (r >>> 1); | ||||||
|  |         x = (l ^ r) & 0xaaaaaaaa; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= x; | ||||||
|  |         l = (l << 31) | (l >>> 1); | ||||||
|  |         x = ((l >>> 8) ^ r) & 0x00ff00ff; | ||||||
|  |         r ^= x; | ||||||
|  |         l ^= (x << 8); | ||||||
|  |         x = ((l >>> 2) ^ r) & 0x33333333; | ||||||
|  |         r ^= x; | ||||||
|  |         l ^= (x << 2); | ||||||
|  |         x = ((r >>> 16) ^ l) & 0x0000ffff; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= (x << 16); | ||||||
|  |         x = ((r >>> 4) ^ l) & 0x0f0f0f0f; | ||||||
|  |         l ^= x; | ||||||
|  |         r ^= (x << 4); | ||||||
|  |  | ||||||
|  |         // Spread ints to bytes | ||||||
|  |         x = [r, l]; | ||||||
|  |         for (i = 0; i < 8; i++) { | ||||||
|  |             b[i] = (x[i>>>2] >>> (8 * (3 - (i % 4)))) % 256; | ||||||
|  |             if (b[i] < 0) { b[i] += 256; } // unsigned | ||||||
|  |         } | ||||||
|  |         return b; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class DESECBCipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._cipher = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "DES-ECB" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static importKey(key, _algorithm, _extractable, _keyUsages) { | ||||||
|  |         const cipher = new DESECBCipher; | ||||||
|  |         cipher._importKey(key); | ||||||
|  |         return cipher; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _importKey(key, _extractable, _keyUsages) { | ||||||
|  |         this._cipher = new DES(key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     encrypt(_algorithm, plaintext) { | ||||||
|  |         const x = new Uint8Array(plaintext); | ||||||
|  |         if (x.length % 8 !== 0 || this._cipher === null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const n = x.length / 8; | ||||||
|  |         for (let i = 0; i < n; i++) { | ||||||
|  |             x.set(this._cipher.enc8(x.slice(i * 8, i * 8 + 8)), i * 8); | ||||||
|  |         } | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class DESCBCCipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._cipher = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "DES-CBC" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static importKey(key, _algorithm, _extractable, _keyUsages) { | ||||||
|  |         const cipher = new DESCBCCipher; | ||||||
|  |         cipher._importKey(key); | ||||||
|  |         return cipher; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _importKey(key) { | ||||||
|  |         this._cipher = new DES(key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     encrypt(algorithm, plaintext) { | ||||||
|  |         const x = new Uint8Array(plaintext); | ||||||
|  |         let y = new Uint8Array(algorithm.iv); | ||||||
|  |         if (x.length % 8 !== 0 || this._cipher === null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const n = x.length / 8; | ||||||
|  |         for (let i = 0; i < n; i++) { | ||||||
|  |             for (let j = 0; j < 8; j++) { | ||||||
|  |                 y[j] ^= plaintext[i * 8 + j]; | ||||||
|  |             } | ||||||
|  |             y = this._cipher.enc8(y); | ||||||
|  |             x.set(y, i * 8); | ||||||
|  |         } | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								core/crypto/dh.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,55 @@ | |||||||
|  | import { modPow, bigIntToU8Array, u8ArrayToBigInt } from "./bigint.js"; | ||||||
|  |  | ||||||
|  | class DHPublicKey { | ||||||
|  |     constructor(key) { | ||||||
|  |         this._key = key; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "DH" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     exportKey() { | ||||||
|  |         return this._key; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class DHCipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._g = null; | ||||||
|  |         this._p = null; | ||||||
|  |         this._gBigInt = null; | ||||||
|  |         this._pBigInt = null; | ||||||
|  |         this._privateKey = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "DH" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static generateKey(algorithm, _extractable) { | ||||||
|  |         const cipher = new DHCipher; | ||||||
|  |         cipher._generateKey(algorithm); | ||||||
|  |         return { privateKey: cipher, publicKey: new DHPublicKey(cipher._publicKey) }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _generateKey(algorithm) { | ||||||
|  |         const g = algorithm.g; | ||||||
|  |         const p = algorithm.p; | ||||||
|  |         this._keyBytes = p.length; | ||||||
|  |         this._gBigInt = u8ArrayToBigInt(g); | ||||||
|  |         this._pBigInt = u8ArrayToBigInt(p); | ||||||
|  |         this._privateKey = window.crypto.getRandomValues(new Uint8Array(this._keyBytes)); | ||||||
|  |         this._privateKeyBigInt = u8ArrayToBigInt(this._privateKey); | ||||||
|  |         this._publicKey = bigIntToU8Array(modPow( | ||||||
|  |             this._gBigInt, this._privateKeyBigInt, this._pBigInt), this._keyBytes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     deriveBits(algorithm, length) { | ||||||
|  |         const bytes = Math.ceil(length / 8); | ||||||
|  |         const pkey = new Uint8Array(algorithm.public); | ||||||
|  |         const len = bytes > this._keyBytes ? bytes : this._keyBytes; | ||||||
|  |         const secret = modPow(u8ArrayToBigInt(pkey), this._privateKeyBigInt, this._pBigInt); | ||||||
|  |         return bigIntToU8Array(secret, len).slice(0, len); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								core/crypto/md5.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,82 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2021 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Performs MD5 hashing on an array of bytes, returns an array of bytes | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export async function MD5(d) { | ||||||
|  |     let s = ""; | ||||||
|  |     for (let i = 0; i < d.length; i++) { | ||||||
|  |         s += String.fromCharCode(d[i]); | ||||||
|  |     } | ||||||
|  |     return M(V(Y(X(s), 8 * s.length))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function M(d) { | ||||||
|  |     let f = new Uint8Array(d.length); | ||||||
|  |     for (let i=0;i<d.length;i++) { | ||||||
|  |         f[i] = d.charCodeAt(i); | ||||||
|  |     } | ||||||
|  |     return f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function X(d) { | ||||||
|  |     let r = Array(d.length >> 2); | ||||||
|  |     for (let m = 0; m < r.length; m++) r[m] = 0; | ||||||
|  |     for (let m = 0; m < 8 * d.length; m += 8) r[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32; | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function V(d) { | ||||||
|  |     let r = ""; | ||||||
|  |     for (let m = 0; m < 32 * d.length; m += 8) r += String.fromCharCode(d[m >> 5] >>> m % 32 & 255); | ||||||
|  |     return r; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function Y(d, g) { | ||||||
|  |     d[g >> 5] |= 128 << g % 32, d[14 + (g + 64 >>> 9 << 4)] = g; | ||||||
|  |     let m = 1732584193, f = -271733879, r = -1732584194, i = 271733878; | ||||||
|  |     for (let n = 0; n < d.length; n += 16) { | ||||||
|  |         let h = m, | ||||||
|  |             t = f, | ||||||
|  |             g = r, | ||||||
|  |             e = i; | ||||||
|  |         f = ii(f = ii(f = ii(f = ii(f = hh(f = hh(f = hh(f = hh(f = gg(f = gg(f = gg(f = gg(f = ff(f = ff(f = ff(f = ff(f, r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551), m = add(m, h), f = add(f, t), r = add(r, g), i = add(i, e); | ||||||
|  |     } | ||||||
|  |     return Array(m, f, r, i); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cmn(d, g, m, f, r, i) { | ||||||
|  |     return add(rol(add(add(g, d), add(f, i)), r), m); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function ff(d, g, m, f, r, i, n) { | ||||||
|  |     return cmn(g & m | ~g & f, d, g, r, i, n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function gg(d, g, m, f, r, i, n) { | ||||||
|  |     return cmn(g & f | m & ~f, d, g, r, i, n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function hh(d, g, m, f, r, i, n) { | ||||||
|  |     return cmn(g ^ m ^ f, d, g, r, i, n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function ii(d, g, m, f, r, i, n) { | ||||||
|  |     return cmn(m ^ (g | ~f), d, g, r, i, n); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function add(d, g) { | ||||||
|  |     let m = (65535 & d) + (65535 & g); | ||||||
|  |     return (d >> 16) + (g >> 16) + (m >> 16) << 16 | 65535 & m; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function rol(d, g) { | ||||||
|  |     return d << g | d >>> 32 - g; | ||||||
|  | } | ||||||
							
								
								
									
										132
									
								
								core/crypto/rsa.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,132 @@ | |||||||
|  | import Base64 from "../base64.js"; | ||||||
|  | import { modPow, bigIntToU8Array, u8ArrayToBigInt } from "./bigint.js"; | ||||||
|  |  | ||||||
|  | export class RSACipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._keyLength = 0; | ||||||
|  |         this._keyBytes = 0; | ||||||
|  |         this._n = null; | ||||||
|  |         this._e = null; | ||||||
|  |         this._d = null; | ||||||
|  |         this._nBigInt = null; | ||||||
|  |         this._eBigInt = null; | ||||||
|  |         this._dBigInt = null; | ||||||
|  |         this._extractable = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get algorithm() { | ||||||
|  |         return { name: "RSA-PKCS1-v1_5" }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _base64urlDecode(data) { | ||||||
|  |         data = data.replace(/-/g, "+").replace(/_/g, "/"); | ||||||
|  |         data = data.padEnd(Math.ceil(data.length / 4) * 4, "="); | ||||||
|  |         return Base64.decode(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _padArray(arr, length) { | ||||||
|  |         const res = new Uint8Array(length); | ||||||
|  |         res.set(arr, length - arr.length); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static async generateKey(algorithm, extractable, _keyUsages) { | ||||||
|  |         const cipher = new RSACipher; | ||||||
|  |         await cipher._generateKey(algorithm, extractable); | ||||||
|  |         return { privateKey: cipher }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _generateKey(algorithm, extractable) { | ||||||
|  |         this._keyLength = algorithm.modulusLength; | ||||||
|  |         this._keyBytes = Math.ceil(this._keyLength / 8); | ||||||
|  |         const key = await window.crypto.subtle.generateKey( | ||||||
|  |             { | ||||||
|  |                 name: "RSA-OAEP", | ||||||
|  |                 modulusLength: algorithm.modulusLength, | ||||||
|  |                 publicExponent: algorithm.publicExponent, | ||||||
|  |                 hash: {name: "SHA-256"}, | ||||||
|  |             }, | ||||||
|  |             true, ["encrypt", "decrypt"]); | ||||||
|  |         const privateKey = await window.crypto.subtle.exportKey("jwk", key.privateKey); | ||||||
|  |         this._n = this._padArray(this._base64urlDecode(privateKey.n), this._keyBytes); | ||||||
|  |         this._nBigInt = u8ArrayToBigInt(this._n); | ||||||
|  |         this._e = this._padArray(this._base64urlDecode(privateKey.e), this._keyBytes); | ||||||
|  |         this._eBigInt = u8ArrayToBigInt(this._e); | ||||||
|  |         this._d = this._padArray(this._base64urlDecode(privateKey.d), this._keyBytes); | ||||||
|  |         this._dBigInt = u8ArrayToBigInt(this._d); | ||||||
|  |         this._extractable = extractable; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static async importKey(key, _algorithm, extractable, keyUsages) { | ||||||
|  |         if (keyUsages.length !== 1 || keyUsages[0] !== "encrypt") { | ||||||
|  |             throw new Error("only support importing RSA public key"); | ||||||
|  |         } | ||||||
|  |         const cipher = new RSACipher; | ||||||
|  |         await cipher._importKey(key, extractable); | ||||||
|  |         return cipher; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async _importKey(key, extractable) { | ||||||
|  |         const n = key.n; | ||||||
|  |         const e = key.e; | ||||||
|  |         if (n.length !== e.length) { | ||||||
|  |             throw new Error("the sizes of modulus and public exponent do not match"); | ||||||
|  |         } | ||||||
|  |         this._keyBytes = n.length; | ||||||
|  |         this._keyLength = this._keyBytes * 8; | ||||||
|  |         this._n = new Uint8Array(this._keyBytes); | ||||||
|  |         this._e = new Uint8Array(this._keyBytes); | ||||||
|  |         this._n.set(n); | ||||||
|  |         this._e.set(e); | ||||||
|  |         this._nBigInt = u8ArrayToBigInt(this._n); | ||||||
|  |         this._eBigInt = u8ArrayToBigInt(this._e); | ||||||
|  |         this._extractable = extractable; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async encrypt(_algorithm, message) { | ||||||
|  |         if (message.length > this._keyBytes - 11) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const ps = new Uint8Array(this._keyBytes - message.length - 3); | ||||||
|  |         window.crypto.getRandomValues(ps); | ||||||
|  |         for (let i = 0; i < ps.length; i++) { | ||||||
|  |             ps[i] = Math.floor(ps[i] * 254 / 255 + 1); | ||||||
|  |         } | ||||||
|  |         const em = new Uint8Array(this._keyBytes); | ||||||
|  |         em[1] = 0x02; | ||||||
|  |         em.set(ps, 2); | ||||||
|  |         em.set(message, ps.length + 3); | ||||||
|  |         const emBigInt = u8ArrayToBigInt(em); | ||||||
|  |         const c = modPow(emBigInt, this._eBigInt, this._nBigInt); | ||||||
|  |         return bigIntToU8Array(c, this._keyBytes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async decrypt(_algorithm, message) { | ||||||
|  |         if (message.length !== this._keyBytes) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         const msgBigInt = u8ArrayToBigInt(message); | ||||||
|  |         const emBigInt = modPow(msgBigInt, this._dBigInt, this._nBigInt); | ||||||
|  |         const em = bigIntToU8Array(emBigInt, this._keyBytes); | ||||||
|  |         if (em[0] !== 0x00 || em[1] !== 0x02) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         let i = 2; | ||||||
|  |         for (; i < em.length; i++) { | ||||||
|  |             if (em[i] === 0x00) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (i === em.length) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return em.slice(i + 1, em.length); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async exportKey() { | ||||||
|  |         if (!this._extractable) { | ||||||
|  |             throw new Error("key is not extractable"); | ||||||
|  |         } | ||||||
|  |         return { n: this._n, e: this._e, d: this._d }; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								core/decoders/copyrect.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,27 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default class CopyRectDecoder { | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (sock.rQwait("COPYRECT", 4)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let deltaX = sock.rQshift16(); | ||||||
|  |         let deltaY = sock.rQshift16(); | ||||||
|  |  | ||||||
|  |         if ((width === 0) || (height === 0)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.copyImage(deltaX, deltaY, x, y, width, height); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										181
									
								
								core/decoders/hextile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,181 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from '../util/logging.js'; | ||||||
|  |  | ||||||
|  | export default class HextileDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         this._tiles = 0; | ||||||
|  |         this._lastsubencoding = 0; | ||||||
|  |         this._tileBuffer = new Uint8Array(16 * 16 * 4); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._tiles === 0) { | ||||||
|  |             this._tilesX = Math.ceil(width / 16); | ||||||
|  |             this._tilesY = Math.ceil(height / 16); | ||||||
|  |             this._totalTiles = this._tilesX * this._tilesY; | ||||||
|  |             this._tiles = this._totalTiles; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         while (this._tiles > 0) { | ||||||
|  |             let bytes = 1; | ||||||
|  |  | ||||||
|  |             if (sock.rQwait("HEXTILE", bytes)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             let subencoding = sock.rQpeek8(); | ||||||
|  |             if (subencoding > 30) {  // Raw | ||||||
|  |                 throw new Error("Illegal hextile subencoding (subencoding: " + | ||||||
|  |                             subencoding + ")"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const currTile = this._totalTiles - this._tiles; | ||||||
|  |             const tileX = currTile % this._tilesX; | ||||||
|  |             const tileY = Math.floor(currTile / this._tilesX); | ||||||
|  |             const tx = x + tileX * 16; | ||||||
|  |             const ty = y + tileY * 16; | ||||||
|  |             const tw = Math.min(16, (x + width) - tx); | ||||||
|  |             const th = Math.min(16, (y + height) - ty); | ||||||
|  |  | ||||||
|  |             // Figure out how much we are expecting | ||||||
|  |             if (subencoding & 0x01) {  // Raw | ||||||
|  |                 bytes += tw * th * 4; | ||||||
|  |             } else { | ||||||
|  |                 if (subencoding & 0x02) {  // Background | ||||||
|  |                     bytes += 4; | ||||||
|  |                 } | ||||||
|  |                 if (subencoding & 0x04) {  // Foreground | ||||||
|  |                     bytes += 4; | ||||||
|  |                 } | ||||||
|  |                 if (subencoding & 0x08) {  // AnySubrects | ||||||
|  |                     bytes++;  // Since we aren't shifting it off | ||||||
|  |  | ||||||
|  |                     if (sock.rQwait("HEXTILE", bytes)) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     let subrects = sock.rQpeekBytes(bytes).at(-1); | ||||||
|  |                     if (subencoding & 0x10) {  // SubrectsColoured | ||||||
|  |                         bytes += subrects * (4 + 2); | ||||||
|  |                     } else { | ||||||
|  |                         bytes += subrects * 2; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (sock.rQwait("HEXTILE", bytes)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // We know the encoding and have a whole tile | ||||||
|  |             sock.rQshift8(); | ||||||
|  |             if (subencoding === 0) { | ||||||
|  |                 if (this._lastsubencoding & 0x01) { | ||||||
|  |                     // Weird: ignore blanks are RAW | ||||||
|  |                     Log.Debug("     Ignoring blank after RAW"); | ||||||
|  |                 } else { | ||||||
|  |                     display.fillRect(tx, ty, tw, th, this._background); | ||||||
|  |                 } | ||||||
|  |             } else if (subencoding & 0x01) {  // Raw | ||||||
|  |                 let pixels = tw * th; | ||||||
|  |                 let data = sock.rQshiftBytes(pixels * 4, false); | ||||||
|  |                 // Max sure the image is fully opaque | ||||||
|  |                 for (let i = 0;i <  pixels;i++) { | ||||||
|  |                     data[i * 4 + 3] = 255; | ||||||
|  |                 } | ||||||
|  |                 display.blitImage(tx, ty, tw, th, data, 0); | ||||||
|  |             } else { | ||||||
|  |                 if (subencoding & 0x02) {  // Background | ||||||
|  |                     this._background = new Uint8Array(sock.rQshiftBytes(4)); | ||||||
|  |                 } | ||||||
|  |                 if (subencoding & 0x04) {  // Foreground | ||||||
|  |                     this._foreground = new Uint8Array(sock.rQshiftBytes(4)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 this._startTile(tx, ty, tw, th, this._background); | ||||||
|  |                 if (subencoding & 0x08) {  // AnySubrects | ||||||
|  |                     let subrects = sock.rQshift8(); | ||||||
|  |  | ||||||
|  |                     for (let s = 0; s < subrects; s++) { | ||||||
|  |                         let color; | ||||||
|  |                         if (subencoding & 0x10) {  // SubrectsColoured | ||||||
|  |                             color = sock.rQshiftBytes(4); | ||||||
|  |                         } else { | ||||||
|  |                             color = this._foreground; | ||||||
|  |                         } | ||||||
|  |                         const xy = sock.rQshift8(); | ||||||
|  |                         const sx = (xy >> 4); | ||||||
|  |                         const sy = (xy & 0x0f); | ||||||
|  |  | ||||||
|  |                         const wh = sock.rQshift8(); | ||||||
|  |                         const sw = (wh >> 4) + 1; | ||||||
|  |                         const sh = (wh & 0x0f) + 1; | ||||||
|  |  | ||||||
|  |                         this._subTile(sx, sy, sw, sh, color); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 this._finishTile(display); | ||||||
|  |             } | ||||||
|  |             this._lastsubencoding = subencoding; | ||||||
|  |             this._tiles--; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // start updating a tile | ||||||
|  |     _startTile(x, y, width, height, color) { | ||||||
|  |         this._tileX = x; | ||||||
|  |         this._tileY = y; | ||||||
|  |         this._tileW = width; | ||||||
|  |         this._tileH = height; | ||||||
|  |  | ||||||
|  |         const red = color[0]; | ||||||
|  |         const green = color[1]; | ||||||
|  |         const blue = color[2]; | ||||||
|  |  | ||||||
|  |         const data = this._tileBuffer; | ||||||
|  |         for (let i = 0; i < width * height * 4; i += 4) { | ||||||
|  |             data[i]     = red; | ||||||
|  |             data[i + 1] = green; | ||||||
|  |             data[i + 2] = blue; | ||||||
|  |             data[i + 3] = 255; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // update sub-rectangle of the current tile | ||||||
|  |     _subTile(x, y, w, h, color) { | ||||||
|  |         const red = color[0]; | ||||||
|  |         const green = color[1]; | ||||||
|  |         const blue = color[2]; | ||||||
|  |         const xend = x + w; | ||||||
|  |         const yend = y + h; | ||||||
|  |  | ||||||
|  |         const data = this._tileBuffer; | ||||||
|  |         const width = this._tileW; | ||||||
|  |         for (let j = y; j < yend; j++) { | ||||||
|  |             for (let i = x; i < xend; i++) { | ||||||
|  |                 const p = (i + (j * width)) * 4; | ||||||
|  |                 data[p]     = red; | ||||||
|  |                 data[p + 1] = green; | ||||||
|  |                 data[p + 2] = blue; | ||||||
|  |                 data[p + 3] = 255; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // draw the current tile to the screen | ||||||
|  |     _finishTile(display) { | ||||||
|  |         display.blitImage(this._tileX, this._tileY, | ||||||
|  |                           this._tileW, this._tileH, | ||||||
|  |                           this._tileBuffer, 0); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										146
									
								
								core/decoders/jpeg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,146 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default class JPEGDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         // RealVNC will reuse the quantization tables | ||||||
|  |         // and Huffman tables, so we need to cache them. | ||||||
|  |         this._cachedQuantTables = []; | ||||||
|  |         this._cachedHuffmanTables = []; | ||||||
|  |  | ||||||
|  |         this._segments = []; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         // A rect of JPEG encodings is simply a JPEG file | ||||||
|  |         while (true) { | ||||||
|  |             let segment = this._readSegment(sock); | ||||||
|  |             if (segment === null) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             this._segments.push(segment); | ||||||
|  |             // End of image? | ||||||
|  |             if (segment[1] === 0xD9) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let huffmanTables = []; | ||||||
|  |         let quantTables = []; | ||||||
|  |         for (let segment of this._segments) { | ||||||
|  |             let type = segment[1]; | ||||||
|  |             if (type === 0xC4) { | ||||||
|  |                 // Huffman tables | ||||||
|  |                 huffmanTables.push(segment); | ||||||
|  |             } else if (type === 0xDB) { | ||||||
|  |                 // Quantization tables | ||||||
|  |                 quantTables.push(segment); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const sofIndex = this._segments.findIndex( | ||||||
|  |             x => x[1] == 0xC0 || x[1] == 0xC2 | ||||||
|  |         ); | ||||||
|  |         if (sofIndex == -1) { | ||||||
|  |             throw new Error("Illegal JPEG image without SOF"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (quantTables.length === 0) { | ||||||
|  |             this._segments.splice(sofIndex+1, 0, | ||||||
|  |                                   ...this._cachedQuantTables); | ||||||
|  |         } | ||||||
|  |         if (huffmanTables.length === 0) { | ||||||
|  |             this._segments.splice(sofIndex+1, 0, | ||||||
|  |                                   ...this._cachedHuffmanTables); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let length = 0; | ||||||
|  |         for (let segment of this._segments) { | ||||||
|  |             length += segment.length; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let data = new Uint8Array(length); | ||||||
|  |         length = 0; | ||||||
|  |         for (let segment of this._segments) { | ||||||
|  |             data.set(segment, length); | ||||||
|  |             length += segment.length; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.imageRect(x, y, width, height, "image/jpeg", data); | ||||||
|  |  | ||||||
|  |         if (huffmanTables.length !== 0) { | ||||||
|  |             this._cachedHuffmanTables = huffmanTables; | ||||||
|  |         } | ||||||
|  |         if (quantTables.length !== 0) { | ||||||
|  |             this._cachedQuantTables = quantTables; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._segments = []; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _readSegment(sock) { | ||||||
|  |         if (sock.rQwait("JPEG", 2)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let marker = sock.rQshift8(); | ||||||
|  |         if (marker != 0xFF) { | ||||||
|  |             throw new Error("Illegal JPEG marker received (byte: " + | ||||||
|  |                                marker + ")"); | ||||||
|  |         } | ||||||
|  |         let type = sock.rQshift8(); | ||||||
|  |         if (type >= 0xD0 && type <= 0xD9 || type == 0x01) { | ||||||
|  |             // No length after marker | ||||||
|  |             return new Uint8Array([marker, type]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (sock.rQwait("JPEG", 2, 2)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let length = sock.rQshift16(); | ||||||
|  |         if (length < 2) { | ||||||
|  |             throw new Error("Illegal JPEG length received (length: " + | ||||||
|  |                                length + ")"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (sock.rQwait("JPEG", length-2, 4)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let extra = 0; | ||||||
|  |         if (type === 0xDA) { | ||||||
|  |             // start of scan | ||||||
|  |             extra += 2; | ||||||
|  |             while (true) { | ||||||
|  |                 if (sock.rQwait("JPEG", length-2+extra, 4)) { | ||||||
|  |                     return null; | ||||||
|  |                 } | ||||||
|  |                 let data = sock.rQpeekBytes(length-2+extra, false); | ||||||
|  |                 if (data.at(-2) === 0xFF && data.at(-1) !== 0x00 && | ||||||
|  |                     !(data.at(-1) >= 0xD0 && data.at(-1) <= 0xD7)) { | ||||||
|  |                     extra -= 2; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 extra++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let segment = new Uint8Array(2 + length + extra); | ||||||
|  |         segment[0] = marker; | ||||||
|  |         segment[1] = type; | ||||||
|  |         segment[2] = length >> 8; | ||||||
|  |         segment[3] = length; | ||||||
|  |         segment.set(sock.rQshiftBytes(length-2+extra, false), 4); | ||||||
|  |  | ||||||
|  |         return segment; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								core/decoders/raw.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,59 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default class RawDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         this._lines = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if ((width === 0) || (height === 0)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._lines === 0) { | ||||||
|  |             this._lines = height; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const pixelSize = depth == 8 ? 1 : 4; | ||||||
|  |         const bytesPerLine = width * pixelSize; | ||||||
|  |  | ||||||
|  |         while (this._lines > 0) { | ||||||
|  |             if (sock.rQwait("RAW", bytesPerLine)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const curY = y + (height - this._lines); | ||||||
|  |  | ||||||
|  |             let data = sock.rQshiftBytes(bytesPerLine, false); | ||||||
|  |  | ||||||
|  |             // Convert data if needed | ||||||
|  |             if (depth == 8) { | ||||||
|  |                 const newdata = new Uint8Array(width * 4); | ||||||
|  |                 for (let i = 0; i < width; i++) { | ||||||
|  |                     newdata[i * 4 + 0] = ((data[i] >> 0) & 0x3) * 255 / 3; | ||||||
|  |                     newdata[i * 4 + 1] = ((data[i] >> 2) & 0x3) * 255 / 3; | ||||||
|  |                     newdata[i * 4 + 2] = ((data[i] >> 4) & 0x3) * 255 / 3; | ||||||
|  |                     newdata[i * 4 + 3] = 255; | ||||||
|  |                 } | ||||||
|  |                 data = newdata; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Max sure the image is fully opaque | ||||||
|  |             for (let i = 0; i < width; i++) { | ||||||
|  |                 data[i * 4 + 3] = 255; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             display.blitImage(x, curY, width, 1, data, 0); | ||||||
|  |             this._lines--; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								core/decoders/rre.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,44 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default class RREDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         this._subrects = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._subrects === 0) { | ||||||
|  |             if (sock.rQwait("RRE", 4 + 4)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._subrects = sock.rQshift32(); | ||||||
|  |  | ||||||
|  |             let color = sock.rQshiftBytes(4);  // Background | ||||||
|  |             display.fillRect(x, y, width, height, color); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         while (this._subrects > 0) { | ||||||
|  |             if (sock.rQwait("RRE", 4 + 8)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             let color = sock.rQshiftBytes(4); | ||||||
|  |             let sx = sock.rQshift16(); | ||||||
|  |             let sy = sock.rQshift16(); | ||||||
|  |             let swidth = sock.rQshift16(); | ||||||
|  |             let sheight = sock.rQshift16(); | ||||||
|  |             display.fillRect(x + sx, y + sy, swidth, sheight, color); | ||||||
|  |  | ||||||
|  |             this._subrects--; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										393
									
								
								core/decoders/tight.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,393 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca) | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from '../util/logging.js'; | ||||||
|  | import Inflator from "../inflator.js"; | ||||||
|  |  | ||||||
|  | export default class TightDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         this._ctl = null; | ||||||
|  |         this._filter = null; | ||||||
|  |         this._numColors = 0; | ||||||
|  |         this._palette = new Uint8Array(1024);  // 256 * 4 (max palette size * max bytes-per-pixel) | ||||||
|  |         this._len = 0; | ||||||
|  |  | ||||||
|  |         this._zlibs = []; | ||||||
|  |         for (let i = 0; i < 4; i++) { | ||||||
|  |             this._zlibs[i] = new Inflator(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._ctl === null) { | ||||||
|  |             if (sock.rQwait("TIGHT compression-control", 1)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._ctl = sock.rQshift8(); | ||||||
|  |  | ||||||
|  |             // Reset streams if the server requests it | ||||||
|  |             for (let i = 0; i < 4; i++) { | ||||||
|  |                 if ((this._ctl >> i) & 1) { | ||||||
|  |                     this._zlibs[i].reset(); | ||||||
|  |                     Log.Info("Reset zlib stream " + i); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Figure out filter | ||||||
|  |             this._ctl = this._ctl >> 4; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let ret; | ||||||
|  |  | ||||||
|  |         if (this._ctl === 0x08) { | ||||||
|  |             ret = this._fillRect(x, y, width, height, | ||||||
|  |                                  sock, display, depth); | ||||||
|  |         } else if (this._ctl === 0x09) { | ||||||
|  |             ret = this._jpegRect(x, y, width, height, | ||||||
|  |                                  sock, display, depth); | ||||||
|  |         } else if (this._ctl === 0x0A) { | ||||||
|  |             ret = this._pngRect(x, y, width, height, | ||||||
|  |                                 sock, display, depth); | ||||||
|  |         } else if ((this._ctl & 0x08) == 0) { | ||||||
|  |             ret = this._basicRect(this._ctl, x, y, width, height, | ||||||
|  |                                   sock, display, depth); | ||||||
|  |         } else { | ||||||
|  |             throw new Error("Illegal tight compression received (ctl: " + | ||||||
|  |                                    this._ctl + ")"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (ret) { | ||||||
|  |             this._ctl = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _fillRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (sock.rQwait("TIGHT", 3)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let pixel = sock.rQshiftBytes(3); | ||||||
|  |         display.fillRect(x, y, width, height, pixel, false); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _jpegRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         let data = this._readData(sock); | ||||||
|  |         if (data === null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.imageRect(x, y, width, height, "image/jpeg", data); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _pngRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         throw new Error("PNG received in standard Tight rect"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _basicRect(ctl, x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._filter === null) { | ||||||
|  |             if (ctl & 0x4) { | ||||||
|  |                 if (sock.rQwait("TIGHT", 1)) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 this._filter = sock.rQshift8(); | ||||||
|  |             } else { | ||||||
|  |                 // Implicit CopyFilter | ||||||
|  |                 this._filter = 0; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let streamId = ctl & 0x3; | ||||||
|  |  | ||||||
|  |         let ret; | ||||||
|  |  | ||||||
|  |         switch (this._filter) { | ||||||
|  |             case 0: // CopyFilter | ||||||
|  |                 ret = this._copyFilter(streamId, x, y, width, height, | ||||||
|  |                                        sock, display, depth); | ||||||
|  |                 break; | ||||||
|  |             case 1: // PaletteFilter | ||||||
|  |                 ret = this._paletteFilter(streamId, x, y, width, height, | ||||||
|  |                                           sock, display, depth); | ||||||
|  |                 break; | ||||||
|  |             case 2: // GradientFilter | ||||||
|  |                 ret = this._gradientFilter(streamId, x, y, width, height, | ||||||
|  |                                            sock, display, depth); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 throw new Error("Illegal tight filter received (ctl: " + | ||||||
|  |                                        this._filter + ")"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (ret) { | ||||||
|  |             this._filter = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _copyFilter(streamId, x, y, width, height, sock, display, depth) { | ||||||
|  |         const uncompressedSize = width * height * 3; | ||||||
|  |         let data; | ||||||
|  |  | ||||||
|  |         if (uncompressedSize === 0) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (uncompressedSize < 12) { | ||||||
|  |             if (sock.rQwait("TIGHT", uncompressedSize)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             data = sock.rQshiftBytes(uncompressedSize); | ||||||
|  |         } else { | ||||||
|  |             data = this._readData(sock); | ||||||
|  |             if (data === null) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._zlibs[streamId].setInput(data); | ||||||
|  |             data = this._zlibs[streamId].inflate(uncompressedSize); | ||||||
|  |             this._zlibs[streamId].setInput(null); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let rgbx = new Uint8Array(width * height * 4); | ||||||
|  |         for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) { | ||||||
|  |             rgbx[i]     = data[j]; | ||||||
|  |             rgbx[i + 1] = data[j + 1]; | ||||||
|  |             rgbx[i + 2] = data[j + 2]; | ||||||
|  |             rgbx[i + 3] = 255;  // Alpha | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.blitImage(x, y, width, height, rgbx, 0, false); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _paletteFilter(streamId, x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._numColors === 0) { | ||||||
|  |             if (sock.rQwait("TIGHT palette", 1)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const numColors = sock.rQpeek8() + 1; | ||||||
|  |             const paletteSize = numColors * 3; | ||||||
|  |  | ||||||
|  |             if (sock.rQwait("TIGHT palette", 1 + paletteSize)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._numColors = numColors; | ||||||
|  |             sock.rQskipBytes(1); | ||||||
|  |  | ||||||
|  |             sock.rQshiftTo(this._palette, paletteSize); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const bpp = (this._numColors <= 2) ? 1 : 8; | ||||||
|  |         const rowSize = Math.floor((width * bpp + 7) / 8); | ||||||
|  |         const uncompressedSize = rowSize * height; | ||||||
|  |  | ||||||
|  |         let data; | ||||||
|  |  | ||||||
|  |         if (uncompressedSize === 0) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (uncompressedSize < 12) { | ||||||
|  |             if (sock.rQwait("TIGHT", uncompressedSize)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             data = sock.rQshiftBytes(uncompressedSize); | ||||||
|  |         } else { | ||||||
|  |             data = this._readData(sock); | ||||||
|  |             if (data === null) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._zlibs[streamId].setInput(data); | ||||||
|  |             data = this._zlibs[streamId].inflate(uncompressedSize); | ||||||
|  |             this._zlibs[streamId].setInput(null); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Convert indexed (palette based) image data to RGB | ||||||
|  |         if (this._numColors == 2) { | ||||||
|  |             this._monoRect(x, y, width, height, data, this._palette, display); | ||||||
|  |         } else { | ||||||
|  |             this._paletteRect(x, y, width, height, data, this._palette, display); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._numColors = 0; | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _monoRect(x, y, width, height, data, palette, display) { | ||||||
|  |         // Convert indexed (palette based) image data to RGB | ||||||
|  |         // TODO: reduce number of calculations inside loop | ||||||
|  |         const dest = this._getScratchBuffer(width * height * 4); | ||||||
|  |         const w = Math.floor((width + 7) / 8); | ||||||
|  |         const w1 = Math.floor(width / 8); | ||||||
|  |  | ||||||
|  |         for (let y = 0; y < height; y++) { | ||||||
|  |             let dp, sp, x; | ||||||
|  |             for (x = 0; x < w1; x++) { | ||||||
|  |                 for (let b = 7; b >= 0; b--) { | ||||||
|  |                     dp = (y * width + x * 8 + 7 - b) * 4; | ||||||
|  |                     sp = (data[y * w + x] >> b & 1) * 3; | ||||||
|  |                     dest[dp]     = palette[sp]; | ||||||
|  |                     dest[dp + 1] = palette[sp + 1]; | ||||||
|  |                     dest[dp + 2] = palette[sp + 2]; | ||||||
|  |                     dest[dp + 3] = 255; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for (let b = 7; b >= 8 - width % 8; b--) { | ||||||
|  |                 dp = (y * width + x * 8 + 7 - b) * 4; | ||||||
|  |                 sp = (data[y * w + x] >> b & 1) * 3; | ||||||
|  |                 dest[dp]     = palette[sp]; | ||||||
|  |                 dest[dp + 1] = palette[sp + 1]; | ||||||
|  |                 dest[dp + 2] = palette[sp + 2]; | ||||||
|  |                 dest[dp + 3] = 255; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.blitImage(x, y, width, height, dest, 0, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _paletteRect(x, y, width, height, data, palette, display) { | ||||||
|  |         // Convert indexed (palette based) image data to RGB | ||||||
|  |         const dest = this._getScratchBuffer(width * height * 4); | ||||||
|  |         const total = width * height * 4; | ||||||
|  |         for (let i = 0, j = 0; i < total; i += 4, j++) { | ||||||
|  |             const sp = data[j] * 3; | ||||||
|  |             dest[i]     = palette[sp]; | ||||||
|  |             dest[i + 1] = palette[sp + 1]; | ||||||
|  |             dest[i + 2] = palette[sp + 2]; | ||||||
|  |             dest[i + 3] = 255; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.blitImage(x, y, width, height, dest, 0, false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _gradientFilter(streamId, x, y, width, height, sock, display, depth) { | ||||||
|  |         // assume the TPIXEL is 3 bytes long | ||||||
|  |         const uncompressedSize = width * height * 3; | ||||||
|  |         let data; | ||||||
|  |  | ||||||
|  |         if (uncompressedSize === 0) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (uncompressedSize < 12) { | ||||||
|  |             if (sock.rQwait("TIGHT", uncompressedSize)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             data = sock.rQshiftBytes(uncompressedSize); | ||||||
|  |         } else { | ||||||
|  |             data = this._readData(sock); | ||||||
|  |             if (data === null) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._zlibs[streamId].setInput(data); | ||||||
|  |             data = this._zlibs[streamId].inflate(uncompressedSize); | ||||||
|  |             this._zlibs[streamId].setInput(null); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let rgbx = new Uint8Array(4 * width * height); | ||||||
|  |  | ||||||
|  |         let rgbxIndex = 0, dataIndex = 0; | ||||||
|  |         let left = new Uint8Array(3); | ||||||
|  |         for (let x = 0; x < width; x++) { | ||||||
|  |             for (let c = 0; c < 3; c++) { | ||||||
|  |                 const prediction = left[c]; | ||||||
|  |                 const value = data[dataIndex++] + prediction; | ||||||
|  |                 rgbx[rgbxIndex++] = value; | ||||||
|  |                 left[c] = value; | ||||||
|  |             } | ||||||
|  |             rgbx[rgbxIndex++] = 255; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let upperIndex = 0; | ||||||
|  |         let upper = new Uint8Array(3), | ||||||
|  |             upperleft = new Uint8Array(3); | ||||||
|  |         for (let y = 1; y < height; y++) { | ||||||
|  |             left.fill(0); | ||||||
|  |             upperleft.fill(0); | ||||||
|  |             for (let x = 0; x < width; x++) { | ||||||
|  |                 for (let c = 0; c < 3; c++) { | ||||||
|  |                     upper[c] = rgbx[upperIndex++]; | ||||||
|  |                     let prediction = left[c] + upper[c] - upperleft[c]; | ||||||
|  |                     if (prediction < 0) { | ||||||
|  |                         prediction = 0; | ||||||
|  |                     } else if (prediction > 255) { | ||||||
|  |                         prediction = 255; | ||||||
|  |                     } | ||||||
|  |                     const value = data[dataIndex++] + prediction; | ||||||
|  |                     rgbx[rgbxIndex++] = value; | ||||||
|  |                     upperleft[c] = upper[c]; | ||||||
|  |                     left[c] = value; | ||||||
|  |                 } | ||||||
|  |                 rgbx[rgbxIndex++] = 255; | ||||||
|  |                 upperIndex++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.blitImage(x, y, width, height, rgbx, 0, false); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _readData(sock) { | ||||||
|  |         if (this._len === 0) { | ||||||
|  |             if (sock.rQwait("TIGHT", 3)) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             let byte; | ||||||
|  |  | ||||||
|  |             byte = sock.rQshift8(); | ||||||
|  |             this._len = byte & 0x7f; | ||||||
|  |             if (byte & 0x80) { | ||||||
|  |                 byte = sock.rQshift8(); | ||||||
|  |                 this._len |= (byte & 0x7f) << 7; | ||||||
|  |                 if (byte & 0x80) { | ||||||
|  |                     byte = sock.rQshift8(); | ||||||
|  |                     this._len |= byte << 14; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (sock.rQwait("TIGHT", this._len)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let data = sock.rQshiftBytes(this._len, false); | ||||||
|  |         this._len = 0; | ||||||
|  |  | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getScratchBuffer(size) { | ||||||
|  |         if (!this._scratchBuffer || (this._scratchBuffer.length < size)) { | ||||||
|  |             this._scratchBuffer = new Uint8Array(size); | ||||||
|  |         } | ||||||
|  |         return this._scratchBuffer; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								core/decoders/tightpng.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,27 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import TightDecoder from './tight.js'; | ||||||
|  |  | ||||||
|  | export default class TightPNGDecoder extends TightDecoder { | ||||||
|  |     _pngRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         let data = this._readData(sock); | ||||||
|  |         if (data === null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         display.imageRect(x, y, width, height, "image/png", data); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _basicRect(ctl, x, y, width, height, sock, display, depth) { | ||||||
|  |         throw new Error("BasicCompression received in TightPNG rect"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										185
									
								
								core/decoders/zrle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,185 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2021 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import Inflate from "../inflator.js"; | ||||||
|  |  | ||||||
|  | const ZRLE_TILE_WIDTH = 64; | ||||||
|  | const ZRLE_TILE_HEIGHT = 64; | ||||||
|  |  | ||||||
|  | export default class ZRLEDecoder { | ||||||
|  |     constructor() { | ||||||
|  |         this._length = 0; | ||||||
|  |         this._inflator = new Inflate(); | ||||||
|  |  | ||||||
|  |         this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4); | ||||||
|  |         this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decodeRect(x, y, width, height, sock, display, depth) { | ||||||
|  |         if (this._length === 0) { | ||||||
|  |             if (sock.rQwait("ZLib data length", 4)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             this._length = sock.rQshift32(); | ||||||
|  |         } | ||||||
|  |         if (sock.rQwait("Zlib data", this._length)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const data = sock.rQshiftBytes(this._length, false); | ||||||
|  |  | ||||||
|  |         this._inflator.setInput(data); | ||||||
|  |  | ||||||
|  |         for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) { | ||||||
|  |             let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty); | ||||||
|  |  | ||||||
|  |             for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) { | ||||||
|  |                 let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx); | ||||||
|  |  | ||||||
|  |                 const tileSize = tw * th; | ||||||
|  |                 const subencoding = this._inflator.inflate(1)[0]; | ||||||
|  |                 if (subencoding === 0) { | ||||||
|  |                     // raw data | ||||||
|  |                     const data = this._readPixels(tileSize); | ||||||
|  |                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||||
|  |                 } else if (subencoding === 1) { | ||||||
|  |                     // solid | ||||||
|  |                     const background = this._readPixels(1); | ||||||
|  |                     display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]); | ||||||
|  |                 } else if (subencoding >= 2 && subencoding <= 16) { | ||||||
|  |                     const data = this._decodePaletteTile(subencoding, tileSize, tw, th); | ||||||
|  |                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||||
|  |                 } else if (subencoding === 128) { | ||||||
|  |                     const data = this._decodeRLETile(tileSize); | ||||||
|  |                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||||
|  |                 } else if (subencoding >= 130 && subencoding <= 255) { | ||||||
|  |                     const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize); | ||||||
|  |                     display.blitImage(tx, ty, tw, th, data, 0, false); | ||||||
|  |                 } else { | ||||||
|  |                     throw new Error('Unknown subencoding: ' + subencoding); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         this._length = 0; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getBitsPerPixelInPalette(paletteSize) { | ||||||
|  |         if (paletteSize <= 2) { | ||||||
|  |             return 1; | ||||||
|  |         } else if (paletteSize <= 4) { | ||||||
|  |             return 2; | ||||||
|  |         } else if (paletteSize <= 16) { | ||||||
|  |             return 4; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _readPixels(pixels) { | ||||||
|  |         let data = this._pixelBuffer; | ||||||
|  |         const buffer = this._inflator.inflate(3*pixels); | ||||||
|  |         for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) { | ||||||
|  |             data[i]     = buffer[j]; | ||||||
|  |             data[i + 1] = buffer[j + 1]; | ||||||
|  |             data[i + 2] = buffer[j + 2]; | ||||||
|  |             data[i + 3] = 255;  // Add the Alpha | ||||||
|  |         } | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _decodePaletteTile(paletteSize, tileSize, tilew, tileh) { | ||||||
|  |         const data = this._tileBuffer; | ||||||
|  |         const palette = this._readPixels(paletteSize); | ||||||
|  |         const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize); | ||||||
|  |         const mask = (1 << bitsPerPixel) - 1; | ||||||
|  |  | ||||||
|  |         let offset = 0; | ||||||
|  |         let encoded = this._inflator.inflate(1)[0]; | ||||||
|  |  | ||||||
|  |         for (let y=0; y<tileh; y++) { | ||||||
|  |             let shift = 8-bitsPerPixel; | ||||||
|  |             for (let x=0; x<tilew; x++) { | ||||||
|  |                 if (shift<0) { | ||||||
|  |                     shift=8-bitsPerPixel; | ||||||
|  |                     encoded = this._inflator.inflate(1)[0]; | ||||||
|  |                 } | ||||||
|  |                 let indexInPalette = (encoded>>shift) & mask; | ||||||
|  |  | ||||||
|  |                 data[offset] = palette[indexInPalette * 4]; | ||||||
|  |                 data[offset + 1] = palette[indexInPalette * 4 + 1]; | ||||||
|  |                 data[offset + 2] = palette[indexInPalette * 4 + 2]; | ||||||
|  |                 data[offset + 3] = palette[indexInPalette * 4 + 3]; | ||||||
|  |                 offset += 4; | ||||||
|  |                 shift-=bitsPerPixel; | ||||||
|  |             } | ||||||
|  |             if (shift<8-bitsPerPixel && y<tileh-1) { | ||||||
|  |                 encoded =  this._inflator.inflate(1)[0]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _decodeRLETile(tileSize) { | ||||||
|  |         const data = this._tileBuffer; | ||||||
|  |         let i = 0; | ||||||
|  |         while (i < tileSize) { | ||||||
|  |             const pixel = this._readPixels(1); | ||||||
|  |             const length = this._readRLELength(); | ||||||
|  |             for (let j = 0; j < length; j++) { | ||||||
|  |                 data[i * 4] = pixel[0]; | ||||||
|  |                 data[i * 4 + 1] = pixel[1]; | ||||||
|  |                 data[i * 4 + 2] = pixel[2]; | ||||||
|  |                 data[i * 4 + 3] = pixel[3]; | ||||||
|  |                 i++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _decodeRLEPaletteTile(paletteSize, tileSize) { | ||||||
|  |         const data = this._tileBuffer; | ||||||
|  |  | ||||||
|  |         // palette | ||||||
|  |         const palette = this._readPixels(paletteSize); | ||||||
|  |  | ||||||
|  |         let offset = 0; | ||||||
|  |         while (offset < tileSize) { | ||||||
|  |             let indexInPalette = this._inflator.inflate(1)[0]; | ||||||
|  |             let length = 1; | ||||||
|  |             if (indexInPalette >= 128) { | ||||||
|  |                 indexInPalette -= 128; | ||||||
|  |                 length = this._readRLELength(); | ||||||
|  |             } | ||||||
|  |             if (indexInPalette > paletteSize) { | ||||||
|  |                 throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize); | ||||||
|  |             } | ||||||
|  |             if (offset + length > tileSize) { | ||||||
|  |                 throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for (let j = 0; j < length; j++) { | ||||||
|  |                 data[offset * 4] = palette[indexInPalette * 4]; | ||||||
|  |                 data[offset * 4 + 1] = palette[indexInPalette * 4 + 1]; | ||||||
|  |                 data[offset * 4 + 2] = palette[indexInPalette * 4 + 2]; | ||||||
|  |                 data[offset * 4 + 3] = palette[indexInPalette * 4 + 3]; | ||||||
|  |                 offset++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _readRLELength() { | ||||||
|  |         let length = 0; | ||||||
|  |         let current = 0; | ||||||
|  |         do { | ||||||
|  |             current = this._inflator.inflate(1)[0]; | ||||||
|  |             length += current; | ||||||
|  |         } while (current === 255); | ||||||
|  |         return length + 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										84
									
								
								core/deflator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,84 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2020 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js"; | ||||||
|  | import { Z_FULL_FLUSH, Z_DEFAULT_COMPRESSION } from "../vendor/pako/lib/zlib/deflate.js"; | ||||||
|  | import ZStream from "../vendor/pako/lib/zlib/zstream.js"; | ||||||
|  |  | ||||||
|  | export default class Deflator { | ||||||
|  |     constructor() { | ||||||
|  |         this.strm = new ZStream(); | ||||||
|  |         this.chunkSize = 1024 * 10 * 10; | ||||||
|  |         this.outputBuffer = new Uint8Array(this.chunkSize); | ||||||
|  |  | ||||||
|  |         deflateInit(this.strm, Z_DEFAULT_COMPRESSION); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     deflate(inData) { | ||||||
|  |         /* eslint-disable camelcase */ | ||||||
|  |         this.strm.input = inData; | ||||||
|  |         this.strm.avail_in = this.strm.input.length; | ||||||
|  |         this.strm.next_in = 0; | ||||||
|  |         this.strm.output = this.outputBuffer; | ||||||
|  |         this.strm.avail_out = this.chunkSize; | ||||||
|  |         this.strm.next_out = 0; | ||||||
|  |         /* eslint-enable camelcase */ | ||||||
|  |  | ||||||
|  |         let lastRet = deflate(this.strm, Z_FULL_FLUSH); | ||||||
|  |         let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); | ||||||
|  |  | ||||||
|  |         if (lastRet < 0) { | ||||||
|  |             throw new Error("zlib deflate failed"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.strm.avail_in > 0) { | ||||||
|  |             // Read chunks until done | ||||||
|  |  | ||||||
|  |             let chunks = [outData]; | ||||||
|  |             let totalLen = outData.length; | ||||||
|  |             do { | ||||||
|  |                 /* eslint-disable camelcase */ | ||||||
|  |                 this.strm.output = new Uint8Array(this.chunkSize); | ||||||
|  |                 this.strm.next_out = 0; | ||||||
|  |                 this.strm.avail_out = this.chunkSize; | ||||||
|  |                 /* eslint-enable camelcase */ | ||||||
|  |  | ||||||
|  |                 lastRet = deflate(this.strm, Z_FULL_FLUSH); | ||||||
|  |  | ||||||
|  |                 if (lastRet < 0) { | ||||||
|  |                     throw new Error("zlib deflate failed"); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); | ||||||
|  |                 totalLen += chunk.length; | ||||||
|  |                 chunks.push(chunk); | ||||||
|  |             } while (this.strm.avail_in > 0); | ||||||
|  |  | ||||||
|  |             // Combine chunks into a single data | ||||||
|  |  | ||||||
|  |             let newData = new Uint8Array(totalLen); | ||||||
|  |             let offset = 0; | ||||||
|  |  | ||||||
|  |             for (let i = 0; i < chunks.length; i++) { | ||||||
|  |                 newData.set(chunks[i], offset); | ||||||
|  |                 offset += chunks[i].length; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             outData = newData; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* eslint-disable camelcase */ | ||||||
|  |         this.strm.input = null; | ||||||
|  |         this.strm.avail_in = 0; | ||||||
|  |         this.strm.next_in = 0; | ||||||
|  |         /* eslint-enable camelcase */ | ||||||
|  |  | ||||||
|  |         return outData; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										528
									
								
								core/display.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,528 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from './util/logging.js'; | ||||||
|  | import Base64 from "./base64.js"; | ||||||
|  | import { toSigned32bit } from './util/int.js'; | ||||||
|  |  | ||||||
|  | export default class Display { | ||||||
|  |     constructor(target) { | ||||||
|  |         this._drawCtx = null; | ||||||
|  |  | ||||||
|  |         this._renderQ = [];  // queue drawing actions for in-oder rendering | ||||||
|  |         this._flushPromise = null; | ||||||
|  |  | ||||||
|  |         // the full frame buffer (logical canvas) size | ||||||
|  |         this._fbWidth = 0; | ||||||
|  |         this._fbHeight = 0; | ||||||
|  |  | ||||||
|  |         this._prevDrawStyle = ""; | ||||||
|  |  | ||||||
|  |         Log.Debug(">> Display.constructor"); | ||||||
|  |  | ||||||
|  |         // The visible canvas | ||||||
|  |         this._target = target; | ||||||
|  |  | ||||||
|  |         if (!this._target) { | ||||||
|  |             throw new Error("Target must be set"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (typeof this._target === 'string') { | ||||||
|  |             throw new Error('target must be a DOM element'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!this._target.getContext) { | ||||||
|  |             throw new Error("no getContext method"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._targetCtx = this._target.getContext('2d'); | ||||||
|  |  | ||||||
|  |         // the visible canvas viewport (i.e. what actually gets seen) | ||||||
|  |         this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height }; | ||||||
|  |  | ||||||
|  |         // The hidden canvas, where we do the actual rendering | ||||||
|  |         this._backbuffer = document.createElement('canvas'); | ||||||
|  |         this._drawCtx = this._backbuffer.getContext('2d'); | ||||||
|  |  | ||||||
|  |         this._damageBounds = { left: 0, top: 0, | ||||||
|  |                                right: this._backbuffer.width, | ||||||
|  |                                bottom: this._backbuffer.height }; | ||||||
|  |  | ||||||
|  |         Log.Debug("User Agent: " + navigator.userAgent); | ||||||
|  |  | ||||||
|  |         Log.Debug("<< Display.constructor"); | ||||||
|  |  | ||||||
|  |         // ===== PROPERTIES ===== | ||||||
|  |  | ||||||
|  |         this._scale = 1.0; | ||||||
|  |         this._clipViewport = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ===== PROPERTIES ===== | ||||||
|  |  | ||||||
|  |     get scale() { return this._scale; } | ||||||
|  |     set scale(scale) { | ||||||
|  |         this._rescale(scale); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get clipViewport() { return this._clipViewport; } | ||||||
|  |     set clipViewport(viewport) { | ||||||
|  |         this._clipViewport = viewport; | ||||||
|  |         // May need to readjust the viewport dimensions | ||||||
|  |         const vp = this._viewportLoc; | ||||||
|  |         this.viewportChangeSize(vp.w, vp.h); | ||||||
|  |         this.viewportChangePos(0, 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get width() { | ||||||
|  |         return this._fbWidth; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get height() { | ||||||
|  |         return this._fbHeight; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ===== PUBLIC METHODS ===== | ||||||
|  |  | ||||||
|  |     viewportChangePos(deltaX, deltaY) { | ||||||
|  |         const vp = this._viewportLoc; | ||||||
|  |         deltaX = Math.floor(deltaX); | ||||||
|  |         deltaY = Math.floor(deltaY); | ||||||
|  |  | ||||||
|  |         if (!this._clipViewport) { | ||||||
|  |             deltaX = -vp.w;  // clamped later of out of bounds | ||||||
|  |             deltaY = -vp.h; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const vx2 = vp.x + vp.w - 1; | ||||||
|  |         const vy2 = vp.y + vp.h - 1; | ||||||
|  |  | ||||||
|  |         // Position change | ||||||
|  |  | ||||||
|  |         if (deltaX < 0 && vp.x + deltaX < 0) { | ||||||
|  |             deltaX = -vp.x; | ||||||
|  |         } | ||||||
|  |         if (vx2 + deltaX >= this._fbWidth) { | ||||||
|  |             deltaX -= vx2 + deltaX - this._fbWidth + 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (vp.y + deltaY < 0) { | ||||||
|  |             deltaY = -vp.y; | ||||||
|  |         } | ||||||
|  |         if (vy2 + deltaY >= this._fbHeight) { | ||||||
|  |             deltaY -= (vy2 + deltaY - this._fbHeight + 1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (deltaX === 0 && deltaY === 0) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         Log.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY); | ||||||
|  |  | ||||||
|  |         vp.x += deltaX; | ||||||
|  |         vp.y += deltaY; | ||||||
|  |  | ||||||
|  |         this._damage(vp.x, vp.y, vp.w, vp.h); | ||||||
|  |  | ||||||
|  |         this.flip(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     viewportChangeSize(width, height) { | ||||||
|  |  | ||||||
|  |         if (!this._clipViewport || | ||||||
|  |             typeof(width) === "undefined" || | ||||||
|  |             typeof(height) === "undefined") { | ||||||
|  |  | ||||||
|  |             Log.Debug("Setting viewport to full display region"); | ||||||
|  |             width = this._fbWidth; | ||||||
|  |             height = this._fbHeight; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         width = Math.floor(width); | ||||||
|  |         height = Math.floor(height); | ||||||
|  |  | ||||||
|  |         if (width > this._fbWidth) { | ||||||
|  |             width = this._fbWidth; | ||||||
|  |         } | ||||||
|  |         if (height > this._fbHeight) { | ||||||
|  |             height = this._fbHeight; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const vp = this._viewportLoc; | ||||||
|  |         if (vp.w !== width || vp.h !== height) { | ||||||
|  |             vp.w = width; | ||||||
|  |             vp.h = height; | ||||||
|  |  | ||||||
|  |             const canvas = this._target; | ||||||
|  |             canvas.width = width; | ||||||
|  |             canvas.height = height; | ||||||
|  |  | ||||||
|  |             // The position might need to be updated if we've grown | ||||||
|  |             this.viewportChangePos(0, 0); | ||||||
|  |  | ||||||
|  |             this._damage(vp.x, vp.y, vp.w, vp.h); | ||||||
|  |             this.flip(); | ||||||
|  |  | ||||||
|  |             // Update the visible size of the target canvas | ||||||
|  |             this._rescale(this._scale); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     absX(x) { | ||||||
|  |         if (this._scale === 0) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         return toSigned32bit(x / this._scale + this._viewportLoc.x); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     absY(y) { | ||||||
|  |         if (this._scale === 0) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         return toSigned32bit(y / this._scale + this._viewportLoc.y); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     resize(width, height) { | ||||||
|  |         this._prevDrawStyle = ""; | ||||||
|  |  | ||||||
|  |         this._fbWidth = width; | ||||||
|  |         this._fbHeight = height; | ||||||
|  |  | ||||||
|  |         const canvas = this._backbuffer; | ||||||
|  |         if (canvas.width !== width || canvas.height !== height) { | ||||||
|  |  | ||||||
|  |             // We have to save the canvas data since changing the size will clear it | ||||||
|  |             let saveImg = null; | ||||||
|  |             if (canvas.width > 0 && canvas.height > 0) { | ||||||
|  |                 saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (canvas.width !== width) { | ||||||
|  |                 canvas.width = width; | ||||||
|  |             } | ||||||
|  |             if (canvas.height !== height) { | ||||||
|  |                 canvas.height = height; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (saveImg) { | ||||||
|  |                 this._drawCtx.putImageData(saveImg, 0, 0); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Readjust the viewport as it may be incorrectly sized | ||||||
|  |         // and positioned | ||||||
|  |         const vp = this._viewportLoc; | ||||||
|  |         this.viewportChangeSize(vp.w, vp.h); | ||||||
|  |         this.viewportChangePos(0, 0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getImageData() { | ||||||
|  |         return this._drawCtx.getImageData(0, 0, this.width, this.height); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     toDataURL(type, encoderOptions) { | ||||||
|  |         return this._backbuffer.toDataURL(type, encoderOptions); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     toBlob(callback, type, quality) { | ||||||
|  |         return this._backbuffer.toBlob(callback, type, quality); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Track what parts of the visible canvas that need updating | ||||||
|  |     _damage(x, y, w, h) { | ||||||
|  |         if (x < this._damageBounds.left) { | ||||||
|  |             this._damageBounds.left = x; | ||||||
|  |         } | ||||||
|  |         if (y < this._damageBounds.top) { | ||||||
|  |             this._damageBounds.top = y; | ||||||
|  |         } | ||||||
|  |         if ((x + w) > this._damageBounds.right) { | ||||||
|  |             this._damageBounds.right = x + w; | ||||||
|  |         } | ||||||
|  |         if ((y + h) > this._damageBounds.bottom) { | ||||||
|  |             this._damageBounds.bottom = y + h; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Update the visible canvas with the contents of the | ||||||
|  |     // rendering canvas | ||||||
|  |     flip(fromQueue) { | ||||||
|  |         if (this._renderQ.length !== 0 && !fromQueue) { | ||||||
|  |             this._renderQPush({ | ||||||
|  |                 'type': 'flip' | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             let x = this._damageBounds.left; | ||||||
|  |             let y = this._damageBounds.top; | ||||||
|  |             let w = this._damageBounds.right - x; | ||||||
|  |             let h = this._damageBounds.bottom - y; | ||||||
|  |  | ||||||
|  |             let vx = x - this._viewportLoc.x; | ||||||
|  |             let vy = y - this._viewportLoc.y; | ||||||
|  |  | ||||||
|  |             if (vx < 0) { | ||||||
|  |                 w += vx; | ||||||
|  |                 x -= vx; | ||||||
|  |                 vx = 0; | ||||||
|  |             } | ||||||
|  |             if (vy < 0) { | ||||||
|  |                 h += vy; | ||||||
|  |                 y -= vy; | ||||||
|  |                 vy = 0; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ((vx + w) > this._viewportLoc.w) { | ||||||
|  |                 w = this._viewportLoc.w - vx; | ||||||
|  |             } | ||||||
|  |             if ((vy + h) > this._viewportLoc.h) { | ||||||
|  |                 h = this._viewportLoc.h - vy; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ((w > 0) && (h > 0)) { | ||||||
|  |                 // FIXME: We may need to disable image smoothing here | ||||||
|  |                 //        as well (see copyImage()), but we haven't | ||||||
|  |                 //        noticed any problem yet. | ||||||
|  |                 this._targetCtx.drawImage(this._backbuffer, | ||||||
|  |                                           x, y, w, h, | ||||||
|  |                                           vx, vy, w, h); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._damageBounds.left = this._damageBounds.top = 65535; | ||||||
|  |             this._damageBounds.right = this._damageBounds.bottom = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pending() { | ||||||
|  |         return this._renderQ.length > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     flush() { | ||||||
|  |         if (this._renderQ.length === 0) { | ||||||
|  |             return Promise.resolve(); | ||||||
|  |         } else { | ||||||
|  |             if (this._flushPromise === null) { | ||||||
|  |                 this._flushPromise = new Promise((resolve) => { | ||||||
|  |                     this._flushResolve = resolve; | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             return this._flushPromise; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fillRect(x, y, width, height, color, fromQueue) { | ||||||
|  |         if (this._renderQ.length !== 0 && !fromQueue) { | ||||||
|  |             this._renderQPush({ | ||||||
|  |                 'type': 'fill', | ||||||
|  |                 'x': x, | ||||||
|  |                 'y': y, | ||||||
|  |                 'width': width, | ||||||
|  |                 'height': height, | ||||||
|  |                 'color': color | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             this._setFillColor(color); | ||||||
|  |             this._drawCtx.fillRect(x, y, width, height); | ||||||
|  |             this._damage(x, y, width, height); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     copyImage(oldX, oldY, newX, newY, w, h, fromQueue) { | ||||||
|  |         if (this._renderQ.length !== 0 && !fromQueue) { | ||||||
|  |             this._renderQPush({ | ||||||
|  |                 'type': 'copy', | ||||||
|  |                 'oldX': oldX, | ||||||
|  |                 'oldY': oldY, | ||||||
|  |                 'x': newX, | ||||||
|  |                 'y': newY, | ||||||
|  |                 'width': w, | ||||||
|  |                 'height': h, | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             // Due to this bug among others [1] we need to disable the image-smoothing to | ||||||
|  |             // avoid getting a blur effect when copying data. | ||||||
|  |             // | ||||||
|  |             // 1. https://bugzilla.mozilla.org/show_bug.cgi?id=1194719 | ||||||
|  |             // | ||||||
|  |             // We need to set these every time since all properties are reset | ||||||
|  |             // when the the size is changed | ||||||
|  |             this._drawCtx.mozImageSmoothingEnabled = false; | ||||||
|  |             this._drawCtx.webkitImageSmoothingEnabled = false; | ||||||
|  |             this._drawCtx.msImageSmoothingEnabled = false; | ||||||
|  |             this._drawCtx.imageSmoothingEnabled = false; | ||||||
|  |  | ||||||
|  |             this._drawCtx.drawImage(this._backbuffer, | ||||||
|  |                                     oldX, oldY, w, h, | ||||||
|  |                                     newX, newY, w, h); | ||||||
|  |             this._damage(newX, newY, w, h); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     imageRect(x, y, width, height, mime, arr) { | ||||||
|  |         /* The internal logic cannot handle empty images, so bail early */ | ||||||
|  |         if ((width === 0) || (height === 0)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const img = new Image(); | ||||||
|  |         img.src = "data: " + mime + ";base64," + Base64.encode(arr); | ||||||
|  |  | ||||||
|  |         this._renderQPush({ | ||||||
|  |             'type': 'img', | ||||||
|  |             'img': img, | ||||||
|  |             'x': x, | ||||||
|  |             'y': y, | ||||||
|  |             'width': width, | ||||||
|  |             'height': height | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     blitImage(x, y, width, height, arr, offset, fromQueue) { | ||||||
|  |         if (this._renderQ.length !== 0 && !fromQueue) { | ||||||
|  |             // NB(directxman12): it's technically more performant here to use preallocated arrays, | ||||||
|  |             // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue, | ||||||
|  |             // this probably isn't getting called *nearly* as much | ||||||
|  |             const newArr = new Uint8Array(width * height * 4); | ||||||
|  |             newArr.set(new Uint8Array(arr.buffer, 0, newArr.length)); | ||||||
|  |             this._renderQPush({ | ||||||
|  |                 'type': 'blit', | ||||||
|  |                 'data': newArr, | ||||||
|  |                 'x': x, | ||||||
|  |                 'y': y, | ||||||
|  |                 'width': width, | ||||||
|  |                 'height': height, | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             // NB(directxman12): arr must be an Type Array view | ||||||
|  |             let data = new Uint8ClampedArray(arr.buffer, | ||||||
|  |                                              arr.byteOffset + offset, | ||||||
|  |                                              width * height * 4); | ||||||
|  |             let img = new ImageData(data, width, height); | ||||||
|  |             this._drawCtx.putImageData(img, x, y); | ||||||
|  |             this._damage(x, y, width, height); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     drawImage(img, x, y) { | ||||||
|  |         this._drawCtx.drawImage(img, x, y); | ||||||
|  |         this._damage(x, y, img.width, img.height); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     autoscale(containerWidth, containerHeight) { | ||||||
|  |         let scaleRatio; | ||||||
|  |  | ||||||
|  |         if (containerWidth === 0 || containerHeight === 0) { | ||||||
|  |             scaleRatio = 0; | ||||||
|  |  | ||||||
|  |         } else { | ||||||
|  |  | ||||||
|  |             const vp = this._viewportLoc; | ||||||
|  |             const targetAspectRatio = containerWidth / containerHeight; | ||||||
|  |             const fbAspectRatio = vp.w / vp.h; | ||||||
|  |  | ||||||
|  |             if (fbAspectRatio >= targetAspectRatio) { | ||||||
|  |                 scaleRatio = containerWidth / vp.w; | ||||||
|  |             } else { | ||||||
|  |                 scaleRatio = containerHeight / vp.h; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._rescale(scaleRatio); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ===== PRIVATE METHODS ===== | ||||||
|  |  | ||||||
|  |     _rescale(factor) { | ||||||
|  |         this._scale = factor; | ||||||
|  |         const vp = this._viewportLoc; | ||||||
|  |  | ||||||
|  |         // NB(directxman12): If you set the width directly, or set the | ||||||
|  |         //                   style width to a number, the canvas is cleared. | ||||||
|  |         //                   However, if you set the style width to a string | ||||||
|  |         //                   ('NNNpx'), the canvas is scaled without clearing. | ||||||
|  |         const width = factor * vp.w + 'px'; | ||||||
|  |         const height = factor * vp.h + 'px'; | ||||||
|  |  | ||||||
|  |         if ((this._target.style.width !== width) || | ||||||
|  |             (this._target.style.height !== height)) { | ||||||
|  |             this._target.style.width = width; | ||||||
|  |             this._target.style.height = height; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _setFillColor(color) { | ||||||
|  |         const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; | ||||||
|  |         if (newStyle !== this._prevDrawStyle) { | ||||||
|  |             this._drawCtx.fillStyle = newStyle; | ||||||
|  |             this._prevDrawStyle = newStyle; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _renderQPush(action) { | ||||||
|  |         this._renderQ.push(action); | ||||||
|  |         if (this._renderQ.length === 1) { | ||||||
|  |             // If this can be rendered immediately it will be, otherwise | ||||||
|  |             // the scanner will wait for the relevant event | ||||||
|  |             this._scanRenderQ(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _resumeRenderQ() { | ||||||
|  |         // "this" is the object that is ready, not the | ||||||
|  |         // display object | ||||||
|  |         this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ); | ||||||
|  |         this._noVNCDisplay._scanRenderQ(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _scanRenderQ() { | ||||||
|  |         let ready = true; | ||||||
|  |         while (ready && this._renderQ.length > 0) { | ||||||
|  |             const a = this._renderQ[0]; | ||||||
|  |             switch (a.type) { | ||||||
|  |                 case 'flip': | ||||||
|  |                     this.flip(true); | ||||||
|  |                     break; | ||||||
|  |                 case 'copy': | ||||||
|  |                     this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true); | ||||||
|  |                     break; | ||||||
|  |                 case 'fill': | ||||||
|  |                     this.fillRect(a.x, a.y, a.width, a.height, a.color, true); | ||||||
|  |                     break; | ||||||
|  |                 case 'blit': | ||||||
|  |                     this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true); | ||||||
|  |                     break; | ||||||
|  |                 case 'img': | ||||||
|  |                     if (a.img.complete) { | ||||||
|  |                         if (a.img.width !== a.width || a.img.height !== a.height) { | ||||||
|  |                             Log.Error("Decoded image has incorrect dimensions. Got " + | ||||||
|  |                                       a.img.width + "x" + a.img.height + ". Expected " + | ||||||
|  |                                       a.width + "x" + a.height + "."); | ||||||
|  |                             return; | ||||||
|  |                         } | ||||||
|  |                         this.drawImage(a.img, a.x, a.y); | ||||||
|  |                     } else { | ||||||
|  |                         a.img._noVNCDisplay = this; | ||||||
|  |                         a.img.addEventListener('load', this._resumeRenderQ); | ||||||
|  |                         // We need to wait for this image to 'load' | ||||||
|  |                         // to keep things in-order | ||||||
|  |                         ready = false; | ||||||
|  |                     } | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (ready) { | ||||||
|  |                 this._renderQ.shift(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._renderQ.length === 0 && | ||||||
|  |             this._flushPromise !== null) { | ||||||
|  |             this._flushResolve(); | ||||||
|  |             this._flushPromise = null; | ||||||
|  |             this._flushResolve = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								core/encodings.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,49 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export const encodings = { | ||||||
|  |     encodingRaw: 0, | ||||||
|  |     encodingCopyRect: 1, | ||||||
|  |     encodingRRE: 2, | ||||||
|  |     encodingHextile: 5, | ||||||
|  |     encodingTight: 7, | ||||||
|  |     encodingZRLE: 16, | ||||||
|  |     encodingTightPNG: -260, | ||||||
|  |     encodingJPEG: 21, | ||||||
|  |  | ||||||
|  |     pseudoEncodingQualityLevel9: -23, | ||||||
|  |     pseudoEncodingQualityLevel0: -32, | ||||||
|  |     pseudoEncodingDesktopSize: -223, | ||||||
|  |     pseudoEncodingLastRect: -224, | ||||||
|  |     pseudoEncodingCursor: -239, | ||||||
|  |     pseudoEncodingQEMUExtendedKeyEvent: -258, | ||||||
|  |     pseudoEncodingQEMULedEvent: -261, | ||||||
|  |     pseudoEncodingDesktopName: -307, | ||||||
|  |     pseudoEncodingExtendedDesktopSize: -308, | ||||||
|  |     pseudoEncodingXvp: -309, | ||||||
|  |     pseudoEncodingFence: -312, | ||||||
|  |     pseudoEncodingContinuousUpdates: -313, | ||||||
|  |     pseudoEncodingCompressLevel9: -247, | ||||||
|  |     pseudoEncodingCompressLevel0: -256, | ||||||
|  |     pseudoEncodingVMwareCursor: 0x574d5664, | ||||||
|  |     pseudoEncodingExtendedClipboard: 0xc0a1e5ce | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export function encodingName(num) { | ||||||
|  |     switch (num) { | ||||||
|  |         case encodings.encodingRaw:      return "Raw"; | ||||||
|  |         case encodings.encodingCopyRect: return "CopyRect"; | ||||||
|  |         case encodings.encodingRRE:      return "RRE"; | ||||||
|  |         case encodings.encodingHextile:  return "Hextile"; | ||||||
|  |         case encodings.encodingTight:    return "Tight"; | ||||||
|  |         case encodings.encodingZRLE:     return "ZRLE"; | ||||||
|  |         case encodings.encodingTightPNG: return "TightPNG"; | ||||||
|  |         case encodings.encodingJPEG:     return "JPEG"; | ||||||
|  |         default:                         return "[unknown encoding " + num + "]"; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								core/inflator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,65 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2020 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js"; | ||||||
|  | import ZStream from "../vendor/pako/lib/zlib/zstream.js"; | ||||||
|  |  | ||||||
|  | export default class Inflate { | ||||||
|  |     constructor() { | ||||||
|  |         this.strm = new ZStream(); | ||||||
|  |         this.chunkSize = 1024 * 10 * 10; | ||||||
|  |         this.strm.output = new Uint8Array(this.chunkSize); | ||||||
|  |  | ||||||
|  |         inflateInit(this.strm); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     setInput(data) { | ||||||
|  |         if (!data) { | ||||||
|  |             //FIXME: flush remaining data. | ||||||
|  |             /* eslint-disable camelcase */ | ||||||
|  |             this.strm.input = null; | ||||||
|  |             this.strm.avail_in = 0; | ||||||
|  |             this.strm.next_in = 0; | ||||||
|  |         } else { | ||||||
|  |             this.strm.input = data; | ||||||
|  |             this.strm.avail_in = this.strm.input.length; | ||||||
|  |             this.strm.next_in = 0; | ||||||
|  |             /* eslint-enable camelcase */ | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inflate(expected) { | ||||||
|  |         // resize our output buffer if it's too small | ||||||
|  |         // (we could just use multiple chunks, but that would cause an extra | ||||||
|  |         // allocation each time to flatten the chunks) | ||||||
|  |         if (expected > this.chunkSize) { | ||||||
|  |             this.chunkSize = expected; | ||||||
|  |             this.strm.output = new Uint8Array(this.chunkSize); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* eslint-disable camelcase */ | ||||||
|  |         this.strm.next_out = 0; | ||||||
|  |         this.strm.avail_out = expected; | ||||||
|  |         /* eslint-enable camelcase */ | ||||||
|  |  | ||||||
|  |         let ret = inflate(this.strm, 0); // Flush argument not used. | ||||||
|  |         if (ret < 0) { | ||||||
|  |             throw new Error("zlib inflate failed"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.strm.next_out != expected) { | ||||||
|  |             throw new Error("Incomplete zlib block"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     reset() { | ||||||
|  |         inflateReset(this.strm); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										311
									
								
								core/input/domkeytable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,311 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2018 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import KeyTable from "./keysym.js"; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Mapping between HTML key values and VNC/X11 keysyms for "special" | ||||||
|  |  * keys that cannot be handled via their Unicode codepoint. | ||||||
|  |  * | ||||||
|  |  * See https://www.w3.org/TR/uievents-key/ for possible values. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | const DOMKeyTable = {}; | ||||||
|  |  | ||||||
|  | function addStandard(key, standard) { | ||||||
|  |     if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); | ||||||
|  |     if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); | ||||||
|  |     DOMKeyTable[key] = [standard, standard, standard, standard]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function addLeftRight(key, left, right) { | ||||||
|  |     if (left === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); | ||||||
|  |     if (right === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); | ||||||
|  |     if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); | ||||||
|  |     DOMKeyTable[key] = [left, left, right, left]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function addNumpad(key, standard, numpad) { | ||||||
|  |     if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); | ||||||
|  |     if (numpad === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); | ||||||
|  |     if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); | ||||||
|  |     DOMKeyTable[key] = [standard, standard, standard, numpad]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 3.2. Modifier Keys | ||||||
|  |  | ||||||
|  | addLeftRight("Alt", KeyTable.XK_Alt_L, KeyTable.XK_Alt_R); | ||||||
|  | addStandard("AltGraph", KeyTable.XK_ISO_Level3_Shift); | ||||||
|  | addStandard("CapsLock", KeyTable.XK_Caps_Lock); | ||||||
|  | addLeftRight("Control", KeyTable.XK_Control_L, KeyTable.XK_Control_R); | ||||||
|  | // - Fn | ||||||
|  | // - FnLock | ||||||
|  | addLeftRight("Meta", KeyTable.XK_Super_L, KeyTable.XK_Super_R); | ||||||
|  | addStandard("NumLock", KeyTable.XK_Num_Lock); | ||||||
|  | addStandard("ScrollLock", KeyTable.XK_Scroll_Lock); | ||||||
|  | addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R); | ||||||
|  | // - Symbol | ||||||
|  | // - SymbolLock | ||||||
|  | // - Hyper | ||||||
|  | // - Super | ||||||
|  |  | ||||||
|  | // 3.3. Whitespace Keys | ||||||
|  |  | ||||||
|  | addNumpad("Enter", KeyTable.XK_Return, KeyTable.XK_KP_Enter); | ||||||
|  | addStandard("Tab", KeyTable.XK_Tab); | ||||||
|  | addNumpad(" ", KeyTable.XK_space, KeyTable.XK_KP_Space); | ||||||
|  |  | ||||||
|  | // 3.4. Navigation Keys | ||||||
|  |  | ||||||
|  | addNumpad("ArrowDown", KeyTable.XK_Down, KeyTable.XK_KP_Down); | ||||||
|  | addNumpad("ArrowLeft", KeyTable.XK_Left, KeyTable.XK_KP_Left); | ||||||
|  | addNumpad("ArrowRight", KeyTable.XK_Right, KeyTable.XK_KP_Right); | ||||||
|  | addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up); | ||||||
|  | addNumpad("End", KeyTable.XK_End, KeyTable.XK_KP_End); | ||||||
|  | addNumpad("Home", KeyTable.XK_Home, KeyTable.XK_KP_Home); | ||||||
|  | addNumpad("PageDown", KeyTable.XK_Next, KeyTable.XK_KP_Next); | ||||||
|  | addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior); | ||||||
|  |  | ||||||
|  | // 3.5. Editing Keys | ||||||
|  |  | ||||||
|  | addStandard("Backspace", KeyTable.XK_BackSpace); | ||||||
|  | // Browsers send "Clear" for the numpad 5 without NumLock because | ||||||
|  | // Windows uses VK_Clear for that key. But Unix expects KP_Begin for | ||||||
|  | // that scenario. | ||||||
|  | addNumpad("Clear", KeyTable.XK_Clear, KeyTable.XK_KP_Begin); | ||||||
|  | addStandard("Copy", KeyTable.XF86XK_Copy); | ||||||
|  | // - CrSel | ||||||
|  | addStandard("Cut", KeyTable.XF86XK_Cut); | ||||||
|  | addNumpad("Delete", KeyTable.XK_Delete, KeyTable.XK_KP_Delete); | ||||||
|  | // - EraseEof | ||||||
|  | // - ExSel | ||||||
|  | addNumpad("Insert", KeyTable.XK_Insert, KeyTable.XK_KP_Insert); | ||||||
|  | addStandard("Paste", KeyTable.XF86XK_Paste); | ||||||
|  | addStandard("Redo", KeyTable.XK_Redo); | ||||||
|  | addStandard("Undo", KeyTable.XK_Undo); | ||||||
|  |  | ||||||
|  | // 3.6. UI Keys | ||||||
|  |  | ||||||
|  | // - Accept | ||||||
|  | // - Again (could just be XK_Redo) | ||||||
|  | // - Attn | ||||||
|  | addStandard("Cancel", KeyTable.XK_Cancel); | ||||||
|  | addStandard("ContextMenu", KeyTable.XK_Menu); | ||||||
|  | addStandard("Escape", KeyTable.XK_Escape); | ||||||
|  | addStandard("Execute", KeyTable.XK_Execute); | ||||||
|  | addStandard("Find", KeyTable.XK_Find); | ||||||
|  | addStandard("Help", KeyTable.XK_Help); | ||||||
|  | addStandard("Pause", KeyTable.XK_Pause); | ||||||
|  | // - Play | ||||||
|  | // - Props | ||||||
|  | addStandard("Select", KeyTable.XK_Select); | ||||||
|  | addStandard("ZoomIn", KeyTable.XF86XK_ZoomIn); | ||||||
|  | addStandard("ZoomOut", KeyTable.XF86XK_ZoomOut); | ||||||
|  |  | ||||||
|  | // 3.7. Device Keys | ||||||
|  |  | ||||||
|  | addStandard("BrightnessDown", KeyTable.XF86XK_MonBrightnessDown); | ||||||
|  | addStandard("BrightnessUp", KeyTable.XF86XK_MonBrightnessUp); | ||||||
|  | addStandard("Eject", KeyTable.XF86XK_Eject); | ||||||
|  | addStandard("LogOff", KeyTable.XF86XK_LogOff); | ||||||
|  | addStandard("Power", KeyTable.XF86XK_PowerOff); | ||||||
|  | addStandard("PowerOff", KeyTable.XF86XK_PowerDown); | ||||||
|  | addStandard("PrintScreen", KeyTable.XK_Print); | ||||||
|  | addStandard("Hibernate", KeyTable.XF86XK_Hibernate); | ||||||
|  | addStandard("Standby", KeyTable.XF86XK_Standby); | ||||||
|  | addStandard("WakeUp", KeyTable.XF86XK_WakeUp); | ||||||
|  |  | ||||||
|  | // 3.8. IME and Composition Keys | ||||||
|  |  | ||||||
|  | addStandard("AllCandidates", KeyTable.XK_MultipleCandidate); | ||||||
|  | addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle); | ||||||
|  | addStandard("CodeInput", KeyTable.XK_Codeinput); | ||||||
|  | addStandard("Compose", KeyTable.XK_Multi_key); | ||||||
|  | addStandard("Convert", KeyTable.XK_Henkan); | ||||||
|  | // - Dead | ||||||
|  | // - FinalMode | ||||||
|  | addStandard("GroupFirst", KeyTable.XK_ISO_First_Group); | ||||||
|  | addStandard("GroupLast", KeyTable.XK_ISO_Last_Group); | ||||||
|  | addStandard("GroupNext", KeyTable.XK_ISO_Next_Group); | ||||||
|  | addStandard("GroupPrevious", KeyTable.XK_ISO_Prev_Group); | ||||||
|  | // - ModeChange (XK_Mode_switch is often used for AltGr) | ||||||
|  | // - NextCandidate | ||||||
|  | addStandard("NonConvert", KeyTable.XK_Muhenkan); | ||||||
|  | addStandard("PreviousCandidate", KeyTable.XK_PreviousCandidate); | ||||||
|  | // - Process | ||||||
|  | addStandard("SingleCandidate", KeyTable.XK_SingleCandidate); | ||||||
|  | addStandard("HangulMode", KeyTable.XK_Hangul); | ||||||
|  | addStandard("HanjaMode", KeyTable.XK_Hangul_Hanja); | ||||||
|  | addStandard("JunjaMode", KeyTable.XK_Hangul_Jeonja); | ||||||
|  | addStandard("Eisu", KeyTable.XK_Eisu_toggle); | ||||||
|  | addStandard("Hankaku", KeyTable.XK_Hankaku); | ||||||
|  | addStandard("Hiragana", KeyTable.XK_Hiragana); | ||||||
|  | addStandard("HiraganaKatakana", KeyTable.XK_Hiragana_Katakana); | ||||||
|  | addStandard("KanaMode", KeyTable.XK_Kana_Shift); // could also be _Kana_Lock | ||||||
|  | addStandard("KanjiMode", KeyTable.XK_Kanji); | ||||||
|  | addStandard("Katakana", KeyTable.XK_Katakana); | ||||||
|  | addStandard("Romaji", KeyTable.XK_Romaji); | ||||||
|  | addStandard("Zenkaku", KeyTable.XK_Zenkaku); | ||||||
|  | addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku); | ||||||
|  |  | ||||||
|  | // 3.9. General-Purpose Function Keys | ||||||
|  |  | ||||||
|  | addStandard("F1", KeyTable.XK_F1); | ||||||
|  | addStandard("F2", KeyTable.XK_F2); | ||||||
|  | addStandard("F3", KeyTable.XK_F3); | ||||||
|  | addStandard("F4", KeyTable.XK_F4); | ||||||
|  | addStandard("F5", KeyTable.XK_F5); | ||||||
|  | addStandard("F6", KeyTable.XK_F6); | ||||||
|  | addStandard("F7", KeyTable.XK_F7); | ||||||
|  | addStandard("F8", KeyTable.XK_F8); | ||||||
|  | addStandard("F9", KeyTable.XK_F9); | ||||||
|  | addStandard("F10", KeyTable.XK_F10); | ||||||
|  | addStandard("F11", KeyTable.XK_F11); | ||||||
|  | addStandard("F12", KeyTable.XK_F12); | ||||||
|  | addStandard("F13", KeyTable.XK_F13); | ||||||
|  | addStandard("F14", KeyTable.XK_F14); | ||||||
|  | addStandard("F15", KeyTable.XK_F15); | ||||||
|  | addStandard("F16", KeyTable.XK_F16); | ||||||
|  | addStandard("F17", KeyTable.XK_F17); | ||||||
|  | addStandard("F18", KeyTable.XK_F18); | ||||||
|  | addStandard("F19", KeyTable.XK_F19); | ||||||
|  | addStandard("F20", KeyTable.XK_F20); | ||||||
|  | addStandard("F21", KeyTable.XK_F21); | ||||||
|  | addStandard("F22", KeyTable.XK_F22); | ||||||
|  | addStandard("F23", KeyTable.XK_F23); | ||||||
|  | addStandard("F24", KeyTable.XK_F24); | ||||||
|  | addStandard("F25", KeyTable.XK_F25); | ||||||
|  | addStandard("F26", KeyTable.XK_F26); | ||||||
|  | addStandard("F27", KeyTable.XK_F27); | ||||||
|  | addStandard("F28", KeyTable.XK_F28); | ||||||
|  | addStandard("F29", KeyTable.XK_F29); | ||||||
|  | addStandard("F30", KeyTable.XK_F30); | ||||||
|  | addStandard("F31", KeyTable.XK_F31); | ||||||
|  | addStandard("F32", KeyTable.XK_F32); | ||||||
|  | addStandard("F33", KeyTable.XK_F33); | ||||||
|  | addStandard("F34", KeyTable.XK_F34); | ||||||
|  | addStandard("F35", KeyTable.XK_F35); | ||||||
|  | // - Soft1... | ||||||
|  |  | ||||||
|  | // 3.10. Multimedia Keys | ||||||
|  |  | ||||||
|  | // - ChannelDown | ||||||
|  | // - ChannelUp | ||||||
|  | addStandard("Close", KeyTable.XF86XK_Close); | ||||||
|  | addStandard("MailForward", KeyTable.XF86XK_MailForward); | ||||||
|  | addStandard("MailReply", KeyTable.XF86XK_Reply); | ||||||
|  | addStandard("MailSend", KeyTable.XF86XK_Send); | ||||||
|  | // - MediaClose | ||||||
|  | addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward); | ||||||
|  | addStandard("MediaPause", KeyTable.XF86XK_AudioPause); | ||||||
|  | addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay); | ||||||
|  | // - MediaPlayPause | ||||||
|  | addStandard("MediaRecord", KeyTable.XF86XK_AudioRecord); | ||||||
|  | addStandard("MediaRewind", KeyTable.XF86XK_AudioRewind); | ||||||
|  | addStandard("MediaStop", KeyTable.XF86XK_AudioStop); | ||||||
|  | addStandard("MediaTrackNext", KeyTable.XF86XK_AudioNext); | ||||||
|  | addStandard("MediaTrackPrevious", KeyTable.XF86XK_AudioPrev); | ||||||
|  | addStandard("New", KeyTable.XF86XK_New); | ||||||
|  | addStandard("Open", KeyTable.XF86XK_Open); | ||||||
|  | addStandard("Print", KeyTable.XK_Print); | ||||||
|  | addStandard("Save", KeyTable.XF86XK_Save); | ||||||
|  | addStandard("SpellCheck", KeyTable.XF86XK_Spell); | ||||||
|  |  | ||||||
|  | // 3.11. Multimedia Numpad Keys | ||||||
|  |  | ||||||
|  | // - Key11 | ||||||
|  | // - Key12 | ||||||
|  |  | ||||||
|  | // 3.12. Audio Keys | ||||||
|  |  | ||||||
|  | // - AudioBalanceLeft | ||||||
|  | // - AudioBalanceRight | ||||||
|  | // - AudioBassBoostDown | ||||||
|  | // - AudioBassBoostToggle | ||||||
|  | // - AudioBassBoostUp | ||||||
|  | // - AudioFaderFront | ||||||
|  | // - AudioFaderRear | ||||||
|  | // - AudioSurroundModeNext | ||||||
|  | // - AudioTrebleDown | ||||||
|  | // - AudioTrebleUp | ||||||
|  | addStandard("AudioVolumeDown", KeyTable.XF86XK_AudioLowerVolume); | ||||||
|  | addStandard("AudioVolumeUp", KeyTable.XF86XK_AudioRaiseVolume); | ||||||
|  | addStandard("AudioVolumeMute", KeyTable.XF86XK_AudioMute); | ||||||
|  | // - MicrophoneToggle | ||||||
|  | // - MicrophoneVolumeDown | ||||||
|  | // - MicrophoneVolumeUp | ||||||
|  | addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute); | ||||||
|  |  | ||||||
|  | // 3.13. Speech Keys | ||||||
|  |  | ||||||
|  | // - SpeechCorrectionList | ||||||
|  | // - SpeechInputToggle | ||||||
|  |  | ||||||
|  | // 3.14. Application Keys | ||||||
|  |  | ||||||
|  | addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer); | ||||||
|  | addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator); | ||||||
|  | addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar); | ||||||
|  | // - LaunchContacts | ||||||
|  | addStandard("LaunchMail", KeyTable.XF86XK_Mail); | ||||||
|  | addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia); | ||||||
|  | addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music); | ||||||
|  | addStandard("LaunchPhone", KeyTable.XF86XK_Phone); | ||||||
|  | addStandard("LaunchScreenSaver", KeyTable.XF86XK_ScreenSaver); | ||||||
|  | addStandard("LaunchSpreadsheet", KeyTable.XF86XK_Excel); | ||||||
|  | addStandard("LaunchWebBrowser", KeyTable.XF86XK_WWW); | ||||||
|  | addStandard("LaunchWebCam", KeyTable.XF86XK_WebCam); | ||||||
|  | addStandard("LaunchWordProcessor", KeyTable.XF86XK_Word); | ||||||
|  |  | ||||||
|  | // 3.15. Browser Keys | ||||||
|  |  | ||||||
|  | addStandard("BrowserBack", KeyTable.XF86XK_Back); | ||||||
|  | addStandard("BrowserFavorites", KeyTable.XF86XK_Favorites); | ||||||
|  | addStandard("BrowserForward", KeyTable.XF86XK_Forward); | ||||||
|  | addStandard("BrowserHome", KeyTable.XF86XK_HomePage); | ||||||
|  | addStandard("BrowserRefresh", KeyTable.XF86XK_Refresh); | ||||||
|  | addStandard("BrowserSearch", KeyTable.XF86XK_Search); | ||||||
|  | addStandard("BrowserStop", KeyTable.XF86XK_Stop); | ||||||
|  |  | ||||||
|  | // 3.16. Mobile Phone Keys | ||||||
|  |  | ||||||
|  | // - A whole bunch... | ||||||
|  |  | ||||||
|  | // 3.17. TV Keys | ||||||
|  |  | ||||||
|  | // - A whole bunch... | ||||||
|  |  | ||||||
|  | // 3.18. Media Controller Keys | ||||||
|  |  | ||||||
|  | // - A whole bunch... | ||||||
|  | addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust); | ||||||
|  | addStandard("MediaAudioTrack", KeyTable.XF86XK_AudioCycleTrack); | ||||||
|  | addStandard("RandomToggle", KeyTable.XF86XK_AudioRandomPlay); | ||||||
|  | addStandard("SplitScreenToggle", KeyTable.XF86XK_SplitScreen); | ||||||
|  | addStandard("Subtitle", KeyTable.XF86XK_Subtitle); | ||||||
|  | addStandard("VideoModeNext", KeyTable.XF86XK_Next_VMode); | ||||||
|  |  | ||||||
|  | // Extra: Numpad | ||||||
|  |  | ||||||
|  | addNumpad("=", KeyTable.XK_equal, KeyTable.XK_KP_Equal); | ||||||
|  | addNumpad("+", KeyTable.XK_plus, KeyTable.XK_KP_Add); | ||||||
|  | addNumpad("-", KeyTable.XK_minus, KeyTable.XK_KP_Subtract); | ||||||
|  | addNumpad("*", KeyTable.XK_asterisk, KeyTable.XK_KP_Multiply); | ||||||
|  | addNumpad("/", KeyTable.XK_slash, KeyTable.XK_KP_Divide); | ||||||
|  | addNumpad(".", KeyTable.XK_period, KeyTable.XK_KP_Decimal); | ||||||
|  | addNumpad(",", KeyTable.XK_comma, KeyTable.XK_KP_Separator); | ||||||
|  | addNumpad("0", KeyTable.XK_0, KeyTable.XK_KP_0); | ||||||
|  | addNumpad("1", KeyTable.XK_1, KeyTable.XK_KP_1); | ||||||
|  | addNumpad("2", KeyTable.XK_2, KeyTable.XK_KP_2); | ||||||
|  | addNumpad("3", KeyTable.XK_3, KeyTable.XK_KP_3); | ||||||
|  | addNumpad("4", KeyTable.XK_4, KeyTable.XK_KP_4); | ||||||
|  | addNumpad("5", KeyTable.XK_5, KeyTable.XK_KP_5); | ||||||
|  | addNumpad("6", KeyTable.XK_6, KeyTable.XK_KP_6); | ||||||
|  | addNumpad("7", KeyTable.XK_7, KeyTable.XK_KP_7); | ||||||
|  | addNumpad("8", KeyTable.XK_8, KeyTable.XK_KP_8); | ||||||
|  | addNumpad("9", KeyTable.XK_9, KeyTable.XK_KP_9); | ||||||
|  |  | ||||||
|  | export default DOMKeyTable; | ||||||
							
								
								
									
										129
									
								
								core/input/fixedkeys.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,129 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2018 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Fallback mapping between HTML key codes (physical keys) and | ||||||
|  |  * HTML key values. This only works for keys that don't vary | ||||||
|  |  * between layouts. We also omit those who manage fine by mapping the | ||||||
|  |  * Unicode representation. | ||||||
|  |  * | ||||||
|  |  * See https://www.w3.org/TR/uievents-code/ for possible codes. | ||||||
|  |  * See https://www.w3.org/TR/uievents-key/ for possible values. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* eslint-disable key-spacing */ | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |  | ||||||
|  | // 3.1.1.1. Writing System Keys | ||||||
|  |  | ||||||
|  |     'Backspace':        'Backspace', | ||||||
|  |  | ||||||
|  | // 3.1.1.2. Functional Keys | ||||||
|  |  | ||||||
|  |     'AltLeft':          'Alt', | ||||||
|  |     'AltRight':         'Alt', // This could also be 'AltGraph' | ||||||
|  |     'CapsLock':         'CapsLock', | ||||||
|  |     'ContextMenu':      'ContextMenu', | ||||||
|  |     'ControlLeft':      'Control', | ||||||
|  |     'ControlRight':     'Control', | ||||||
|  |     'Enter':            'Enter', | ||||||
|  |     'MetaLeft':         'Meta', | ||||||
|  |     'MetaRight':        'Meta', | ||||||
|  |     'ShiftLeft':        'Shift', | ||||||
|  |     'ShiftRight':       'Shift', | ||||||
|  |     'Tab':              'Tab', | ||||||
|  |     // FIXME: Japanese/Korean keys | ||||||
|  |  | ||||||
|  | // 3.1.2. Control Pad Section | ||||||
|  |  | ||||||
|  |     'Delete':           'Delete', | ||||||
|  |     'End':              'End', | ||||||
|  |     'Help':             'Help', | ||||||
|  |     'Home':             'Home', | ||||||
|  |     'Insert':           'Insert', | ||||||
|  |     'PageDown':         'PageDown', | ||||||
|  |     'PageUp':           'PageUp', | ||||||
|  |  | ||||||
|  | // 3.1.3. Arrow Pad Section | ||||||
|  |  | ||||||
|  |     'ArrowDown':        'ArrowDown', | ||||||
|  |     'ArrowLeft':        'ArrowLeft', | ||||||
|  |     'ArrowRight':       'ArrowRight', | ||||||
|  |     'ArrowUp':          'ArrowUp', | ||||||
|  |  | ||||||
|  | // 3.1.4. Numpad Section | ||||||
|  |  | ||||||
|  |     'NumLock':          'NumLock', | ||||||
|  |     'NumpadBackspace':  'Backspace', | ||||||
|  |     'NumpadClear':      'Clear', | ||||||
|  |  | ||||||
|  | // 3.1.5. Function Section | ||||||
|  |  | ||||||
|  |     'Escape':           'Escape', | ||||||
|  |     'F1':               'F1', | ||||||
|  |     'F2':               'F2', | ||||||
|  |     'F3':               'F3', | ||||||
|  |     'F4':               'F4', | ||||||
|  |     'F5':               'F5', | ||||||
|  |     'F6':               'F6', | ||||||
|  |     'F7':               'F7', | ||||||
|  |     'F8':               'F8', | ||||||
|  |     'F9':               'F9', | ||||||
|  |     'F10':              'F10', | ||||||
|  |     'F11':              'F11', | ||||||
|  |     'F12':              'F12', | ||||||
|  |     'F13':              'F13', | ||||||
|  |     'F14':              'F14', | ||||||
|  |     'F15':              'F15', | ||||||
|  |     'F16':              'F16', | ||||||
|  |     'F17':              'F17', | ||||||
|  |     'F18':              'F18', | ||||||
|  |     'F19':              'F19', | ||||||
|  |     'F20':              'F20', | ||||||
|  |     'F21':              'F21', | ||||||
|  |     'F22':              'F22', | ||||||
|  |     'F23':              'F23', | ||||||
|  |     'F24':              'F24', | ||||||
|  |     'F25':              'F25', | ||||||
|  |     'F26':              'F26', | ||||||
|  |     'F27':              'F27', | ||||||
|  |     'F28':              'F28', | ||||||
|  |     'F29':              'F29', | ||||||
|  |     'F30':              'F30', | ||||||
|  |     'F31':              'F31', | ||||||
|  |     'F32':              'F32', | ||||||
|  |     'F33':              'F33', | ||||||
|  |     'F34':              'F34', | ||||||
|  |     'F35':              'F35', | ||||||
|  |     'PrintScreen':      'PrintScreen', | ||||||
|  |     'ScrollLock':       'ScrollLock', | ||||||
|  |     'Pause':            'Pause', | ||||||
|  |  | ||||||
|  | // 3.1.6. Media Keys | ||||||
|  |  | ||||||
|  |     'BrowserBack':      'BrowserBack', | ||||||
|  |     'BrowserFavorites': 'BrowserFavorites', | ||||||
|  |     'BrowserForward':   'BrowserForward', | ||||||
|  |     'BrowserHome':      'BrowserHome', | ||||||
|  |     'BrowserRefresh':   'BrowserRefresh', | ||||||
|  |     'BrowserSearch':    'BrowserSearch', | ||||||
|  |     'BrowserStop':      'BrowserStop', | ||||||
|  |     'Eject':            'Eject', | ||||||
|  |     'LaunchApp1':       'LaunchMyComputer', | ||||||
|  |     'LaunchApp2':       'LaunchCalendar', | ||||||
|  |     'LaunchMail':       'LaunchMail', | ||||||
|  |     'MediaPlayPause':   'MediaPlay', | ||||||
|  |     'MediaStop':        'MediaStop', | ||||||
|  |     'MediaTrackNext':   'MediaTrackNext', | ||||||
|  |     'MediaTrackPrevious': 'MediaTrackPrevious', | ||||||
|  |     'Power':            'Power', | ||||||
|  |     'Sleep':            'Sleep', | ||||||
|  |     'AudioVolumeDown':  'AudioVolumeDown', | ||||||
|  |     'AudioVolumeMute':  'AudioVolumeMute', | ||||||
|  |     'AudioVolumeUp':    'AudioVolumeUp', | ||||||
|  |     'WakeUp':           'WakeUp', | ||||||
|  | }; | ||||||
							
								
								
									
										567
									
								
								core/input/gesturehandler.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,567 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2020 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | const GH_NOGESTURE = 0; | ||||||
|  | const GH_ONETAP    = 1; | ||||||
|  | const GH_TWOTAP    = 2; | ||||||
|  | const GH_THREETAP  = 4; | ||||||
|  | const GH_DRAG      = 8; | ||||||
|  | const GH_LONGPRESS = 16; | ||||||
|  | const GH_TWODRAG   = 32; | ||||||
|  | const GH_PINCH     = 64; | ||||||
|  |  | ||||||
|  | const GH_INITSTATE = 127; | ||||||
|  |  | ||||||
|  | const GH_MOVE_THRESHOLD = 50; | ||||||
|  | const GH_ANGLE_THRESHOLD = 90; // Degrees | ||||||
|  |  | ||||||
|  | // Timeout when waiting for gestures (ms) | ||||||
|  | const GH_MULTITOUCH_TIMEOUT = 250; | ||||||
|  |  | ||||||
|  | // Maximum time between press and release for a tap (ms) | ||||||
|  | const GH_TAP_TIMEOUT = 1000; | ||||||
|  |  | ||||||
|  | // Timeout when waiting for longpress (ms) | ||||||
|  | const GH_LONGPRESS_TIMEOUT = 1000; | ||||||
|  |  | ||||||
|  | // Timeout when waiting to decide between PINCH and TWODRAG (ms) | ||||||
|  | const GH_TWOTOUCH_TIMEOUT = 50; | ||||||
|  |  | ||||||
|  | export default class GestureHandler { | ||||||
|  |     constructor() { | ||||||
|  |         this._target = null; | ||||||
|  |  | ||||||
|  |         this._state = GH_INITSTATE; | ||||||
|  |  | ||||||
|  |         this._tracked = []; | ||||||
|  |         this._ignored = []; | ||||||
|  |  | ||||||
|  |         this._waitingRelease = false; | ||||||
|  |         this._releaseStart = 0.0; | ||||||
|  |  | ||||||
|  |         this._longpressTimeoutId = null; | ||||||
|  |         this._twoTouchTimeoutId = null; | ||||||
|  |  | ||||||
|  |         this._boundEventHandler = this._eventHandler.bind(this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     attach(target) { | ||||||
|  |         this.detach(); | ||||||
|  |  | ||||||
|  |         this._target = target; | ||||||
|  |         this._target.addEventListener('touchstart', | ||||||
|  |                                       this._boundEventHandler); | ||||||
|  |         this._target.addEventListener('touchmove', | ||||||
|  |                                       this._boundEventHandler); | ||||||
|  |         this._target.addEventListener('touchend', | ||||||
|  |                                       this._boundEventHandler); | ||||||
|  |         this._target.addEventListener('touchcancel', | ||||||
|  |                                       this._boundEventHandler); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     detach() { | ||||||
|  |         if (!this._target) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._stopLongpressTimeout(); | ||||||
|  |         this._stopTwoTouchTimeout(); | ||||||
|  |  | ||||||
|  |         this._target.removeEventListener('touchstart', | ||||||
|  |                                          this._boundEventHandler); | ||||||
|  |         this._target.removeEventListener('touchmove', | ||||||
|  |                                          this._boundEventHandler); | ||||||
|  |         this._target.removeEventListener('touchend', | ||||||
|  |                                          this._boundEventHandler); | ||||||
|  |         this._target.removeEventListener('touchcancel', | ||||||
|  |                                          this._boundEventHandler); | ||||||
|  |         this._target = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _eventHandler(e) { | ||||||
|  |         let fn; | ||||||
|  |  | ||||||
|  |         e.stopPropagation(); | ||||||
|  |         e.preventDefault(); | ||||||
|  |  | ||||||
|  |         switch (e.type) { | ||||||
|  |             case 'touchstart': | ||||||
|  |                 fn = this._touchStart; | ||||||
|  |                 break; | ||||||
|  |             case 'touchmove': | ||||||
|  |                 fn = this._touchMove; | ||||||
|  |                 break; | ||||||
|  |             case 'touchend': | ||||||
|  |             case 'touchcancel': | ||||||
|  |                 fn = this._touchEnd; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (let i = 0; i < e.changedTouches.length; i++) { | ||||||
|  |             let touch = e.changedTouches[i]; | ||||||
|  |             fn.call(this, touch.identifier, touch.clientX, touch.clientY); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _touchStart(id, x, y) { | ||||||
|  |         // Ignore any new touches if there is already an active gesture, | ||||||
|  |         // or we're in a cleanup state | ||||||
|  |         if (this._hasDetectedGesture() || (this._state === GH_NOGESTURE)) { | ||||||
|  |             this._ignored.push(id); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Did it take too long between touches that we should no longer | ||||||
|  |         // consider this a single gesture? | ||||||
|  |         if ((this._tracked.length > 0) && | ||||||
|  |             ((Date.now() - this._tracked[0].started) > GH_MULTITOUCH_TIMEOUT)) { | ||||||
|  |             this._state = GH_NOGESTURE; | ||||||
|  |             this._ignored.push(id); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // If we're waiting for fingers to release then we should no longer | ||||||
|  |         // recognize new touches | ||||||
|  |         if (this._waitingRelease) { | ||||||
|  |             this._state = GH_NOGESTURE; | ||||||
|  |             this._ignored.push(id); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._tracked.push({ | ||||||
|  |             id: id, | ||||||
|  |             started: Date.now(), | ||||||
|  |             active: true, | ||||||
|  |             firstX: x, | ||||||
|  |             firstY: y, | ||||||
|  |             lastX: x, | ||||||
|  |             lastY: y, | ||||||
|  |             angle: 0 | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         switch (this._tracked.length) { | ||||||
|  |             case 1: | ||||||
|  |                 this._startLongpressTimeout(); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 2: | ||||||
|  |                 this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS); | ||||||
|  |                 this._stopLongpressTimeout(); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 3: | ||||||
|  |                 this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 this._state = GH_NOGESTURE; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _touchMove(id, x, y) { | ||||||
|  |         let touch = this._tracked.find(t => t.id === id); | ||||||
|  |  | ||||||
|  |         // If this is an update for a touch we're not tracking, ignore it | ||||||
|  |         if (touch === undefined) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Update the touches last position with the event coordinates | ||||||
|  |         touch.lastX = x; | ||||||
|  |         touch.lastY = y; | ||||||
|  |  | ||||||
|  |         let deltaX = x - touch.firstX; | ||||||
|  |         let deltaY = y - touch.firstY; | ||||||
|  |  | ||||||
|  |         // Update angle when the touch has moved | ||||||
|  |         if ((touch.firstX !== touch.lastX) || | ||||||
|  |             (touch.firstY !== touch.lastY)) { | ||||||
|  |             touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!this._hasDetectedGesture()) { | ||||||
|  |             // Ignore moves smaller than the minimum threshold | ||||||
|  |             if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Can't be a tap or long press as we've seen movement | ||||||
|  |             this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS); | ||||||
|  |             this._stopLongpressTimeout(); | ||||||
|  |  | ||||||
|  |             if (this._tracked.length !== 1) { | ||||||
|  |                 this._state &= ~(GH_DRAG); | ||||||
|  |             } | ||||||
|  |             if (this._tracked.length !== 2) { | ||||||
|  |                 this._state &= ~(GH_TWODRAG | GH_PINCH); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // We need to figure out which of our different two touch gestures | ||||||
|  |             // this might be | ||||||
|  |             if (this._tracked.length === 2) { | ||||||
|  |  | ||||||
|  |                 // The other touch is the one where the id doesn't match | ||||||
|  |                 let prevTouch = this._tracked.find(t => t.id !== id); | ||||||
|  |  | ||||||
|  |                 // How far the previous touch point has moved since start | ||||||
|  |                 let prevDeltaMove = Math.hypot(prevTouch.firstX - prevTouch.lastX, | ||||||
|  |                                                prevTouch.firstY - prevTouch.lastY); | ||||||
|  |  | ||||||
|  |                 // We know that the current touch moved far enough, | ||||||
|  |                 // but unless both touches moved further than their | ||||||
|  |                 // threshold we don't want to disqualify any gestures | ||||||
|  |                 if (prevDeltaMove > GH_MOVE_THRESHOLD) { | ||||||
|  |  | ||||||
|  |                     // The angle difference between the direction of the touch points | ||||||
|  |                     let deltaAngle = Math.abs(touch.angle - prevTouch.angle); | ||||||
|  |                     deltaAngle = Math.abs(((deltaAngle + 180) % 360) - 180); | ||||||
|  |  | ||||||
|  |                     // PINCH or TWODRAG can be eliminated depending on the angle | ||||||
|  |                     if (deltaAngle > GH_ANGLE_THRESHOLD) { | ||||||
|  |                         this._state &= ~GH_TWODRAG; | ||||||
|  |                     } else { | ||||||
|  |                         this._state &= ~GH_PINCH; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (this._isTwoTouchTimeoutRunning()) { | ||||||
|  |                         this._stopTwoTouchTimeout(); | ||||||
|  |                     } | ||||||
|  |                 } else if (!this._isTwoTouchTimeoutRunning()) { | ||||||
|  |                     // We can't determine the gesture right now, let's | ||||||
|  |                     // wait and see if more events are on their way | ||||||
|  |                     this._startTwoTouchTimeout(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!this._hasDetectedGesture()) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this._pushEvent('gesturestart'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._pushEvent('gesturemove'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _touchEnd(id, x, y) { | ||||||
|  |         // Check if this is an ignored touch | ||||||
|  |         if (this._ignored.indexOf(id) !== -1) { | ||||||
|  |             // Remove this touch from ignored | ||||||
|  |             this._ignored.splice(this._ignored.indexOf(id), 1); | ||||||
|  |  | ||||||
|  |             // And reset the state if there are no more touches | ||||||
|  |             if ((this._ignored.length === 0) && | ||||||
|  |                 (this._tracked.length === 0)) { | ||||||
|  |                 this._state = GH_INITSTATE; | ||||||
|  |                 this._waitingRelease = false; | ||||||
|  |             } | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // We got a touchend before the timer triggered, | ||||||
|  |         // this cannot result in a gesture anymore. | ||||||
|  |         if (!this._hasDetectedGesture() && | ||||||
|  |             this._isTwoTouchTimeoutRunning()) { | ||||||
|  |             this._stopTwoTouchTimeout(); | ||||||
|  |             this._state = GH_NOGESTURE; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Some gestures don't trigger until a touch is released | ||||||
|  |         if (!this._hasDetectedGesture()) { | ||||||
|  |             // Can't be a gesture that relies on movement | ||||||
|  |             this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH); | ||||||
|  |             // Or something that relies on more time | ||||||
|  |             this._state &= ~GH_LONGPRESS; | ||||||
|  |             this._stopLongpressTimeout(); | ||||||
|  |  | ||||||
|  |             if (!this._waitingRelease) { | ||||||
|  |                 this._releaseStart = Date.now(); | ||||||
|  |                 this._waitingRelease = true; | ||||||
|  |  | ||||||
|  |                 // Can't be a tap that requires more touches than we current have | ||||||
|  |                 switch (this._tracked.length) { | ||||||
|  |                     case 1: | ||||||
|  |                         this._state &= ~(GH_TWOTAP | GH_THREETAP); | ||||||
|  |                         break; | ||||||
|  |  | ||||||
|  |                     case 2: | ||||||
|  |                         this._state &= ~(GH_ONETAP | GH_THREETAP); | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Waiting for all touches to release? (i.e. some tap) | ||||||
|  |         if (this._waitingRelease) { | ||||||
|  |             // Were all touches released at roughly the same time? | ||||||
|  |             if ((Date.now() - this._releaseStart) > GH_MULTITOUCH_TIMEOUT) { | ||||||
|  |                 this._state = GH_NOGESTURE; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Did too long time pass between press and release? | ||||||
|  |             if (this._tracked.some(t => (Date.now() - t.started) > GH_TAP_TIMEOUT)) { | ||||||
|  |                 this._state = GH_NOGESTURE; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             let touch = this._tracked.find(t => t.id === id); | ||||||
|  |             touch.active = false; | ||||||
|  |  | ||||||
|  |             // Are we still waiting for more releases? | ||||||
|  |             if (this._hasDetectedGesture()) { | ||||||
|  |                 this._pushEvent('gesturestart'); | ||||||
|  |             } else { | ||||||
|  |                 // Have we reached a dead end? | ||||||
|  |                 if (this._state !== GH_NOGESTURE) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this._hasDetectedGesture()) { | ||||||
|  |             this._pushEvent('gestureend'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Ignore any remaining touches until they are ended | ||||||
|  |         for (let i = 0; i < this._tracked.length; i++) { | ||||||
|  |             if (this._tracked[i].active) { | ||||||
|  |                 this._ignored.push(this._tracked[i].id); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         this._tracked = []; | ||||||
|  |  | ||||||
|  |         this._state = GH_NOGESTURE; | ||||||
|  |  | ||||||
|  |         // Remove this touch from ignored if it's in there | ||||||
|  |         if (this._ignored.indexOf(id) !== -1) { | ||||||
|  |             this._ignored.splice(this._ignored.indexOf(id), 1); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // We reset the state if ignored is empty | ||||||
|  |         if ((this._ignored.length === 0)) { | ||||||
|  |             this._state = GH_INITSTATE; | ||||||
|  |             this._waitingRelease = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _hasDetectedGesture() { | ||||||
|  |         if (this._state === GH_NOGESTURE) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // Check to see if the bitmask value is a power of 2 | ||||||
|  |         // (i.e. only one bit set). If it is, we have a state. | ||||||
|  |         if (this._state & (this._state - 1)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // For taps we also need to have all touches released | ||||||
|  |         // before we've fully detected the gesture | ||||||
|  |         if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) { | ||||||
|  |             if (this._tracked.some(t => t.active)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _startLongpressTimeout() { | ||||||
|  |         this._stopLongpressTimeout(); | ||||||
|  |         this._longpressTimeoutId = setTimeout(() => this._longpressTimeout(), | ||||||
|  |                                               GH_LONGPRESS_TIMEOUT); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _stopLongpressTimeout() { | ||||||
|  |         clearTimeout(this._longpressTimeoutId); | ||||||
|  |         this._longpressTimeoutId = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _longpressTimeout() { | ||||||
|  |         if (this._hasDetectedGesture()) { | ||||||
|  |             throw new Error("A longpress gesture failed, conflict with a different gesture"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._state = GH_LONGPRESS; | ||||||
|  |         this._pushEvent('gesturestart'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _startTwoTouchTimeout() { | ||||||
|  |         this._stopTwoTouchTimeout(); | ||||||
|  |         this._twoTouchTimeoutId = setTimeout(() => this._twoTouchTimeout(), | ||||||
|  |                                              GH_TWOTOUCH_TIMEOUT); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _stopTwoTouchTimeout() { | ||||||
|  |         clearTimeout(this._twoTouchTimeoutId); | ||||||
|  |         this._twoTouchTimeoutId = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _isTwoTouchTimeoutRunning() { | ||||||
|  |         return this._twoTouchTimeoutId !== null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _twoTouchTimeout() { | ||||||
|  |         if (this._tracked.length === 0) { | ||||||
|  |             throw new Error("A pinch or two drag gesture failed, no tracked touches"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // How far each touch point has moved since start | ||||||
|  |         let avgM = this._getAverageMovement(); | ||||||
|  |         let avgMoveH = Math.abs(avgM.x); | ||||||
|  |         let avgMoveV = Math.abs(avgM.y); | ||||||
|  |  | ||||||
|  |         // The difference in the distance between where | ||||||
|  |         // the touch points started and where they are now | ||||||
|  |         let avgD = this._getAverageDistance(); | ||||||
|  |         let deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) - | ||||||
|  |                                           Math.hypot(avgD.last.x, avgD.last.y)); | ||||||
|  |  | ||||||
|  |         if ((avgMoveV < deltaTouchDistance) && | ||||||
|  |             (avgMoveH < deltaTouchDistance)) { | ||||||
|  |             this._state = GH_PINCH; | ||||||
|  |         } else { | ||||||
|  |             this._state = GH_TWODRAG; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._pushEvent('gesturestart'); | ||||||
|  |         this._pushEvent('gesturemove'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _pushEvent(type) { | ||||||
|  |         let detail = { type: this._stateToGesture(this._state) }; | ||||||
|  |  | ||||||
|  |         // For most gesture events the current (average) position is the | ||||||
|  |         // most useful | ||||||
|  |         let avg = this._getPosition(); | ||||||
|  |         let pos = avg.last; | ||||||
|  |  | ||||||
|  |         // However we have a slight distance to detect gestures, so for the | ||||||
|  |         // first gesture event we want to use the first positions we saw | ||||||
|  |         if (type === 'gesturestart') { | ||||||
|  |             pos = avg.first; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // For these gestures, we always want the event coordinates | ||||||
|  |         // to be where the gesture began, not the current touch location. | ||||||
|  |         switch (this._state) { | ||||||
|  |             case GH_TWODRAG: | ||||||
|  |             case GH_PINCH: | ||||||
|  |                 pos = avg.first; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         detail['clientX'] = pos.x; | ||||||
|  |         detail['clientY'] = pos.y; | ||||||
|  |  | ||||||
|  |         // FIXME: other coordinates? | ||||||
|  |  | ||||||
|  |         // Some gestures also have a magnitude | ||||||
|  |         if (this._state === GH_PINCH) { | ||||||
|  |             let distance = this._getAverageDistance(); | ||||||
|  |             if (type === 'gesturestart') { | ||||||
|  |                 detail['magnitudeX'] = distance.first.x; | ||||||
|  |                 detail['magnitudeY'] = distance.first.y; | ||||||
|  |             } else { | ||||||
|  |                 detail['magnitudeX'] = distance.last.x; | ||||||
|  |                 detail['magnitudeY'] = distance.last.y; | ||||||
|  |             } | ||||||
|  |         } else if (this._state === GH_TWODRAG) { | ||||||
|  |             if (type === 'gesturestart') { | ||||||
|  |                 detail['magnitudeX'] = 0.0; | ||||||
|  |                 detail['magnitudeY'] = 0.0; | ||||||
|  |             } else { | ||||||
|  |                 let movement = this._getAverageMovement(); | ||||||
|  |                 detail['magnitudeX'] = movement.x; | ||||||
|  |                 detail['magnitudeY'] = movement.y; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let gev = new CustomEvent(type, { detail: detail }); | ||||||
|  |         this._target.dispatchEvent(gev); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _stateToGesture(state) { | ||||||
|  |         switch (state) { | ||||||
|  |             case GH_ONETAP: | ||||||
|  |                 return 'onetap'; | ||||||
|  |             case GH_TWOTAP: | ||||||
|  |                 return 'twotap'; | ||||||
|  |             case GH_THREETAP: | ||||||
|  |                 return 'threetap'; | ||||||
|  |             case GH_DRAG: | ||||||
|  |                 return 'drag'; | ||||||
|  |             case GH_LONGPRESS: | ||||||
|  |                 return 'longpress'; | ||||||
|  |             case GH_TWODRAG: | ||||||
|  |                 return 'twodrag'; | ||||||
|  |             case GH_PINCH: | ||||||
|  |                 return 'pinch'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new Error("Unknown gesture state: " + state); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getPosition() { | ||||||
|  |         if (this._tracked.length === 0) { | ||||||
|  |             throw new Error("Failed to get gesture position, no tracked touches"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let size = this._tracked.length; | ||||||
|  |         let fx = 0, fy = 0, lx = 0, ly = 0; | ||||||
|  |  | ||||||
|  |         for (let i = 0; i < this._tracked.length; i++) { | ||||||
|  |             fx += this._tracked[i].firstX; | ||||||
|  |             fy += this._tracked[i].firstY; | ||||||
|  |             lx += this._tracked[i].lastX; | ||||||
|  |             ly += this._tracked[i].lastY; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return { first: { x: fx / size, | ||||||
|  |                           y: fy / size }, | ||||||
|  |                  last: { x: lx / size, | ||||||
|  |                          y: ly / size } }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getAverageMovement() { | ||||||
|  |         if (this._tracked.length === 0) { | ||||||
|  |             throw new Error("Failed to get gesture movement, no tracked touches"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let totalH, totalV; | ||||||
|  |         totalH = totalV = 0; | ||||||
|  |         let size = this._tracked.length; | ||||||
|  |  | ||||||
|  |         for (let i = 0; i < this._tracked.length; i++) { | ||||||
|  |             totalH += this._tracked[i].lastX - this._tracked[i].firstX; | ||||||
|  |             totalV += this._tracked[i].lastY - this._tracked[i].firstY; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return { x: totalH / size, | ||||||
|  |                  y: totalV / size }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getAverageDistance() { | ||||||
|  |         if (this._tracked.length === 0) { | ||||||
|  |             throw new Error("Failed to get gesture distance, no tracked touches"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Distance between the first and last tracked touches | ||||||
|  |  | ||||||
|  |         let first = this._tracked[0]; | ||||||
|  |         let last = this._tracked[this._tracked.length - 1]; | ||||||
|  |  | ||||||
|  |         let fdx = Math.abs(last.firstX - first.firstX); | ||||||
|  |         let fdy = Math.abs(last.firstY - first.firstY); | ||||||
|  |  | ||||||
|  |         let ldx = Math.abs(last.lastX - first.lastX); | ||||||
|  |         let ldy = Math.abs(last.lastY - first.lastY); | ||||||
|  |  | ||||||
|  |         return { first: { x: fdx, y: fdy }, | ||||||
|  |                  last: { x: ldx, y: ldy } }; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										292
									
								
								core/input/keyboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,292 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from '../util/logging.js'; | ||||||
|  | import { stopEvent } from '../util/events.js'; | ||||||
|  | import * as KeyboardUtil from "./util.js"; | ||||||
|  | import KeyTable from "./keysym.js"; | ||||||
|  | import * as browser from "../util/browser.js"; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Keyboard event handler | ||||||
|  | // | ||||||
|  |  | ||||||
|  | export default class Keyboard { | ||||||
|  |     constructor(target) { | ||||||
|  |         this._target = target || null; | ||||||
|  |  | ||||||
|  |         this._keyDownList = {};         // List of depressed keys | ||||||
|  |                                         // (even if they are happy) | ||||||
|  |         this._altGrArmed = false;       // Windows AltGr detection | ||||||
|  |  | ||||||
|  |         // keep these here so we can refer to them later | ||||||
|  |         this._eventHandlers = { | ||||||
|  |             'keyup': this._handleKeyUp.bind(this), | ||||||
|  |             'keydown': this._handleKeyDown.bind(this), | ||||||
|  |             'blur': this._allKeysUp.bind(this), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // ===== EVENT HANDLERS ===== | ||||||
|  |  | ||||||
|  |         this.onkeyevent = () => {}; // Handler for key press/release | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ===== PRIVATE METHODS ===== | ||||||
|  |  | ||||||
|  |     _sendKeyEvent(keysym, code, down, numlock = null, capslock = null) { | ||||||
|  |         if (down) { | ||||||
|  |             this._keyDownList[code] = keysym; | ||||||
|  |         } else { | ||||||
|  |             // Do we really think this key is down? | ||||||
|  |             if (!(code in this._keyDownList)) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             delete this._keyDownList[code]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Log.Debug("onkeyevent " + (down ? "down" : "up") + | ||||||
|  |                   ", keysym: " + keysym, ", code: " + code + | ||||||
|  |                   ", numlock: " + numlock + ", capslock: " + capslock); | ||||||
|  |         this.onkeyevent(keysym, code, down, numlock, capslock); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _getKeyCode(e) { | ||||||
|  |         const code = KeyboardUtil.getKeycode(e); | ||||||
|  |         if (code !== 'Unidentified') { | ||||||
|  |             return code; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Unstable, but we don't have anything else to go on | ||||||
|  |         if (e.keyCode) { | ||||||
|  |             // 229 is used for composition events | ||||||
|  |             if (e.keyCode !== 229) { | ||||||
|  |                 return 'Platform' + e.keyCode; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // A precursor to the final DOM3 standard. Unfortunately it | ||||||
|  |         // is not layout independent, so it is as bad as using keyCode | ||||||
|  |         if (e.keyIdentifier) { | ||||||
|  |             // Non-character key? | ||||||
|  |             if (e.keyIdentifier.substr(0, 2) !== 'U+') { | ||||||
|  |                 return e.keyIdentifier; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const codepoint = parseInt(e.keyIdentifier.substr(2), 16); | ||||||
|  |             const char = String.fromCharCode(codepoint).toUpperCase(); | ||||||
|  |  | ||||||
|  |             return 'Platform' + char.charCodeAt(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 'Unidentified'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleKeyDown(e) { | ||||||
|  |         const code = this._getKeyCode(e); | ||||||
|  |         let keysym = KeyboardUtil.getKeysym(e); | ||||||
|  |         let numlock = e.getModifierState('NumLock'); | ||||||
|  |         let capslock = e.getModifierState('CapsLock'); | ||||||
|  |  | ||||||
|  |         // getModifierState for NumLock is not supported on mac and ios and always returns false. | ||||||
|  |         // Set to null to indicate unknown/unsupported instead. | ||||||
|  |         if (browser.isMac() || browser.isIOS()) { | ||||||
|  |             numlock = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Windows doesn't have a proper AltGr, but handles it using | ||||||
|  |         // fake Ctrl+Alt. However the remote end might not be Windows, | ||||||
|  |         // so we need to merge those in to a single AltGr event. We | ||||||
|  |         // detect this case by seeing the two key events directly after | ||||||
|  |         // each other with a very short time between them (<50ms). | ||||||
|  |         if (this._altGrArmed) { | ||||||
|  |             this._altGrArmed = false; | ||||||
|  |             clearTimeout(this._altGrTimeout); | ||||||
|  |  | ||||||
|  |             if ((code === "AltRight") && | ||||||
|  |                 ((e.timeStamp - this._altGrCtrlTime) < 50)) { | ||||||
|  |                 // FIXME: We fail to detect this if either Ctrl key is | ||||||
|  |                 //        first manually pressed as Windows then no | ||||||
|  |                 //        longer sends the fake Ctrl down event. It | ||||||
|  |                 //        does however happily send real Ctrl events | ||||||
|  |                 //        even when AltGr is already down. Some | ||||||
|  |                 //        browsers detect this for us though and set the | ||||||
|  |                 //        key to "AltGraph". | ||||||
|  |                 keysym = KeyTable.XK_ISO_Level3_Shift; | ||||||
|  |             } else { | ||||||
|  |                 this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true, numlock, capslock); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // We cannot handle keys we cannot track, but we also need | ||||||
|  |         // to deal with virtual keyboards which omit key info | ||||||
|  |         if (code === 'Unidentified') { | ||||||
|  |             if (keysym) { | ||||||
|  |                 // If it's a virtual keyboard then it should be | ||||||
|  |                 // sufficient to just send press and release right | ||||||
|  |                 // after each other | ||||||
|  |                 this._sendKeyEvent(keysym, code, true, numlock, capslock); | ||||||
|  |                 this._sendKeyEvent(keysym, code, false, numlock, capslock); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             stopEvent(e); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Alt behaves more like AltGraph on macOS, so shuffle the | ||||||
|  |         // keys around a bit to make things more sane for the remote | ||||||
|  |         // server. This method is used by RealVNC and TigerVNC (and | ||||||
|  |         // possibly others). | ||||||
|  |         if (browser.isMac() || browser.isIOS()) { | ||||||
|  |             switch (keysym) { | ||||||
|  |                 case KeyTable.XK_Super_L: | ||||||
|  |                     keysym = KeyTable.XK_Alt_L; | ||||||
|  |                     break; | ||||||
|  |                 case KeyTable.XK_Super_R: | ||||||
|  |                     keysym = KeyTable.XK_Super_L; | ||||||
|  |                     break; | ||||||
|  |                 case KeyTable.XK_Alt_L: | ||||||
|  |                     keysym = KeyTable.XK_Mode_switch; | ||||||
|  |                     break; | ||||||
|  |                 case KeyTable.XK_Alt_R: | ||||||
|  |                     keysym = KeyTable.XK_ISO_Level3_Shift; | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Is this key already pressed? If so, then we must use the | ||||||
|  |         // same keysym or we'll confuse the server | ||||||
|  |         if (code in this._keyDownList) { | ||||||
|  |             keysym = this._keyDownList[code]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // macOS doesn't send proper key releases if a key is pressed | ||||||
|  |         // while meta is held down | ||||||
|  |         if ((browser.isMac() || browser.isIOS()) && | ||||||
|  |             (e.metaKey && code !== 'MetaLeft' && code !== 'MetaRight')) { | ||||||
|  |             this._sendKeyEvent(keysym, code, true, numlock, capslock); | ||||||
|  |             this._sendKeyEvent(keysym, code, false, numlock, capslock); | ||||||
|  |             stopEvent(e); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // macOS doesn't send proper key events for modifiers, only | ||||||
|  |         // state change events. That gets extra confusing for CapsLock | ||||||
|  |         // which toggles on each press, but not on release. So pretend | ||||||
|  |         // it was a quick press and release of the button. | ||||||
|  |         if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) { | ||||||
|  |             this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true, numlock, capslock); | ||||||
|  |             this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false, numlock, capslock); | ||||||
|  |             stopEvent(e); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Windows doesn't send proper key releases for a bunch of | ||||||
|  |         // Japanese IM keys so we have to fake the release right away | ||||||
|  |         const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku, | ||||||
|  |                             KeyTable.XK_Eisu_toggle, | ||||||
|  |                             KeyTable.XK_Katakana, | ||||||
|  |                             KeyTable.XK_Hiragana, | ||||||
|  |                             KeyTable.XK_Romaji ]; | ||||||
|  |         if (browser.isWindows() && jpBadKeys.includes(keysym)) { | ||||||
|  |             this._sendKeyEvent(keysym, code, true, numlock, capslock); | ||||||
|  |             this._sendKeyEvent(keysym, code, false, numlock, capslock); | ||||||
|  |             stopEvent(e); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         stopEvent(e); | ||||||
|  |  | ||||||
|  |         // Possible start of AltGr sequence? (see above) | ||||||
|  |         if ((code === "ControlLeft") && browser.isWindows() && | ||||||
|  |             !("ControlLeft" in this._keyDownList)) { | ||||||
|  |             this._altGrArmed = true; | ||||||
|  |             this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100); | ||||||
|  |             this._altGrCtrlTime = e.timeStamp; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._sendKeyEvent(keysym, code, true, numlock, capslock); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleKeyUp(e) { | ||||||
|  |         stopEvent(e); | ||||||
|  |  | ||||||
|  |         const code = this._getKeyCode(e); | ||||||
|  |  | ||||||
|  |         // We can't get a release in the middle of an AltGr sequence, so | ||||||
|  |         // abort that detection | ||||||
|  |         if (this._altGrArmed) { | ||||||
|  |             this._altGrArmed = false; | ||||||
|  |             clearTimeout(this._altGrTimeout); | ||||||
|  |             this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // See comment in _handleKeyDown() | ||||||
|  |         if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) { | ||||||
|  |             this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true); | ||||||
|  |             this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._sendKeyEvent(this._keyDownList[code], code, false); | ||||||
|  |  | ||||||
|  |         // Windows has a rather nasty bug where it won't send key | ||||||
|  |         // release events for a Shift button if the other Shift is still | ||||||
|  |         // pressed | ||||||
|  |         if (browser.isWindows() && ((code === 'ShiftLeft') || | ||||||
|  |                                     (code === 'ShiftRight'))) { | ||||||
|  |             if ('ShiftRight' in this._keyDownList) { | ||||||
|  |                 this._sendKeyEvent(this._keyDownList['ShiftRight'], | ||||||
|  |                                    'ShiftRight', false); | ||||||
|  |             } | ||||||
|  |             if ('ShiftLeft' in this._keyDownList) { | ||||||
|  |                 this._sendKeyEvent(this._keyDownList['ShiftLeft'], | ||||||
|  |                                    'ShiftLeft', false); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleAltGrTimeout() { | ||||||
|  |         this._altGrArmed = false; | ||||||
|  |         clearTimeout(this._altGrTimeout); | ||||||
|  |         this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _allKeysUp() { | ||||||
|  |         Log.Debug(">> Keyboard.allKeysUp"); | ||||||
|  |         for (let code in this._keyDownList) { | ||||||
|  |             this._sendKeyEvent(this._keyDownList[code], code, false); | ||||||
|  |         } | ||||||
|  |         Log.Debug("<< Keyboard.allKeysUp"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // ===== PUBLIC METHODS ===== | ||||||
|  |  | ||||||
|  |     grab() { | ||||||
|  |         //Log.Debug(">> Keyboard.grab"); | ||||||
|  |  | ||||||
|  |         this._target.addEventListener('keydown', this._eventHandlers.keydown); | ||||||
|  |         this._target.addEventListener('keyup', this._eventHandlers.keyup); | ||||||
|  |  | ||||||
|  |         // Release (key up) if window loses focus | ||||||
|  |         window.addEventListener('blur', this._eventHandlers.blur); | ||||||
|  |  | ||||||
|  |         //Log.Debug("<< Keyboard.grab"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ungrab() { | ||||||
|  |         //Log.Debug(">> Keyboard.ungrab"); | ||||||
|  |  | ||||||
|  |         this._target.removeEventListener('keydown', this._eventHandlers.keydown); | ||||||
|  |         this._target.removeEventListener('keyup', this._eventHandlers.keyup); | ||||||
|  |         window.removeEventListener('blur', this._eventHandlers.blur); | ||||||
|  |  | ||||||
|  |         // Release (key up) all keys that are in a down state | ||||||
|  |         this._allKeysUp(); | ||||||
|  |  | ||||||
|  |         //Log.Debug(">> Keyboard.ungrab"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										616
									
								
								core/input/keysym.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,616 @@ | |||||||
|  | /* eslint-disable key-spacing */ | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |     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 */ | ||||||
|  |  | ||||||
|  |     /* International & multi-key character composition */ | ||||||
|  |  | ||||||
|  |     XK_Multi_key:                   0xff20, /* Multi-key character compose */ | ||||||
|  |     XK_Codeinput:                   0xff37, | ||||||
|  |     XK_SingleCandidate:             0xff3c, | ||||||
|  |     XK_MultipleCandidate:           0xff3d, | ||||||
|  |     XK_PreviousCandidate:           0xff3e, | ||||||
|  |  | ||||||
|  |     /* Japanese keyboard support */ | ||||||
|  |  | ||||||
|  |     XK_Kanji:                       0xff21, /* Kanji, Kanji convert */ | ||||||
|  |     XK_Muhenkan:                    0xff22, /* Cancel Conversion */ | ||||||
|  |     XK_Henkan_Mode:                 0xff23, /* Start/Stop Conversion */ | ||||||
|  |     XK_Henkan:                      0xff23, /* Alias for Henkan_Mode */ | ||||||
|  |     XK_Romaji:                      0xff24, /* to Romaji */ | ||||||
|  |     XK_Hiragana:                    0xff25, /* to Hiragana */ | ||||||
|  |     XK_Katakana:                    0xff26, /* to Katakana */ | ||||||
|  |     XK_Hiragana_Katakana:           0xff27, /* Hiragana/Katakana toggle */ | ||||||
|  |     XK_Zenkaku:                     0xff28, /* to Zenkaku */ | ||||||
|  |     XK_Hankaku:                     0xff29, /* to Hankaku */ | ||||||
|  |     XK_Zenkaku_Hankaku:             0xff2a, /* Zenkaku/Hankaku toggle */ | ||||||
|  |     XK_Touroku:                     0xff2b, /* Add to Dictionary */ | ||||||
|  |     XK_Massyo:                      0xff2c, /* Delete from Dictionary */ | ||||||
|  |     XK_Kana_Lock:                   0xff2d, /* Kana Lock */ | ||||||
|  |     XK_Kana_Shift:                  0xff2e, /* Kana Shift */ | ||||||
|  |     XK_Eisu_Shift:                  0xff2f, /* Alphanumeric Shift */ | ||||||
|  |     XK_Eisu_toggle:                 0xff30, /* Alphanumeric toggle */ | ||||||
|  |     XK_Kanji_Bangou:                0xff37, /* Codeinput */ | ||||||
|  |     XK_Zen_Koho:                    0xff3d, /* Multiple/All Candidate(s) */ | ||||||
|  |     XK_Mae_Koho:                    0xff3e, /* Previous Candidate */ | ||||||
|  |  | ||||||
|  |     /* 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 */ | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Keyboard (XKB) Extension function and modifier keys | ||||||
|  |      * (from Appendix C of "The X Keyboard Extension: Protocol Specification") | ||||||
|  |      * Byte 3 = 0xfe | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     XK_ISO_Level3_Shift:            0xfe03, /* AltGr */ | ||||||
|  |     XK_ISO_Next_Group:              0xfe08, | ||||||
|  |     XK_ISO_Prev_Group:              0xfe0a, | ||||||
|  |     XK_ISO_First_Group:             0xfe0c, | ||||||
|  |     XK_ISO_Last_Group:              0xfe0e, | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * 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 */ | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Korean | ||||||
|  |      * Byte 3 = 0x0e | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     XK_Hangul:                      0xff31, /* Hangul start/stop(toggle) */ | ||||||
|  |     XK_Hangul_Hanja:                0xff34, /* Start Hangul->Hanja Conversion */ | ||||||
|  |     XK_Hangul_Jeonja:               0xff38, /* Jeonja mode */ | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * XFree86 vendor specific keysyms. | ||||||
|  |      * | ||||||
|  |      * The XFree86 keysym range is 0x10080001 - 0x1008FFFF. | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     XF86XK_ModeLock:                0x1008FF01, | ||||||
|  |     XF86XK_MonBrightnessUp:         0x1008FF02, | ||||||
|  |     XF86XK_MonBrightnessDown:       0x1008FF03, | ||||||
|  |     XF86XK_KbdLightOnOff:           0x1008FF04, | ||||||
|  |     XF86XK_KbdBrightnessUp:         0x1008FF05, | ||||||
|  |     XF86XK_KbdBrightnessDown:       0x1008FF06, | ||||||
|  |     XF86XK_Standby:                 0x1008FF10, | ||||||
|  |     XF86XK_AudioLowerVolume:        0x1008FF11, | ||||||
|  |     XF86XK_AudioMute:               0x1008FF12, | ||||||
|  |     XF86XK_AudioRaiseVolume:        0x1008FF13, | ||||||
|  |     XF86XK_AudioPlay:               0x1008FF14, | ||||||
|  |     XF86XK_AudioStop:               0x1008FF15, | ||||||
|  |     XF86XK_AudioPrev:               0x1008FF16, | ||||||
|  |     XF86XK_AudioNext:               0x1008FF17, | ||||||
|  |     XF86XK_HomePage:                0x1008FF18, | ||||||
|  |     XF86XK_Mail:                    0x1008FF19, | ||||||
|  |     XF86XK_Start:                   0x1008FF1A, | ||||||
|  |     XF86XK_Search:                  0x1008FF1B, | ||||||
|  |     XF86XK_AudioRecord:             0x1008FF1C, | ||||||
|  |     XF86XK_Calculator:              0x1008FF1D, | ||||||
|  |     XF86XK_Memo:                    0x1008FF1E, | ||||||
|  |     XF86XK_ToDoList:                0x1008FF1F, | ||||||
|  |     XF86XK_Calendar:                0x1008FF20, | ||||||
|  |     XF86XK_PowerDown:               0x1008FF21, | ||||||
|  |     XF86XK_ContrastAdjust:          0x1008FF22, | ||||||
|  |     XF86XK_RockerUp:                0x1008FF23, | ||||||
|  |     XF86XK_RockerDown:              0x1008FF24, | ||||||
|  |     XF86XK_RockerEnter:             0x1008FF25, | ||||||
|  |     XF86XK_Back:                    0x1008FF26, | ||||||
|  |     XF86XK_Forward:                 0x1008FF27, | ||||||
|  |     XF86XK_Stop:                    0x1008FF28, | ||||||
|  |     XF86XK_Refresh:                 0x1008FF29, | ||||||
|  |     XF86XK_PowerOff:                0x1008FF2A, | ||||||
|  |     XF86XK_WakeUp:                  0x1008FF2B, | ||||||
|  |     XF86XK_Eject:                   0x1008FF2C, | ||||||
|  |     XF86XK_ScreenSaver:             0x1008FF2D, | ||||||
|  |     XF86XK_WWW:                     0x1008FF2E, | ||||||
|  |     XF86XK_Sleep:                   0x1008FF2F, | ||||||
|  |     XF86XK_Favorites:               0x1008FF30, | ||||||
|  |     XF86XK_AudioPause:              0x1008FF31, | ||||||
|  |     XF86XK_AudioMedia:              0x1008FF32, | ||||||
|  |     XF86XK_MyComputer:              0x1008FF33, | ||||||
|  |     XF86XK_VendorHome:              0x1008FF34, | ||||||
|  |     XF86XK_LightBulb:               0x1008FF35, | ||||||
|  |     XF86XK_Shop:                    0x1008FF36, | ||||||
|  |     XF86XK_History:                 0x1008FF37, | ||||||
|  |     XF86XK_OpenURL:                 0x1008FF38, | ||||||
|  |     XF86XK_AddFavorite:             0x1008FF39, | ||||||
|  |     XF86XK_HotLinks:                0x1008FF3A, | ||||||
|  |     XF86XK_BrightnessAdjust:        0x1008FF3B, | ||||||
|  |     XF86XK_Finance:                 0x1008FF3C, | ||||||
|  |     XF86XK_Community:               0x1008FF3D, | ||||||
|  |     XF86XK_AudioRewind:             0x1008FF3E, | ||||||
|  |     XF86XK_BackForward:             0x1008FF3F, | ||||||
|  |     XF86XK_Launch0:                 0x1008FF40, | ||||||
|  |     XF86XK_Launch1:                 0x1008FF41, | ||||||
|  |     XF86XK_Launch2:                 0x1008FF42, | ||||||
|  |     XF86XK_Launch3:                 0x1008FF43, | ||||||
|  |     XF86XK_Launch4:                 0x1008FF44, | ||||||
|  |     XF86XK_Launch5:                 0x1008FF45, | ||||||
|  |     XF86XK_Launch6:                 0x1008FF46, | ||||||
|  |     XF86XK_Launch7:                 0x1008FF47, | ||||||
|  |     XF86XK_Launch8:                 0x1008FF48, | ||||||
|  |     XF86XK_Launch9:                 0x1008FF49, | ||||||
|  |     XF86XK_LaunchA:                 0x1008FF4A, | ||||||
|  |     XF86XK_LaunchB:                 0x1008FF4B, | ||||||
|  |     XF86XK_LaunchC:                 0x1008FF4C, | ||||||
|  |     XF86XK_LaunchD:                 0x1008FF4D, | ||||||
|  |     XF86XK_LaunchE:                 0x1008FF4E, | ||||||
|  |     XF86XK_LaunchF:                 0x1008FF4F, | ||||||
|  |     XF86XK_ApplicationLeft:         0x1008FF50, | ||||||
|  |     XF86XK_ApplicationRight:        0x1008FF51, | ||||||
|  |     XF86XK_Book:                    0x1008FF52, | ||||||
|  |     XF86XK_CD:                      0x1008FF53, | ||||||
|  |     XF86XK_Calculater:              0x1008FF54, | ||||||
|  |     XF86XK_Clear:                   0x1008FF55, | ||||||
|  |     XF86XK_Close:                   0x1008FF56, | ||||||
|  |     XF86XK_Copy:                    0x1008FF57, | ||||||
|  |     XF86XK_Cut:                     0x1008FF58, | ||||||
|  |     XF86XK_Display:                 0x1008FF59, | ||||||
|  |     XF86XK_DOS:                     0x1008FF5A, | ||||||
|  |     XF86XK_Documents:               0x1008FF5B, | ||||||
|  |     XF86XK_Excel:                   0x1008FF5C, | ||||||
|  |     XF86XK_Explorer:                0x1008FF5D, | ||||||
|  |     XF86XK_Game:                    0x1008FF5E, | ||||||
|  |     XF86XK_Go:                      0x1008FF5F, | ||||||
|  |     XF86XK_iTouch:                  0x1008FF60, | ||||||
|  |     XF86XK_LogOff:                  0x1008FF61, | ||||||
|  |     XF86XK_Market:                  0x1008FF62, | ||||||
|  |     XF86XK_Meeting:                 0x1008FF63, | ||||||
|  |     XF86XK_MenuKB:                  0x1008FF65, | ||||||
|  |     XF86XK_MenuPB:                  0x1008FF66, | ||||||
|  |     XF86XK_MySites:                 0x1008FF67, | ||||||
|  |     XF86XK_New:                     0x1008FF68, | ||||||
|  |     XF86XK_News:                    0x1008FF69, | ||||||
|  |     XF86XK_OfficeHome:              0x1008FF6A, | ||||||
|  |     XF86XK_Open:                    0x1008FF6B, | ||||||
|  |     XF86XK_Option:                  0x1008FF6C, | ||||||
|  |     XF86XK_Paste:                   0x1008FF6D, | ||||||
|  |     XF86XK_Phone:                   0x1008FF6E, | ||||||
|  |     XF86XK_Q:                       0x1008FF70, | ||||||
|  |     XF86XK_Reply:                   0x1008FF72, | ||||||
|  |     XF86XK_Reload:                  0x1008FF73, | ||||||
|  |     XF86XK_RotateWindows:           0x1008FF74, | ||||||
|  |     XF86XK_RotationPB:              0x1008FF75, | ||||||
|  |     XF86XK_RotationKB:              0x1008FF76, | ||||||
|  |     XF86XK_Save:                    0x1008FF77, | ||||||
|  |     XF86XK_ScrollUp:                0x1008FF78, | ||||||
|  |     XF86XK_ScrollDown:              0x1008FF79, | ||||||
|  |     XF86XK_ScrollClick:             0x1008FF7A, | ||||||
|  |     XF86XK_Send:                    0x1008FF7B, | ||||||
|  |     XF86XK_Spell:                   0x1008FF7C, | ||||||
|  |     XF86XK_SplitScreen:             0x1008FF7D, | ||||||
|  |     XF86XK_Support:                 0x1008FF7E, | ||||||
|  |     XF86XK_TaskPane:                0x1008FF7F, | ||||||
|  |     XF86XK_Terminal:                0x1008FF80, | ||||||
|  |     XF86XK_Tools:                   0x1008FF81, | ||||||
|  |     XF86XK_Travel:                  0x1008FF82, | ||||||
|  |     XF86XK_UserPB:                  0x1008FF84, | ||||||
|  |     XF86XK_User1KB:                 0x1008FF85, | ||||||
|  |     XF86XK_User2KB:                 0x1008FF86, | ||||||
|  |     XF86XK_Video:                   0x1008FF87, | ||||||
|  |     XF86XK_WheelButton:             0x1008FF88, | ||||||
|  |     XF86XK_Word:                    0x1008FF89, | ||||||
|  |     XF86XK_Xfer:                    0x1008FF8A, | ||||||
|  |     XF86XK_ZoomIn:                  0x1008FF8B, | ||||||
|  |     XF86XK_ZoomOut:                 0x1008FF8C, | ||||||
|  |     XF86XK_Away:                    0x1008FF8D, | ||||||
|  |     XF86XK_Messenger:               0x1008FF8E, | ||||||
|  |     XF86XK_WebCam:                  0x1008FF8F, | ||||||
|  |     XF86XK_MailForward:             0x1008FF90, | ||||||
|  |     XF86XK_Pictures:                0x1008FF91, | ||||||
|  |     XF86XK_Music:                   0x1008FF92, | ||||||
|  |     XF86XK_Battery:                 0x1008FF93, | ||||||
|  |     XF86XK_Bluetooth:               0x1008FF94, | ||||||
|  |     XF86XK_WLAN:                    0x1008FF95, | ||||||
|  |     XF86XK_UWB:                     0x1008FF96, | ||||||
|  |     XF86XK_AudioForward:            0x1008FF97, | ||||||
|  |     XF86XK_AudioRepeat:             0x1008FF98, | ||||||
|  |     XF86XK_AudioRandomPlay:         0x1008FF99, | ||||||
|  |     XF86XK_Subtitle:                0x1008FF9A, | ||||||
|  |     XF86XK_AudioCycleTrack:         0x1008FF9B, | ||||||
|  |     XF86XK_CycleAngle:              0x1008FF9C, | ||||||
|  |     XF86XK_FrameBack:               0x1008FF9D, | ||||||
|  |     XF86XK_FrameForward:            0x1008FF9E, | ||||||
|  |     XF86XK_Time:                    0x1008FF9F, | ||||||
|  |     XF86XK_Select:                  0x1008FFA0, | ||||||
|  |     XF86XK_View:                    0x1008FFA1, | ||||||
|  |     XF86XK_TopMenu:                 0x1008FFA2, | ||||||
|  |     XF86XK_Red:                     0x1008FFA3, | ||||||
|  |     XF86XK_Green:                   0x1008FFA4, | ||||||
|  |     XF86XK_Yellow:                  0x1008FFA5, | ||||||
|  |     XF86XK_Blue:                    0x1008FFA6, | ||||||
|  |     XF86XK_Suspend:                 0x1008FFA7, | ||||||
|  |     XF86XK_Hibernate:               0x1008FFA8, | ||||||
|  |     XF86XK_TouchpadToggle:          0x1008FFA9, | ||||||
|  |     XF86XK_TouchpadOn:              0x1008FFB0, | ||||||
|  |     XF86XK_TouchpadOff:             0x1008FFB1, | ||||||
|  |     XF86XK_AudioMicMute:            0x1008FFB2, | ||||||
|  |     XF86XK_Switch_VT_1:             0x1008FE01, | ||||||
|  |     XF86XK_Switch_VT_2:             0x1008FE02, | ||||||
|  |     XF86XK_Switch_VT_3:             0x1008FE03, | ||||||
|  |     XF86XK_Switch_VT_4:             0x1008FE04, | ||||||
|  |     XF86XK_Switch_VT_5:             0x1008FE05, | ||||||
|  |     XF86XK_Switch_VT_6:             0x1008FE06, | ||||||
|  |     XF86XK_Switch_VT_7:             0x1008FE07, | ||||||
|  |     XF86XK_Switch_VT_8:             0x1008FE08, | ||||||
|  |     XF86XK_Switch_VT_9:             0x1008FE09, | ||||||
|  |     XF86XK_Switch_VT_10:            0x1008FE0A, | ||||||
|  |     XF86XK_Switch_VT_11:            0x1008FE0B, | ||||||
|  |     XF86XK_Switch_VT_12:            0x1008FE0C, | ||||||
|  |     XF86XK_Ungrab:                  0x1008FE20, | ||||||
|  |     XF86XK_ClearGrab:               0x1008FE21, | ||||||
|  |     XF86XK_Next_VMode:              0x1008FE22, | ||||||
|  |     XF86XK_Prev_VMode:              0x1008FE23, | ||||||
|  |     XF86XK_LogWindowTree:           0x1008FE24, | ||||||
|  |     XF86XK_LogGrabInfo:             0x1008FE25, | ||||||
|  | }; | ||||||
							
								
								
									
										688
									
								
								core/input/keysymdef.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,688 @@ | |||||||
|  | /* | ||||||
|  |  * Mapping from Unicode codepoints to X11/RFB keysyms | ||||||
|  |  * | ||||||
|  |  * This file was automatically generated from keysymdef.h | ||||||
|  |  * DO NOT EDIT! | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* Functions at the bottom */ | ||||||
|  |  | ||||||
|  | const codepoints = { | ||||||
|  |     0x0100: 0x03c0, // XK_Amacron | ||||||
|  |     0x0101: 0x03e0, // XK_amacron | ||||||
|  |     0x0102: 0x01c3, // XK_Abreve | ||||||
|  |     0x0103: 0x01e3, // XK_abreve | ||||||
|  |     0x0104: 0x01a1, // XK_Aogonek | ||||||
|  |     0x0105: 0x01b1, // XK_aogonek | ||||||
|  |     0x0106: 0x01c6, // XK_Cacute | ||||||
|  |     0x0107: 0x01e6, // XK_cacute | ||||||
|  |     0x0108: 0x02c6, // XK_Ccircumflex | ||||||
|  |     0x0109: 0x02e6, // XK_ccircumflex | ||||||
|  |     0x010a: 0x02c5, // XK_Cabovedot | ||||||
|  |     0x010b: 0x02e5, // XK_cabovedot | ||||||
|  |     0x010c: 0x01c8, // XK_Ccaron | ||||||
|  |     0x010d: 0x01e8, // XK_ccaron | ||||||
|  |     0x010e: 0x01cf, // XK_Dcaron | ||||||
|  |     0x010f: 0x01ef, // XK_dcaron | ||||||
|  |     0x0110: 0x01d0, // XK_Dstroke | ||||||
|  |     0x0111: 0x01f0, // XK_dstroke | ||||||
|  |     0x0112: 0x03aa, // XK_Emacron | ||||||
|  |     0x0113: 0x03ba, // XK_emacron | ||||||
|  |     0x0116: 0x03cc, // XK_Eabovedot | ||||||
|  |     0x0117: 0x03ec, // XK_eabovedot | ||||||
|  |     0x0118: 0x01ca, // XK_Eogonek | ||||||
|  |     0x0119: 0x01ea, // XK_eogonek | ||||||
|  |     0x011a: 0x01cc, // XK_Ecaron | ||||||
|  |     0x011b: 0x01ec, // XK_ecaron | ||||||
|  |     0x011c: 0x02d8, // XK_Gcircumflex | ||||||
|  |     0x011d: 0x02f8, // XK_gcircumflex | ||||||
|  |     0x011e: 0x02ab, // XK_Gbreve | ||||||
|  |     0x011f: 0x02bb, // XK_gbreve | ||||||
|  |     0x0120: 0x02d5, // XK_Gabovedot | ||||||
|  |     0x0121: 0x02f5, // XK_gabovedot | ||||||
|  |     0x0122: 0x03ab, // XK_Gcedilla | ||||||
|  |     0x0123: 0x03bb, // XK_gcedilla | ||||||
|  |     0x0124: 0x02a6, // XK_Hcircumflex | ||||||
|  |     0x0125: 0x02b6, // XK_hcircumflex | ||||||
|  |     0x0126: 0x02a1, // XK_Hstroke | ||||||
|  |     0x0127: 0x02b1, // XK_hstroke | ||||||
|  |     0x0128: 0x03a5, // XK_Itilde | ||||||
|  |     0x0129: 0x03b5, // XK_itilde | ||||||
|  |     0x012a: 0x03cf, // XK_Imacron | ||||||
|  |     0x012b: 0x03ef, // XK_imacron | ||||||
|  |     0x012e: 0x03c7, // XK_Iogonek | ||||||
|  |     0x012f: 0x03e7, // XK_iogonek | ||||||
|  |     0x0130: 0x02a9, // XK_Iabovedot | ||||||
|  |     0x0131: 0x02b9, // XK_idotless | ||||||
|  |     0x0134: 0x02ac, // XK_Jcircumflex | ||||||
|  |     0x0135: 0x02bc, // XK_jcircumflex | ||||||
|  |     0x0136: 0x03d3, // XK_Kcedilla | ||||||
|  |     0x0137: 0x03f3, // XK_kcedilla | ||||||
|  |     0x0138: 0x03a2, // XK_kra | ||||||
|  |     0x0139: 0x01c5, // XK_Lacute | ||||||
|  |     0x013a: 0x01e5, // XK_lacute | ||||||
|  |     0x013b: 0x03a6, // XK_Lcedilla | ||||||
|  |     0x013c: 0x03b6, // XK_lcedilla | ||||||
|  |     0x013d: 0x01a5, // XK_Lcaron | ||||||
|  |     0x013e: 0x01b5, // XK_lcaron | ||||||
|  |     0x0141: 0x01a3, // XK_Lstroke | ||||||
|  |     0x0142: 0x01b3, // XK_lstroke | ||||||
|  |     0x0143: 0x01d1, // XK_Nacute | ||||||
|  |     0x0144: 0x01f1, // XK_nacute | ||||||
|  |     0x0145: 0x03d1, // XK_Ncedilla | ||||||
|  |     0x0146: 0x03f1, // XK_ncedilla | ||||||
|  |     0x0147: 0x01d2, // XK_Ncaron | ||||||
|  |     0x0148: 0x01f2, // XK_ncaron | ||||||
|  |     0x014a: 0x03bd, // XK_ENG | ||||||
|  |     0x014b: 0x03bf, // XK_eng | ||||||
|  |     0x014c: 0x03d2, // XK_Omacron | ||||||
|  |     0x014d: 0x03f2, // XK_omacron | ||||||
|  |     0x0150: 0x01d5, // XK_Odoubleacute | ||||||
|  |     0x0151: 0x01f5, // XK_odoubleacute | ||||||
|  |     0x0152: 0x13bc, // XK_OE | ||||||
|  |     0x0153: 0x13bd, // XK_oe | ||||||
|  |     0x0154: 0x01c0, // XK_Racute | ||||||
|  |     0x0155: 0x01e0, // XK_racute | ||||||
|  |     0x0156: 0x03a3, // XK_Rcedilla | ||||||
|  |     0x0157: 0x03b3, // XK_rcedilla | ||||||
|  |     0x0158: 0x01d8, // XK_Rcaron | ||||||
|  |     0x0159: 0x01f8, // XK_rcaron | ||||||
|  |     0x015a: 0x01a6, // XK_Sacute | ||||||
|  |     0x015b: 0x01b6, // XK_sacute | ||||||
|  |     0x015c: 0x02de, // XK_Scircumflex | ||||||
|  |     0x015d: 0x02fe, // XK_scircumflex | ||||||
|  |     0x015e: 0x01aa, // XK_Scedilla | ||||||
|  |     0x015f: 0x01ba, // XK_scedilla | ||||||
|  |     0x0160: 0x01a9, // XK_Scaron | ||||||
|  |     0x0161: 0x01b9, // XK_scaron | ||||||
|  |     0x0162: 0x01de, // XK_Tcedilla | ||||||
|  |     0x0163: 0x01fe, // XK_tcedilla | ||||||
|  |     0x0164: 0x01ab, // XK_Tcaron | ||||||
|  |     0x0165: 0x01bb, // XK_tcaron | ||||||
|  |     0x0166: 0x03ac, // XK_Tslash | ||||||
|  |     0x0167: 0x03bc, // XK_tslash | ||||||
|  |     0x0168: 0x03dd, // XK_Utilde | ||||||
|  |     0x0169: 0x03fd, // XK_utilde | ||||||
|  |     0x016a: 0x03de, // XK_Umacron | ||||||
|  |     0x016b: 0x03fe, // XK_umacron | ||||||
|  |     0x016c: 0x02dd, // XK_Ubreve | ||||||
|  |     0x016d: 0x02fd, // XK_ubreve | ||||||
|  |     0x016e: 0x01d9, // XK_Uring | ||||||
|  |     0x016f: 0x01f9, // XK_uring | ||||||
|  |     0x0170: 0x01db, // XK_Udoubleacute | ||||||
|  |     0x0171: 0x01fb, // XK_udoubleacute | ||||||
|  |     0x0172: 0x03d9, // XK_Uogonek | ||||||
|  |     0x0173: 0x03f9, // XK_uogonek | ||||||
|  |     0x0178: 0x13be, // XK_Ydiaeresis | ||||||
|  |     0x0179: 0x01ac, // XK_Zacute | ||||||
|  |     0x017a: 0x01bc, // XK_zacute | ||||||
|  |     0x017b: 0x01af, // XK_Zabovedot | ||||||
|  |     0x017c: 0x01bf, // XK_zabovedot | ||||||
|  |     0x017d: 0x01ae, // XK_Zcaron | ||||||
|  |     0x017e: 0x01be, // XK_zcaron | ||||||
|  |     0x0192: 0x08f6, // XK_function | ||||||
|  |     0x01d2: 0x10001d1, // XK_Ocaron | ||||||
|  |     0x02c7: 0x01b7, // XK_caron | ||||||
|  |     0x02d8: 0x01a2, // XK_breve | ||||||
|  |     0x02d9: 0x01ff, // XK_abovedot | ||||||
|  |     0x02db: 0x01b2, // XK_ogonek | ||||||
|  |     0x02dd: 0x01bd, // XK_doubleacute | ||||||
|  |     0x0385: 0x07ae, // XK_Greek_accentdieresis | ||||||
|  |     0x0386: 0x07a1, // XK_Greek_ALPHAaccent | ||||||
|  |     0x0388: 0x07a2, // XK_Greek_EPSILONaccent | ||||||
|  |     0x0389: 0x07a3, // XK_Greek_ETAaccent | ||||||
|  |     0x038a: 0x07a4, // XK_Greek_IOTAaccent | ||||||
|  |     0x038c: 0x07a7, // XK_Greek_OMICRONaccent | ||||||
|  |     0x038e: 0x07a8, // XK_Greek_UPSILONaccent | ||||||
|  |     0x038f: 0x07ab, // XK_Greek_OMEGAaccent | ||||||
|  |     0x0390: 0x07b6, // XK_Greek_iotaaccentdieresis | ||||||
|  |     0x0391: 0x07c1, // XK_Greek_ALPHA | ||||||
|  |     0x0392: 0x07c2, // XK_Greek_BETA | ||||||
|  |     0x0393: 0x07c3, // XK_Greek_GAMMA | ||||||
|  |     0x0394: 0x07c4, // XK_Greek_DELTA | ||||||
|  |     0x0395: 0x07c5, // XK_Greek_EPSILON | ||||||
|  |     0x0396: 0x07c6, // XK_Greek_ZETA | ||||||
|  |     0x0397: 0x07c7, // XK_Greek_ETA | ||||||
|  |     0x0398: 0x07c8, // XK_Greek_THETA | ||||||
|  |     0x0399: 0x07c9, // XK_Greek_IOTA | ||||||
|  |     0x039a: 0x07ca, // XK_Greek_KAPPA | ||||||
|  |     0x039b: 0x07cb, // XK_Greek_LAMDA | ||||||
|  |     0x039c: 0x07cc, // XK_Greek_MU | ||||||
|  |     0x039d: 0x07cd, // XK_Greek_NU | ||||||
|  |     0x039e: 0x07ce, // XK_Greek_XI | ||||||
|  |     0x039f: 0x07cf, // XK_Greek_OMICRON | ||||||
|  |     0x03a0: 0x07d0, // XK_Greek_PI | ||||||
|  |     0x03a1: 0x07d1, // XK_Greek_RHO | ||||||
|  |     0x03a3: 0x07d2, // XK_Greek_SIGMA | ||||||
|  |     0x03a4: 0x07d4, // XK_Greek_TAU | ||||||
|  |     0x03a5: 0x07d5, // XK_Greek_UPSILON | ||||||
|  |     0x03a6: 0x07d6, // XK_Greek_PHI | ||||||
|  |     0x03a7: 0x07d7, // XK_Greek_CHI | ||||||
|  |     0x03a8: 0x07d8, // XK_Greek_PSI | ||||||
|  |     0x03a9: 0x07d9, // XK_Greek_OMEGA | ||||||
|  |     0x03aa: 0x07a5, // XK_Greek_IOTAdieresis | ||||||
|  |     0x03ab: 0x07a9, // XK_Greek_UPSILONdieresis | ||||||
|  |     0x03ac: 0x07b1, // XK_Greek_alphaaccent | ||||||
|  |     0x03ad: 0x07b2, // XK_Greek_epsilonaccent | ||||||
|  |     0x03ae: 0x07b3, // XK_Greek_etaaccent | ||||||
|  |     0x03af: 0x07b4, // XK_Greek_iotaaccent | ||||||
|  |     0x03b0: 0x07ba, // XK_Greek_upsilonaccentdieresis | ||||||
|  |     0x03b1: 0x07e1, // XK_Greek_alpha | ||||||
|  |     0x03b2: 0x07e2, // XK_Greek_beta | ||||||
|  |     0x03b3: 0x07e3, // XK_Greek_gamma | ||||||
|  |     0x03b4: 0x07e4, // XK_Greek_delta | ||||||
|  |     0x03b5: 0x07e5, // XK_Greek_epsilon | ||||||
|  |     0x03b6: 0x07e6, // XK_Greek_zeta | ||||||
|  |     0x03b7: 0x07e7, // XK_Greek_eta | ||||||
|  |     0x03b8: 0x07e8, // XK_Greek_theta | ||||||
|  |     0x03b9: 0x07e9, // XK_Greek_iota | ||||||
|  |     0x03ba: 0x07ea, // XK_Greek_kappa | ||||||
|  |     0x03bb: 0x07eb, // XK_Greek_lamda | ||||||
|  |     0x03bc: 0x07ec, // XK_Greek_mu | ||||||
|  |     0x03bd: 0x07ed, // XK_Greek_nu | ||||||
|  |     0x03be: 0x07ee, // XK_Greek_xi | ||||||
|  |     0x03bf: 0x07ef, // XK_Greek_omicron | ||||||
|  |     0x03c0: 0x07f0, // XK_Greek_pi | ||||||
|  |     0x03c1: 0x07f1, // XK_Greek_rho | ||||||
|  |     0x03c2: 0x07f3, // XK_Greek_finalsmallsigma | ||||||
|  |     0x03c3: 0x07f2, // XK_Greek_sigma | ||||||
|  |     0x03c4: 0x07f4, // XK_Greek_tau | ||||||
|  |     0x03c5: 0x07f5, // XK_Greek_upsilon | ||||||
|  |     0x03c6: 0x07f6, // XK_Greek_phi | ||||||
|  |     0x03c7: 0x07f7, // XK_Greek_chi | ||||||
|  |     0x03c8: 0x07f8, // XK_Greek_psi | ||||||
|  |     0x03c9: 0x07f9, // XK_Greek_omega | ||||||
|  |     0x03ca: 0x07b5, // XK_Greek_iotadieresis | ||||||
|  |     0x03cb: 0x07b9, // XK_Greek_upsilondieresis | ||||||
|  |     0x03cc: 0x07b7, // XK_Greek_omicronaccent | ||||||
|  |     0x03cd: 0x07b8, // XK_Greek_upsilonaccent | ||||||
|  |     0x03ce: 0x07bb, // XK_Greek_omegaaccent | ||||||
|  |     0x0401: 0x06b3, // XK_Cyrillic_IO | ||||||
|  |     0x0402: 0x06b1, // XK_Serbian_DJE | ||||||
|  |     0x0403: 0x06b2, // XK_Macedonia_GJE | ||||||
|  |     0x0404: 0x06b4, // XK_Ukrainian_IE | ||||||
|  |     0x0405: 0x06b5, // XK_Macedonia_DSE | ||||||
|  |     0x0406: 0x06b6, // XK_Ukrainian_I | ||||||
|  |     0x0407: 0x06b7, // XK_Ukrainian_YI | ||||||
|  |     0x0408: 0x06b8, // XK_Cyrillic_JE | ||||||
|  |     0x0409: 0x06b9, // XK_Cyrillic_LJE | ||||||
|  |     0x040a: 0x06ba, // XK_Cyrillic_NJE | ||||||
|  |     0x040b: 0x06bb, // XK_Serbian_TSHE | ||||||
|  |     0x040c: 0x06bc, // XK_Macedonia_KJE | ||||||
|  |     0x040e: 0x06be, // XK_Byelorussian_SHORTU | ||||||
|  |     0x040f: 0x06bf, // XK_Cyrillic_DZHE | ||||||
|  |     0x0410: 0x06e1, // XK_Cyrillic_A | ||||||
|  |     0x0411: 0x06e2, // XK_Cyrillic_BE | ||||||
|  |     0x0412: 0x06f7, // XK_Cyrillic_VE | ||||||
|  |     0x0413: 0x06e7, // XK_Cyrillic_GHE | ||||||
|  |     0x0414: 0x06e4, // XK_Cyrillic_DE | ||||||
|  |     0x0415: 0x06e5, // XK_Cyrillic_IE | ||||||
|  |     0x0416: 0x06f6, // XK_Cyrillic_ZHE | ||||||
|  |     0x0417: 0x06fa, // XK_Cyrillic_ZE | ||||||
|  |     0x0418: 0x06e9, // XK_Cyrillic_I | ||||||
|  |     0x0419: 0x06ea, // XK_Cyrillic_SHORTI | ||||||
|  |     0x041a: 0x06eb, // XK_Cyrillic_KA | ||||||
|  |     0x041b: 0x06ec, // XK_Cyrillic_EL | ||||||
|  |     0x041c: 0x06ed, // XK_Cyrillic_EM | ||||||
|  |     0x041d: 0x06ee, // XK_Cyrillic_EN | ||||||
|  |     0x041e: 0x06ef, // XK_Cyrillic_O | ||||||
|  |     0x041f: 0x06f0, // XK_Cyrillic_PE | ||||||
|  |     0x0420: 0x06f2, // XK_Cyrillic_ER | ||||||
|  |     0x0421: 0x06f3, // XK_Cyrillic_ES | ||||||
|  |     0x0422: 0x06f4, // XK_Cyrillic_TE | ||||||
|  |     0x0423: 0x06f5, // XK_Cyrillic_U | ||||||
|  |     0x0424: 0x06e6, // XK_Cyrillic_EF | ||||||
|  |     0x0425: 0x06e8, // XK_Cyrillic_HA | ||||||
|  |     0x0426: 0x06e3, // XK_Cyrillic_TSE | ||||||
|  |     0x0427: 0x06fe, // XK_Cyrillic_CHE | ||||||
|  |     0x0428: 0x06fb, // XK_Cyrillic_SHA | ||||||
|  |     0x0429: 0x06fd, // XK_Cyrillic_SHCHA | ||||||
|  |     0x042a: 0x06ff, // XK_Cyrillic_HARDSIGN | ||||||
|  |     0x042b: 0x06f9, // XK_Cyrillic_YERU | ||||||
|  |     0x042c: 0x06f8, // XK_Cyrillic_SOFTSIGN | ||||||
|  |     0x042d: 0x06fc, // XK_Cyrillic_E | ||||||
|  |     0x042e: 0x06e0, // XK_Cyrillic_YU | ||||||
|  |     0x042f: 0x06f1, // XK_Cyrillic_YA | ||||||
|  |     0x0430: 0x06c1, // XK_Cyrillic_a | ||||||
|  |     0x0431: 0x06c2, // XK_Cyrillic_be | ||||||
|  |     0x0432: 0x06d7, // XK_Cyrillic_ve | ||||||
|  |     0x0433: 0x06c7, // XK_Cyrillic_ghe | ||||||
|  |     0x0434: 0x06c4, // XK_Cyrillic_de | ||||||
|  |     0x0435: 0x06c5, // XK_Cyrillic_ie | ||||||
|  |     0x0436: 0x06d6, // XK_Cyrillic_zhe | ||||||
|  |     0x0437: 0x06da, // XK_Cyrillic_ze | ||||||
|  |     0x0438: 0x06c9, // XK_Cyrillic_i | ||||||
|  |     0x0439: 0x06ca, // XK_Cyrillic_shorti | ||||||
|  |     0x043a: 0x06cb, // XK_Cyrillic_ka | ||||||
|  |     0x043b: 0x06cc, // XK_Cyrillic_el | ||||||
|  |     0x043c: 0x06cd, // XK_Cyrillic_em | ||||||
|  |     0x043d: 0x06ce, // XK_Cyrillic_en | ||||||
|  |     0x043e: 0x06cf, // XK_Cyrillic_o | ||||||
|  |     0x043f: 0x06d0, // XK_Cyrillic_pe | ||||||
|  |     0x0440: 0x06d2, // XK_Cyrillic_er | ||||||
|  |     0x0441: 0x06d3, // XK_Cyrillic_es | ||||||
|  |     0x0442: 0x06d4, // XK_Cyrillic_te | ||||||
|  |     0x0443: 0x06d5, // XK_Cyrillic_u | ||||||
|  |     0x0444: 0x06c6, // XK_Cyrillic_ef | ||||||
|  |     0x0445: 0x06c8, // XK_Cyrillic_ha | ||||||
|  |     0x0446: 0x06c3, // XK_Cyrillic_tse | ||||||
|  |     0x0447: 0x06de, // XK_Cyrillic_che | ||||||
|  |     0x0448: 0x06db, // XK_Cyrillic_sha | ||||||
|  |     0x0449: 0x06dd, // XK_Cyrillic_shcha | ||||||
|  |     0x044a: 0x06df, // XK_Cyrillic_hardsign | ||||||
|  |     0x044b: 0x06d9, // XK_Cyrillic_yeru | ||||||
|  |     0x044c: 0x06d8, // XK_Cyrillic_softsign | ||||||
|  |     0x044d: 0x06dc, // XK_Cyrillic_e | ||||||
|  |     0x044e: 0x06c0, // XK_Cyrillic_yu | ||||||
|  |     0x044f: 0x06d1, // XK_Cyrillic_ya | ||||||
|  |     0x0451: 0x06a3, // XK_Cyrillic_io | ||||||
|  |     0x0452: 0x06a1, // XK_Serbian_dje | ||||||
|  |     0x0453: 0x06a2, // XK_Macedonia_gje | ||||||
|  |     0x0454: 0x06a4, // XK_Ukrainian_ie | ||||||
|  |     0x0455: 0x06a5, // XK_Macedonia_dse | ||||||
|  |     0x0456: 0x06a6, // XK_Ukrainian_i | ||||||
|  |     0x0457: 0x06a7, // XK_Ukrainian_yi | ||||||
|  |     0x0458: 0x06a8, // XK_Cyrillic_je | ||||||
|  |     0x0459: 0x06a9, // XK_Cyrillic_lje | ||||||
|  |     0x045a: 0x06aa, // XK_Cyrillic_nje | ||||||
|  |     0x045b: 0x06ab, // XK_Serbian_tshe | ||||||
|  |     0x045c: 0x06ac, // XK_Macedonia_kje | ||||||
|  |     0x045e: 0x06ae, // XK_Byelorussian_shortu | ||||||
|  |     0x045f: 0x06af, // XK_Cyrillic_dzhe | ||||||
|  |     0x0490: 0x06bd, // XK_Ukrainian_GHE_WITH_UPTURN | ||||||
|  |     0x0491: 0x06ad, // XK_Ukrainian_ghe_with_upturn | ||||||
|  |     0x05d0: 0x0ce0, // XK_hebrew_aleph | ||||||
|  |     0x05d1: 0x0ce1, // XK_hebrew_bet | ||||||
|  |     0x05d2: 0x0ce2, // XK_hebrew_gimel | ||||||
|  |     0x05d3: 0x0ce3, // XK_hebrew_dalet | ||||||
|  |     0x05d4: 0x0ce4, // XK_hebrew_he | ||||||
|  |     0x05d5: 0x0ce5, // XK_hebrew_waw | ||||||
|  |     0x05d6: 0x0ce6, // XK_hebrew_zain | ||||||
|  |     0x05d7: 0x0ce7, // XK_hebrew_chet | ||||||
|  |     0x05d8: 0x0ce8, // XK_hebrew_tet | ||||||
|  |     0x05d9: 0x0ce9, // XK_hebrew_yod | ||||||
|  |     0x05da: 0x0cea, // XK_hebrew_finalkaph | ||||||
|  |     0x05db: 0x0ceb, // XK_hebrew_kaph | ||||||
|  |     0x05dc: 0x0cec, // XK_hebrew_lamed | ||||||
|  |     0x05dd: 0x0ced, // XK_hebrew_finalmem | ||||||
|  |     0x05de: 0x0cee, // XK_hebrew_mem | ||||||
|  |     0x05df: 0x0cef, // XK_hebrew_finalnun | ||||||
|  |     0x05e0: 0x0cf0, // XK_hebrew_nun | ||||||
|  |     0x05e1: 0x0cf1, // XK_hebrew_samech | ||||||
|  |     0x05e2: 0x0cf2, // XK_hebrew_ayin | ||||||
|  |     0x05e3: 0x0cf3, // XK_hebrew_finalpe | ||||||
|  |     0x05e4: 0x0cf4, // XK_hebrew_pe | ||||||
|  |     0x05e5: 0x0cf5, // XK_hebrew_finalzade | ||||||
|  |     0x05e6: 0x0cf6, // XK_hebrew_zade | ||||||
|  |     0x05e7: 0x0cf7, // XK_hebrew_qoph | ||||||
|  |     0x05e8: 0x0cf8, // XK_hebrew_resh | ||||||
|  |     0x05e9: 0x0cf9, // XK_hebrew_shin | ||||||
|  |     0x05ea: 0x0cfa, // XK_hebrew_taw | ||||||
|  |     0x060c: 0x05ac, // XK_Arabic_comma | ||||||
|  |     0x061b: 0x05bb, // XK_Arabic_semicolon | ||||||
|  |     0x061f: 0x05bf, // XK_Arabic_question_mark | ||||||
|  |     0x0621: 0x05c1, // XK_Arabic_hamza | ||||||
|  |     0x0622: 0x05c2, // XK_Arabic_maddaonalef | ||||||
|  |     0x0623: 0x05c3, // XK_Arabic_hamzaonalef | ||||||
|  |     0x0624: 0x05c4, // XK_Arabic_hamzaonwaw | ||||||
|  |     0x0625: 0x05c5, // XK_Arabic_hamzaunderalef | ||||||
|  |     0x0626: 0x05c6, // XK_Arabic_hamzaonyeh | ||||||
|  |     0x0627: 0x05c7, // XK_Arabic_alef | ||||||
|  |     0x0628: 0x05c8, // XK_Arabic_beh | ||||||
|  |     0x0629: 0x05c9, // XK_Arabic_tehmarbuta | ||||||
|  |     0x062a: 0x05ca, // XK_Arabic_teh | ||||||
|  |     0x062b: 0x05cb, // XK_Arabic_theh | ||||||
|  |     0x062c: 0x05cc, // XK_Arabic_jeem | ||||||
|  |     0x062d: 0x05cd, // XK_Arabic_hah | ||||||
|  |     0x062e: 0x05ce, // XK_Arabic_khah | ||||||
|  |     0x062f: 0x05cf, // XK_Arabic_dal | ||||||
|  |     0x0630: 0x05d0, // XK_Arabic_thal | ||||||
|  |     0x0631: 0x05d1, // XK_Arabic_ra | ||||||
|  |     0x0632: 0x05d2, // XK_Arabic_zain | ||||||
|  |     0x0633: 0x05d3, // XK_Arabic_seen | ||||||
|  |     0x0634: 0x05d4, // XK_Arabic_sheen | ||||||
|  |     0x0635: 0x05d5, // XK_Arabic_sad | ||||||
|  |     0x0636: 0x05d6, // XK_Arabic_dad | ||||||
|  |     0x0637: 0x05d7, // XK_Arabic_tah | ||||||
|  |     0x0638: 0x05d8, // XK_Arabic_zah | ||||||
|  |     0x0639: 0x05d9, // XK_Arabic_ain | ||||||
|  |     0x063a: 0x05da, // XK_Arabic_ghain | ||||||
|  |     0x0640: 0x05e0, // XK_Arabic_tatweel | ||||||
|  |     0x0641: 0x05e1, // XK_Arabic_feh | ||||||
|  |     0x0642: 0x05e2, // XK_Arabic_qaf | ||||||
|  |     0x0643: 0x05e3, // XK_Arabic_kaf | ||||||
|  |     0x0644: 0x05e4, // XK_Arabic_lam | ||||||
|  |     0x0645: 0x05e5, // XK_Arabic_meem | ||||||
|  |     0x0646: 0x05e6, // XK_Arabic_noon | ||||||
|  |     0x0647: 0x05e7, // XK_Arabic_ha | ||||||
|  |     0x0648: 0x05e8, // XK_Arabic_waw | ||||||
|  |     0x0649: 0x05e9, // XK_Arabic_alefmaksura | ||||||
|  |     0x064a: 0x05ea, // XK_Arabic_yeh | ||||||
|  |     0x064b: 0x05eb, // XK_Arabic_fathatan | ||||||
|  |     0x064c: 0x05ec, // XK_Arabic_dammatan | ||||||
|  |     0x064d: 0x05ed, // XK_Arabic_kasratan | ||||||
|  |     0x064e: 0x05ee, // XK_Arabic_fatha | ||||||
|  |     0x064f: 0x05ef, // XK_Arabic_damma | ||||||
|  |     0x0650: 0x05f0, // XK_Arabic_kasra | ||||||
|  |     0x0651: 0x05f1, // XK_Arabic_shadda | ||||||
|  |     0x0652: 0x05f2, // XK_Arabic_sukun | ||||||
|  |     0x0e01: 0x0da1, // XK_Thai_kokai | ||||||
|  |     0x0e02: 0x0da2, // XK_Thai_khokhai | ||||||
|  |     0x0e03: 0x0da3, // XK_Thai_khokhuat | ||||||
|  |     0x0e04: 0x0da4, // XK_Thai_khokhwai | ||||||
|  |     0x0e05: 0x0da5, // XK_Thai_khokhon | ||||||
|  |     0x0e06: 0x0da6, // XK_Thai_khorakhang | ||||||
|  |     0x0e07: 0x0da7, // XK_Thai_ngongu | ||||||
|  |     0x0e08: 0x0da8, // XK_Thai_chochan | ||||||
|  |     0x0e09: 0x0da9, // XK_Thai_choching | ||||||
|  |     0x0e0a: 0x0daa, // XK_Thai_chochang | ||||||
|  |     0x0e0b: 0x0dab, // XK_Thai_soso | ||||||
|  |     0x0e0c: 0x0dac, // XK_Thai_chochoe | ||||||
|  |     0x0e0d: 0x0dad, // XK_Thai_yoying | ||||||
|  |     0x0e0e: 0x0dae, // XK_Thai_dochada | ||||||
|  |     0x0e0f: 0x0daf, // XK_Thai_topatak | ||||||
|  |     0x0e10: 0x0db0, // XK_Thai_thothan | ||||||
|  |     0x0e11: 0x0db1, // XK_Thai_thonangmontho | ||||||
|  |     0x0e12: 0x0db2, // XK_Thai_thophuthao | ||||||
|  |     0x0e13: 0x0db3, // XK_Thai_nonen | ||||||
|  |     0x0e14: 0x0db4, // XK_Thai_dodek | ||||||
|  |     0x0e15: 0x0db5, // XK_Thai_totao | ||||||
|  |     0x0e16: 0x0db6, // XK_Thai_thothung | ||||||
|  |     0x0e17: 0x0db7, // XK_Thai_thothahan | ||||||
|  |     0x0e18: 0x0db8, // XK_Thai_thothong | ||||||
|  |     0x0e19: 0x0db9, // XK_Thai_nonu | ||||||
|  |     0x0e1a: 0x0dba, // XK_Thai_bobaimai | ||||||
|  |     0x0e1b: 0x0dbb, // XK_Thai_popla | ||||||
|  |     0x0e1c: 0x0dbc, // XK_Thai_phophung | ||||||
|  |     0x0e1d: 0x0dbd, // XK_Thai_fofa | ||||||
|  |     0x0e1e: 0x0dbe, // XK_Thai_phophan | ||||||
|  |     0x0e1f: 0x0dbf, // XK_Thai_fofan | ||||||
|  |     0x0e20: 0x0dc0, // XK_Thai_phosamphao | ||||||
|  |     0x0e21: 0x0dc1, // XK_Thai_moma | ||||||
|  |     0x0e22: 0x0dc2, // XK_Thai_yoyak | ||||||
|  |     0x0e23: 0x0dc3, // XK_Thai_rorua | ||||||
|  |     0x0e24: 0x0dc4, // XK_Thai_ru | ||||||
|  |     0x0e25: 0x0dc5, // XK_Thai_loling | ||||||
|  |     0x0e26: 0x0dc6, // XK_Thai_lu | ||||||
|  |     0x0e27: 0x0dc7, // XK_Thai_wowaen | ||||||
|  |     0x0e28: 0x0dc8, // XK_Thai_sosala | ||||||
|  |     0x0e29: 0x0dc9, // XK_Thai_sorusi | ||||||
|  |     0x0e2a: 0x0dca, // XK_Thai_sosua | ||||||
|  |     0x0e2b: 0x0dcb, // XK_Thai_hohip | ||||||
|  |     0x0e2c: 0x0dcc, // XK_Thai_lochula | ||||||
|  |     0x0e2d: 0x0dcd, // XK_Thai_oang | ||||||
|  |     0x0e2e: 0x0dce, // XK_Thai_honokhuk | ||||||
|  |     0x0e2f: 0x0dcf, // XK_Thai_paiyannoi | ||||||
|  |     0x0e30: 0x0dd0, // XK_Thai_saraa | ||||||
|  |     0x0e31: 0x0dd1, // XK_Thai_maihanakat | ||||||
|  |     0x0e32: 0x0dd2, // XK_Thai_saraaa | ||||||
|  |     0x0e33: 0x0dd3, // XK_Thai_saraam | ||||||
|  |     0x0e34: 0x0dd4, // XK_Thai_sarai | ||||||
|  |     0x0e35: 0x0dd5, // XK_Thai_saraii | ||||||
|  |     0x0e36: 0x0dd6, // XK_Thai_saraue | ||||||
|  |     0x0e37: 0x0dd7, // XK_Thai_sarauee | ||||||
|  |     0x0e38: 0x0dd8, // XK_Thai_sarau | ||||||
|  |     0x0e39: 0x0dd9, // XK_Thai_sarauu | ||||||
|  |     0x0e3a: 0x0dda, // XK_Thai_phinthu | ||||||
|  |     0x0e3f: 0x0ddf, // XK_Thai_baht | ||||||
|  |     0x0e40: 0x0de0, // XK_Thai_sarae | ||||||
|  |     0x0e41: 0x0de1, // XK_Thai_saraae | ||||||
|  |     0x0e42: 0x0de2, // XK_Thai_sarao | ||||||
|  |     0x0e43: 0x0de3, // XK_Thai_saraaimaimuan | ||||||
|  |     0x0e44: 0x0de4, // XK_Thai_saraaimaimalai | ||||||
|  |     0x0e45: 0x0de5, // XK_Thai_lakkhangyao | ||||||
|  |     0x0e46: 0x0de6, // XK_Thai_maiyamok | ||||||
|  |     0x0e47: 0x0de7, // XK_Thai_maitaikhu | ||||||
|  |     0x0e48: 0x0de8, // XK_Thai_maiek | ||||||
|  |     0x0e49: 0x0de9, // XK_Thai_maitho | ||||||
|  |     0x0e4a: 0x0dea, // XK_Thai_maitri | ||||||
|  |     0x0e4b: 0x0deb, // XK_Thai_maichattawa | ||||||
|  |     0x0e4c: 0x0dec, // XK_Thai_thanthakhat | ||||||
|  |     0x0e4d: 0x0ded, // XK_Thai_nikhahit | ||||||
|  |     0x0e50: 0x0df0, // XK_Thai_leksun | ||||||
|  |     0x0e51: 0x0df1, // XK_Thai_leknung | ||||||
|  |     0x0e52: 0x0df2, // XK_Thai_leksong | ||||||
|  |     0x0e53: 0x0df3, // XK_Thai_leksam | ||||||
|  |     0x0e54: 0x0df4, // XK_Thai_leksi | ||||||
|  |     0x0e55: 0x0df5, // XK_Thai_lekha | ||||||
|  |     0x0e56: 0x0df6, // XK_Thai_lekhok | ||||||
|  |     0x0e57: 0x0df7, // XK_Thai_lekchet | ||||||
|  |     0x0e58: 0x0df8, // XK_Thai_lekpaet | ||||||
|  |     0x0e59: 0x0df9, // XK_Thai_lekkao | ||||||
|  |     0x2002: 0x0aa2, // XK_enspace | ||||||
|  |     0x2003: 0x0aa1, // XK_emspace | ||||||
|  |     0x2004: 0x0aa3, // XK_em3space | ||||||
|  |     0x2005: 0x0aa4, // XK_em4space | ||||||
|  |     0x2007: 0x0aa5, // XK_digitspace | ||||||
|  |     0x2008: 0x0aa6, // XK_punctspace | ||||||
|  |     0x2009: 0x0aa7, // XK_thinspace | ||||||
|  |     0x200a: 0x0aa8, // XK_hairspace | ||||||
|  |     0x2012: 0x0abb, // XK_figdash | ||||||
|  |     0x2013: 0x0aaa, // XK_endash | ||||||
|  |     0x2014: 0x0aa9, // XK_emdash | ||||||
|  |     0x2015: 0x07af, // XK_Greek_horizbar | ||||||
|  |     0x2017: 0x0cdf, // XK_hebrew_doublelowline | ||||||
|  |     0x2018: 0x0ad0, // XK_leftsinglequotemark | ||||||
|  |     0x2019: 0x0ad1, // XK_rightsinglequotemark | ||||||
|  |     0x201a: 0x0afd, // XK_singlelowquotemark | ||||||
|  |     0x201c: 0x0ad2, // XK_leftdoublequotemark | ||||||
|  |     0x201d: 0x0ad3, // XK_rightdoublequotemark | ||||||
|  |     0x201e: 0x0afe, // XK_doublelowquotemark | ||||||
|  |     0x2020: 0x0af1, // XK_dagger | ||||||
|  |     0x2021: 0x0af2, // XK_doubledagger | ||||||
|  |     0x2022: 0x0ae6, // XK_enfilledcircbullet | ||||||
|  |     0x2025: 0x0aaf, // XK_doubbaselinedot | ||||||
|  |     0x2026: 0x0aae, // XK_ellipsis | ||||||
|  |     0x2030: 0x0ad5, // XK_permille | ||||||
|  |     0x2032: 0x0ad6, // XK_minutes | ||||||
|  |     0x2033: 0x0ad7, // XK_seconds | ||||||
|  |     0x2038: 0x0afc, // XK_caret | ||||||
|  |     0x203e: 0x047e, // XK_overline | ||||||
|  |     0x20a9: 0x0eff, // XK_Korean_Won | ||||||
|  |     0x20ac: 0x20ac, // XK_EuroSign | ||||||
|  |     0x2105: 0x0ab8, // XK_careof | ||||||
|  |     0x2116: 0x06b0, // XK_numerosign | ||||||
|  |     0x2117: 0x0afb, // XK_phonographcopyright | ||||||
|  |     0x211e: 0x0ad4, // XK_prescription | ||||||
|  |     0x2122: 0x0ac9, // XK_trademark | ||||||
|  |     0x2153: 0x0ab0, // XK_onethird | ||||||
|  |     0x2154: 0x0ab1, // XK_twothirds | ||||||
|  |     0x2155: 0x0ab2, // XK_onefifth | ||||||
|  |     0x2156: 0x0ab3, // XK_twofifths | ||||||
|  |     0x2157: 0x0ab4, // XK_threefifths | ||||||
|  |     0x2158: 0x0ab5, // XK_fourfifths | ||||||
|  |     0x2159: 0x0ab6, // XK_onesixth | ||||||
|  |     0x215a: 0x0ab7, // XK_fivesixths | ||||||
|  |     0x215b: 0x0ac3, // XK_oneeighth | ||||||
|  |     0x215c: 0x0ac4, // XK_threeeighths | ||||||
|  |     0x215d: 0x0ac5, // XK_fiveeighths | ||||||
|  |     0x215e: 0x0ac6, // XK_seveneighths | ||||||
|  |     0x2190: 0x08fb, // XK_leftarrow | ||||||
|  |     0x2191: 0x08fc, // XK_uparrow | ||||||
|  |     0x2192: 0x08fd, // XK_rightarrow | ||||||
|  |     0x2193: 0x08fe, // XK_downarrow | ||||||
|  |     0x21d2: 0x08ce, // XK_implies | ||||||
|  |     0x21d4: 0x08cd, // XK_ifonlyif | ||||||
|  |     0x2202: 0x08ef, // XK_partialderivative | ||||||
|  |     0x2207: 0x08c5, // XK_nabla | ||||||
|  |     0x2218: 0x0bca, // XK_jot | ||||||
|  |     0x221a: 0x08d6, // XK_radical | ||||||
|  |     0x221d: 0x08c1, // XK_variation | ||||||
|  |     0x221e: 0x08c2, // XK_infinity | ||||||
|  |     0x2227: 0x08de, // XK_logicaland | ||||||
|  |     0x2228: 0x08df, // XK_logicalor | ||||||
|  |     0x2229: 0x08dc, // XK_intersection | ||||||
|  |     0x222a: 0x08dd, // XK_union | ||||||
|  |     0x222b: 0x08bf, // XK_integral | ||||||
|  |     0x2234: 0x08c0, // XK_therefore | ||||||
|  |     0x223c: 0x08c8, // XK_approximate | ||||||
|  |     0x2243: 0x08c9, // XK_similarequal | ||||||
|  |     0x2245: 0x1002248, // XK_approxeq | ||||||
|  |     0x2260: 0x08bd, // XK_notequal | ||||||
|  |     0x2261: 0x08cf, // XK_identical | ||||||
|  |     0x2264: 0x08bc, // XK_lessthanequal | ||||||
|  |     0x2265: 0x08be, // XK_greaterthanequal | ||||||
|  |     0x2282: 0x08da, // XK_includedin | ||||||
|  |     0x2283: 0x08db, // XK_includes | ||||||
|  |     0x22a2: 0x0bfc, // XK_righttack | ||||||
|  |     0x22a3: 0x0bdc, // XK_lefttack | ||||||
|  |     0x22a4: 0x0bc2, // XK_downtack | ||||||
|  |     0x22a5: 0x0bce, // XK_uptack | ||||||
|  |     0x2308: 0x0bd3, // XK_upstile | ||||||
|  |     0x230a: 0x0bc4, // XK_downstile | ||||||
|  |     0x2315: 0x0afa, // XK_telephonerecorder | ||||||
|  |     0x2320: 0x08a4, // XK_topintegral | ||||||
|  |     0x2321: 0x08a5, // XK_botintegral | ||||||
|  |     0x2395: 0x0bcc, // XK_quad | ||||||
|  |     0x239b: 0x08ab, // XK_topleftparens | ||||||
|  |     0x239d: 0x08ac, // XK_botleftparens | ||||||
|  |     0x239e: 0x08ad, // XK_toprightparens | ||||||
|  |     0x23a0: 0x08ae, // XK_botrightparens | ||||||
|  |     0x23a1: 0x08a7, // XK_topleftsqbracket | ||||||
|  |     0x23a3: 0x08a8, // XK_botleftsqbracket | ||||||
|  |     0x23a4: 0x08a9, // XK_toprightsqbracket | ||||||
|  |     0x23a6: 0x08aa, // XK_botrightsqbracket | ||||||
|  |     0x23a8: 0x08af, // XK_leftmiddlecurlybrace | ||||||
|  |     0x23ac: 0x08b0, // XK_rightmiddlecurlybrace | ||||||
|  |     0x23b7: 0x08a1, // XK_leftradical | ||||||
|  |     0x23ba: 0x09ef, // XK_horizlinescan1 | ||||||
|  |     0x23bb: 0x09f0, // XK_horizlinescan3 | ||||||
|  |     0x23bc: 0x09f2, // XK_horizlinescan7 | ||||||
|  |     0x23bd: 0x09f3, // XK_horizlinescan9 | ||||||
|  |     0x2409: 0x09e2, // XK_ht | ||||||
|  |     0x240a: 0x09e5, // XK_lf | ||||||
|  |     0x240b: 0x09e9, // XK_vt | ||||||
|  |     0x240c: 0x09e3, // XK_ff | ||||||
|  |     0x240d: 0x09e4, // XK_cr | ||||||
|  |     0x2423: 0x0aac, // XK_signifblank | ||||||
|  |     0x2424: 0x09e8, // XK_nl | ||||||
|  |     0x2500: 0x08a3, // XK_horizconnector | ||||||
|  |     0x2502: 0x08a6, // XK_vertconnector | ||||||
|  |     0x250c: 0x08a2, // XK_topleftradical | ||||||
|  |     0x2510: 0x09eb, // XK_uprightcorner | ||||||
|  |     0x2514: 0x09ed, // XK_lowleftcorner | ||||||
|  |     0x2518: 0x09ea, // XK_lowrightcorner | ||||||
|  |     0x251c: 0x09f4, // XK_leftt | ||||||
|  |     0x2524: 0x09f5, // XK_rightt | ||||||
|  |     0x252c: 0x09f7, // XK_topt | ||||||
|  |     0x2534: 0x09f6, // XK_bott | ||||||
|  |     0x253c: 0x09ee, // XK_crossinglines | ||||||
|  |     0x2592: 0x09e1, // XK_checkerboard | ||||||
|  |     0x25aa: 0x0ae7, // XK_enfilledsqbullet | ||||||
|  |     0x25ab: 0x0ae1, // XK_enopensquarebullet | ||||||
|  |     0x25ac: 0x0adb, // XK_filledrectbullet | ||||||
|  |     0x25ad: 0x0ae2, // XK_openrectbullet | ||||||
|  |     0x25ae: 0x0adf, // XK_emfilledrect | ||||||
|  |     0x25af: 0x0acf, // XK_emopenrectangle | ||||||
|  |     0x25b2: 0x0ae8, // XK_filledtribulletup | ||||||
|  |     0x25b3: 0x0ae3, // XK_opentribulletup | ||||||
|  |     0x25b6: 0x0add, // XK_filledrighttribullet | ||||||
|  |     0x25b7: 0x0acd, // XK_rightopentriangle | ||||||
|  |     0x25bc: 0x0ae9, // XK_filledtribulletdown | ||||||
|  |     0x25bd: 0x0ae4, // XK_opentribulletdown | ||||||
|  |     0x25c0: 0x0adc, // XK_filledlefttribullet | ||||||
|  |     0x25c1: 0x0acc, // XK_leftopentriangle | ||||||
|  |     0x25c6: 0x09e0, // XK_soliddiamond | ||||||
|  |     0x25cb: 0x0ace, // XK_emopencircle | ||||||
|  |     0x25cf: 0x0ade, // XK_emfilledcircle | ||||||
|  |     0x25e6: 0x0ae0, // XK_enopencircbullet | ||||||
|  |     0x2606: 0x0ae5, // XK_openstar | ||||||
|  |     0x260e: 0x0af9, // XK_telephone | ||||||
|  |     0x2613: 0x0aca, // XK_signaturemark | ||||||
|  |     0x261c: 0x0aea, // XK_leftpointer | ||||||
|  |     0x261e: 0x0aeb, // XK_rightpointer | ||||||
|  |     0x2640: 0x0af8, // XK_femalesymbol | ||||||
|  |     0x2642: 0x0af7, // XK_malesymbol | ||||||
|  |     0x2663: 0x0aec, // XK_club | ||||||
|  |     0x2665: 0x0aee, // XK_heart | ||||||
|  |     0x2666: 0x0aed, // XK_diamond | ||||||
|  |     0x266d: 0x0af6, // XK_musicalflat | ||||||
|  |     0x266f: 0x0af5, // XK_musicalsharp | ||||||
|  |     0x2713: 0x0af3, // XK_checkmark | ||||||
|  |     0x2717: 0x0af4, // XK_ballotcross | ||||||
|  |     0x271d: 0x0ad9, // XK_latincross | ||||||
|  |     0x2720: 0x0af0, // XK_maltesecross | ||||||
|  |     0x27e8: 0x0abc, // XK_leftanglebracket | ||||||
|  |     0x27e9: 0x0abe, // XK_rightanglebracket | ||||||
|  |     0x3001: 0x04a4, // XK_kana_comma | ||||||
|  |     0x3002: 0x04a1, // XK_kana_fullstop | ||||||
|  |     0x300c: 0x04a2, // XK_kana_openingbracket | ||||||
|  |     0x300d: 0x04a3, // XK_kana_closingbracket | ||||||
|  |     0x309b: 0x04de, // XK_voicedsound | ||||||
|  |     0x309c: 0x04df, // XK_semivoicedsound | ||||||
|  |     0x30a1: 0x04a7, // XK_kana_a | ||||||
|  |     0x30a2: 0x04b1, // XK_kana_A | ||||||
|  |     0x30a3: 0x04a8, // XK_kana_i | ||||||
|  |     0x30a4: 0x04b2, // XK_kana_I | ||||||
|  |     0x30a5: 0x04a9, // XK_kana_u | ||||||
|  |     0x30a6: 0x04b3, // XK_kana_U | ||||||
|  |     0x30a7: 0x04aa, // XK_kana_e | ||||||
|  |     0x30a8: 0x04b4, // XK_kana_E | ||||||
|  |     0x30a9: 0x04ab, // XK_kana_o | ||||||
|  |     0x30aa: 0x04b5, // XK_kana_O | ||||||
|  |     0x30ab: 0x04b6, // XK_kana_KA | ||||||
|  |     0x30ad: 0x04b7, // XK_kana_KI | ||||||
|  |     0x30af: 0x04b8, // XK_kana_KU | ||||||
|  |     0x30b1: 0x04b9, // XK_kana_KE | ||||||
|  |     0x30b3: 0x04ba, // XK_kana_KO | ||||||
|  |     0x30b5: 0x04bb, // XK_kana_SA | ||||||
|  |     0x30b7: 0x04bc, // XK_kana_SHI | ||||||
|  |     0x30b9: 0x04bd, // XK_kana_SU | ||||||
|  |     0x30bb: 0x04be, // XK_kana_SE | ||||||
|  |     0x30bd: 0x04bf, // XK_kana_SO | ||||||
|  |     0x30bf: 0x04c0, // XK_kana_TA | ||||||
|  |     0x30c1: 0x04c1, // XK_kana_CHI | ||||||
|  |     0x30c3: 0x04af, // XK_kana_tsu | ||||||
|  |     0x30c4: 0x04c2, // XK_kana_TSU | ||||||
|  |     0x30c6: 0x04c3, // XK_kana_TE | ||||||
|  |     0x30c8: 0x04c4, // XK_kana_TO | ||||||
|  |     0x30ca: 0x04c5, // XK_kana_NA | ||||||
|  |     0x30cb: 0x04c6, // XK_kana_NI | ||||||
|  |     0x30cc: 0x04c7, // XK_kana_NU | ||||||
|  |     0x30cd: 0x04c8, // XK_kana_NE | ||||||
|  |     0x30ce: 0x04c9, // XK_kana_NO | ||||||
|  |     0x30cf: 0x04ca, // XK_kana_HA | ||||||
|  |     0x30d2: 0x04cb, // XK_kana_HI | ||||||
|  |     0x30d5: 0x04cc, // XK_kana_FU | ||||||
|  |     0x30d8: 0x04cd, // XK_kana_HE | ||||||
|  |     0x30db: 0x04ce, // XK_kana_HO | ||||||
|  |     0x30de: 0x04cf, // XK_kana_MA | ||||||
|  |     0x30df: 0x04d0, // XK_kana_MI | ||||||
|  |     0x30e0: 0x04d1, // XK_kana_MU | ||||||
|  |     0x30e1: 0x04d2, // XK_kana_ME | ||||||
|  |     0x30e2: 0x04d3, // XK_kana_MO | ||||||
|  |     0x30e3: 0x04ac, // XK_kana_ya | ||||||
|  |     0x30e4: 0x04d4, // XK_kana_YA | ||||||
|  |     0x30e5: 0x04ad, // XK_kana_yu | ||||||
|  |     0x30e6: 0x04d5, // XK_kana_YU | ||||||
|  |     0x30e7: 0x04ae, // XK_kana_yo | ||||||
|  |     0x30e8: 0x04d6, // XK_kana_YO | ||||||
|  |     0x30e9: 0x04d7, // XK_kana_RA | ||||||
|  |     0x30ea: 0x04d8, // XK_kana_RI | ||||||
|  |     0x30eb: 0x04d9, // XK_kana_RU | ||||||
|  |     0x30ec: 0x04da, // XK_kana_RE | ||||||
|  |     0x30ed: 0x04db, // XK_kana_RO | ||||||
|  |     0x30ef: 0x04dc, // XK_kana_WA | ||||||
|  |     0x30f2: 0x04a6, // XK_kana_WO | ||||||
|  |     0x30f3: 0x04dd, // XK_kana_N | ||||||
|  |     0x30fb: 0x04a5, // XK_kana_conjunctive | ||||||
|  |     0x30fc: 0x04b0, // XK_prolongedsound | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |     lookup(u) { | ||||||
|  |         // Latin-1 is one-to-one mapping | ||||||
|  |         if ((u >= 0x20) && (u <= 0xff)) { | ||||||
|  |             return u; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Lookup table (fairly random) | ||||||
|  |         const keysym = codepoints[u]; | ||||||
|  |         if (keysym !== undefined) { | ||||||
|  |             return keysym; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // General mapping as final fallback | ||||||
|  |         return 0x01000000 | u; | ||||||
|  |     }, | ||||||
|  | }; | ||||||
							
								
								
									
										191
									
								
								core/input/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,191 @@ | |||||||
|  | import KeyTable from "./keysym.js"; | ||||||
|  | import keysyms from "./keysymdef.js"; | ||||||
|  | import vkeys from "./vkeys.js"; | ||||||
|  | import fixedkeys from "./fixedkeys.js"; | ||||||
|  | import DOMKeyTable from "./domkeytable.js"; | ||||||
|  | import * as browser from "../util/browser.js"; | ||||||
|  |  | ||||||
|  | // Get 'KeyboardEvent.code', handling legacy browsers | ||||||
|  | export function getKeycode(evt) { | ||||||
|  |     // Are we getting proper key identifiers? | ||||||
|  |     // (unfortunately Firefox and Chrome are crappy here and gives | ||||||
|  |     // us an empty string on some platforms, rather than leaving it | ||||||
|  |     // undefined) | ||||||
|  |     if (evt.code) { | ||||||
|  |         // Mozilla isn't fully in sync with the spec yet | ||||||
|  |         switch (evt.code) { | ||||||
|  |             case 'OSLeft': return 'MetaLeft'; | ||||||
|  |             case 'OSRight': return 'MetaRight'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return evt.code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // The de-facto standard is to use Windows Virtual-Key codes | ||||||
|  |     // in the 'keyCode' field for non-printable characters | ||||||
|  |     if (evt.keyCode in vkeys) { | ||||||
|  |         let code = vkeys[evt.keyCode]; | ||||||
|  |  | ||||||
|  |         // macOS has messed up this code for some reason | ||||||
|  |         if (browser.isMac() && (code === 'ContextMenu')) { | ||||||
|  |             code = 'MetaRight'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // The keyCode doesn't distinguish between left and right | ||||||
|  |         // for the standard modifiers | ||||||
|  |         if (evt.location === 2) { | ||||||
|  |             switch (code) { | ||||||
|  |                 case 'ShiftLeft': return 'ShiftRight'; | ||||||
|  |                 case 'ControlLeft': return 'ControlRight'; | ||||||
|  |                 case 'AltLeft': return 'AltRight'; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Nor a bunch of the numpad keys | ||||||
|  |         if (evt.location === 3) { | ||||||
|  |             switch (code) { | ||||||
|  |                 case 'Delete': return 'NumpadDecimal'; | ||||||
|  |                 case 'Insert': return 'Numpad0'; | ||||||
|  |                 case 'End': return 'Numpad1'; | ||||||
|  |                 case 'ArrowDown': return 'Numpad2'; | ||||||
|  |                 case 'PageDown': return 'Numpad3'; | ||||||
|  |                 case 'ArrowLeft': return 'Numpad4'; | ||||||
|  |                 case 'ArrowRight': return 'Numpad6'; | ||||||
|  |                 case 'Home': return 'Numpad7'; | ||||||
|  |                 case 'ArrowUp': return 'Numpad8'; | ||||||
|  |                 case 'PageUp': return 'Numpad9'; | ||||||
|  |                 case 'Enter': return 'NumpadEnter'; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return code; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 'Unidentified'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get 'KeyboardEvent.key', handling legacy browsers | ||||||
|  | export function getKey(evt) { | ||||||
|  |     // Are we getting a proper key value? | ||||||
|  |     if ((evt.key !== undefined) && (evt.key !== 'Unidentified')) { | ||||||
|  |         // Mozilla isn't fully in sync with the spec yet | ||||||
|  |         switch (evt.key) { | ||||||
|  |             case 'OS': return 'Meta'; | ||||||
|  |             case 'LaunchMyComputer': return 'LaunchApplication1'; | ||||||
|  |             case 'LaunchCalculator': return 'LaunchApplication2'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // iOS leaks some OS names | ||||||
|  |         switch (evt.key) { | ||||||
|  |             case 'UIKeyInputUpArrow': return 'ArrowUp'; | ||||||
|  |             case 'UIKeyInputDownArrow': return 'ArrowDown'; | ||||||
|  |             case 'UIKeyInputLeftArrow': return 'ArrowLeft'; | ||||||
|  |             case 'UIKeyInputRightArrow': return 'ArrowRight'; | ||||||
|  |             case 'UIKeyInputEscape': return 'Escape'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Broken behaviour in Chrome | ||||||
|  |         if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) { | ||||||
|  |             return 'Delete'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return evt.key; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Try to deduce it based on the physical key | ||||||
|  |     const code = getKeycode(evt); | ||||||
|  |     if (code in fixedkeys) { | ||||||
|  |         return fixedkeys[code]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // If that failed, then see if we have a printable character | ||||||
|  |     if (evt.charCode) { | ||||||
|  |         return String.fromCharCode(evt.charCode); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // At this point we have nothing left to go on | ||||||
|  |     return 'Unidentified'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get the most reliable keysym value we can get from a key event | ||||||
|  | export function getKeysym(evt) { | ||||||
|  |     const key = getKey(evt); | ||||||
|  |  | ||||||
|  |     if (key === 'Unidentified') { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // First look up special keys | ||||||
|  |     if (key in DOMKeyTable) { | ||||||
|  |         let location = evt.location; | ||||||
|  |  | ||||||
|  |         // Safari screws up location for the right cmd key | ||||||
|  |         if ((key === 'Meta') && (location === 0)) { | ||||||
|  |             location = 2; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // And for Clear | ||||||
|  |         if ((key === 'Clear') && (location === 3)) { | ||||||
|  |             let code = getKeycode(evt); | ||||||
|  |             if (code === 'NumLock') { | ||||||
|  |                 location = 0; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ((location === undefined) || (location > 3)) { | ||||||
|  |             location = 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // The original Meta key now gets confused with the Windows key | ||||||
|  |         // https://bugs.chromium.org/p/chromium/issues/detail?id=1020141 | ||||||
|  |         // https://bugzilla.mozilla.org/show_bug.cgi?id=1232918 | ||||||
|  |         if (key === 'Meta') { | ||||||
|  |             let code = getKeycode(evt); | ||||||
|  |             if (code === 'AltLeft') { | ||||||
|  |                 return KeyTable.XK_Meta_L; | ||||||
|  |             } else if (code === 'AltRight') { | ||||||
|  |                 return KeyTable.XK_Meta_R; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // macOS has Clear instead of NumLock, but the remote system is | ||||||
|  |         // probably not macOS, so lying here is probably best... | ||||||
|  |         if (key === 'Clear') { | ||||||
|  |             let code = getKeycode(evt); | ||||||
|  |             if (code === 'NumLock') { | ||||||
|  |                 return KeyTable.XK_Num_Lock; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Windows sends alternating symbols for some keys when using a | ||||||
|  |         // Japanese layout. We have no way of synchronising with the IM | ||||||
|  |         // running on the remote system, so we send some combined keysym | ||||||
|  |         // instead and hope for the best. | ||||||
|  |         if (browser.isWindows()) { | ||||||
|  |             switch (key) { | ||||||
|  |                 case 'Zenkaku': | ||||||
|  |                 case 'Hankaku': | ||||||
|  |                     return KeyTable.XK_Zenkaku_Hankaku; | ||||||
|  |                 case 'Romaji': | ||||||
|  |                 case 'KanaMode': | ||||||
|  |                     return KeyTable.XK_Romaji; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return DOMKeyTable[key][location]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Now we need to look at the Unicode symbol instead | ||||||
|  |  | ||||||
|  |     // Special key? (FIXME: Should have been caught earlier) | ||||||
|  |     if (key.length !== 1) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const codepoint = key.charCodeAt(); | ||||||
|  |     if (codepoint) { | ||||||
|  |         return keysyms.lookup(codepoint); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return null; | ||||||
|  | } | ||||||
							
								
								
									
										116
									
								
								core/input/vkeys.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,116 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2018 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Mapping between Microsoft® Windows® Virtual-Key codes and | ||||||
|  |  * HTML key codes. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |     0x08: 'Backspace', | ||||||
|  |     0x09: 'Tab', | ||||||
|  |     0x0a: 'NumpadClear', | ||||||
|  |     0x0d: 'Enter', | ||||||
|  |     0x10: 'ShiftLeft', | ||||||
|  |     0x11: 'ControlLeft', | ||||||
|  |     0x12: 'AltLeft', | ||||||
|  |     0x13: 'Pause', | ||||||
|  |     0x14: 'CapsLock', | ||||||
|  |     0x15: 'Lang1', | ||||||
|  |     0x19: 'Lang2', | ||||||
|  |     0x1b: 'Escape', | ||||||
|  |     0x1c: 'Convert', | ||||||
|  |     0x1d: 'NonConvert', | ||||||
|  |     0x20: 'Space', | ||||||
|  |     0x21: 'PageUp', | ||||||
|  |     0x22: 'PageDown', | ||||||
|  |     0x23: 'End', | ||||||
|  |     0x24: 'Home', | ||||||
|  |     0x25: 'ArrowLeft', | ||||||
|  |     0x26: 'ArrowUp', | ||||||
|  |     0x27: 'ArrowRight', | ||||||
|  |     0x28: 'ArrowDown', | ||||||
|  |     0x29: 'Select', | ||||||
|  |     0x2c: 'PrintScreen', | ||||||
|  |     0x2d: 'Insert', | ||||||
|  |     0x2e: 'Delete', | ||||||
|  |     0x2f: 'Help', | ||||||
|  |     0x30: 'Digit0', | ||||||
|  |     0x31: 'Digit1', | ||||||
|  |     0x32: 'Digit2', | ||||||
|  |     0x33: 'Digit3', | ||||||
|  |     0x34: 'Digit4', | ||||||
|  |     0x35: 'Digit5', | ||||||
|  |     0x36: 'Digit6', | ||||||
|  |     0x37: 'Digit7', | ||||||
|  |     0x38: 'Digit8', | ||||||
|  |     0x39: 'Digit9', | ||||||
|  |     0x5b: 'MetaLeft', | ||||||
|  |     0x5c: 'MetaRight', | ||||||
|  |     0x5d: 'ContextMenu', | ||||||
|  |     0x5f: 'Sleep', | ||||||
|  |     0x60: 'Numpad0', | ||||||
|  |     0x61: 'Numpad1', | ||||||
|  |     0x62: 'Numpad2', | ||||||
|  |     0x63: 'Numpad3', | ||||||
|  |     0x64: 'Numpad4', | ||||||
|  |     0x65: 'Numpad5', | ||||||
|  |     0x66: 'Numpad6', | ||||||
|  |     0x67: 'Numpad7', | ||||||
|  |     0x68: 'Numpad8', | ||||||
|  |     0x69: 'Numpad9', | ||||||
|  |     0x6a: 'NumpadMultiply', | ||||||
|  |     0x6b: 'NumpadAdd', | ||||||
|  |     0x6c: 'NumpadDecimal', | ||||||
|  |     0x6d: 'NumpadSubtract', | ||||||
|  |     0x6e: 'NumpadDecimal', // Duplicate, because buggy on Windows | ||||||
|  |     0x6f: 'NumpadDivide', | ||||||
|  |     0x70: 'F1', | ||||||
|  |     0x71: 'F2', | ||||||
|  |     0x72: 'F3', | ||||||
|  |     0x73: 'F4', | ||||||
|  |     0x74: 'F5', | ||||||
|  |     0x75: 'F6', | ||||||
|  |     0x76: 'F7', | ||||||
|  |     0x77: 'F8', | ||||||
|  |     0x78: 'F9', | ||||||
|  |     0x79: 'F10', | ||||||
|  |     0x7a: 'F11', | ||||||
|  |     0x7b: 'F12', | ||||||
|  |     0x7c: 'F13', | ||||||
|  |     0x7d: 'F14', | ||||||
|  |     0x7e: 'F15', | ||||||
|  |     0x7f: 'F16', | ||||||
|  |     0x80: 'F17', | ||||||
|  |     0x81: 'F18', | ||||||
|  |     0x82: 'F19', | ||||||
|  |     0x83: 'F20', | ||||||
|  |     0x84: 'F21', | ||||||
|  |     0x85: 'F22', | ||||||
|  |     0x86: 'F23', | ||||||
|  |     0x87: 'F24', | ||||||
|  |     0x90: 'NumLock', | ||||||
|  |     0x91: 'ScrollLock', | ||||||
|  |     0xa6: 'BrowserBack', | ||||||
|  |     0xa7: 'BrowserForward', | ||||||
|  |     0xa8: 'BrowserRefresh', | ||||||
|  |     0xa9: 'BrowserStop', | ||||||
|  |     0xaa: 'BrowserSearch', | ||||||
|  |     0xab: 'BrowserFavorites', | ||||||
|  |     0xac: 'BrowserHome', | ||||||
|  |     0xad: 'AudioVolumeMute', | ||||||
|  |     0xae: 'AudioVolumeDown', | ||||||
|  |     0xaf: 'AudioVolumeUp', | ||||||
|  |     0xb0: 'MediaTrackNext', | ||||||
|  |     0xb1: 'MediaTrackPrevious', | ||||||
|  |     0xb2: 'MediaStop', | ||||||
|  |     0xb3: 'MediaPlayPause', | ||||||
|  |     0xb4: 'LaunchMail', | ||||||
|  |     0xb5: 'MediaSelect', | ||||||
|  |     0xb6: 'LaunchApp1', | ||||||
|  |     0xb7: 'LaunchApp2', | ||||||
|  |     0xe1: 'AltRight', // Only when it is AltGraph | ||||||
|  | }; | ||||||
							
								
								
									
										173
									
								
								core/input/xtscancodes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,173 @@ | |||||||
|  | /* | ||||||
|  |  * This file is auto-generated from keymaps.csv | ||||||
|  |  * Database checksum sha256(76d68c10e97d37fe2ea459e210125ae41796253fb217e900bf2983ade13a7920) | ||||||
|  |  * To re-generate, run: | ||||||
|  |  *   keymap-gen code-map --lang=js keymaps.csv html atset1 | ||||||
|  | */ | ||||||
|  | export default { | ||||||
|  |   "Again": 0xe005, /* html:Again (Again) -> linux:129 (KEY_AGAIN) -> atset1:57349 */ | ||||||
|  |   "AltLeft": 0x38, /* html:AltLeft (AltLeft) -> linux:56 (KEY_LEFTALT) -> atset1:56 */ | ||||||
|  |   "AltRight": 0xe038, /* html:AltRight (AltRight) -> linux:100 (KEY_RIGHTALT) -> atset1:57400 */ | ||||||
|  |   "ArrowDown": 0xe050, /* html:ArrowDown (ArrowDown) -> linux:108 (KEY_DOWN) -> atset1:57424 */ | ||||||
|  |   "ArrowLeft": 0xe04b, /* html:ArrowLeft (ArrowLeft) -> linux:105 (KEY_LEFT) -> atset1:57419 */ | ||||||
|  |   "ArrowRight": 0xe04d, /* html:ArrowRight (ArrowRight) -> linux:106 (KEY_RIGHT) -> atset1:57421 */ | ||||||
|  |   "ArrowUp": 0xe048, /* html:ArrowUp (ArrowUp) -> linux:103 (KEY_UP) -> atset1:57416 */ | ||||||
|  |   "AudioVolumeDown": 0xe02e, /* html:AudioVolumeDown (AudioVolumeDown) -> linux:114 (KEY_VOLUMEDOWN) -> atset1:57390 */ | ||||||
|  |   "AudioVolumeMute": 0xe020, /* html:AudioVolumeMute (AudioVolumeMute) -> linux:113 (KEY_MUTE) -> atset1:57376 */ | ||||||
|  |   "AudioVolumeUp": 0xe030, /* html:AudioVolumeUp (AudioVolumeUp) -> linux:115 (KEY_VOLUMEUP) -> atset1:57392 */ | ||||||
|  |   "Backquote": 0x29, /* html:Backquote (Backquote) -> linux:41 (KEY_GRAVE) -> atset1:41 */ | ||||||
|  |   "Backslash": 0x2b, /* html:Backslash (Backslash) -> linux:43 (KEY_BACKSLASH) -> atset1:43 */ | ||||||
|  |   "Backspace": 0xe, /* html:Backspace (Backspace) -> linux:14 (KEY_BACKSPACE) -> atset1:14 */ | ||||||
|  |   "BracketLeft": 0x1a, /* html:BracketLeft (BracketLeft) -> linux:26 (KEY_LEFTBRACE) -> atset1:26 */ | ||||||
|  |   "BracketRight": 0x1b, /* html:BracketRight (BracketRight) -> linux:27 (KEY_RIGHTBRACE) -> atset1:27 */ | ||||||
|  |   "BrowserBack": 0xe06a, /* html:BrowserBack (BrowserBack) -> linux:158 (KEY_BACK) -> atset1:57450 */ | ||||||
|  |   "BrowserFavorites": 0xe066, /* html:BrowserFavorites (BrowserFavorites) -> linux:156 (KEY_BOOKMARKS) -> atset1:57446 */ | ||||||
|  |   "BrowserForward": 0xe069, /* html:BrowserForward (BrowserForward) -> linux:159 (KEY_FORWARD) -> atset1:57449 */ | ||||||
|  |   "BrowserHome": 0xe032, /* html:BrowserHome (BrowserHome) -> linux:172 (KEY_HOMEPAGE) -> atset1:57394 */ | ||||||
|  |   "BrowserRefresh": 0xe067, /* html:BrowserRefresh (BrowserRefresh) -> linux:173 (KEY_REFRESH) -> atset1:57447 */ | ||||||
|  |   "BrowserSearch": 0xe065, /* html:BrowserSearch (BrowserSearch) -> linux:217 (KEY_SEARCH) -> atset1:57445 */ | ||||||
|  |   "BrowserStop": 0xe068, /* html:BrowserStop (BrowserStop) -> linux:128 (KEY_STOP) -> atset1:57448 */ | ||||||
|  |   "CapsLock": 0x3a, /* html:CapsLock (CapsLock) -> linux:58 (KEY_CAPSLOCK) -> atset1:58 */ | ||||||
|  |   "Comma": 0x33, /* html:Comma (Comma) -> linux:51 (KEY_COMMA) -> atset1:51 */ | ||||||
|  |   "ContextMenu": 0xe05d, /* html:ContextMenu (ContextMenu) -> linux:127 (KEY_COMPOSE) -> atset1:57437 */ | ||||||
|  |   "ControlLeft": 0x1d, /* html:ControlLeft (ControlLeft) -> linux:29 (KEY_LEFTCTRL) -> atset1:29 */ | ||||||
|  |   "ControlRight": 0xe01d, /* html:ControlRight (ControlRight) -> linux:97 (KEY_RIGHTCTRL) -> atset1:57373 */ | ||||||
|  |   "Convert": 0x79, /* html:Convert (Convert) -> linux:92 (KEY_HENKAN) -> atset1:121 */ | ||||||
|  |   "Copy": 0xe078, /* html:Copy (Copy) -> linux:133 (KEY_COPY) -> atset1:57464 */ | ||||||
|  |   "Cut": 0xe03c, /* html:Cut (Cut) -> linux:137 (KEY_CUT) -> atset1:57404 */ | ||||||
|  |   "Delete": 0xe053, /* html:Delete (Delete) -> linux:111 (KEY_DELETE) -> atset1:57427 */ | ||||||
|  |   "Digit0": 0xb, /* html:Digit0 (Digit0) -> linux:11 (KEY_0) -> atset1:11 */ | ||||||
|  |   "Digit1": 0x2, /* html:Digit1 (Digit1) -> linux:2 (KEY_1) -> atset1:2 */ | ||||||
|  |   "Digit2": 0x3, /* html:Digit2 (Digit2) -> linux:3 (KEY_2) -> atset1:3 */ | ||||||
|  |   "Digit3": 0x4, /* html:Digit3 (Digit3) -> linux:4 (KEY_3) -> atset1:4 */ | ||||||
|  |   "Digit4": 0x5, /* html:Digit4 (Digit4) -> linux:5 (KEY_4) -> atset1:5 */ | ||||||
|  |   "Digit5": 0x6, /* html:Digit5 (Digit5) -> linux:6 (KEY_5) -> atset1:6 */ | ||||||
|  |   "Digit6": 0x7, /* html:Digit6 (Digit6) -> linux:7 (KEY_6) -> atset1:7 */ | ||||||
|  |   "Digit7": 0x8, /* html:Digit7 (Digit7) -> linux:8 (KEY_7) -> atset1:8 */ | ||||||
|  |   "Digit8": 0x9, /* html:Digit8 (Digit8) -> linux:9 (KEY_8) -> atset1:9 */ | ||||||
|  |   "Digit9": 0xa, /* html:Digit9 (Digit9) -> linux:10 (KEY_9) -> atset1:10 */ | ||||||
|  |   "Eject": 0xe07d, /* html:Eject (Eject) -> linux:162 (KEY_EJECTCLOSECD) -> atset1:57469 */ | ||||||
|  |   "End": 0xe04f, /* html:End (End) -> linux:107 (KEY_END) -> atset1:57423 */ | ||||||
|  |   "Enter": 0x1c, /* html:Enter (Enter) -> linux:28 (KEY_ENTER) -> atset1:28 */ | ||||||
|  |   "Equal": 0xd, /* html:Equal (Equal) -> linux:13 (KEY_EQUAL) -> atset1:13 */ | ||||||
|  |   "Escape": 0x1, /* html:Escape (Escape) -> linux:1 (KEY_ESC) -> atset1:1 */ | ||||||
|  |   "F1": 0x3b, /* html:F1 (F1) -> linux:59 (KEY_F1) -> atset1:59 */ | ||||||
|  |   "F10": 0x44, /* html:F10 (F10) -> linux:68 (KEY_F10) -> atset1:68 */ | ||||||
|  |   "F11": 0x57, /* html:F11 (F11) -> linux:87 (KEY_F11) -> atset1:87 */ | ||||||
|  |   "F12": 0x58, /* html:F12 (F12) -> linux:88 (KEY_F12) -> atset1:88 */ | ||||||
|  |   "F13": 0x5d, /* html:F13 (F13) -> linux:183 (KEY_F13) -> atset1:93 */ | ||||||
|  |   "F14": 0x5e, /* html:F14 (F14) -> linux:184 (KEY_F14) -> atset1:94 */ | ||||||
|  |   "F15": 0x5f, /* html:F15 (F15) -> linux:185 (KEY_F15) -> atset1:95 */ | ||||||
|  |   "F16": 0x55, /* html:F16 (F16) -> linux:186 (KEY_F16) -> atset1:85 */ | ||||||
|  |   "F17": 0xe003, /* html:F17 (F17) -> linux:187 (KEY_F17) -> atset1:57347 */ | ||||||
|  |   "F18": 0xe077, /* html:F18 (F18) -> linux:188 (KEY_F18) -> atset1:57463 */ | ||||||
|  |   "F19": 0xe004, /* html:F19 (F19) -> linux:189 (KEY_F19) -> atset1:57348 */ | ||||||
|  |   "F2": 0x3c, /* html:F2 (F2) -> linux:60 (KEY_F2) -> atset1:60 */ | ||||||
|  |   "F20": 0x5a, /* html:F20 (F20) -> linux:190 (KEY_F20) -> atset1:90 */ | ||||||
|  |   "F21": 0x74, /* html:F21 (F21) -> linux:191 (KEY_F21) -> atset1:116 */ | ||||||
|  |   "F22": 0xe079, /* html:F22 (F22) -> linux:192 (KEY_F22) -> atset1:57465 */ | ||||||
|  |   "F23": 0x6d, /* html:F23 (F23) -> linux:193 (KEY_F23) -> atset1:109 */ | ||||||
|  |   "F24": 0x6f, /* html:F24 (F24) -> linux:194 (KEY_F24) -> atset1:111 */ | ||||||
|  |   "F3": 0x3d, /* html:F3 (F3) -> linux:61 (KEY_F3) -> atset1:61 */ | ||||||
|  |   "F4": 0x3e, /* html:F4 (F4) -> linux:62 (KEY_F4) -> atset1:62 */ | ||||||
|  |   "F5": 0x3f, /* html:F5 (F5) -> linux:63 (KEY_F5) -> atset1:63 */ | ||||||
|  |   "F6": 0x40, /* html:F6 (F6) -> linux:64 (KEY_F6) -> atset1:64 */ | ||||||
|  |   "F7": 0x41, /* html:F7 (F7) -> linux:65 (KEY_F7) -> atset1:65 */ | ||||||
|  |   "F8": 0x42, /* html:F8 (F8) -> linux:66 (KEY_F8) -> atset1:66 */ | ||||||
|  |   "F9": 0x43, /* html:F9 (F9) -> linux:67 (KEY_F9) -> atset1:67 */ | ||||||
|  |   "Find": 0xe041, /* html:Find (Find) -> linux:136 (KEY_FIND) -> atset1:57409 */ | ||||||
|  |   "Help": 0xe075, /* html:Help (Help) -> linux:138 (KEY_HELP) -> atset1:57461 */ | ||||||
|  |   "Hiragana": 0x77, /* html:Hiragana (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */ | ||||||
|  |   "Home": 0xe047, /* html:Home (Home) -> linux:102 (KEY_HOME) -> atset1:57415 */ | ||||||
|  |   "Insert": 0xe052, /* html:Insert (Insert) -> linux:110 (KEY_INSERT) -> atset1:57426 */ | ||||||
|  |   "IntlBackslash": 0x56, /* html:IntlBackslash (IntlBackslash) -> linux:86 (KEY_102ND) -> atset1:86 */ | ||||||
|  |   "IntlRo": 0x73, /* html:IntlRo (IntlRo) -> linux:89 (KEY_RO) -> atset1:115 */ | ||||||
|  |   "IntlYen": 0x7d, /* html:IntlYen (IntlYen) -> linux:124 (KEY_YEN) -> atset1:125 */ | ||||||
|  |   "KanaMode": 0x70, /* html:KanaMode (KanaMode) -> linux:93 (KEY_KATAKANAHIRAGANA) -> atset1:112 */ | ||||||
|  |   "Katakana": 0x78, /* html:Katakana (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */ | ||||||
|  |   "KeyA": 0x1e, /* html:KeyA (KeyA) -> linux:30 (KEY_A) -> atset1:30 */ | ||||||
|  |   "KeyB": 0x30, /* html:KeyB (KeyB) -> linux:48 (KEY_B) -> atset1:48 */ | ||||||
|  |   "KeyC": 0x2e, /* html:KeyC (KeyC) -> linux:46 (KEY_C) -> atset1:46 */ | ||||||
|  |   "KeyD": 0x20, /* html:KeyD (KeyD) -> linux:32 (KEY_D) -> atset1:32 */ | ||||||
|  |   "KeyE": 0x12, /* html:KeyE (KeyE) -> linux:18 (KEY_E) -> atset1:18 */ | ||||||
|  |   "KeyF": 0x21, /* html:KeyF (KeyF) -> linux:33 (KEY_F) -> atset1:33 */ | ||||||
|  |   "KeyG": 0x22, /* html:KeyG (KeyG) -> linux:34 (KEY_G) -> atset1:34 */ | ||||||
|  |   "KeyH": 0x23, /* html:KeyH (KeyH) -> linux:35 (KEY_H) -> atset1:35 */ | ||||||
|  |   "KeyI": 0x17, /* html:KeyI (KeyI) -> linux:23 (KEY_I) -> atset1:23 */ | ||||||
|  |   "KeyJ": 0x24, /* html:KeyJ (KeyJ) -> linux:36 (KEY_J) -> atset1:36 */ | ||||||
|  |   "KeyK": 0x25, /* html:KeyK (KeyK) -> linux:37 (KEY_K) -> atset1:37 */ | ||||||
|  |   "KeyL": 0x26, /* html:KeyL (KeyL) -> linux:38 (KEY_L) -> atset1:38 */ | ||||||
|  |   "KeyM": 0x32, /* html:KeyM (KeyM) -> linux:50 (KEY_M) -> atset1:50 */ | ||||||
|  |   "KeyN": 0x31, /* html:KeyN (KeyN) -> linux:49 (KEY_N) -> atset1:49 */ | ||||||
|  |   "KeyO": 0x18, /* html:KeyO (KeyO) -> linux:24 (KEY_O) -> atset1:24 */ | ||||||
|  |   "KeyP": 0x19, /* html:KeyP (KeyP) -> linux:25 (KEY_P) -> atset1:25 */ | ||||||
|  |   "KeyQ": 0x10, /* html:KeyQ (KeyQ) -> linux:16 (KEY_Q) -> atset1:16 */ | ||||||
|  |   "KeyR": 0x13, /* html:KeyR (KeyR) -> linux:19 (KEY_R) -> atset1:19 */ | ||||||
|  |   "KeyS": 0x1f, /* html:KeyS (KeyS) -> linux:31 (KEY_S) -> atset1:31 */ | ||||||
|  |   "KeyT": 0x14, /* html:KeyT (KeyT) -> linux:20 (KEY_T) -> atset1:20 */ | ||||||
|  |   "KeyU": 0x16, /* html:KeyU (KeyU) -> linux:22 (KEY_U) -> atset1:22 */ | ||||||
|  |   "KeyV": 0x2f, /* html:KeyV (KeyV) -> linux:47 (KEY_V) -> atset1:47 */ | ||||||
|  |   "KeyW": 0x11, /* html:KeyW (KeyW) -> linux:17 (KEY_W) -> atset1:17 */ | ||||||
|  |   "KeyX": 0x2d, /* html:KeyX (KeyX) -> linux:45 (KEY_X) -> atset1:45 */ | ||||||
|  |   "KeyY": 0x15, /* html:KeyY (KeyY) -> linux:21 (KEY_Y) -> atset1:21 */ | ||||||
|  |   "KeyZ": 0x2c, /* html:KeyZ (KeyZ) -> linux:44 (KEY_Z) -> atset1:44 */ | ||||||
|  |   "Lang1": 0x72, /* html:Lang1 (Lang1) -> linux:122 (KEY_HANGEUL) -> atset1:114 */ | ||||||
|  |   "Lang2": 0x71, /* html:Lang2 (Lang2) -> linux:123 (KEY_HANJA) -> atset1:113 */ | ||||||
|  |   "Lang3": 0x78, /* html:Lang3 (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */ | ||||||
|  |   "Lang4": 0x77, /* html:Lang4 (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */ | ||||||
|  |   "Lang5": 0x76, /* html:Lang5 (Lang5) -> linux:85 (KEY_ZENKAKUHANKAKU) -> atset1:118 */ | ||||||
|  |   "LaunchApp1": 0xe06b, /* html:LaunchApp1 (LaunchApp1) -> linux:157 (KEY_COMPUTER) -> atset1:57451 */ | ||||||
|  |   "LaunchApp2": 0xe021, /* html:LaunchApp2 (LaunchApp2) -> linux:140 (KEY_CALC) -> atset1:57377 */ | ||||||
|  |   "LaunchMail": 0xe06c, /* html:LaunchMail (LaunchMail) -> linux:155 (KEY_MAIL) -> atset1:57452 */ | ||||||
|  |   "MediaPlayPause": 0xe022, /* html:MediaPlayPause (MediaPlayPause) -> linux:164 (KEY_PLAYPAUSE) -> atset1:57378 */ | ||||||
|  |   "MediaSelect": 0xe06d, /* html:MediaSelect (MediaSelect) -> linux:226 (KEY_MEDIA) -> atset1:57453 */ | ||||||
|  |   "MediaStop": 0xe024, /* html:MediaStop (MediaStop) -> linux:166 (KEY_STOPCD) -> atset1:57380 */ | ||||||
|  |   "MediaTrackNext": 0xe019, /* html:MediaTrackNext (MediaTrackNext) -> linux:163 (KEY_NEXTSONG) -> atset1:57369 */ | ||||||
|  |   "MediaTrackPrevious": 0xe010, /* html:MediaTrackPrevious (MediaTrackPrevious) -> linux:165 (KEY_PREVIOUSSONG) -> atset1:57360 */ | ||||||
|  |   "MetaLeft": 0xe05b, /* html:MetaLeft (MetaLeft) -> linux:125 (KEY_LEFTMETA) -> atset1:57435 */ | ||||||
|  |   "MetaRight": 0xe05c, /* html:MetaRight (MetaRight) -> linux:126 (KEY_RIGHTMETA) -> atset1:57436 */ | ||||||
|  |   "Minus": 0xc, /* html:Minus (Minus) -> linux:12 (KEY_MINUS) -> atset1:12 */ | ||||||
|  |   "NonConvert": 0x7b, /* html:NonConvert (NonConvert) -> linux:94 (KEY_MUHENKAN) -> atset1:123 */ | ||||||
|  |   "NumLock": 0x45, /* html:NumLock (NumLock) -> linux:69 (KEY_NUMLOCK) -> atset1:69 */ | ||||||
|  |   "Numpad0": 0x52, /* html:Numpad0 (Numpad0) -> linux:82 (KEY_KP0) -> atset1:82 */ | ||||||
|  |   "Numpad1": 0x4f, /* html:Numpad1 (Numpad1) -> linux:79 (KEY_KP1) -> atset1:79 */ | ||||||
|  |   "Numpad2": 0x50, /* html:Numpad2 (Numpad2) -> linux:80 (KEY_KP2) -> atset1:80 */ | ||||||
|  |   "Numpad3": 0x51, /* html:Numpad3 (Numpad3) -> linux:81 (KEY_KP3) -> atset1:81 */ | ||||||
|  |   "Numpad4": 0x4b, /* html:Numpad4 (Numpad4) -> linux:75 (KEY_KP4) -> atset1:75 */ | ||||||
|  |   "Numpad5": 0x4c, /* html:Numpad5 (Numpad5) -> linux:76 (KEY_KP5) -> atset1:76 */ | ||||||
|  |   "Numpad6": 0x4d, /* html:Numpad6 (Numpad6) -> linux:77 (KEY_KP6) -> atset1:77 */ | ||||||
|  |   "Numpad7": 0x47, /* html:Numpad7 (Numpad7) -> linux:71 (KEY_KP7) -> atset1:71 */ | ||||||
|  |   "Numpad8": 0x48, /* html:Numpad8 (Numpad8) -> linux:72 (KEY_KP8) -> atset1:72 */ | ||||||
|  |   "Numpad9": 0x49, /* html:Numpad9 (Numpad9) -> linux:73 (KEY_KP9) -> atset1:73 */ | ||||||
|  |   "NumpadAdd": 0x4e, /* html:NumpadAdd (NumpadAdd) -> linux:78 (KEY_KPPLUS) -> atset1:78 */ | ||||||
|  |   "NumpadComma": 0x7e, /* html:NumpadComma (NumpadComma) -> linux:121 (KEY_KPCOMMA) -> atset1:126 */ | ||||||
|  |   "NumpadDecimal": 0x53, /* html:NumpadDecimal (NumpadDecimal) -> linux:83 (KEY_KPDOT) -> atset1:83 */ | ||||||
|  |   "NumpadDivide": 0xe035, /* html:NumpadDivide (NumpadDivide) -> linux:98 (KEY_KPSLASH) -> atset1:57397 */ | ||||||
|  |   "NumpadEnter": 0xe01c, /* html:NumpadEnter (NumpadEnter) -> linux:96 (KEY_KPENTER) -> atset1:57372 */ | ||||||
|  |   "NumpadEqual": 0x59, /* html:NumpadEqual (NumpadEqual) -> linux:117 (KEY_KPEQUAL) -> atset1:89 */ | ||||||
|  |   "NumpadMultiply": 0x37, /* html:NumpadMultiply (NumpadMultiply) -> linux:55 (KEY_KPASTERISK) -> atset1:55 */ | ||||||
|  |   "NumpadParenLeft": 0xe076, /* html:NumpadParenLeft (NumpadParenLeft) -> linux:179 (KEY_KPLEFTPAREN) -> atset1:57462 */ | ||||||
|  |   "NumpadParenRight": 0xe07b, /* html:NumpadParenRight (NumpadParenRight) -> linux:180 (KEY_KPRIGHTPAREN) -> atset1:57467 */ | ||||||
|  |   "NumpadSubtract": 0x4a, /* html:NumpadSubtract (NumpadSubtract) -> linux:74 (KEY_KPMINUS) -> atset1:74 */ | ||||||
|  |   "Open": 0x64, /* html:Open (Open) -> linux:134 (KEY_OPEN) -> atset1:100 */ | ||||||
|  |   "PageDown": 0xe051, /* html:PageDown (PageDown) -> linux:109 (KEY_PAGEDOWN) -> atset1:57425 */ | ||||||
|  |   "PageUp": 0xe049, /* html:PageUp (PageUp) -> linux:104 (KEY_PAGEUP) -> atset1:57417 */ | ||||||
|  |   "Paste": 0x65, /* html:Paste (Paste) -> linux:135 (KEY_PASTE) -> atset1:101 */ | ||||||
|  |   "Pause": 0xe046, /* html:Pause (Pause) -> linux:119 (KEY_PAUSE) -> atset1:57414 */ | ||||||
|  |   "Period": 0x34, /* html:Period (Period) -> linux:52 (KEY_DOT) -> atset1:52 */ | ||||||
|  |   "Power": 0xe05e, /* html:Power (Power) -> linux:116 (KEY_POWER) -> atset1:57438 */ | ||||||
|  |   "PrintScreen": 0x54, /* html:PrintScreen (PrintScreen) -> linux:99 (KEY_SYSRQ) -> atset1:84 */ | ||||||
|  |   "Props": 0xe006, /* html:Props (Props) -> linux:130 (KEY_PROPS) -> atset1:57350 */ | ||||||
|  |   "Quote": 0x28, /* html:Quote (Quote) -> linux:40 (KEY_APOSTROPHE) -> atset1:40 */ | ||||||
|  |   "ScrollLock": 0x46, /* html:ScrollLock (ScrollLock) -> linux:70 (KEY_SCROLLLOCK) -> atset1:70 */ | ||||||
|  |   "Semicolon": 0x27, /* html:Semicolon (Semicolon) -> linux:39 (KEY_SEMICOLON) -> atset1:39 */ | ||||||
|  |   "ShiftLeft": 0x2a, /* html:ShiftLeft (ShiftLeft) -> linux:42 (KEY_LEFTSHIFT) -> atset1:42 */ | ||||||
|  |   "ShiftRight": 0x36, /* html:ShiftRight (ShiftRight) -> linux:54 (KEY_RIGHTSHIFT) -> atset1:54 */ | ||||||
|  |   "Slash": 0x35, /* html:Slash (Slash) -> linux:53 (KEY_SLASH) -> atset1:53 */ | ||||||
|  |   "Sleep": 0xe05f, /* html:Sleep (Sleep) -> linux:142 (KEY_SLEEP) -> atset1:57439 */ | ||||||
|  |   "Space": 0x39, /* html:Space (Space) -> linux:57 (KEY_SPACE) -> atset1:57 */ | ||||||
|  |   "Suspend": 0xe025, /* html:Suspend (Suspend) -> linux:205 (KEY_SUSPEND) -> atset1:57381 */ | ||||||
|  |   "Tab": 0xf, /* html:Tab (Tab) -> linux:15 (KEY_TAB) -> atset1:15 */ | ||||||
|  |   "Undo": 0xe007, /* html:Undo (Undo) -> linux:131 (KEY_UNDO) -> atset1:57351 */ | ||||||
|  |   "WakeUp": 0xe063, /* html:WakeUp (WakeUp) -> linux:143 (KEY_WAKEUP) -> atset1:57443 */ | ||||||
|  | }; | ||||||
							
								
								
									
										312
									
								
								core/ra2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,312 @@ | |||||||
|  | import { encodeUTF8 } from './util/strings.js'; | ||||||
|  | import EventTargetMixin from './util/eventtarget.js'; | ||||||
|  | import legacyCrypto from './crypto/crypto.js'; | ||||||
|  |  | ||||||
|  | class RA2Cipher { | ||||||
|  |     constructor() { | ||||||
|  |         this._cipher = null; | ||||||
|  |         this._counter = new Uint8Array(16); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async setKey(key) { | ||||||
|  |         this._cipher = await legacyCrypto.importKey( | ||||||
|  |             "raw", key, { name: "AES-EAX" }, false, ["encrypt, decrypt"]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async makeMessage(message) { | ||||||
|  |         const ad = new Uint8Array([(message.length & 0xff00) >>> 8, message.length & 0xff]); | ||||||
|  |         const encrypted = await legacyCrypto.encrypt({ | ||||||
|  |             name: "AES-EAX", | ||||||
|  |             iv: this._counter, | ||||||
|  |             additionalData: ad, | ||||||
|  |         }, this._cipher, message); | ||||||
|  |         for (let i = 0; i < 16 && this._counter[i]++ === 255; i++); | ||||||
|  |         const res = new Uint8Array(message.length + 2 + 16); | ||||||
|  |         res.set(ad); | ||||||
|  |         res.set(encrypted, 2); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async receiveMessage(length, encrypted) { | ||||||
|  |         const ad = new Uint8Array([(length & 0xff00) >>> 8, length & 0xff]); | ||||||
|  |         const res = await legacyCrypto.decrypt({ | ||||||
|  |             name: "AES-EAX", | ||||||
|  |             iv: this._counter, | ||||||
|  |             additionalData: ad, | ||||||
|  |         }, this._cipher, encrypted); | ||||||
|  |         for (let i = 0; i < 16 && this._counter[i]++ === 255; i++); | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default class RSAAESAuthenticationState extends EventTargetMixin { | ||||||
|  |     constructor(sock, getCredentials) { | ||||||
|  |         super(); | ||||||
|  |         this._hasStarted = false; | ||||||
|  |         this._checkSock = null; | ||||||
|  |         this._checkCredentials = null; | ||||||
|  |         this._approveServerResolve = null; | ||||||
|  |         this._sockReject = null; | ||||||
|  |         this._credentialsReject = null; | ||||||
|  |         this._approveServerReject = null; | ||||||
|  |         this._sock = sock; | ||||||
|  |         this._getCredentials = getCredentials; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _waitSockAsync(len) { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             const hasData = () => !this._sock.rQwait('RA2', len); | ||||||
|  |             if (hasData()) { | ||||||
|  |                 resolve(); | ||||||
|  |             } else { | ||||||
|  |                 this._checkSock = () => { | ||||||
|  |                     if (hasData()) { | ||||||
|  |                         resolve(); | ||||||
|  |                         this._checkSock = null; | ||||||
|  |                         this._sockReject = null; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |                 this._sockReject = reject; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _waitApproveKeyAsync() { | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             this._approveServerResolve = resolve; | ||||||
|  |             this._approveServerReject = reject; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _waitCredentialsAsync(subtype) { | ||||||
|  |         const hasCredentials = () => { | ||||||
|  |             if (subtype === 1 && this._getCredentials().username !== undefined && | ||||||
|  |                 this._getCredentials().password !== undefined) { | ||||||
|  |                 return true; | ||||||
|  |             } else if (subtype === 2 && this._getCredentials().password !== undefined) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         }; | ||||||
|  |         return new Promise((resolve, reject) => { | ||||||
|  |             if (hasCredentials()) { | ||||||
|  |                 resolve(); | ||||||
|  |             } else { | ||||||
|  |                 this._checkCredentials = () => { | ||||||
|  |                     if (hasCredentials()) { | ||||||
|  |                         resolve(); | ||||||
|  |                         this._checkCredentials = null; | ||||||
|  |                         this._credentialsReject = null; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |                 this._credentialsReject = reject; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     checkInternalEvents() { | ||||||
|  |         if (this._checkSock !== null) { | ||||||
|  |             this._checkSock(); | ||||||
|  |         } | ||||||
|  |         if (this._checkCredentials !== null) { | ||||||
|  |             this._checkCredentials(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     approveServer() { | ||||||
|  |         if (this._approveServerResolve !== null) { | ||||||
|  |             this._approveServerResolve(); | ||||||
|  |             this._approveServerResolve = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     disconnect() { | ||||||
|  |         if (this._sockReject !== null) { | ||||||
|  |             this._sockReject(new Error("disconnect normally")); | ||||||
|  |             this._sockReject = null; | ||||||
|  |         } | ||||||
|  |         if (this._credentialsReject !== null) { | ||||||
|  |             this._credentialsReject(new Error("disconnect normally")); | ||||||
|  |             this._credentialsReject = null; | ||||||
|  |         } | ||||||
|  |         if (this._approveServerReject !== null) { | ||||||
|  |             this._approveServerReject(new Error("disconnect normally")); | ||||||
|  |             this._approveServerReject = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async negotiateRA2neAuthAsync() { | ||||||
|  |         this._hasStarted = true; | ||||||
|  |         // 1: Receive server public key | ||||||
|  |         await this._waitSockAsync(4); | ||||||
|  |         const serverKeyLengthBuffer = this._sock.rQpeekBytes(4); | ||||||
|  |         const serverKeyLength = this._sock.rQshift32(); | ||||||
|  |         if (serverKeyLength < 1024) { | ||||||
|  |             throw new Error("RA2: server public key is too short: " + serverKeyLength); | ||||||
|  |         } else if (serverKeyLength > 8192) { | ||||||
|  |             throw new Error("RA2: server public key is too long: " + serverKeyLength); | ||||||
|  |         } | ||||||
|  |         const serverKeyBytes = Math.ceil(serverKeyLength / 8); | ||||||
|  |         await this._waitSockAsync(serverKeyBytes * 2); | ||||||
|  |         const serverN = this._sock.rQshiftBytes(serverKeyBytes); | ||||||
|  |         const serverE = this._sock.rQshiftBytes(serverKeyBytes); | ||||||
|  |         const serverRSACipher = await legacyCrypto.importKey( | ||||||
|  |             "raw", { n: serverN, e: serverE }, { name: "RSA-PKCS1-v1_5" }, false, ["encrypt"]); | ||||||
|  |         const serverPublickey = new Uint8Array(4 + serverKeyBytes * 2); | ||||||
|  |         serverPublickey.set(serverKeyLengthBuffer); | ||||||
|  |         serverPublickey.set(serverN, 4); | ||||||
|  |         serverPublickey.set(serverE, 4 + serverKeyBytes); | ||||||
|  |  | ||||||
|  |         // verify server public key | ||||||
|  |         let approveKey = this._waitApproveKeyAsync(); | ||||||
|  |         this.dispatchEvent(new CustomEvent("serververification", { | ||||||
|  |             detail: { type: "RSA", publickey: serverPublickey } | ||||||
|  |         })); | ||||||
|  |         await approveKey; | ||||||
|  |  | ||||||
|  |         // 2: Send client public key | ||||||
|  |         const clientKeyLength = 2048; | ||||||
|  |         const clientKeyBytes = Math.ceil(clientKeyLength / 8); | ||||||
|  |         const clientRSACipher = (await legacyCrypto.generateKey({ | ||||||
|  |             name: "RSA-PKCS1-v1_5", | ||||||
|  |             modulusLength: clientKeyLength, | ||||||
|  |             publicExponent: new Uint8Array([1, 0, 1]), | ||||||
|  |         }, true, ["encrypt"])).privateKey; | ||||||
|  |         const clientExportedRSAKey = await legacyCrypto.exportKey("raw", clientRSACipher); | ||||||
|  |         const clientN = clientExportedRSAKey.n; | ||||||
|  |         const clientE = clientExportedRSAKey.e; | ||||||
|  |         const clientPublicKey = new Uint8Array(4 + clientKeyBytes * 2); | ||||||
|  |         clientPublicKey[0] = (clientKeyLength & 0xff000000) >>> 24; | ||||||
|  |         clientPublicKey[1] = (clientKeyLength & 0xff0000) >>> 16; | ||||||
|  |         clientPublicKey[2] = (clientKeyLength & 0xff00) >>> 8; | ||||||
|  |         clientPublicKey[3] = clientKeyLength & 0xff; | ||||||
|  |         clientPublicKey.set(clientN, 4); | ||||||
|  |         clientPublicKey.set(clientE, 4 + clientKeyBytes); | ||||||
|  |         this._sock.sQpushBytes(clientPublicKey); | ||||||
|  |         this._sock.flush(); | ||||||
|  |  | ||||||
|  |         // 3: Send client random | ||||||
|  |         const clientRandom = new Uint8Array(16); | ||||||
|  |         window.crypto.getRandomValues(clientRandom); | ||||||
|  |         const clientEncryptedRandom = await legacyCrypto.encrypt( | ||||||
|  |             { name: "RSA-PKCS1-v1_5" }, serverRSACipher, clientRandom); | ||||||
|  |         const clientRandomMessage = new Uint8Array(2 + serverKeyBytes); | ||||||
|  |         clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8; | ||||||
|  |         clientRandomMessage[1] = serverKeyBytes & 0xff; | ||||||
|  |         clientRandomMessage.set(clientEncryptedRandom, 2); | ||||||
|  |         this._sock.sQpushBytes(clientRandomMessage); | ||||||
|  |         this._sock.flush(); | ||||||
|  |  | ||||||
|  |         // 4: Receive server random | ||||||
|  |         await this._waitSockAsync(2); | ||||||
|  |         if (this._sock.rQshift16() !== clientKeyBytes) { | ||||||
|  |             throw new Error("RA2: wrong encrypted message length"); | ||||||
|  |         } | ||||||
|  |         const serverEncryptedRandom = this._sock.rQshiftBytes(clientKeyBytes); | ||||||
|  |         const serverRandom = await legacyCrypto.decrypt( | ||||||
|  |             { name: "RSA-PKCS1-v1_5" }, clientRSACipher, serverEncryptedRandom); | ||||||
|  |         if (serverRandom === null || serverRandom.length !== 16) { | ||||||
|  |             throw new Error("RA2: corrupted server encrypted random"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 5: Compute session keys and set ciphers | ||||||
|  |         let clientSessionKey = new Uint8Array(32); | ||||||
|  |         let serverSessionKey = new Uint8Array(32); | ||||||
|  |         clientSessionKey.set(serverRandom); | ||||||
|  |         clientSessionKey.set(clientRandom, 16); | ||||||
|  |         serverSessionKey.set(clientRandom); | ||||||
|  |         serverSessionKey.set(serverRandom, 16); | ||||||
|  |         clientSessionKey = await window.crypto.subtle.digest("SHA-1", clientSessionKey); | ||||||
|  |         clientSessionKey = new Uint8Array(clientSessionKey).slice(0, 16); | ||||||
|  |         serverSessionKey = await window.crypto.subtle.digest("SHA-1", serverSessionKey); | ||||||
|  |         serverSessionKey = new Uint8Array(serverSessionKey).slice(0, 16); | ||||||
|  |         const clientCipher = new RA2Cipher(); | ||||||
|  |         await clientCipher.setKey(clientSessionKey); | ||||||
|  |         const serverCipher = new RA2Cipher(); | ||||||
|  |         await serverCipher.setKey(serverSessionKey); | ||||||
|  |  | ||||||
|  |         // 6: Compute and exchange hashes | ||||||
|  |         let serverHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2); | ||||||
|  |         let clientHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2); | ||||||
|  |         serverHash.set(serverPublickey); | ||||||
|  |         serverHash.set(clientPublicKey, 4 + serverKeyBytes * 2); | ||||||
|  |         clientHash.set(clientPublicKey); | ||||||
|  |         clientHash.set(serverPublickey, 4 + clientKeyBytes * 2); | ||||||
|  |         serverHash = await window.crypto.subtle.digest("SHA-1", serverHash); | ||||||
|  |         clientHash = await window.crypto.subtle.digest("SHA-1", clientHash); | ||||||
|  |         serverHash = new Uint8Array(serverHash); | ||||||
|  |         clientHash = new Uint8Array(clientHash); | ||||||
|  |         this._sock.sQpushBytes(await clientCipher.makeMessage(clientHash)); | ||||||
|  |         this._sock.flush(); | ||||||
|  |         await this._waitSockAsync(2 + 20 + 16); | ||||||
|  |         if (this._sock.rQshift16() !== 20) { | ||||||
|  |             throw new Error("RA2: wrong server hash"); | ||||||
|  |         } | ||||||
|  |         const serverHashReceived = await serverCipher.receiveMessage( | ||||||
|  |             20, this._sock.rQshiftBytes(20 + 16)); | ||||||
|  |         if (serverHashReceived === null) { | ||||||
|  |             throw new Error("RA2: failed to authenticate the message"); | ||||||
|  |         } | ||||||
|  |         for (let i = 0; i < 20; i++) { | ||||||
|  |             if (serverHashReceived[i] !== serverHash[i]) { | ||||||
|  |                 throw new Error("RA2: wrong server hash"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 7: Receive subtype | ||||||
|  |         await this._waitSockAsync(2 + 1 + 16); | ||||||
|  |         if (this._sock.rQshift16() !== 1) { | ||||||
|  |             throw new Error("RA2: wrong subtype"); | ||||||
|  |         } | ||||||
|  |         let subtype = (await serverCipher.receiveMessage( | ||||||
|  |             1, this._sock.rQshiftBytes(1 + 16))); | ||||||
|  |         if (subtype === null) { | ||||||
|  |             throw new Error("RA2: failed to authenticate the message"); | ||||||
|  |         } | ||||||
|  |         subtype = subtype[0]; | ||||||
|  |         let waitCredentials = this._waitCredentialsAsync(subtype); | ||||||
|  |         if (subtype === 1) { | ||||||
|  |             if (this._getCredentials().username === undefined || | ||||||
|  |                 this._getCredentials().password === undefined) { | ||||||
|  |                 this.dispatchEvent(new CustomEvent( | ||||||
|  |                     "credentialsrequired", | ||||||
|  |                     { detail: { types: ["username", "password"] } })); | ||||||
|  |             } | ||||||
|  |         } else if (subtype === 2) { | ||||||
|  |             if (this._getCredentials().password === undefined) { | ||||||
|  |                 this.dispatchEvent(new CustomEvent( | ||||||
|  |                     "credentialsrequired", | ||||||
|  |                     { detail: { types: ["password"] } })); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             throw new Error("RA2: wrong subtype"); | ||||||
|  |         } | ||||||
|  |         await waitCredentials; | ||||||
|  |         let username; | ||||||
|  |         if (subtype === 1) { | ||||||
|  |             username = encodeUTF8(this._getCredentials().username).slice(0, 255); | ||||||
|  |         } else { | ||||||
|  |             username = ""; | ||||||
|  |         } | ||||||
|  |         const password = encodeUTF8(this._getCredentials().password).slice(0, 255); | ||||||
|  |         const credentials = new Uint8Array(username.length + password.length + 2); | ||||||
|  |         credentials[0] = username.length; | ||||||
|  |         credentials[username.length + 1] = password.length; | ||||||
|  |         for (let i = 0; i < username.length; i++) { | ||||||
|  |             credentials[i + 1] = username.charCodeAt(i); | ||||||
|  |         } | ||||||
|  |         for (let i = 0; i < password.length; i++) { | ||||||
|  |             credentials[username.length + 2 + i] = password.charCodeAt(i); | ||||||
|  |         } | ||||||
|  |         this._sock.sQpushBytes(await clientCipher.makeMessage(credentials)); | ||||||
|  |         this._sock.flush(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get hasStarted() { | ||||||
|  |         return this._hasStarted; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     set hasStarted(s) { | ||||||
|  |         this._hasStarted = s; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3260
									
								
								core/rfb.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										152
									
								
								core/util/browser.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,152 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  * | ||||||
|  |  * Browser feature support detection | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import * as Log from './logging.js'; | ||||||
|  |  | ||||||
|  | // Touch detection | ||||||
|  | export let isTouchDevice = ('ontouchstart' in document.documentElement) || | ||||||
|  |                                  // requried for Chrome debugger | ||||||
|  |                                  (document.ontouchstart !== undefined) || | ||||||
|  |                                  // required for MS Surface | ||||||
|  |                                  (navigator.maxTouchPoints > 0) || | ||||||
|  |                                  (navigator.msMaxTouchPoints > 0); | ||||||
|  | window.addEventListener('touchstart', function onFirstTouch() { | ||||||
|  |     isTouchDevice = true; | ||||||
|  |     window.removeEventListener('touchstart', onFirstTouch, false); | ||||||
|  | }, false); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // The goal is to find a certain physical width, the devicePixelRatio | ||||||
|  | // brings us a bit closer but is not optimal. | ||||||
|  | export let dragThreshold = 10 * (window.devicePixelRatio || 1); | ||||||
|  |  | ||||||
|  | let _supportsCursorURIs = false; | ||||||
|  |  | ||||||
|  | try { | ||||||
|  |     const target = document.createElement('canvas'); | ||||||
|  |     target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; | ||||||
|  |  | ||||||
|  |     if (target.style.cursor.indexOf("url") === 0) { | ||||||
|  |         Log.Info("Data URI scheme cursor supported"); | ||||||
|  |         _supportsCursorURIs = true; | ||||||
|  |     } else { | ||||||
|  |         Log.Warn("Data URI scheme cursor not supported"); | ||||||
|  |     } | ||||||
|  | } catch (exc) { | ||||||
|  |     Log.Error("Data URI scheme cursor test exception: " + exc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const supportsCursorURIs = _supportsCursorURIs; | ||||||
|  |  | ||||||
|  | let _hasScrollbarGutter = true; | ||||||
|  | try { | ||||||
|  |     // Create invisible container | ||||||
|  |     const container = document.createElement('div'); | ||||||
|  |     container.style.visibility = 'hidden'; | ||||||
|  |     container.style.overflow = 'scroll'; // forcing scrollbars | ||||||
|  |     document.body.appendChild(container); | ||||||
|  |  | ||||||
|  |     // Create a div and place it in the container | ||||||
|  |     const child = document.createElement('div'); | ||||||
|  |     container.appendChild(child); | ||||||
|  |  | ||||||
|  |     // Calculate the difference between the container's full width | ||||||
|  |     // and the child's width - the difference is the scrollbars | ||||||
|  |     const scrollbarWidth = (container.offsetWidth - child.offsetWidth); | ||||||
|  |  | ||||||
|  |     // Clean up | ||||||
|  |     container.parentNode.removeChild(container); | ||||||
|  |  | ||||||
|  |     _hasScrollbarGutter = scrollbarWidth != 0; | ||||||
|  | } catch (exc) { | ||||||
|  |     Log.Error("Scrollbar test exception: " + exc); | ||||||
|  | } | ||||||
|  | export const hasScrollbarGutter = _hasScrollbarGutter; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * The functions for detection of platforms and browsers below are exported | ||||||
|  |  * but the use of these should be minimized as much as possible. | ||||||
|  |  * | ||||||
|  |  * It's better to use feature detection than platform detection. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* OS */ | ||||||
|  |  | ||||||
|  | export function isMac() { | ||||||
|  |     return !!(/mac/i).exec(navigator.platform); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isWindows() { | ||||||
|  |     return !!(/win/i).exec(navigator.platform); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isIOS() { | ||||||
|  |     return (!!(/ipad/i).exec(navigator.platform) || | ||||||
|  |             !!(/iphone/i).exec(navigator.platform) || | ||||||
|  |             !!(/ipod/i).exec(navigator.platform)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isAndroid() { | ||||||
|  |     /* Android sets navigator.platform to Linux :/ */ | ||||||
|  |     return !!navigator.userAgent.match('Android '); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isChromeOS() { | ||||||
|  |     /* ChromeOS sets navigator.platform to Linux :/ */ | ||||||
|  |     return !!navigator.userAgent.match(' CrOS '); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Browser */ | ||||||
|  |  | ||||||
|  | export function isSafari() { | ||||||
|  |     return !!navigator.userAgent.match('Safari/...') && | ||||||
|  |            !navigator.userAgent.match('Chrome/...') && | ||||||
|  |            !navigator.userAgent.match('Chromium/...') && | ||||||
|  |            !navigator.userAgent.match('Epiphany/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isFirefox() { | ||||||
|  |     return !!navigator.userAgent.match('Firefox/...') && | ||||||
|  |            !navigator.userAgent.match('Seamonkey/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isChrome() { | ||||||
|  |     return !!navigator.userAgent.match('Chrome/...') && | ||||||
|  |            !navigator.userAgent.match('Chromium/...') && | ||||||
|  |            !navigator.userAgent.match('Edg/...') && | ||||||
|  |            !navigator.userAgent.match('OPR/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isChromium() { | ||||||
|  |     return !!navigator.userAgent.match('Chromium/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isOpera() { | ||||||
|  |     return !!navigator.userAgent.match('OPR/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isEdge() { | ||||||
|  |     return !!navigator.userAgent.match('Edg/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Engine */ | ||||||
|  |  | ||||||
|  | export function isGecko() { | ||||||
|  |     return !!navigator.userAgent.match('Gecko/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isWebKit() { | ||||||
|  |     return !!navigator.userAgent.match('AppleWebKit/...') && | ||||||
|  |            !navigator.userAgent.match('Chrome/...'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function isBlink() { | ||||||
|  |     return !!navigator.userAgent.match('Chrome/...'); | ||||||
|  | } | ||||||
							
								
								
									
										262
									
								
								core/util/cursor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,262 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 or any later version (see LICENSE.txt) | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import { supportsCursorURIs, isTouchDevice } from './browser.js'; | ||||||
|  |  | ||||||
|  | const useFallback = !supportsCursorURIs || isTouchDevice; | ||||||
|  |  | ||||||
|  | export default class Cursor { | ||||||
|  |     constructor() { | ||||||
|  |         this._target  = null; | ||||||
|  |         this._visible = true;         | ||||||
|  |  | ||||||
|  |         this._canvas = document.createElement('canvas'); | ||||||
|  |  | ||||||
|  |         if (useFallback) { | ||||||
|  |             this._canvas.style.position = 'fixed'; | ||||||
|  |             this._canvas.style.zIndex = '65535'; | ||||||
|  |             this._canvas.style.pointerEvents = 'none'; | ||||||
|  |             // Safari on iOS can select the cursor image | ||||||
|  |             // https://bugs.webkit.org/show_bug.cgi?id=249223 | ||||||
|  |             this._canvas.style.userSelect = 'none'; | ||||||
|  |             this._canvas.style.WebkitUserSelect = 'none'; | ||||||
|  |             // Can't use "display" because of Firefox bug #1445997 | ||||||
|  |             this._canvas.style.visibility = 'hidden'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._position = { x: 0, y: 0 }; | ||||||
|  |         this._hotSpot = { x: 0, y: 0 }; | ||||||
|  |  | ||||||
|  |         this._eventHandlers = { | ||||||
|  |             'mouseover': this._handleMouseOver.bind(this), | ||||||
|  |             'mouseleave': this._handleMouseLeave.bind(this), | ||||||
|  |             'mousemove': this._handleMouseMove.bind(this), | ||||||
|  |             'mouseup': this._handleMouseUp.bind(this), | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     attach(target) { | ||||||
|  |         if (this._target) { | ||||||
|  |             this.detach(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._target = target; | ||||||
|  |  | ||||||
|  |         if (useFallback) { | ||||||
|  |             document.body.appendChild(this._canvas); | ||||||
|  |  | ||||||
|  |             const options = { capture: true, passive: true }; | ||||||
|  |             this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options); | ||||||
|  |             this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options); | ||||||
|  |             this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options); | ||||||
|  |             this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     detach() { | ||||||
|  |         if (!this._target) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (useFallback) { | ||||||
|  |             const options = { capture: true, passive: true }; | ||||||
|  |             this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options); | ||||||
|  |             this._target.removeEventListener('mouseleave', this._eventHandlers.mouseleave, options); | ||||||
|  |             this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options); | ||||||
|  |             this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options); | ||||||
|  |  | ||||||
|  |             if (document.contains(this._canvas)) { | ||||||
|  |                 document.body.removeChild(this._canvas); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._target = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     change(rgba, hotx, hoty, w, h) { | ||||||
|  |         if ((w === 0) || (h === 0)) { | ||||||
|  |             this.clear(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this._position.x = this._position.x + this._hotSpot.x - hotx; | ||||||
|  |         this._position.y = this._position.y + this._hotSpot.y - hoty; | ||||||
|  |         this._hotSpot.x = hotx; | ||||||
|  |         this._hotSpot.y = hoty; | ||||||
|  |  | ||||||
|  |         let ctx = this._canvas.getContext('2d'); | ||||||
|  |  | ||||||
|  |         this._canvas.width = w; | ||||||
|  |         this._canvas.height = h; | ||||||
|  |  | ||||||
|  |         let img = new ImageData(new Uint8ClampedArray(rgba), w, h); | ||||||
|  |         ctx.clearRect(0, 0, w, h); | ||||||
|  |         ctx.putImageData(img, 0, 0); | ||||||
|  |  | ||||||
|  |         if (useFallback) { | ||||||
|  |             this._updatePosition(); | ||||||
|  |         } else { | ||||||
|  |             let url = this._canvas.toDataURL(); | ||||||
|  |             this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default'; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     clear() { | ||||||
|  |         this._target.style.cursor = 'none'; | ||||||
|  |         this._canvas.width = 0; | ||||||
|  |         this._canvas.height = 0; | ||||||
|  |         this._position.x = this._position.x + this._hotSpot.x; | ||||||
|  |         this._position.y = this._position.y + this._hotSpot.y; | ||||||
|  |         this._hotSpot.x = 0; | ||||||
|  |         this._hotSpot.y = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     setVisibility(visible) { | ||||||
|  |         this._visible = visible; | ||||||
|  |         if (visible) { | ||||||
|  |             this._showCursor(); | ||||||
|  |         } else { | ||||||
|  |             this._hideCursor(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Mouse events might be emulated, this allows | ||||||
|  |     // moving the cursor in such cases | ||||||
|  |     move(clientX, clientY) { | ||||||
|  |         if (!useFallback) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // clientX/clientY are relative the _visual viewport_, | ||||||
|  |         // but our position is relative the _layout viewport_, | ||||||
|  |         // so try to compensate when we can | ||||||
|  |         if (window.visualViewport) { | ||||||
|  |             this._position.x = clientX + window.visualViewport.offsetLeft; | ||||||
|  |             this._position.y = clientY + window.visualViewport.offsetTop; | ||||||
|  |         } else { | ||||||
|  |             this._position.x = clientX; | ||||||
|  |             this._position.y = clientY; | ||||||
|  |         } | ||||||
|  |         this._updatePosition(); | ||||||
|  |         let target = document.elementFromPoint(clientX, clientY); | ||||||
|  |         this._updateVisibility(target); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleMouseOver(event) { | ||||||
|  |         // This event could be because we're entering the target, or | ||||||
|  |         // moving around amongst its sub elements. Let the move handler | ||||||
|  |         // sort things out. | ||||||
|  |         this._handleMouseMove(event); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleMouseLeave(event) { | ||||||
|  |         // Check if we should show the cursor on the element we are leaving to | ||||||
|  |         this._updateVisibility(event.relatedTarget); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleMouseMove(event) { | ||||||
|  |         this._updateVisibility(event.target); | ||||||
|  |  | ||||||
|  |         this._position.x = event.clientX - this._hotSpot.x; | ||||||
|  |         this._position.y = event.clientY - this._hotSpot.y; | ||||||
|  |  | ||||||
|  |         this._updatePosition(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _handleMouseUp(event) { | ||||||
|  |         // We might get this event because of a drag operation that | ||||||
|  |         // moved outside of the target. Check what's under the cursor | ||||||
|  |         // now and adjust visibility based on that. | ||||||
|  |         let target = document.elementFromPoint(event.clientX, event.clientY); | ||||||
|  |         this._updateVisibility(target); | ||||||
|  |  | ||||||
|  |         // Captures end with a mouseup but we can't know the event order of | ||||||
|  |         // mouseup vs releaseCapture. | ||||||
|  |         // | ||||||
|  |         // In the cases when releaseCapture comes first, the code above is | ||||||
|  |         // enough. | ||||||
|  |         // | ||||||
|  |         // In the cases when the mouseup comes first, we need wait for the | ||||||
|  |         // browser to flush all events and then check again if the cursor | ||||||
|  |         // should be visible. | ||||||
|  |         if (this._captureIsActive()) { | ||||||
|  |             window.setTimeout(() => { | ||||||
|  |                 // We might have detached at this point | ||||||
|  |                 if (!this._target) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 // Refresh the target from elementFromPoint since queued events | ||||||
|  |                 // might have altered the DOM | ||||||
|  |                 target = document.elementFromPoint(event.clientX, | ||||||
|  |                                                    event.clientY); | ||||||
|  |                 this._updateVisibility(target); | ||||||
|  |             }, 0); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _showCursor() { | ||||||
|  |         if (this._canvas.style.visibility === 'hidden') { | ||||||
|  |             this._canvas.style.visibility = ''; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _hideCursor() { | ||||||
|  |         if (this._canvas.style.visibility !== 'hidden') { | ||||||
|  |             this._canvas.style.visibility = 'hidden'; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Should we currently display the cursor? | ||||||
|  |     // (i.e. are we over the target, or a child of the target without a | ||||||
|  |     // different cursor set) | ||||||
|  |     _shouldShowCursor(target) { | ||||||
|  |         if (!target) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if (!this._visible) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // Easy case | ||||||
|  |         if (target === this._target) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         // Other part of the DOM? | ||||||
|  |         if (!this._target.contains(target)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // Has the child its own cursor? | ||||||
|  |         // FIXME: How can we tell that a sub element has an | ||||||
|  |         //        explicit "cursor: none;"? | ||||||
|  |         if (window.getComputedStyle(target).cursor !== 'none') { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _updateVisibility(target) { | ||||||
|  |         // When the cursor target has capture we want to show the cursor. | ||||||
|  |         // So, if a capture is active - look at the captured element instead. | ||||||
|  |         if (this._captureIsActive()) { | ||||||
|  |             target = document.captureElement; | ||||||
|  |         } | ||||||
|  |         if (this._shouldShowCursor(target)) { | ||||||
|  |             this._showCursor(); | ||||||
|  |         } else { | ||||||
|  |             this._hideCursor(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _updatePosition() { | ||||||
|  |         this._canvas.style.left = this._position.x + "px"; | ||||||
|  |         this._canvas.style.top = this._position.y + "px"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _captureIsActive() { | ||||||
|  |         return document.captureElement && | ||||||
|  |             document.documentElement.contains(document.captureElement); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								core/util/element.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,32 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2020 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * HTML element utility functions | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export function clientToElement(x, y, elem) { | ||||||
|  |     const bounds = elem.getBoundingClientRect(); | ||||||
|  |     let pos = { x: 0, y: 0 }; | ||||||
|  |     // Clip to target bounds | ||||||
|  |     if (x < bounds.left) { | ||||||
|  |         pos.x = 0; | ||||||
|  |     } else if (x >= bounds.right) { | ||||||
|  |         pos.x = bounds.width - 1; | ||||||
|  |     } else { | ||||||
|  |         pos.x = x - bounds.left; | ||||||
|  |     } | ||||||
|  |     if (y < bounds.top) { | ||||||
|  |         pos.y = 0; | ||||||
|  |     } else if (y >= bounds.bottom) { | ||||||
|  |         pos.y = bounds.height - 1; | ||||||
|  |     } else { | ||||||
|  |         pos.y = y - bounds.top; | ||||||
|  |     } | ||||||
|  |     return pos; | ||||||
|  | } | ||||||
							
								
								
									
										138
									
								
								core/util/events.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,138 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2018 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cross-browser event and position routines | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export function getPointerEvent(e) { | ||||||
|  |     return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function stopEvent(e) { | ||||||
|  |     e.stopPropagation(); | ||||||
|  |     e.preventDefault(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Emulate Element.setCapture() when not supported | ||||||
|  | let _captureRecursion = false; | ||||||
|  | let _elementForUnflushedEvents = null; | ||||||
|  | document.captureElement = null; | ||||||
|  | function _captureProxy(e) { | ||||||
|  |     // Recursion protection as we'll see our own event | ||||||
|  |     if (_captureRecursion) return; | ||||||
|  |  | ||||||
|  |     // Clone the event as we cannot dispatch an already dispatched event | ||||||
|  |     const newEv = new e.constructor(e.type, e); | ||||||
|  |  | ||||||
|  |     _captureRecursion = true; | ||||||
|  |     if (document.captureElement) { | ||||||
|  |         document.captureElement.dispatchEvent(newEv); | ||||||
|  |     } else { | ||||||
|  |         _elementForUnflushedEvents.dispatchEvent(newEv); | ||||||
|  |     } | ||||||
|  |     _captureRecursion = false; | ||||||
|  |  | ||||||
|  |     // Avoid double events | ||||||
|  |     e.stopPropagation(); | ||||||
|  |  | ||||||
|  |     // Respect the wishes of the redirected event handlers | ||||||
|  |     if (newEv.defaultPrevented) { | ||||||
|  |         e.preventDefault(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Implicitly release the capture on button release | ||||||
|  |     if (e.type === "mouseup") { | ||||||
|  |         releaseCapture(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Follow cursor style of target element | ||||||
|  | function _capturedElemChanged() { | ||||||
|  |     const proxyElem = document.getElementById("noVNC_mouse_capture_elem"); | ||||||
|  |     proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const _captureObserver = new MutationObserver(_capturedElemChanged); | ||||||
|  |  | ||||||
|  | export function setCapture(target) { | ||||||
|  |     if (target.setCapture) { | ||||||
|  |  | ||||||
|  |         target.setCapture(); | ||||||
|  |         document.captureElement = target; | ||||||
|  |     } else { | ||||||
|  |         // Release any existing capture in case this method is | ||||||
|  |         // called multiple times without coordination | ||||||
|  |         releaseCapture(); | ||||||
|  |  | ||||||
|  |         let proxyElem = document.getElementById("noVNC_mouse_capture_elem"); | ||||||
|  |  | ||||||
|  |         if (proxyElem === null) { | ||||||
|  |             proxyElem = document.createElement("div"); | ||||||
|  |             proxyElem.id = "noVNC_mouse_capture_elem"; | ||||||
|  |             proxyElem.style.position = "fixed"; | ||||||
|  |             proxyElem.style.top = "0px"; | ||||||
|  |             proxyElem.style.left = "0px"; | ||||||
|  |             proxyElem.style.width = "100%"; | ||||||
|  |             proxyElem.style.height = "100%"; | ||||||
|  |             proxyElem.style.zIndex = 10000; | ||||||
|  |             proxyElem.style.display = "none"; | ||||||
|  |             document.body.appendChild(proxyElem); | ||||||
|  |  | ||||||
|  |             // This is to make sure callers don't get confused by having | ||||||
|  |             // our blocking element as the target | ||||||
|  |             proxyElem.addEventListener('contextmenu', _captureProxy); | ||||||
|  |  | ||||||
|  |             proxyElem.addEventListener('mousemove', _captureProxy); | ||||||
|  |             proxyElem.addEventListener('mouseup', _captureProxy); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         document.captureElement = target; | ||||||
|  |  | ||||||
|  |         // Track cursor and get initial cursor | ||||||
|  |         _captureObserver.observe(target, {attributes: true}); | ||||||
|  |         _capturedElemChanged(); | ||||||
|  |  | ||||||
|  |         proxyElem.style.display = ""; | ||||||
|  |  | ||||||
|  |         // We listen to events on window in order to keep tracking if it | ||||||
|  |         // happens to leave the viewport | ||||||
|  |         window.addEventListener('mousemove', _captureProxy); | ||||||
|  |         window.addEventListener('mouseup', _captureProxy); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function releaseCapture() { | ||||||
|  |     if (document.releaseCapture) { | ||||||
|  |  | ||||||
|  |         document.releaseCapture(); | ||||||
|  |         document.captureElement = null; | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |         if (!document.captureElement) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // There might be events already queued. The event proxy needs | ||||||
|  |         // access to the captured element for these queued events. | ||||||
|  |         // E.g. contextmenu (right-click) in Microsoft Edge | ||||||
|  |         // | ||||||
|  |         // Before removing the capturedElem pointer we save it to a | ||||||
|  |         // temporary variable that the unflushed events can use. | ||||||
|  |         _elementForUnflushedEvents = document.captureElement; | ||||||
|  |         document.captureElement = null; | ||||||
|  |  | ||||||
|  |         _captureObserver.disconnect(); | ||||||
|  |  | ||||||
|  |         const proxyElem = document.getElementById("noVNC_mouse_capture_elem"); | ||||||
|  |         proxyElem.style.display = "none"; | ||||||
|  |  | ||||||
|  |         window.removeEventListener('mousemove', _captureProxy); | ||||||
|  |         window.removeEventListener('mouseup', _captureProxy); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								core/util/eventtarget.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,35 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2019 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export default class EventTargetMixin { | ||||||
|  |     constructor() { | ||||||
|  |         this._listeners = new Map(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     addEventListener(type, callback) { | ||||||
|  |         if (!this._listeners.has(type)) { | ||||||
|  |             this._listeners.set(type, new Set()); | ||||||
|  |         } | ||||||
|  |         this._listeners.get(type).add(callback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     removeEventListener(type, callback) { | ||||||
|  |         if (this._listeners.has(type)) { | ||||||
|  |             this._listeners.get(type).delete(callback); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dispatchEvent(event) { | ||||||
|  |         if (!this._listeners.has(event.type)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         this._listeners.get(event.type) | ||||||
|  |             .forEach(callback => callback.call(this, event)); | ||||||
|  |         return !event.defaultPrevented; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								core/util/int.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,15 @@ | |||||||
|  | /* | ||||||
|  |  * noVNC: HTML5 VNC client | ||||||
|  |  * Copyright (C) 2020 The noVNC Authors | ||||||
|  |  * Licensed under MPL 2.0 (see LICENSE.txt) | ||||||
|  |  * | ||||||
|  |  * See README.md for usage and integration instructions. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | export function toUnsigned32bit(toConvert) { | ||||||
|  |     return toConvert >>> 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function toSigned32bit(toConvert) { | ||||||
|  |     return toConvert | 0; | ||||||
|  | } | ||||||