]>
Commit | Line | Data |
---|---|---|
64ab5c4d JM |
1 | Array.prototype.shift8 = function () { |
2 | return this.shift(); | |
65e27ddd | 3 | } |
64ab5c4d | 4 | Array.prototype.push8 = function (num) { |
489d1676 | 5 | this.push(num & 0xFF); |
65e27ddd JM |
6 | } |
7 | ||
64ab5c4d JM |
8 | Array.prototype.shift16 = function () { |
9 | return (this.shift() << 8) + | |
10 | (this.shift() ); | |
65e27ddd | 11 | } |
64ab5c4d | 12 | Array.prototype.push16 = function (num) { |
489d1676 JM |
13 | this.push((num >> 8) & 0xFF, |
14 | (num ) & 0xFF ); | |
65e27ddd JM |
15 | } |
16 | ||
489d1676 | 17 | |
64ab5c4d JM |
18 | Array.prototype.shift32 = function () { |
19 | return (this.shift() << 24) + | |
20 | (this.shift() << 16) + | |
21 | (this.shift() << 8) + | |
22 | (this.shift() ); | |
489d1676 | 23 | } |
64ab5c4d | 24 | Array.prototype.push32 = function (num) { |
489d1676 JM |
25 | this.push((num >> 24) & 0xFF, |
26 | (num >> 16) & 0xFF, | |
27 | (num >> 8) & 0xFF, | |
28 | (num ) & 0xFF ); | |
65e27ddd | 29 | } |
489d1676 | 30 | |
64ab5c4d JM |
31 | Array.prototype.shiftStr = function (len) { |
32 | var arr = this.splice(0, len); | |
33 | return arr.map(function (num) { | |
34 | return String.fromCharCode(num); } ).join(''); | |
35 | } | |
36 | ||
37 | Array.prototype.shiftBytes = function (len) { | |
38 | return this.splice(0, len); | |
65e27ddd JM |
39 | } |
40 | ||
cc0410a3 JM |
41 | /* |
42 | * Pending frame buffer update data | |
43 | */ | |
44 | var FBU = { | |
45 | rects : 0, | |
ed7e776d | 46 | subrects : 0, |
0f628064 | 47 | tiles : 0, |
cc0410a3 JM |
48 | bytes : 0, |
49 | x : 0, | |
50 | y : 0, | |
51 | width : 0, | |
52 | height : 0, | |
53 | encoding : 0, | |
b7ec5487 | 54 | subencoding : -1, |
9f4af5a7 | 55 | background: null, |
cc0410a3 JM |
56 | arr : null}; |
57 | ||
d9cbdc7d | 58 | |
65e27ddd | 59 | /* |
cc0410a3 | 60 | * RFB namespace |
65e27ddd JM |
61 | */ |
62 | ||
64ab5c4d JM |
63 | RFB = { |
64 | ||
cc0410a3 JM |
65 | ws : null, // Web Socket object |
66 | ||
67 | version : "RFB 003.003\n", | |
68 | state : 'ProtocolVersion', | |
69 | shared : 1, | |
9f4af5a7 | 70 | poll_rate : 1413, |
64ab5c4d | 71 | |
cc0410a3 JM |
72 | host : '', |
73 | port : 5900, | |
74 | password : '', | |
75 | ||
76 | fb_width : 0, | |
77 | fb_height : 0, | |
78 | fb_name : "", | |
79 | fb_Bpp : 4, | |
f7618085 | 80 | rre_chunk : 100, |
cc0410a3 JM |
81 | |
82 | ||
83 | /* | |
84 | * Server message handlers | |
85 | */ | |
86 | ||
65e27ddd | 87 | /* RFB/VNC initialisation */ |
64ab5c4d | 88 | init_msg: function (data) { |
b7ec5487 | 89 | console.log(">> init_msg: " + RFB.state); |
489d1676 | 90 | |
64ab5c4d | 91 | switch (RFB.state) { |
65e27ddd JM |
92 | |
93 | case 'ProtocolVersion' : | |
65e27ddd | 94 | if (data.length != 12) { |
b7ec5487 | 95 | console.log("Invalid protocol version from server"); |
64ab5c4d | 96 | RFB.state = 'reset'; |
65e27ddd JM |
97 | return; |
98 | } | |
b7ec5487 JM |
99 | console.log("Server ProtocolVersion: " + data.shiftStr(11)); |
100 | console.log("Sending ProtocolVersion: " + RFB.version.substr(0,11)); | |
cc0410a3 | 101 | RFB.send_string(RFB.version); |
64ab5c4d | 102 | RFB.state = 'Authentication'; |
65e27ddd JM |
103 | break; |
104 | ||
105 | case 'Authentication' : | |
64ab5c4d | 106 | if (data.length < 4) { |
b7ec5487 | 107 | console.log("Invalid auth frame"); |
64ab5c4d | 108 | RFB.state = 'reset'; |
65e27ddd JM |
109 | return; |
110 | } | |
64ab5c4d | 111 | var scheme = data.shift32(); |
b7ec5487 | 112 | console.log("Auth scheme: " + scheme); |
65e27ddd JM |
113 | switch (scheme) { |
114 | case 0: // connection failed | |
64ab5c4d JM |
115 | var strlen = data.shift32(); |
116 | var reason = data.shiftStr(strlen); | |
b7ec5487 | 117 | console.log("auth failed: " + reason); |
64ab5c4d | 118 | RFB.state = "failed"; |
65e27ddd JM |
119 | return; |
120 | case 1: // no authentication | |
64ab5c4d JM |
121 | RFB.send_array([RFB.shared]); // ClientInitialisation |
122 | RFB.state = "ServerInitialisation"; | |
65e27ddd JM |
123 | break; |
124 | case 2: // VNC authentication | |
8580b989 | 125 | var challenge = data.shiftBytes(16); |
b7ec5487 JM |
126 | console.log("Password: " + RFB.password); |
127 | console.log("Challenge: " + challenge + "(" + challenge.length + ")"); | |
cc0410a3 | 128 | passwd = RFB.passwdTwiddle(RFB.password); |
b7ec5487 | 129 | //console.log("passwd: " + passwd + "(" + passwd.length + ")"); |
5aeb9880 | 130 | response = des(passwd, challenge, 1); |
b7ec5487 | 131 | //console.log("reponse: " + response + "(" + response.length + ")"); |
8580b989 JM |
132 | |
133 | RFB.send_array(response); | |
134 | RFB.state = "SecurityResult"; | |
65e27ddd JM |
135 | break; |
136 | } | |
137 | break; | |
138 | ||
64ab5c4d | 139 | case 'SecurityResult' : |
65e27ddd | 140 | if (data.length != 4) { |
b7ec5487 | 141 | console.log("Invalid server auth response"); |
64ab5c4d | 142 | RFB.state = 'reset'; |
65e27ddd JM |
143 | return; |
144 | } | |
64ab5c4d | 145 | var resp = data.shift32(); |
65e27ddd JM |
146 | switch (resp) { |
147 | case 0: // OK | |
b7ec5487 | 148 | console.log("Authentication OK"); |
65e27ddd JM |
149 | break; |
150 | case 1: // failed | |
b7ec5487 | 151 | console.log("Authentication failed"); |
64ab5c4d | 152 | RFB.state = "reset"; |
65e27ddd JM |
153 | return; |
154 | case 2: // too-many | |
b7ec5487 | 155 | console.log("Too many authentication attempts"); |
64ab5c4d | 156 | RFB.state = "failed"; |
65e27ddd JM |
157 | return; |
158 | } | |
64ab5c4d JM |
159 | RFB.send_array([RFB.shared]); // ClientInitialisation |
160 | RFB.state = "ServerInitialisation"; | |
65e27ddd JM |
161 | break; |
162 | ||
163 | case 'ServerInitialisation' : | |
65e27ddd | 164 | if (data.length < 24) { |
b7ec5487 | 165 | console.log("Invalid server initialisation"); |
64ab5c4d | 166 | RFB.state = 'reset'; |
65e27ddd JM |
167 | return; |
168 | } | |
489d1676 JM |
169 | |
170 | /* Screen size */ | |
b7ec5487 | 171 | //console.log("data: " + data); |
cc0410a3 JM |
172 | RFB.fb_width = data.shift16(); |
173 | RFB.fb_height = data.shift16(); | |
489d1676 | 174 | |
b7ec5487 | 175 | console.log("Screen size: " + RFB.fb_width + "x" + RFB.fb_height); |
489d1676 JM |
176 | |
177 | /* PIXEL_FORMAT */ | |
64ab5c4d JM |
178 | var bpp = data.shift8(); |
179 | var depth = data.shift8(); | |
180 | var big_endian = data.shift8(); | |
181 | var true_color = data.shift8(); | |
489d1676 | 182 | |
b7ec5487 JM |
183 | console.log("bpp: " + bpp); |
184 | console.log("depth: " + depth); | |
185 | console.log("big_endian: " + big_endian); | |
186 | console.log("true_color: " + true_color); | |
489d1676 JM |
187 | |
188 | /* Connection name/title */ | |
64ab5c4d JM |
189 | data.shiftStr(12); |
190 | var name_length = data.shift32(); | |
cc0410a3 | 191 | RFB.fb_name = data.shiftStr(name_length); |
489d1676 | 192 | |
b7ec5487 | 193 | console.log("Name: " + RFB.fb_name); |
cc0410a3 | 194 | $('status').innerHTML = "Connected to: " + RFB.fb_name; |
489d1676 | 195 | |
cc0410a3 | 196 | Canvas.init('vnc', RFB.fb_width, RFB.fb_height, RFB.keyDown, RFB.keyUp); |
64ab5c4d | 197 | |
9f4af5a7 JM |
198 | var init = []; |
199 | init = init.concat(RFB.pixelFormat()); | |
200 | init = init.concat(RFB.encodings()); | |
201 | init = init.concat(RFB.fbUpdateRequest(0, 0, 0, RFB.fb_width, RFB.fb_height)); | |
202 | RFB.send_array(init); | |
203 | ||
204 | /* Start polling */ | |
205 | RFB.poller.delay(RFB.poll_rate); | |
489d1676 | 206 | |
64ab5c4d | 207 | RFB.state = 'normal'; |
65e27ddd JM |
208 | break; |
209 | } | |
b7ec5487 | 210 | console.log("<< init_msg (" + RFB.state + ")"); |
64ab5c4d | 211 | }, |
65e27ddd | 212 | |
ed7e776d JM |
213 | /* Framebuffer update display functions */ |
214 | display_raw: function () { | |
b7ec5487 | 215 | console.log(">> display_raw"); |
ed7e776d | 216 | Canvas.rfbImage(FBU.x, FBU.y, FBU.width, FBU.height, FBU.arr); |
0f628064 | 217 | FBU.arr.splice(0, FBU.width * FBU.height * RFB.fb_Bpp); |
b7ec5487 | 218 | FBU.rects --; |
ed7e776d JM |
219 | }, |
220 | ||
221 | display_copy_rect: function () { | |
b7ec5487 | 222 | console.log(">> display_copy_rect"); |
ed7e776d JM |
223 | var old_x = FBU.arr.shift16(); |
224 | var old_y = FBU.arr.shift16(); | |
225 | Canvas.copyImage(old_x, old_y, FBU.x, FBU.y, FBU.width, FBU.height); | |
226 | FBU.rects --; | |
227 | }, | |
228 | ||
229 | display_rre: function () { | |
b7ec5487 | 230 | //console.log(">> display_rre (" + FBU.arr.length + " bytes)"); |
ed7e776d | 231 | if (FBU.subrects == 0) { |
ed7e776d | 232 | FBU.subrects = FBU.arr.shift32(); |
b7ec5487 | 233 | console.log(">> display_rre " + "(" + FBU.subrects + " subrects)"); |
6dab56f9 | 234 | var color = FBU.arr.shiftBytes(RFB.fb_Bpp); // Background |
ed7e776d | 235 | Canvas.rfbRect(FBU.x, FBU.y, FBU.width, FBU.height, color); |
f7618085 | 236 | } |
0f628064 | 237 | while ((FBU.subrects > 0) && (FBU.arr.length >= (RFB.fb_Bpp + 8))) { |
ed7e776d | 238 | FBU.subrects --; |
6dab56f9 JM |
239 | var color = FBU.arr.shiftBytes(RFB.fb_Bpp); |
240 | var x = FBU.arr.shift16(); | |
241 | var y = FBU.arr.shift16(); | |
242 | var width = FBU.arr.shift16(); | |
243 | var height = FBU.arr.shift16(); | |
244 | Canvas.rfbRect(FBU.x + x, FBU.y + y, width, height, color); | |
ed7e776d | 245 | } |
b7ec5487 | 246 | //console.log(" display_rre: rects: " + FBU.rects + ", FBU.subrects: " + FBU.subrects); |
ed7e776d JM |
247 | |
248 | if (FBU.subrects > 0) { | |
f7618085 JM |
249 | var chunk = Math.min(RFB.rre_chunk, FBU.subrects); |
250 | FBU.bytes = (RFB.fb_Bpp + 8) * chunk; | |
ed7e776d | 251 | } else { |
6dab56f9 | 252 | FBU.rects --; |
ed7e776d | 253 | } |
b7ec5487 | 254 | //console.log("<< display_rre, FBU.bytes: " + FBU.bytes); |
ed7e776d JM |
255 | }, |
256 | ||
0f628064 | 257 | display_hextile: function() { |
9f4af5a7 JM |
258 | //console.log(">> display_hextile, tiles: " + FBU.tiles + ", arr.length: " + FBU.arr.length + ", bytes: " + FBU.bytes); |
259 | var subencoding, subrects, cur_tile, tile_x, x, w, tile_y, y, h; | |
b7ec5487 JM |
260 | |
261 | /* FBU.bytes comes in as 0, FBU.arr.length at least 2 */ | |
262 | while ((FBU.tiles > 0) && (FBU.arr.length >= FBU.bytes)) { | |
9f4af5a7 JM |
263 | cur_tile = FBU.total_tiles - FBU.tiles; |
264 | tile_x = cur_tile % FBU.tiles_x; | |
265 | tile_y = Math.floor(cur_tile / FBU.tiles_x); | |
266 | x = FBU.x + tile_x * 16; | |
267 | y = FBU.y + tile_y * 16; | |
268 | w = Math.min(16, (FBU.x + FBU.width) - x) | |
269 | h = Math.min(16, (FBU.y + FBU.height) - y) | |
270 | subrects = 0; | |
b7ec5487 JM |
271 | if (FBU.subencoding == -1) { |
272 | /* We enter with at least 2 bytes */ | |
9f4af5a7 JM |
273 | subencoding = FBU.arr[0]; // Peek |
274 | //console.log(" display_hextile, subencoding: " + subencoding); | |
275 | FBU.bytes++; // Since we aren't shifting it off | |
b7ec5487 JM |
276 | //console.log(" subencoding: " + subencoding); |
277 | if (subencoding > 30) { // Raw | |
278 | console.log("Illegal subencoding " + subencoding); | |
279 | RFB.state = "failed"; | |
280 | return; | |
281 | } | |
282 | ||
283 | /* Figure out how much we are expecting */ | |
284 | if (subencoding & 0x01) { // Raw | |
9f4af5a7 JM |
285 | //console.log(" Raw subencoding"); |
286 | FBU.bytes = w * h * RFB.fb_Bpp; | |
287 | if (FBU.arr[FBU.bytes] == 0) { | |
288 | /* Weird: ignore blanks after RAW */ | |
289 | //console.log(" Ignoring blank after RAW"); | |
290 | FBU.bytes ++; | |
b7ec5487 | 291 | } |
b7ec5487 JM |
292 | } else { |
293 | if (subencoding & 0x02) { // Background | |
294 | FBU.bytes += RFB.fb_Bpp; | |
295 | } | |
296 | if (subencoding & 0x04) { // Foreground | |
297 | FBU.bytes += RFB.fb_Bpp; | |
298 | } | |
299 | if (subencoding & 0x08) { // AnySubrects | |
9f4af5a7 JM |
300 | FBU.bytes++; // Since we aren't shifting it off |
301 | if (FBU.arr.length < FBU.bytes) { | |
302 | /* Wait for subrects byte */ | |
303 | //console.log(" waiting for subrects byte"); | |
304 | return; | |
305 | } | |
306 | subrects = FBU.arr[FBU.bytes-1]; // Peek | |
307 | if (subencoding & 0x10) { // SubrectsColoured | |
b7ec5487 JM |
308 | FBU.bytes += subrects * (RFB.fb_Bpp + 2); |
309 | } else { | |
310 | FBU.bytes += subrects * 2; | |
311 | } | |
312 | } | |
313 | } | |
314 | } | |
315 | ||
9f4af5a7 JM |
316 | //console.log(" tile:" + cur_tile + "/" + (FBU.total_tiles - 1) + ", subencoding:" + subencoding + ", subrects:" + subrects + ", tile:" + tile_x + "," + tile_y + " [" + x + "," + y + "], arr.length:" + FBU.arr.length + ", bytes:" + FBU.bytes); |
317 | //console.log(" arr[0..30]: " + FBU.arr.slice(0,30)); | |
b7ec5487 | 318 | if (FBU.arr.length < FBU.bytes) { |
9f4af5a7 | 319 | //console.log(" waiting for " + (FBU.bytes - FBU.arr.length) + "bytes"); |
b7ec5487 JM |
320 | return; |
321 | } | |
322 | ||
323 | if (subencoding > -1) { | |
324 | /* We know the encoding and have a whole tile */ | |
325 | FBU.subencoding = FBU.arr.shift(); | |
326 | if (FBU.subencoding == 0) { | |
9f4af5a7 | 327 | Canvas.rfbRect(x, y, w, h, FBU.background); |
b7ec5487 | 328 | } else if (FBU.subencoding & 0x01) { // Raw |
9f4af5a7 JM |
329 | Canvas.rfbImage(x, y, w, h, FBU.arr); |
330 | FBU.arr.splice(0, FBU.bytes - 1); | |
b7ec5487 JM |
331 | } else { |
332 | if (FBU.subencoding & 0x02) { // Background | |
333 | FBU.background = FBU.arr.shiftBytes(RFB.fb_Bpp); | |
9f4af5a7 | 334 | //console.log(" background: " + FBU.background); |
b7ec5487 JM |
335 | } |
336 | if (FBU.subencoding & 0x04) { // Foreground | |
337 | FBU.foreground = FBU.arr.shiftBytes(RFB.fb_Bpp); | |
9f4af5a7 | 338 | //console.log(" foreground: " + FBU.foreground); |
b7ec5487 | 339 | } |
9f4af5a7 | 340 | Canvas.rfbRect(x, y, w, h, FBU.background); |
b7ec5487 JM |
341 | if (FBU.subencoding & 0x08) { // AnySubrects |
342 | subrects = FBU.arr.shift8(); | |
343 | for (var i = 0; i < subrects; i ++) { | |
9f4af5a7 | 344 | if (FBU.subencoding & 0x10) { // SubrectsColoured |
b7ec5487 JM |
345 | var color = FBU.arr.shiftBytes(RFB.fb_Bpp); |
346 | } else { | |
347 | var color = FBU.foreground; | |
348 | } | |
349 | var xy = FBU.arr.shift8(); | |
9f4af5a7 JM |
350 | var sx = x + (xy >> 4); |
351 | var sy = y + (xy & 0x0f); | |
b7ec5487 JM |
352 | |
353 | var wh = FBU.arr.shift8(); | |
9f4af5a7 JM |
354 | var sw = (wh >> 4) + 1; |
355 | var sh = (wh & 0x0f) + 1; | |
b7ec5487 | 356 | |
9f4af5a7 | 357 | Canvas.rfbRect(sx, sy, sw, sh, color); |
b7ec5487 JM |
358 | } |
359 | } | |
360 | } | |
361 | FBU.subencoding = -1; | |
362 | FBU.tiles --; | |
363 | FBU.bytes = 0; | |
364 | } | |
0f628064 JM |
365 | } |
366 | ||
b7ec5487 JM |
367 | if (FBU.tiles > 0) { |
368 | FBU.bytes = 2; | |
369 | } else { | |
370 | FBU.background = [255, 255, 0, 0]; // Yellow: invalid | |
371 | FBU.rects --; | |
372 | } | |
373 | ||
9f4af5a7 | 374 | //console.log("<< display_hextile"); |
0f628064 JM |
375 | }, |
376 | ||
ed7e776d | 377 | |
65e27ddd | 378 | /* Normal RFB/VNC messages */ |
64ab5c4d | 379 | normal_msg: function (data) { |
b7ec5487 | 380 | //console.log(">> normal_msg"); |
cc0410a3 | 381 | if ((FBU.rects > 0) || (FBU.bytes > 0)) { |
64ab5c4d | 382 | var msg_type = 0; |
c8460b03 | 383 | } else { |
64ab5c4d | 384 | var msg_type = data.shift8(); |
489d1676 | 385 | } |
65e27ddd JM |
386 | switch (msg_type) { |
387 | case 0: // FramebufferUpdate | |
cc0410a3 | 388 | if (FBU.rects == 0) { |
64ab5c4d | 389 | data.shift8(); |
cc0410a3 | 390 | FBU.rects = data.shift16(); |
b7ec5487 | 391 | console.log("FramebufferUpdate, " + FBU.rects + " rects"); |
cc0410a3 JM |
392 | FBU.bytes = 0; |
393 | FBU.arr = []; | |
64ab5c4d | 394 | } else { |
b7ec5487 | 395 | //console.log("FramebufferUpdate continuation"); |
64ab5c4d JM |
396 | } |
397 | ||
0f628064 JM |
398 | if (data.length > 0 ) { |
399 | FBU.arr = FBU.arr.concat(data); | |
400 | } | |
401 | ||
402 | while (FBU.arr.length > 0) { | |
cc0410a3 | 403 | if (FBU.bytes == 0) { |
0f628064 JM |
404 | FBU.x = FBU.arr.shift16(); |
405 | FBU.y = FBU.arr.shift16(); | |
406 | FBU.width = FBU.arr.shift16(); | |
407 | FBU.height = FBU.arr.shift16(); | |
408 | FBU.encoding = parseInt(FBU.arr.shift32(), 10); | |
b7ec5487 | 409 | console.log("encoding: " + FBU.encoding); |
cc0410a3 | 410 | switch (FBU.encoding) { |
64ab5c4d | 411 | case 0: // Raw |
cc0410a3 | 412 | FBU.bytes = FBU.width * FBU.height * RFB.fb_Bpp; |
64ab5c4d JM |
413 | break; |
414 | case 1: // Copy-Rect | |
48617e27 | 415 | FBU.bytes = 4; |
64ab5c4d | 416 | break; |
ed7e776d | 417 | case 2: // RRE |
ed7e776d JM |
418 | FBU.bytes = 4 + RFB.fb_Bpp; |
419 | break; | |
0f628064 | 420 | case 5: // hextile |
b7ec5487 JM |
421 | FBU.bytes = 2; // No header; get it started |
422 | FBU.tiles_x = Math.ceil(FBU.width/16); | |
423 | FBU.tiles_y = Math.ceil(FBU.height/16); | |
424 | FBU.total_tiles = FBU.tiles_x * FBU.tiles_y; | |
425 | FBU.tiles = FBU.total_tiles; | |
426 | break; | |
427 | default: | |
428 | console.log("Unsupported encoding " + FBU.encoding); | |
429 | RFB.state = "failed"; | |
0f628064 | 430 | break; |
64ab5c4d JM |
431 | } |
432 | } | |
b7ec5487 | 433 | //console.log("FBU.arr.length: " + FBU.arr.length + ", FBU.bytes: " + FBU.bytes); |
64ab5c4d | 434 | |
0f628064 | 435 | if (FBU.arr.length >= FBU.bytes) { |
b7ec5487 | 436 | //console.log('Done rect:'); |
0f628064 JM |
437 | FBU.bytes = 0; |
438 | ||
439 | switch (FBU.encoding) { | |
440 | case 0: RFB.display_raw(); break; // Raw | |
441 | case 1: RFB.display_copy_rect(); break; // Copy-Rect | |
442 | case 2: RFB.display_rre(); break; // RRE | |
443 | case 5: RFB.display_hextile(); break; // hextile | |
444 | } | |
445 | } else { | |
446 | /* We don't have enough yet */ | |
447 | FBU.bytes = FBU.bytes - data.length; | |
448 | break; | |
449 | } | |
b7ec5487 | 450 | if (RFB.state != "normal") return; |
64ab5c4d | 451 | } |
0f628064 | 452 | |
b7ec5487 | 453 | //console.log("Finished frame buffer update"); |
65e27ddd JM |
454 | break; |
455 | case 1: // SetColourMapEntries | |
b7ec5487 | 456 | console.log("SetColourMapEntries"); |
65e27ddd JM |
457 | break; |
458 | case 2: // Bell | |
b7ec5487 | 459 | console.log("Bell"); |
65e27ddd JM |
460 | break; |
461 | case 3: // ServerCutText | |
b7ec5487 | 462 | console.log("ServerCutText"); |
65e27ddd JM |
463 | break; |
464 | default: | |
b7ec5487 | 465 | console.log("Unknown server message type: " + msg_type); |
65e27ddd JM |
466 | break; |
467 | } | |
b7ec5487 | 468 | //console.log("<< normal_msg"); |
64ab5c4d | 469 | }, |
65e27ddd JM |
470 | |
471 | /* | |
472 | * Client message routines | |
473 | */ | |
474 | ||
9f4af5a7 | 475 | pixelFormat: function () { |
b7ec5487 | 476 | console.log(">> setPixelFormat"); |
9f4af5a7 JM |
477 | var arr; |
478 | arr = [0]; // msg-type | |
64ab5c4d JM |
479 | arr.push8(0); // padding |
480 | arr.push8(0); // padding | |
481 | arr.push8(0); // padding | |
482 | ||
cc0410a3 | 483 | arr.push8(RFB.fb_Bpp * 8); // bits-per-pixel |
64ab5c4d JM |
484 | arr.push8(24); // depth |
485 | arr.push8(0); // little-endian | |
486 | arr.push8(1); // true-color | |
487 | ||
488 | arr.push16(255); // red-max | |
489 | arr.push16(255); // green-max | |
490 | arr.push16(255); // blue-max | |
9f4af5a7 | 491 | arr.push8(0); // red-shift |
64ab5c4d | 492 | arr.push8(8); // green-shift |
9f4af5a7 | 493 | arr.push8(16); // blue-shift |
64ab5c4d | 494 | |
9f4af5a7 JM |
495 | arr.push8(0); // padding |
496 | arr.push8(0); // padding | |
497 | arr.push8(0); // padding | |
b7ec5487 | 498 | console.log("<< setPixelFormat"); |
9f4af5a7 | 499 | return arr; |
64ab5c4d JM |
500 | }, |
501 | ||
502 | fixColourMapEntries: function () { | |
503 | }, | |
504 | ||
9f4af5a7 | 505 | encodings: function () { |
b7ec5487 | 506 | console.log(">> setEncodings"); |
9f4af5a7 JM |
507 | var arr; |
508 | arr = [2]; // msg-type | |
64ab5c4d | 509 | arr.push8(0); // padding |
b7ec5487 JM |
510 | |
511 | //arr.push16(3); // encoding count | |
512 | arr.push16(4); // encoding count | |
513 | arr.push32(5); // hextile encoding | |
514 | ||
ed7e776d | 515 | arr.push32(2); // RRE encoding |
64ab5c4d JM |
516 | arr.push32(1); // copy-rect encoding |
517 | arr.push32(0); // raw encoding | |
b7ec5487 | 518 | console.log("<< setEncodings"); |
9f4af5a7 | 519 | return arr; |
64ab5c4d | 520 | }, |
65e27ddd | 521 | |
64ab5c4d | 522 | fbUpdateRequest: function (incremental, x, y, xw, yw) { |
b7ec5487 | 523 | //console.log(">> fbUpdateRequest"); |
9f4af5a7 JM |
524 | var arr; |
525 | arr = [3]; // msg-type | |
64ab5c4d JM |
526 | arr.push8(incremental); |
527 | arr.push16(x); | |
528 | arr.push16(y); | |
529 | arr.push16(xw); | |
530 | arr.push16(yw); | |
b7ec5487 | 531 | //console.log("<< fbUpdateRequest"); |
9f4af5a7 | 532 | return arr; |
64ab5c4d | 533 | }, |
65e27ddd | 534 | |
d9cbdc7d | 535 | keyEvent: function (keysym, down) { |
b7ec5487 | 536 | console.log(">> keyEvent, keysym: " + keysym + ", down: " + down); |
9f4af5a7 JM |
537 | var arr; |
538 | arr = [4]; // msg-type | |
64ab5c4d JM |
539 | arr.push8(down); |
540 | arr.push16(0); | |
d9cbdc7d | 541 | arr.push32(keysym); |
b7ec5487 | 542 | //console.log("keyEvent array: " + arr); |
9f4af5a7 | 543 | arr = arr.concat(RFB.fbUpdateRequest(1, 0, 0, RFB.fb_width, RFB.fb_height)); |
64ab5c4d | 544 | RFB.send_array(arr); |
b7ec5487 | 545 | //console.log("<< keyEvent"); |
64ab5c4d | 546 | }, |
65e27ddd | 547 | |
64ab5c4d JM |
548 | pointerEvent: function () { |
549 | }, | |
65e27ddd | 550 | |
64ab5c4d JM |
551 | clientCutText: function () { |
552 | }, | |
553 | ||
554 | ||
555 | /* | |
556 | * Utility routines | |
557 | */ | |
558 | ||
559 | send_string: function (str) { | |
b7ec5487 | 560 | //console.log(">> send_string: " + str); |
9f4af5a7 JM |
561 | RFB.send_array(str.split('').map( |
562 | function (chr) { return chr.charCodeAt(0) } ) ); | |
64ab5c4d JM |
563 | }, |
564 | ||
565 | send_array: function (arr) { | |
9f4af5a7 | 566 | //console.log(">> send_array: " + arr); |
b7ec5487 | 567 | //console.log(">> send_array: " + Base64.encode_array(arr)); |
cc0410a3 | 568 | RFB.ws.send(Base64.encode_array(arr)); |
64ab5c4d JM |
569 | }, |
570 | ||
532a9fd9 JM |
571 | /* Mirror bits of each character and return as array */ |
572 | passwdTwiddle: function (passwd) { | |
9f4af5a7 JM |
573 | var arr; |
574 | arr = []; | |
532a9fd9 JM |
575 | for (var i=0; i< passwd.length; i++) { |
576 | var c = passwd.charCodeAt(i); | |
577 | arr.push( ((c & 0x80) >> 7) + | |
578 | ((c & 0x40) >> 5) + | |
579 | ((c & 0x20) >> 3) + | |
580 | ((c & 0x10) >> 1) + | |
581 | ((c & 0x08) << 1) + | |
582 | ((c & 0x04) << 3) + | |
583 | ((c & 0x02) << 5) + | |
584 | ((c & 0x01) << 7) ); | |
585 | } | |
586 | return arr; | |
587 | }, | |
588 | ||
64ab5c4d JM |
589 | poller: function () { |
590 | if (RFB.state == 'normal') { | |
9f4af5a7 | 591 | RFB.send_array(RFB.fbUpdateRequest(1, 0, 0, RFB.fb_width, RFB.fb_height)); |
64ab5c4d JM |
592 | RFB.poller.delay(RFB.poll_rate); |
593 | } | |
594 | }, | |
595 | ||
596 | keyDown: function (e) { | |
b7ec5487 | 597 | //console.log(">> keyDown: " + e.key + "(" + e.code + ")"); |
64ab5c4d | 598 | e.stop(); |
d9cbdc7d | 599 | RFB.keyEvent(Canvas.getKeysym(e), 1); |
64ab5c4d JM |
600 | }, |
601 | ||
602 | keyUp: function (e) { | |
b7ec5487 | 603 | //console.log(">> keyUp: " + e.key + "(" + e.code + ")"); |
64ab5c4d | 604 | e.stop(); |
d9cbdc7d | 605 | RFB.keyEvent(Canvas.getKeysym(e), 0); |
64ab5c4d | 606 | }, |
65e27ddd JM |
607 | |
608 | ||
609 | /* | |
610 | * Setup routines | |
611 | */ | |
612 | ||
532a9fd9 | 613 | init_ws: function () { |
b7ec5487 | 614 | console.log(">> init_ws"); |
cc0410a3 | 615 | var uri = "ws://" + RFB.host + ":" + RFB.port; |
b7ec5487 | 616 | console.log("connecting to " + uri); |
cc0410a3 JM |
617 | RFB.ws = new WebSocket(uri); |
618 | RFB.ws.onmessage = function(e) { | |
b7ec5487 | 619 | //console.log(">> onmessage"); |
489d1676 | 620 | var data = Base64.decode_array(e.data); |
b7ec5487 | 621 | //console.log("decoded array: " + data); |
64ab5c4d JM |
622 | if (RFB.state != 'normal') { |
623 | RFB.init_msg(data); | |
65e27ddd | 624 | } else { |
64ab5c4d | 625 | RFB.normal_msg(data); |
65e27ddd | 626 | } |
64ab5c4d | 627 | if (RFB.state == 'reset') { |
65e27ddd | 628 | /* close and reset connection */ |
532a9fd9 JM |
629 | RFB.disconnect(); |
630 | RFB.init_ws(); | |
64ab5c4d | 631 | } else if (RFB.state == 'failed') { |
b7ec5487 | 632 | console.log("Giving up!"); |
532a9fd9 | 633 | RFB.disconnect(); |
65e27ddd | 634 | } |
b7ec5487 | 635 | //console.log("<< onmessage"); |
65e27ddd | 636 | }; |
cc0410a3 | 637 | RFB.ws.onopen = function(e) { |
b7ec5487 | 638 | console.log(">> onopen"); |
64ab5c4d | 639 | RFB.state = "ProtocolVersion"; |
b7ec5487 | 640 | console.log("<< onopen"); |
65e27ddd | 641 | }; |
cc0410a3 | 642 | RFB.ws.onclose = function(e) { |
b7ec5487 | 643 | console.log(">> onclose"); |
64ab5c4d | 644 | RFB.state = "closed"; |
b7ec5487 | 645 | console.log("<< onclose"); |
65e27ddd | 646 | } |
64ab5c4d | 647 | |
b7ec5487 | 648 | console.log("<< init_ws"); |
64ab5c4d | 649 | }, |
65e27ddd | 650 | |
532a9fd9 | 651 | connect: function () { |
b7ec5487 | 652 | console.log(">> connect"); |
cc0410a3 JM |
653 | RFB.host = $('host').value; |
654 | RFB.port = $('port').value; | |
655 | RFB.password = $('password').value; | |
532a9fd9 | 656 | if ((!host) || (!port)) { |
b7ec5487 | 657 | console.log("must set host and port"); |
532a9fd9 JM |
658 | return; |
659 | } | |
cc0410a3 JM |
660 | if (RFB.ws) { |
661 | RFB.ws.close(); | |
65e27ddd | 662 | } |
532a9fd9 JM |
663 | RFB.init_ws(); |
664 | $('connectButton').value = "Disconnect"; | |
665 | $('connectButton').onclick = RFB.disconnect; | |
b7ec5487 | 666 | console.log("<< connect"); |
532a9fd9 JM |
667 | |
668 | }, | |
65e27ddd | 669 | |
532a9fd9 | 670 | disconnect: function () { |
b7ec5487 | 671 | console.log(">> disconnect"); |
cc0410a3 JM |
672 | if (RFB.ws) { |
673 | RFB.ws.close(); | |
532a9fd9 JM |
674 | } |
675 | if (Canvas.ctx) { | |
676 | Canvas.clear(); | |
677 | } | |
678 | $('connectButton').value = "Connect"; | |
679 | $('connectButton').onclick = RFB.connect; | |
680 | $('status').innerHTML = "Disconnected"; | |
b7ec5487 | 681 | console.log("<< disconnect"); |
65e27ddd JM |
682 | } |
683 | ||
64ab5c4d | 684 | }; /* End of RFB */ |