Skip to content

Commit 65171fa

Browse files
author
Filipe Calaça Barbosa
committed
* Version 0.2.0
* Added Pseudo Cursor Encoding
1 parent b89f224 commit 65171fa

File tree

3 files changed

+98
-38
lines changed

3 files changed

+98
-38
lines changed

Diff for: README.md

+13-8
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
[![Forks][forks-shield]][forks-url]
2424
[![Stargazers][stars-shield]][stars-url]
2525
[![Issues][issues-shield]][issues-url]
26-
[![MIT License][license-shield]][license-url]
2726
[![LinkedIn][linkedin-shield]][linkedin-url]
2827

2928

@@ -77,6 +76,7 @@ const initOptions = {
7776
VncClient.consts.encodings.hextile,
7877
VncClient.consts.encodings.raw,
7978
VncClient.consts.encodings.pseudoDesktopSize,
79+
VncClient.consts.encodings.pseudoCursor
8080
],
8181
debugLevel: 1 // Verbosity level (1 - 5) when debug is set to true
8282
};
@@ -163,7 +163,7 @@ client.changeFps(1);
163163
client.connect({host: '127.0.0.1', port: 5900, password: 'abc123'});
164164

165165
client.on('frameUpdated', (data) => {
166-
new Jimp({width: client.clientWidth, height: client.clientHeight, data}, (err, image) => {
166+
new Jimp({width: client.clientWidth, height: client.clientHeight, data: client.getFb()}, (err, image) => {
167167
if (err) {
168168
console.log(err);
169169
}
@@ -210,7 +210,7 @@ process.on('SIGINT', function () {
210210
function timer() {
211211
timerRef = setTimeout(() => {
212212
timer();
213-
out?.stdin?.write(client.fb);
213+
out?.stdin?.write(client.getFb());
214214
}, 1000 / fps);
215215
}
216216

@@ -280,6 +280,9 @@ client.sendPointerEvent(xPosition, yPosition, button1, button2, button3, button4
280280
client.clientCutText(text);
281281

282282
client.resetState(); // Reset the state of the client, clear the frame buffer and purge all data
283+
284+
client.getFb(); // Returns the framebuffer with cursor printed to it if using Cursor Pseudo Encoding
285+
283286
```
284287
285288
<!-- ROADMAP -->
@@ -295,12 +298,14 @@ CopyRect <br>
295298
Hextile <br>
296299
ZRLE <br>
297300
PseudoDesktopSize <br>
301+
Pseudo Cursor Encoding <br>
302+
QEMU Audio <br>
303+
QEMU Relative Pointer <br>
298304
3.7 and 3.8 protocol implementations
299305
300306
### TODO:
301307
302308
Tight Encoding <br>
303-
Pseudo Cursor Encoding <br>
304309
Save session data to file <br>
305310
Replay session from rect data saved to file
306311
@@ -323,19 +328,19 @@ Project Link: [https://github.com/filipecbmoc/vnc-rfb-client](https://github.com
323328
<!-- MARKDOWN LINKS & IMAGES -->
324329
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
325330
326-
[contributors-shield]: https://img.shields.io/github/contributors/github_username/repo.svg?style=for-the-badge
331+
[contributors-shield]: https://img.shields.io/github/contributors/filipecbmoc/vnc-rfb-client?style=for-the-badge
327332
328333
[contributors-url]: https://github.com/filipecbmoc/vnc-rfb-client/graphs/contributors
329334
330-
[forks-shield]: https://img.shields.io/github/forks/github_username/repo.svg?style=for-the-badge
335+
[forks-shield]: https://img.shields.io/github/forks/filipecbmoc/vnc-rfb-client?style=for-the-badge
331336
332337
[forks-url]: https://github.com/filipecbmoc/vnc-rfb-client/network/members
333338
334-
[stars-shield]: https://img.shields.io/github/stars/github_username/repo.svg?style=for-the-badge
339+
[stars-shield]: https://img.shields.io/github/stars/filipecbmoc/vnc-rfb-client?style=for-the-badge
335340
336341
[stars-url]: https://github.com/filipecbmoc/vnc-rfb-client/stargazers
337342
338-
[issues-shield]: https://img.shields.io/github/issues/github_username/repo.svg?style=for-the-badge
343+
[issues-shield]: https://img.shields.io/github/issues/filipecbmoc/vnc-rfb-client?style=for-the-badge
339344
340345
[issues-url]: https://github.com/filipecbmoc/vnc-rfb-client/issues
341346

Diff for: package.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
{
22
"name": "vnc-rfb-client",
3-
"version": "0.1.9",
3+
"version": "0.2.0",
44
"dependencies": {},
55
"main": "vncclient.js",
66
"scripts": {
77
"test": "echo \"Error: no test specified\" && exit 1"
88
},
9-
"keywords": ["vnc", "rfb", "zrle", "hextile", "copyrect", "rfc 6143"],
9+
"keywords": [
10+
"vnc",
11+
"rfb",
12+
"zrle",
13+
"hextile",
14+
"copyrect",
15+
"rfc 6143"
16+
],
1017
"author": "Filipe Calaça Barbosa",
1118
"license": "MIT",
1219
"devDependencies": {},

Diff for: vncclient.js

+76-28
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class VncClient extends Events {
6969
encodings.pseudoDesktopSize
7070
];
7171

72-
this._audioChannels = options.audioChannels || 2;
73-
this._audioFrequency = options.audioFrequency || 22050;
72+
this._audioChannels = options.audioChannels || 2;
73+
this._audioFrequency = options.audioFrequency || 22050;
7474

7575
this._rects = 0;
7676
this._decoders = {};
@@ -553,12 +553,12 @@ class VncClient extends Events {
553553
rect.height = this._socketBuffer.readUInt16BE();
554554
rect.encoding = this._socketBuffer.readInt32BE();
555555

556-
if(rect.encoding === encodings.pseudoQemuAudio){
557-
this.sendAudio(true);
558-
this.sendAudioConfig(this._audioChannels,this._audioFrequency);//todo: future: setFrequency(...) to update mid thing
559-
} else if(rect.encoding === encodings.pseudoQemuPointerMotionChange){
560-
this._relativePointer=rect.x==0;
561-
} else if (rect.encoding === encodings.pseudoCursor) {
556+
if (rect.encoding === encodings.pseudoQemuAudio) {
557+
this.sendAudio(true);
558+
this.sendAudioConfig(this._audioChannels, this._audioFrequency);//todo: future: setFrequency(...) to update mid thing
559+
} else if (rect.encoding === encodings.pseudoQemuPointerMotionChange) {
560+
this._relativePointer = rect.x == 0;
561+
} else if (rect.encoding === encodings.pseudoCursor) {
562562
const dataSize = rect.width * rect.height * (this.pixelFormat.bitsPerPixel / 8);
563563
const bitmaskSize = Math.floor((rect.width + 7) / 8) * rect.height;
564564
this._cursor.width = rect.width;
@@ -644,18 +644,18 @@ class VncClient extends Events {
644644
async _handleQemuAudio() {
645645
this._socketBuffer.setOffset(2);
646646
let operation = this._socketBuffer.readUInt16BE();
647-
if(operation==2){
648-
const length = this._socketBuffer.readUInt32BE();
647+
if (operation == 2) {
648+
const length = this._socketBuffer.readUInt32BE();
649649

650-
//this._log(`Audio received. Length: ${length}.`);
650+
//this._log(`Audio received. Length: ${length}.`);
651651

652-
await this._socketBuffer.waitBytes(length);
652+
await this._socketBuffer.waitBytes(length);
653653

654-
let audioBuffer = [];
655-
for(let i=0;i<length/2;i++)audioBuffer.push(this._socketBuffer.readUInt16BE());
654+
let audioBuffer = [];
655+
for (let i = 0; i < length / 2; i++) audioBuffer.push(this._socketBuffer.readUInt16BE());
656656

657-
this._audioData = audioBuffer;
658-
}
657+
this._audioData = audioBuffer;
658+
}
659659

660660
this.emit('audioStream', this._audioData);
661661
this._socketBuffer.flush();
@@ -684,8 +684,8 @@ class VncClient extends Events {
684684

685685
this._password = '';
686686

687-
this._audioChannels=2;
688-
this._audioFrequency=22050;
687+
this._audioChannels = 2;
688+
this._audioFrequency = 22050;
689689

690690
this._handshaked = false;
691691

@@ -731,9 +731,54 @@ class VncClient extends Events {
731731
x: 0,
732732
y: 0,
733733
cursorPixels: null,
734-
bitmask: null
734+
bitmask: null,
735+
posX: 0,
736+
posY: 0
737+
}
738+
739+
}
740+
741+
/**
742+
* Get the frame buffer with de cursor printed to it if using Cursor Pseudo Encoding
743+
* @returns {null|Buffer|*}
744+
*/
745+
getFb() {
746+
if (!this._cursor.width) {
747+
// If there is no cursor, just return de framebuffer
748+
return this.fb;
749+
} else {
750+
// If there is a cursor, draw a cursor on the framebuffer and return the final result
751+
const tempFb = new Buffer.from(this.fb);
752+
for (let h = 0; h < this._cursor.height; h++) {
753+
for (let w = 0; w < this._cursor.width; w++) {
754+
const fbBytePosOffset = this._getPixelBytePos(this._cursor.posX + w, this._cursor.posY + h, this.clientWidth, this.clientHeight);
755+
const cursorBytePosOffset = this._getPixelBytePos(w, h, this._cursor.width, this._cursor.height);
756+
const bitmapByte = this._cursor.bitmask.slice(Math.floor(cursorBytePosOffset / 4 / 8), Math.floor(cursorBytePosOffset / 4 / 8) + 1);
757+
const bitmapBit = (cursorBytePosOffset / 4) % 8;
758+
const activePixel = bitmapBit === 0 ? bitmapByte[0] & 128 : bitmapBit === 1 ? bitmapByte[0] & 64 :
759+
bitmapBit === 2 ? bitmapByte[0] & 32 : bitmapBit === 3 ? bitmapByte[0] & 16 :
760+
bitmapBit === 4 ? bitmapByte[0] & 8 : bitmapBit === 5 ? bitmapByte[0] & 4 :
761+
bitmapBit === 6 ? bitmapByte[0] & 2 : bitmapByte[0] & 1;
762+
763+
if (activePixel) {
764+
if (this.pixelFormat.bitsPerPixel === 8) {
765+
const index = this._cursor.cursorPixels.readUInt8(cursorBytePosOffset);
766+
const color = this._colorMap[index];
767+
tempFb.writeIntBE(color, fbBytePosOffset, 4);
768+
} else {
769+
const bytesLength = this.pixelFormat.bitsPerPixel / 8;
770+
const color = this._cursor.cursorPixels.readIntBE(cursorBytePosOffset, bytesLength);
771+
tempFb.writeIntBE(color, fbBytePosOffset, bytesLength);
772+
}
773+
}
774+
}
775+
}
776+
return tempFb;
735777
}
778+
}
736779

780+
_getPixelBytePos(x, y, width, height) {
781+
return ((y * width) + x) * 4;
737782
}
738783

739784
/**
@@ -744,7 +789,7 @@ class VncClient extends Events {
744789
sendKeyEvent(key, down = false) {
745790

746791
const message = new Buffer(8);
747-
message.writeUInt8(4); // Message type
792+
message.writeUInt8(clientMsgTypes.keyEvent); // Message type
748793
message.writeUInt8(down ? 1 : 0, 1); // Down flag
749794
message.writeUInt8(0, 2); // Padding
750795
message.writeUInt8(0, 3); // Padding
@@ -784,11 +829,14 @@ class VncClient extends Events {
784829
buttonMask += button1 ? 1 : 0;
785830

786831
const message = new Buffer(6);
787-
message.writeUInt8(5); // Message type
832+
message.writeUInt8(clientMsgTypes.pointerEvent); // Message type
788833
message.writeUInt8(buttonMask, 1); // Button Mask
789-
const reladd=this._relativePointer?0x7FFF:0;
790-
message.writeUInt16BE(xPosition+reladd, 2); // X Position
791-
message.writeUInt16BE(yPosition+reladd, 4); // Y Position
834+
const reladd = this._relativePointer ? 0x7FFF : 0;
835+
message.writeUInt16BE(xPosition + reladd, 2); // X Position
836+
message.writeUInt16BE(yPosition + reladd, 4); // Y Position
837+
838+
this._cursor.posX = xPosition;
839+
this._cursor.posY = yPosition;
792840

793841
this.sendData(message, false);
794842

@@ -802,7 +850,7 @@ class VncClient extends Events {
802850

803851
const textBuffer = new Buffer.from(text, 'latin1');
804852
const message = new Buffer(8 + textBuffer.length);
805-
message.writeUInt8(6); // Message type
853+
message.writeUInt8(clientMsgTypes.cutText); // Message type
806854
message.writeUInt8(0, 1); // Padding
807855
message.writeUInt8(0, 2); // Padding
808856
message.writeUInt8(0, 3); // Padding
@@ -817,8 +865,8 @@ class VncClient extends Events {
817865
const message = new Buffer(4);
818866
message.writeUInt8(clientMsgTypes.qemuAudio); // Message type
819867
message.writeUInt8(1, 1); // Submessage Type
820-
message.writeUInt16BE(enable?0:1, 2); // Operation
821-
this._connection.write(message);
868+
message.writeUInt16BE(enable ? 0 : 1, 2); // Operation
869+
this.sendData(message);
822870
}
823871

824872
sendAudioConfig(channels, frequency) {
@@ -829,7 +877,7 @@ class VncClient extends Events {
829877
message.writeUInt8(0/*U8*/, 4); // Sample Format
830878
message.writeUInt8(channels, 5); // Number of Channels
831879
message.writeUInt32BE(frequency, 6); // Frequency
832-
this._connection.write(message);
880+
this.sendData(message);
833881
}
834882

835883
/**

0 commit comments

Comments
 (0)