Move mouse event handling to RFB class
Move the last remaining bits to the RFB class to keep things simple, as the Mouse class no longer provides any real value.
This commit is contained in:
parent
88589a44f7
commit
50cde2faab
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* 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 { setCapture, stopEvent, getPointerEvent } from '../util/events.js';
|
||||
|
||||
export default class Mouse {
|
||||
constructor(target) {
|
||||
this._target = target || document;
|
||||
|
||||
this._pos = null;
|
||||
|
||||
this._eventHandlers = {
|
||||
'mousedown': this._handleMouseDown.bind(this),
|
||||
'mouseup': this._handleMouseUp.bind(this),
|
||||
'mousemove': this._handleMouseMove.bind(this),
|
||||
'mousedisable': this._handleMouseDisable.bind(this)
|
||||
};
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
|
||||
this.onmousebutton = () => {}; // Handler for mouse button press/release
|
||||
this.onmousemove = () => {}; // Handler for mouse movement
|
||||
}
|
||||
|
||||
// ===== PRIVATE METHODS =====
|
||||
|
||||
_resetDoubleClickTimer() {
|
||||
this._doubleClickTimer = null;
|
||||
}
|
||||
|
||||
_handleMouseButton(e, down) {
|
||||
this._updateMousePosition(e);
|
||||
let pos = this._pos;
|
||||
|
||||
let bmask = 1 << e.button;
|
||||
|
||||
Log.Debug("onmousebutton " + (down ? "down" : "up") +
|
||||
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
|
||||
this.onmousebutton(pos.x, pos.y, down, bmask);
|
||||
|
||||
stopEvent(e);
|
||||
}
|
||||
|
||||
_handleMouseDown(e) {
|
||||
setCapture(this._target);
|
||||
|
||||
this._handleMouseButton(e, 1);
|
||||
}
|
||||
|
||||
_handleMouseUp(e) {
|
||||
this._handleMouseButton(e, 0);
|
||||
}
|
||||
|
||||
_handleMouseMove(e) {
|
||||
this._updateMousePosition(e);
|
||||
this.onmousemove(this._pos.x, this._pos.y);
|
||||
stopEvent(e);
|
||||
}
|
||||
|
||||
_handleMouseDisable(e) {
|
||||
/*
|
||||
* Stop propagation if inside canvas area
|
||||
* Note: This is only needed for the 'click' event as it fails
|
||||
* to fire properly for the target element so we have
|
||||
* to listen on the document element instead.
|
||||
*/
|
||||
if (e.target == this._target) {
|
||||
stopEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Update coordinates relative to target
|
||||
_updateMousePosition(e) {
|
||||
e = getPointerEvent(e);
|
||||
const bounds = this._target.getBoundingClientRect();
|
||||
let x;
|
||||
let y;
|
||||
// Clip to target bounds
|
||||
if (e.clientX < bounds.left) {
|
||||
x = 0;
|
||||
} else if (e.clientX >= bounds.right) {
|
||||
x = bounds.width - 1;
|
||||
} else {
|
||||
x = e.clientX - bounds.left;
|
||||
}
|
||||
if (e.clientY < bounds.top) {
|
||||
y = 0;
|
||||
} else if (e.clientY >= bounds.bottom) {
|
||||
y = bounds.height - 1;
|
||||
} else {
|
||||
y = e.clientY - bounds.top;
|
||||
}
|
||||
this._pos = {x: x, y: y};
|
||||
}
|
||||
|
||||
// ===== PUBLIC METHODS =====
|
||||
|
||||
grab() {
|
||||
const t = this._target;
|
||||
t.addEventListener('mousedown', this._eventHandlers.mousedown);
|
||||
t.addEventListener('mouseup', this._eventHandlers.mouseup);
|
||||
t.addEventListener('mousemove', this._eventHandlers.mousemove);
|
||||
|
||||
// Prevent middle-click pasting (see above for why we bind to document)
|
||||
document.addEventListener('click', this._eventHandlers.mousedisable);
|
||||
|
||||
// preventDefault() on mousedown doesn't stop this event for some
|
||||
// reason so we have to explicitly block it
|
||||
t.addEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||
}
|
||||
|
||||
ungrab() {
|
||||
const t = this._target;
|
||||
|
||||
t.removeEventListener('mousedown', this._eventHandlers.mousedown);
|
||||
t.removeEventListener('mouseup', this._eventHandlers.mouseup);
|
||||
t.removeEventListener('mousemove', this._eventHandlers.mousemove);
|
||||
|
||||
document.removeEventListener('click', this._eventHandlers.mousedisable);
|
||||
|
||||
t.removeEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||
}
|
||||
}
|
72
core/rfb.js
72
core/rfb.js
|
@ -12,12 +12,12 @@ import * as Log from './util/logging.js';
|
|||
import { encodeUTF8, decodeUTF8 } from './util/strings.js';
|
||||
import { dragThreshold } from './util/browser.js';
|
||||
import { clientToElement } from './util/element.js';
|
||||
import { setCapture } from './util/events.js';
|
||||
import EventTargetMixin from './util/eventtarget.js';
|
||||
import Display from "./display.js";
|
||||
import Inflator from "./inflator.js";
|
||||
import Deflator from "./deflator.js";
|
||||
import Keyboard from "./input/keyboard.js";
|
||||
import Mouse from "./input/mouse.js";
|
||||
import GestureHandler from "./input/gesturehandler.js";
|
||||
import Cursor from "./util/cursor.js";
|
||||
import Websock from "./websock.js";
|
||||
|
@ -129,7 +129,6 @@ export default class RFB extends EventTargetMixin {
|
|||
this._display = null; // Display object
|
||||
this._flushing = false; // Display flushing state
|
||||
this._keyboard = null; // Keyboard input handler object
|
||||
this._mouse = null; // Mouse input handler object
|
||||
this._gestures = null; // Gesture input handler object
|
||||
|
||||
// Timers
|
||||
|
@ -169,6 +168,7 @@ export default class RFB extends EventTargetMixin {
|
|||
this._eventHandlers = {
|
||||
focusCanvas: this._focusCanvas.bind(this),
|
||||
windowResize: this._windowResize.bind(this),
|
||||
handleMouse: this._handleMouse.bind(this),
|
||||
handleWheel: this._handleWheel.bind(this),
|
||||
handleGesture: this._handleGesture.bind(this),
|
||||
};
|
||||
|
@ -229,10 +229,6 @@ export default class RFB extends EventTargetMixin {
|
|||
this._keyboard = new Keyboard(this._canvas);
|
||||
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
|
||||
|
||||
this._mouse = new Mouse(this._canvas);
|
||||
this._mouse.onmousebutton = this._handleMouseButton.bind(this);
|
||||
this._mouse.onmousemove = this._handleMouseMove.bind(this);
|
||||
|
||||
this._gestures = new GestureHandler();
|
||||
|
||||
this._sock = new Websock();
|
||||
|
@ -321,10 +317,8 @@ export default class RFB extends EventTargetMixin {
|
|||
this._rfbConnectionState === "connected") {
|
||||
if (viewOnly) {
|
||||
this._keyboard.ungrab();
|
||||
this._mouse.ungrab();
|
||||
} else {
|
||||
this._keyboard.grab();
|
||||
this._mouse.grab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -539,6 +533,16 @@ export default class RFB extends EventTargetMixin {
|
|||
this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
|
||||
// Mouse events
|
||||
this._canvas.addEventListener('mousedown', this._eventHandlers.handleMouse);
|
||||
this._canvas.addEventListener('mouseup', this._eventHandlers.handleMouse);
|
||||
this._canvas.addEventListener('mousemove', this._eventHandlers.handleMouse);
|
||||
// Prevent middle-click pasting (see handler for why we bind to document)
|
||||
this._canvas.addEventListener('click', this._eventHandlers.handleMouse);
|
||||
// preventDefault() on mousedown doesn't stop this event for some
|
||||
// reason so we have to explicitly block it
|
||||
this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse);
|
||||
|
||||
// Wheel events
|
||||
this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);
|
||||
|
||||
|
@ -557,11 +561,15 @@ export default class RFB extends EventTargetMixin {
|
|||
this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture);
|
||||
this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture);
|
||||
this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel);
|
||||
this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse);
|
||||
this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse);
|
||||
this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);
|
||||
this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);
|
||||
this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);
|
||||
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
window.removeEventListener('resize', this._eventHandlers.windowResize);
|
||||
this._keyboard.ungrab();
|
||||
this._mouse.ungrab();
|
||||
this._gestures.detach();
|
||||
this._sock.close();
|
||||
try {
|
||||
|
@ -859,6 +867,51 @@ export default class RFB extends EventTargetMixin {
|
|||
this.sendKey(keysym, code, down);
|
||||
}
|
||||
|
||||
_handleMouse(ev) {
|
||||
/*
|
||||
* We don't check connection status or viewOnly here as the
|
||||
* mouse events might be used to control the viewport
|
||||
*/
|
||||
|
||||
if (ev.type === 'click') {
|
||||
/*
|
||||
* Note: This is only needed for the 'click' event as it fails
|
||||
* to fire properly for the target element so we have
|
||||
* to listen on the document element instead.
|
||||
*/
|
||||
if (ev.target !== this._canvas) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: if we're in view-only and not dragging,
|
||||
// should we stop events?
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
if ((ev.type === 'click') || (ev.type === 'contextmenu')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = clientToElement(ev.clientX, ev.clientY,
|
||||
this._canvas);
|
||||
|
||||
switch (ev.type) {
|
||||
case 'mousedown':
|
||||
setCapture(this._canvas);
|
||||
this._handleMouseButton(pos.x, pos.y,
|
||||
true, 1 << ev.button);
|
||||
break;
|
||||
case 'mouseup':
|
||||
this._handleMouseButton(pos.x, pos.y,
|
||||
false, 1 << ev.button);
|
||||
break;
|
||||
case 'mousemove':
|
||||
this._handleMouseMove(pos.x, pos.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_handleMouseButton(x, y, down, bmask) {
|
||||
if (this.dragViewport) {
|
||||
if (down && !this._viewportDragging) {
|
||||
|
@ -1678,7 +1731,6 @@ export default class RFB extends EventTargetMixin {
|
|||
this._resize(width, height);
|
||||
|
||||
if (!this._viewOnly) { this._keyboard.grab(); }
|
||||
if (!this._viewOnly) { this._mouse.grab(); }
|
||||
|
||||
this._fbDepth = 24;
|
||||
|
||||
|
|
|
@ -11,9 +11,6 @@ official external API.
|
|||
|
||||
## 1.1 Module List
|
||||
|
||||
* __Mouse__ (core/input/mouse.js): Mouse input event handler with
|
||||
limited touch support.
|
||||
|
||||
* __Keyboard__ (core/input/keyboard.js): Keyboard input event handler with
|
||||
non-US keyboard support. Translates keyDown and keyUp events to X11
|
||||
keysym values.
|
||||
|
@ -35,52 +32,29 @@ callback event name, and the callback function.
|
|||
|
||||
## 2. Modules
|
||||
|
||||
## 2.1 Mouse Module
|
||||
## 2.1 Keyboard Module
|
||||
|
||||
### 2.1.1 Configuration Attributes
|
||||
|
||||
| name | type | mode | default | description
|
||||
| ----------- | ---- | ---- | -------- | ------------
|
||||
| touchButton | int | RW | 1 | Button mask (1, 2, 4) for which click to send on touch devices. 0 means ignore clicks.
|
||||
|
||||
### 2.1.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------ | ---------- | ------------
|
||||
| grab | () | Begin capturing mouse events
|
||||
| ungrab | () | Stop capturing mouse events
|
||||
|
||||
### 2.1.2 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ------------- | ------------------- | ------------
|
||||
| onmousebutton | (x, y, down, bmask) | Handler for mouse button click/release
|
||||
| onmousemove | (x, y) | Handler for mouse movement
|
||||
|
||||
|
||||
## 2.2 Keyboard Module
|
||||
|
||||
### 2.2.1 Configuration Attributes
|
||||
|
||||
None
|
||||
|
||||
### 2.2.2 Methods
|
||||
### 2.1.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------ | ---------- | ------------
|
||||
| grab | () | Begin capturing keyboard events
|
||||
| ungrab | () | Stop capturing keyboard events
|
||||
|
||||
### 2.2.3 Callbacks
|
||||
### 2.1.3 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ---------- | -------------------- | ------------
|
||||
| onkeypress | (keysym, code, down) | Handler for key press/release
|
||||
|
||||
|
||||
## 2.3 Display Module
|
||||
## 2.2 Display Module
|
||||
|
||||
### 2.3.1 Configuration Attributes
|
||||
### 2.2.1 Configuration Attributes
|
||||
|
||||
| name | type | mode | default | description
|
||||
| ------------ | ----- | ---- | ------- | ------------
|
||||
|
@ -89,7 +63,7 @@ None
|
|||
| width | int | RO | | Display area width
|
||||
| height | int | RO | | Display area height
|
||||
|
||||
### 2.3.2 Methods
|
||||
### 2.2.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------------------ | ------------------------------------------------------- | ------------
|
||||
|
@ -113,7 +87,7 @@ None
|
|||
| drawImage | (img, x, y) | Draw image and track damage
|
||||
| autoscale | (containerWidth, containerHeight) | Scale the display
|
||||
|
||||
### 2.3.3 Callbacks
|
||||
### 2.2.3 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ------- | ---------- | ------------
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
const expect = chai.expect;
|
||||
|
||||
import Mouse from '../core/input/mouse.js';
|
||||
|
||||
describe('Mouse Event Handling', function () {
|
||||
"use strict";
|
||||
|
||||
let target;
|
||||
|
||||
beforeEach(function () {
|
||||
// For these tests we can assume that the canvas is 100x100
|
||||
// located at coordinates 10x10
|
||||
target = document.createElement('canvas');
|
||||
target.style.position = "absolute";
|
||||
target.style.top = "10px";
|
||||
target.style.left = "10px";
|
||||
target.style.width = "100px";
|
||||
target.style.height = "100px";
|
||||
document.body.appendChild(target);
|
||||
});
|
||||
afterEach(function () {
|
||||
document.body.removeChild(target);
|
||||
target = null;
|
||||
});
|
||||
|
||||
// The real constructors might not work everywhere we
|
||||
// want to run these tests
|
||||
const mouseevent = (typeArg, MouseEventInit) => {
|
||||
const e = { type: typeArg };
|
||||
for (let key in MouseEventInit) {
|
||||
e[key] = MouseEventInit[key];
|
||||
}
|
||||
e.stopPropagation = sinon.spy();
|
||||
e.preventDefault = sinon.spy();
|
||||
return e;
|
||||
};
|
||||
|
||||
describe('Decode Mouse Events', function () {
|
||||
it('should decode mousedown events', function (done) {
|
||||
const mouse = new Mouse(target);
|
||||
mouse.onmousebutton = (x, y, down, bmask) => {
|
||||
expect(bmask).to.be.equal(0x01);
|
||||
expect(down).to.be.equal(1);
|
||||
done();
|
||||
};
|
||||
mouse._handleMouseDown(mouseevent('mousedown', { button: 0 }));
|
||||
});
|
||||
it('should decode mouseup events', function (done) {
|
||||
let calls = 0;
|
||||
const mouse = new Mouse(target);
|
||||
mouse.onmousebutton = (x, y, down, bmask) => {
|
||||
expect(bmask).to.be.equal(0x01);
|
||||
if (calls++ === 1) {
|
||||
expect(down).to.not.be.equal(1);
|
||||
done();
|
||||
}
|
||||
};
|
||||
mouse._handleMouseDown(mouseevent('mousedown', { button: 0 }));
|
||||
mouse._handleMouseUp(mouseevent('mouseup', { button: 0 }));
|
||||
});
|
||||
it('should decode mousemove events', function (done) {
|
||||
const mouse = new Mouse(target);
|
||||
mouse.onmousemove = (x, y) => {
|
||||
// Note that target relative coordinates are sent
|
||||
expect(x).to.be.equal(40);
|
||||
expect(y).to.be.equal(10);
|
||||
done();
|
||||
};
|
||||
mouse._handleMouseMove(mouseevent('mousemove',
|
||||
{ clientX: 50, clientY: 20 }));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1579,12 +1579,10 @@ describe('Remote Frame Buffer Protocol Client', function () {
|
|||
expect(client._display.resize).to.have.been.calledWith(27, 32);
|
||||
});
|
||||
|
||||
it('should grab the mouse and keyboard', function () {
|
||||
it('should grab the keyboard', function () {
|
||||
sinon.spy(client._keyboard, 'grab');
|
||||
sinon.spy(client._mouse, 'grab');
|
||||
sendServerInit({}, client);
|
||||
expect(client._keyboard.grab).to.have.been.calledOnce;
|
||||
expect(client._mouse.grab).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
describe('Initial Update Request', function () {
|
||||
|
@ -2739,6 +2737,11 @@ describe('Remote Frame Buffer Protocol Client', function () {
|
|||
client = makeRFB();
|
||||
client._display.resize(100, 100);
|
||||
|
||||
// We need to disable this as focusing the canvas will
|
||||
// cause the browser to scoll to it, messing up our
|
||||
// client coordinate calculations
|
||||
client.focusOnClick = false;
|
||||
|
||||
pointerEvent = sinon.spy(RFB.messages, 'pointerEvent');
|
||||
keyEvent = sinon.spy(RFB.messages, 'keyEvent');
|
||||
qemuKeyEvent = sinon.spy(RFB.messages, 'QEMUExtendedKeyEvent');
|
||||
|
@ -2769,136 +2772,279 @@ describe('Remote Frame Buffer Protocol Client', function () {
|
|||
}
|
||||
|
||||
describe('Mouse Events', function () {
|
||||
function sendMouseMoveEvent(x, y) {
|
||||
let pos = elementToClient(x, y);
|
||||
let ev;
|
||||
|
||||
try {
|
||||
ev = new MouseEvent('mousemove',
|
||||
{ 'screenX': pos.x + window.screenX,
|
||||
'screenY': pos.y + window.screenY,
|
||||
'clientX': pos.x,
|
||||
'clientY': pos.y });
|
||||
} catch (e) {
|
||||
ev = document.createEvent('MouseEvent');
|
||||
ev.initMouseEvent('mousemove',
|
||||
true, true, window, 0,
|
||||
pos.x + window.screenX,
|
||||
pos.y + window.screenY,
|
||||
pos.x, pos.y,
|
||||
false, false, false, false,
|
||||
0, null);
|
||||
}
|
||||
|
||||
client._canvas.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
function sendMouseButtonEvent(x, y, down, button) {
|
||||
let pos = elementToClient(x, y);
|
||||
let ev;
|
||||
|
||||
try {
|
||||
ev = new MouseEvent(down ? 'mousedown' : 'mouseup',
|
||||
{ 'screenX': pos.x + window.screenX,
|
||||
'screenY': pos.y + window.screenY,
|
||||
'clientX': pos.x,
|
||||
'clientY': pos.y,
|
||||
'button': button,
|
||||
'buttons': 1 << button });
|
||||
} catch (e) {
|
||||
ev = document.createEvent('MouseEvent');
|
||||
ev.initMouseEvent(down ? 'mousedown' : 'mouseup',
|
||||
true, true, window, 0,
|
||||
pos.x + window.screenX,
|
||||
pos.y + window.screenY,
|
||||
pos.x, pos.y,
|
||||
false, false, false, false,
|
||||
button, null);
|
||||
}
|
||||
|
||||
client._canvas.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
it('should not send button messages in view-only mode', function () {
|
||||
client._viewOnly = true;
|
||||
client._handleMouseButton(0, 0, 1, 0x001);
|
||||
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||
sendMouseButtonEvent(10, 10, true, 0);
|
||||
clock.tick(50);
|
||||
expect(pointerEvent).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('should not send movement messages in view-only mode', function () {
|
||||
client._viewOnly = true;
|
||||
client._handleMouseMove(0, 0);
|
||||
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||
sendMouseMoveEvent(10, 10);
|
||||
clock.tick(50);
|
||||
expect(pointerEvent).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('should send a pointer event on mouse button presses', function () {
|
||||
client._handleMouseButton(10, 12, 1, 0x001);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
it('should handle left mouse button', function () {
|
||||
sendMouseButtonEvent(10, 10, true, 0);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x1);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseButtonEvent(10, 10, false, 0);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x0);
|
||||
});
|
||||
|
||||
it('should send a mask of 1 on mousedown', function () {
|
||||
client._handleMouseButton(11, 13, 1, 0x001);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledWith(
|
||||
client._sock, 11, 13, 0x001);
|
||||
it('should handle middle mouse button', function () {
|
||||
sendMouseButtonEvent(10, 10, true, 1);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x2);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseButtonEvent(10, 10, false, 1);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x0);
|
||||
});
|
||||
|
||||
it('should send a mask of 0 on mouseup', function () {
|
||||
client._mouseButtonMask = 0x001;
|
||||
client._handleMouseButton(105, 120, 0, 0x001);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledWith(
|
||||
client._sock, 105, 120, 0x000);
|
||||
it('should handle right mouse button', function () {
|
||||
sendMouseButtonEvent(10, 10, true, 2);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x4);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseButtonEvent(10, 10, false, 2);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
10, 10, 0x0);
|
||||
});
|
||||
|
||||
it('should send a mask of 0 on mousemove', function () {
|
||||
client._handleMouseMove(100, 200);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledWith(
|
||||
client._sock, 100, 200, 0x000);
|
||||
it('should handle multiple mouse buttons', function () {
|
||||
sendMouseButtonEvent(10, 10, true, 0);
|
||||
sendMouseButtonEvent(10, 10, true, 2);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledTwice;
|
||||
expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock,
|
||||
10, 10, 0x1);
|
||||
expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock,
|
||||
10, 10, 0x5);
|
||||
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseButtonEvent(10, 10, false, 0);
|
||||
sendMouseButtonEvent(10, 10, false, 2);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledTwice;
|
||||
expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock,
|
||||
10, 10, 0x4);
|
||||
expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock,
|
||||
10, 10, 0x0);
|
||||
});
|
||||
|
||||
it('should set the button mask so that future mouse movements use it', function () {
|
||||
client._handleMouseButton(10, 12, 1, 0x010);
|
||||
client._handleMouseMove(13, 9);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledWith(
|
||||
client._sock, 13, 9, 0x010);
|
||||
it('should handle mouse movement', function () {
|
||||
sendMouseMoveEvent(50, 70);
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
50, 70, 0x0);
|
||||
});
|
||||
|
||||
it('should handle click and drag', function () {
|
||||
sendMouseButtonEvent(10, 10, true, 0);
|
||||
sendMouseMoveEvent(50, 70);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledTwice;
|
||||
expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock,
|
||||
10, 10, 0x1);
|
||||
expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock,
|
||||
50, 70, 0x1);
|
||||
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseButtonEvent(50, 70, false, 0);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
50, 70, 0x0);
|
||||
});
|
||||
|
||||
describe('Event Aggregation', function () {
|
||||
it('should send a single pointer event on mouse movement', function () {
|
||||
client._handleMouseMove(100, 200);
|
||||
this.clock.tick(100);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
sendMouseMoveEvent(50, 70);
|
||||
clock.tick(100);
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
50, 70, 0x0);
|
||||
});
|
||||
|
||||
it('should delay one move if two events are too close', function () {
|
||||
client._handleMouseMove(18, 30);
|
||||
client._handleMouseMove(20, 50);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
this.clock.tick(100);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||
sendMouseMoveEvent(18, 30);
|
||||
sendMouseMoveEvent(20, 50);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
18, 30, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
clock.tick(100);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
20, 50, 0x0);
|
||||
});
|
||||
|
||||
it('should only send first and last move of many close events', function () {
|
||||
client._handleMouseMove(18, 40);
|
||||
client._handleMouseMove(20, 50);
|
||||
client._handleMouseMove(21, 55);
|
||||
sendMouseMoveEvent(18, 30);
|
||||
sendMouseMoveEvent(20, 50);
|
||||
sendMouseMoveEvent(21, 55);
|
||||
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
this.clock.tick(60);
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
18, 30, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||
expect(RFB.messages.pointerEvent.firstCall).to.have.been.calledWith(
|
||||
client._sock, 18, 40, 0x000);
|
||||
expect(RFB.messages.pointerEvent.secondCall).to.have.been.calledWith(
|
||||
client._sock, 21, 55, 0x000);
|
||||
clock.tick(100);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
21, 55, 0x0);
|
||||
});
|
||||
|
||||
// We selected the 17ms since that is ~60 FPS
|
||||
it('should send move events every 17 ms', function () {
|
||||
client._handleMouseMove(1, 10); // instant send
|
||||
this.clock.tick(10);
|
||||
client._handleMouseMove(2, 20); // delayed
|
||||
this.clock.tick(10); // timeout send
|
||||
client._handleMouseMove(3, 30); // delayed
|
||||
this.clock.tick(10);
|
||||
client._handleMouseMove(4, 40); // delayed
|
||||
this.clock.tick(10); // timeout send
|
||||
client._handleMouseMove(5, 50); // delayed
|
||||
sendMouseMoveEvent(1, 10); // instant send
|
||||
clock.tick(10);
|
||||
|
||||
expect(RFB.messages.pointerEvent).to.have.callCount(3);
|
||||
expect(RFB.messages.pointerEvent.firstCall).to.have.been.calledWith(
|
||||
client._sock, 1, 10, 0x000);
|
||||
expect(RFB.messages.pointerEvent.secondCall).to.have.been.calledWith(
|
||||
client._sock, 2, 20, 0x000);
|
||||
expect(RFB.messages.pointerEvent.thirdCall).to.have.been.calledWith(
|
||||
client._sock, 4, 40, 0x000);
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
1, 10, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseMoveEvent(2, 20); // delayed
|
||||
clock.tick(10); // timeout send
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
2, 20, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseMoveEvent(3, 30); // delayed
|
||||
clock.tick(10);
|
||||
sendMouseMoveEvent(4, 40); // delayed
|
||||
clock.tick(10); // timeout send
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
4, 40, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseMoveEvent(5, 50); // delayed
|
||||
|
||||
expect(pointerEvent).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('should send waiting move events before a button press', function () {
|
||||
client._handleMouseMove(13, 9);
|
||||
client._handleMouseMove(20, 70);
|
||||
client._handleMouseButton(10, 12, 1, 0x100);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledThrice;
|
||||
expect(RFB.messages.pointerEvent.firstCall).to.have.been.calledWith(
|
||||
client._sock, 13, 9, 0x000);
|
||||
expect(RFB.messages.pointerEvent.secondCall).to.have.been.calledWith(
|
||||
client._sock, 10, 12, 0x000);
|
||||
expect(RFB.messages.pointerEvent.thirdCall).to.have.been.calledWith(
|
||||
client._sock, 10, 12, 0x100);
|
||||
});
|
||||
sendMouseMoveEvent(13, 9);
|
||||
|
||||
it('should not delay events when button mask changes', function () {
|
||||
client._handleMouseMove(13, 9); // instant
|
||||
client._handleMouseMove(11, 10); // delayed
|
||||
client._handleMouseButton(10, 12, 1, 0x010); // flush delayed
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledThrice;
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
13, 9, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseMoveEvent(20, 70);
|
||||
|
||||
expect(pointerEvent).to.not.have.been.called;
|
||||
|
||||
sendMouseButtonEvent(20, 70, true, 0);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledTwice;
|
||||
expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock,
|
||||
20, 70, 0x0);
|
||||
expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock,
|
||||
20, 70, 0x1);
|
||||
});
|
||||
|
||||
it('should send move events with enough time apart normally', function () {
|
||||
client._handleMouseMove(58, 60);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
sendMouseMoveEvent(58, 60);
|
||||
|
||||
this.clock.tick(20);
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
58, 60, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
client._handleMouseMove(25, 60);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||
clock.tick(20);
|
||||
|
||||
sendMouseMoveEvent(25, 60);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
25, 60, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
});
|
||||
|
||||
it('should not send waiting move events if disconnected', function () {
|
||||
client._handleMouseMove(88, 99);
|
||||
client._handleMouseMove(66, 77);
|
||||
sendMouseMoveEvent(88, 99);
|
||||
|
||||
expect(pointerEvent).to.have.been.calledOnceWith(client._sock,
|
||||
88, 99, 0x0);
|
||||
pointerEvent.resetHistory();
|
||||
|
||||
sendMouseMoveEvent(66, 77);
|
||||
client.disconnect();
|
||||
this.clock.tick(20);
|
||||
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||
clock.tick(20);
|
||||
|
||||
expect(pointerEvent).to.not.have.been.called;
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('should block click events', function () {
|
||||
/* FIXME */
|
||||
});
|
||||
|
||||
it.skip('should block contextmenu events', function () {
|
||||
/* FIXME */
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue