Merge branch 'extra-mouse-buttons' of https://github.com/CendioHalim/noVNC
This commit is contained in:
commit
c7bd247daa
|
@ -30,6 +30,7 @@ export const encodings = {
|
||||||
pseudoEncodingXvp: -309,
|
pseudoEncodingXvp: -309,
|
||||||
pseudoEncodingFence: -312,
|
pseudoEncodingFence: -312,
|
||||||
pseudoEncodingContinuousUpdates: -313,
|
pseudoEncodingContinuousUpdates: -313,
|
||||||
|
pseudoEncodingExtendedMouseButtons: -316,
|
||||||
pseudoEncodingCompressLevel9: -247,
|
pseudoEncodingCompressLevel9: -247,
|
||||||
pseudoEncodingCompressLevel0: -256,
|
pseudoEncodingCompressLevel0: -256,
|
||||||
pseudoEncodingVMwareCursor: 0x574d5664,
|
pseudoEncodingVMwareCursor: 0x574d5664,
|
||||||
|
|
51
core/rfb.js
51
core/rfb.js
|
@ -152,6 +152,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
|
|
||||||
this._qemuExtKeyEventSupported = false;
|
this._qemuExtKeyEventSupported = false;
|
||||||
|
|
||||||
|
this._extendedPointerEventSupported = false;
|
||||||
|
|
||||||
this._clipboardText = null;
|
this._clipboardText = null;
|
||||||
this._clipboardServerCapabilitiesActions = {};
|
this._clipboardServerCapabilitiesActions = {};
|
||||||
this._clipboardServerCapabilitiesFormats = {};
|
this._clipboardServerCapabilitiesFormats = {};
|
||||||
|
@ -1051,10 +1053,11 @@ export default class RFB extends EventTargetMixin {
|
||||||
1: 1 << 2, // Right
|
1: 1 << 2, // Right
|
||||||
2: 1 << 1, // Middle
|
2: 1 << 1, // Middle
|
||||||
3: 1 << 7, // Back
|
3: 1 << 7, // Back
|
||||||
|
4: 1 << 8, // Forward
|
||||||
};
|
};
|
||||||
|
|
||||||
let bmask = 0;
|
let bmask = 0;
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
if (buttons & (1 << i)) {
|
if (buttons & (1 << i)) {
|
||||||
bmask |= buttonMaskMap[i];
|
bmask |= buttonMaskMap[i];
|
||||||
}
|
}
|
||||||
|
@ -1189,8 +1192,20 @@ export default class RFB extends EventTargetMixin {
|
||||||
if (this._rfbConnectionState !== 'connected') { return; }
|
if (this._rfbConnectionState !== 'connected') { return; }
|
||||||
if (this._viewOnly) { return; } // View only, skip mouse events
|
if (this._viewOnly) { return; } // View only, skip mouse events
|
||||||
|
|
||||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x),
|
// Highest bit in mask is never sent to the server
|
||||||
this._display.absY(y), mask);
|
if (mask & 0x8000) {
|
||||||
|
throw new Error("Illegal mouse button mask (mask: " + mask + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
let extendedMouseButtons = mask & 0x7f80;
|
||||||
|
|
||||||
|
if (this._extendedPointerEventSupported && extendedMouseButtons) {
|
||||||
|
RFB.messages.extendedPointerEvent(this._sock, this._display.absX(x),
|
||||||
|
this._display.absY(y), mask);
|
||||||
|
} else {
|
||||||
|
RFB.messages.pointerEvent(this._sock, this._display.absX(x),
|
||||||
|
this._display.absY(y), mask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleWheel(ev) {
|
_handleWheel(ev) {
|
||||||
|
@ -2229,6 +2244,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
||||||
encs.push(encodings.pseudoEncodingDesktopName);
|
encs.push(encodings.pseudoEncodingDesktopName);
|
||||||
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
||||||
|
encs.push(encodings.pseudoEncodingExtendedMouseButtons);
|
||||||
|
|
||||||
if (this._fbDepth == 24) {
|
if (this._fbDepth == 24) {
|
||||||
encs.push(encodings.pseudoEncodingVMwareCursor);
|
encs.push(encodings.pseudoEncodingVMwareCursor);
|
||||||
|
@ -2658,6 +2674,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
case encodings.pseudoEncodingExtendedDesktopSize:
|
case encodings.pseudoEncodingExtendedDesktopSize:
|
||||||
return this._handleExtendedDesktopSize();
|
return this._handleExtendedDesktopSize();
|
||||||
|
|
||||||
|
case encodings.pseudoEncodingExtendedMouseButtons:
|
||||||
|
this._extendedPointerEventSupported = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
case encodings.pseudoEncodingQEMULedEvent:
|
case encodings.pseudoEncodingQEMULedEvent:
|
||||||
return this._handleLedEvent();
|
return this._handleLedEvent();
|
||||||
|
|
||||||
|
@ -3067,6 +3087,10 @@ RFB.messages = {
|
||||||
pointerEvent(sock, x, y, mask) {
|
pointerEvent(sock, x, y, mask) {
|
||||||
sock.sQpush8(5); // msg-type
|
sock.sQpush8(5); // msg-type
|
||||||
|
|
||||||
|
// Marker bit must be set to 0, otherwise the server might
|
||||||
|
// confuse the marker bit with the highest bit in a normal
|
||||||
|
// PointerEvent message.
|
||||||
|
mask = mask & 0x7f;
|
||||||
sock.sQpush8(mask);
|
sock.sQpush8(mask);
|
||||||
|
|
||||||
sock.sQpush16(x);
|
sock.sQpush16(x);
|
||||||
|
@ -3075,6 +3099,27 @@ RFB.messages = {
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
extendedPointerEvent(sock, x, y, mask) {
|
||||||
|
sock.sQpush8(5); // msg-type
|
||||||
|
|
||||||
|
let higherBits = (mask >> 7) & 0xff;
|
||||||
|
|
||||||
|
// Bits 2-7 are reserved
|
||||||
|
if (higherBits & 0xfc) {
|
||||||
|
throw new Error("Invalid mouse button mask: " + mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lowerBits = mask & 0x7f;
|
||||||
|
lowerBits |= 0x80; // Set marker bit to 1
|
||||||
|
|
||||||
|
sock.sQpush8(lowerBits);
|
||||||
|
sock.sQpush16(x);
|
||||||
|
sock.sQpush16(y);
|
||||||
|
sock.sQpush8(higherBits);
|
||||||
|
|
||||||
|
sock.flush();
|
||||||
|
},
|
||||||
|
|
||||||
// Used to build Notify and Request data.
|
// Used to build Notify and Request data.
|
||||||
_buildExtendedClipboardFlags(actions, formats) {
|
_buildExtendedClipboardFlags(actions, formats) {
|
||||||
let data = new Uint8Array(4);
|
let data = new Uint8Array(4);
|
||||||
|
|
|
@ -233,6 +233,30 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
client._canvas.dispatchEvent(ev);
|
client._canvas.dispatchEvent(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendFbuMsg(rectInfo, rectData, client, rectCnt) {
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
if (!rectCnt || rectCnt > -1) {
|
||||||
|
// header
|
||||||
|
data.push(0); // msg type
|
||||||
|
data.push(0); // padding
|
||||||
|
push16(data, rectCnt || rectData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < rectData.length; i++) {
|
||||||
|
if (rectInfo[i]) {
|
||||||
|
push16(data, rectInfo[i].x);
|
||||||
|
push16(data, rectInfo[i].y);
|
||||||
|
push16(data, rectInfo[i].width);
|
||||||
|
push16(data, rectInfo[i].height);
|
||||||
|
push32(data, rectInfo[i].encoding);
|
||||||
|
}
|
||||||
|
data = data.concat(rectData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
client._sock._websocket._receiveData(new Uint8Array(data));
|
||||||
|
}
|
||||||
|
|
||||||
describe('Connecting/Disconnecting', function () {
|
describe('Connecting/Disconnecting', function () {
|
||||||
describe('#RFB (constructor)', function () {
|
describe('#RFB (constructor)', function () {
|
||||||
let open, attach;
|
let open, attach;
|
||||||
|
@ -2757,30 +2781,6 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Framebuffer update handling', function () {
|
describe('Framebuffer update handling', function () {
|
||||||
function sendFbuMsg(rectInfo, rectData, client, rectCnt) {
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
if (!rectCnt || rectCnt > -1) {
|
|
||||||
// header
|
|
||||||
data.push(0); // msg type
|
|
||||||
data.push(0); // padding
|
|
||||||
push16(data, rectCnt || rectData.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < rectData.length; i++) {
|
|
||||||
if (rectInfo[i]) {
|
|
||||||
push16(data, rectInfo[i].x);
|
|
||||||
push16(data, rectInfo[i].y);
|
|
||||||
push16(data, rectInfo[i].width);
|
|
||||||
push16(data, rectInfo[i].height);
|
|
||||||
push32(data, rectInfo[i].encoding);
|
|
||||||
}
|
|
||||||
data = data.concat(rectData[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
client._sock._websocket._receiveData(new Uint8Array(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should send an update request if there is sufficient data', function () {
|
it('should send an update request if there is sufficient data', function () {
|
||||||
let esock = new Websock();
|
let esock = new Websock();
|
||||||
let ews = new FakeWebSocket();
|
let ews = new FakeWebSocket();
|
||||||
|
@ -3265,6 +3265,7 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
expect(spy.args[0][0].detail.name).to.equal('som€ nam€');
|
expect(spy.args[0][0].detail.name).to.equal('som€ nam€');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Caps Lock and Num Lock remote fixup', function () {
|
describe('Caps Lock and Num Lock remote fixup', function () {
|
||||||
|
@ -3757,6 +3758,7 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
describe('Asynchronous events', function () {
|
describe('Asynchronous events', function () {
|
||||||
let client;
|
let client;
|
||||||
let pointerEvent;
|
let pointerEvent;
|
||||||
|
let extendedPointerEvent;
|
||||||
let keyEvent;
|
let keyEvent;
|
||||||
let qemuKeyEvent;
|
let qemuKeyEvent;
|
||||||
|
|
||||||
|
@ -3770,12 +3772,14 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
client.focusOnClick = false;
|
client.focusOnClick = false;
|
||||||
|
|
||||||
pointerEvent = sinon.spy(RFB.messages, 'pointerEvent');
|
pointerEvent = sinon.spy(RFB.messages, 'pointerEvent');
|
||||||
|
extendedPointerEvent = sinon.spy(RFB.messages, 'extendedPointerEvent');
|
||||||
keyEvent = sinon.spy(RFB.messages, 'keyEvent');
|
keyEvent = sinon.spy(RFB.messages, 'keyEvent');
|
||||||
qemuKeyEvent = sinon.spy(RFB.messages, 'QEMUExtendedKeyEvent');
|
qemuKeyEvent = sinon.spy(RFB.messages, 'QEMUExtendedKeyEvent');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
pointerEvent.restore();
|
pointerEvent.restore();
|
||||||
|
extendedPointerEvent.restore();
|
||||||
keyEvent.restore();
|
keyEvent.restore();
|
||||||
qemuKeyEvent.restore();
|
qemuKeyEvent.restore();
|
||||||
});
|
});
|
||||||
|
@ -3884,6 +3888,23 @@ describe('Remote Frame Buffer protocol client', function () {
|
||||||
50, 70, 0x0);
|
50, 70, 0x0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should send extended pointer event when server supports extended pointer events', function () {
|
||||||
|
// Enable extended pointer events
|
||||||
|
sendFbuMsg([{ x: 0, y: 0, width: 0, height: 0, encoding: -316 }], [[]], client);
|
||||||
|
|
||||||
|
sendMouseButtonEvent(50, 70, true, 0x10, client);
|
||||||
|
|
||||||
|
expect(extendedPointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||||
|
50, 70, 0x100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send normal pointer event when server does not support extended pointer events', function () {
|
||||||
|
sendMouseButtonEvent(50, 70, true, 0x10, client);
|
||||||
|
|
||||||
|
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||||
|
50, 70, 0x100);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Event aggregation', function () {
|
describe('Event aggregation', function () {
|
||||||
it('should send a single pointer event on mouse movement', function () {
|
it('should send a single pointer event on mouse movement', function () {
|
||||||
sendMouseMoveEvent(50, 70, 0x0, client);
|
sendMouseMoveEvent(50, 70, 0x0, client);
|
||||||
|
@ -5135,11 +5156,36 @@ describe('RFB messages', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send correct data for pointer events', function () {
|
it('should send correct data for pointer events', function () {
|
||||||
|
RFB.messages.pointerEvent(sock, 12345, 54321, 0x2b);
|
||||||
|
let expected =
|
||||||
|
[ 5, 0x2b, 0x30, 0x39, 0xd4, 0x31];
|
||||||
|
expect(sock).to.have.sent(new Uint8Array(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send correct data for pointer events with marker bit set', function () {
|
||||||
RFB.messages.pointerEvent(sock, 12345, 54321, 0xab);
|
RFB.messages.pointerEvent(sock, 12345, 54321, 0xab);
|
||||||
let expected =
|
let expected =
|
||||||
[ 5, 0xab, 0x30, 0x39, 0xd4, 0x31];
|
[ 5, 0x2b, 0x30, 0x39, 0xd4, 0x31];
|
||||||
expect(sock).to.have.sent(new Uint8Array(expected));
|
expect(sock).to.have.sent(new Uint8Array(expected));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should send correct data for pointer events with extended button bits set', function () {
|
||||||
|
RFB.messages.pointerEvent(sock, 12345, 54321, 0x3ab);
|
||||||
|
let expected =
|
||||||
|
[ 5, 0x2b, 0x30, 0x39, 0xd4, 0x31];
|
||||||
|
expect(sock).to.have.sent(new Uint8Array(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send correct data for extended pointer events', function () {
|
||||||
|
RFB.messages.extendedPointerEvent(sock, 12345, 54321, 0xab);
|
||||||
|
let expected =
|
||||||
|
[ 5, 0xab, 0x30, 0x39, 0xd4, 0x31, 0x1];
|
||||||
|
expect(sock).to.have.sent(new Uint8Array(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not send invalid data for extended pointer events', function () {
|
||||||
|
expect(() => RFB.messages.extendedPointerEvent(sock, 12345, 54321, 0x3ab)).to.throw(Error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Clipboard events', function () {
|
describe('Clipboard events', function () {
|
||||||
|
|
Loading…
Reference in New Issue