Merge branch 'mouse-buttonstate-remove' of https://github.com/CendioHalim/noVNC

This commit is contained in:
Pierre Ossman 2025-01-14 12:56:19 +01:00
commit 9cdbd28761
2 changed files with 505 additions and 283 deletions

View File

@ -1033,6 +1033,35 @@ export default class RFB extends EventTargetMixin {
this.sendKey(keysym, code, down);
}
static _convertButtonMask(buttons) {
/* The bits in MouseEvent.buttons property correspond
* to the following mouse buttons:
* 0: Left
* 1: Right
* 2: Middle
* 3: Back
* 4: Forward
*
* These bits needs to be converted to what they are defined as
* in the RFB protocol.
*/
const buttonMaskMap = {
0: 1 << 0, // Left
1: 1 << 2, // Right
2: 1 << 1, // Middle
3: 1 << 7, // Back
};
let bmask = 0;
for (let i = 0; i < 4; i++) {
if (buttons & (1 << i)) {
bmask |= buttonMaskMap[i];
}
}
return bmask;
}
_handleMouse(ev) {
/*
* We don't check connection status or viewOnly here as the
@ -1062,80 +1091,75 @@ export default class RFB extends EventTargetMixin {
let pos = clientToElement(ev.clientX, ev.clientY,
this._canvas);
let bmask = RFB._convertButtonMask(ev.buttons);
let down = ev.type == 'mousedown';
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) {
this._viewportDragging = true;
this._viewportDragPos = {'x': x, 'y': y};
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
this._viewportHasMoved = false;
// Skip sending mouse events
return;
this._flushMouseMoveTimer(pos.x, pos.y);
// Skip sending mouse events, instead save the current
// mouse mask so we can send it later.
this._mouseButtonMask = bmask;
break;
} else {
this._viewportDragging = false;
// If we actually performed a drag then we are done
// here and should not send any mouse events
if (this._viewportHasMoved) {
return;
this._mouseButtonMask = bmask;
break;
}
// Otherwise we treat this as a mouse click event.
// Send the button down event here, as the button up
// event is sent at the end of this function.
this._sendMouse(x, y, bmask);
// Send the previously saved button mask, followed
// by the current button mask at the end of this
// function.
this._sendMouse(pos.x, pos.y, this._mouseButtonMask);
}
}
// Flush waiting move event first
if (this._mouseMoveTimer !== null) {
clearTimeout(this._mouseMoveTimer);
this._mouseMoveTimer = null;
this._sendMouse(x, y, this._mouseButtonMask);
}
if (down) {
this._mouseButtonMask |= bmask;
} else {
this._mouseButtonMask &= ~bmask;
setCapture(this._canvas);
}
this._sendMouse(x, y, this._mouseButtonMask);
}
_handleMouseMove(x, y) {
this._handleMouseButton(pos.x, pos.y, bmask);
break;
case 'mousemove':
if (this._viewportDragging) {
const deltaX = this._viewportDragPos.x - x;
const deltaY = this._viewportDragPos.y - y;
const deltaX = this._viewportDragPos.x - pos.x;
const deltaY = this._viewportDragPos.y - pos.y;
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold ||
Math.abs(deltaY) > dragThreshold)) {
this._viewportHasMoved = true;
this._viewportDragPos = {'x': x, 'y': y};
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
this._display.viewportChangePos(deltaX, deltaY);
}
// Skip sending mouse events
return;
break;
}
this._handleMouseMove(pos.x, pos.y);
break;
}
}
_handleMouseButton(x, y, bmask) {
// Flush waiting move event first
this._flushMouseMoveTimer(x, y);
this._mouseButtonMask = bmask;
this._sendMouse(x, y, this._mouseButtonMask);
}
_handleMouseMove(x, y) {
this._mousePos = { 'x': x, 'y': y };
// Limit many mouse move events to one every MOUSE_MOVE_DELAY ms
@ -1179,6 +1203,7 @@ export default class RFB extends EventTargetMixin {
let pos = clientToElement(ev.clientX, ev.clientY,
this._canvas);
let bmask = RFB._convertButtonMask(ev.buttons);
let dX = ev.deltaX;
let dY = ev.deltaY;
@ -1198,26 +1223,27 @@ export default class RFB extends EventTargetMixin {
this._accumulatedWheelDeltaX += dX;
this._accumulatedWheelDeltaY += dY;
// Generate a mouse wheel step event when the accumulated delta
// for one of the axes is large enough.
if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
if (this._accumulatedWheelDeltaX < 0) {
this._handleMouseButton(pos.x, pos.y, true, 1 << 5);
this._handleMouseButton(pos.x, pos.y, false, 1 << 5);
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 5);
this._handleMouseButton(pos.x, pos.y, bmask);
} else if (this._accumulatedWheelDeltaX > 0) {
this._handleMouseButton(pos.x, pos.y, true, 1 << 6);
this._handleMouseButton(pos.x, pos.y, false, 1 << 6);
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 6);
this._handleMouseButton(pos.x, pos.y, bmask);
}
this._accumulatedWheelDeltaX = 0;
}
if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
if (this._accumulatedWheelDeltaY < 0) {
this._handleMouseButton(pos.x, pos.y, true, 1 << 3);
this._handleMouseButton(pos.x, pos.y, false, 1 << 3);
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 3);
this._handleMouseButton(pos.x, pos.y, bmask);
} else if (this._accumulatedWheelDeltaY > 0) {
this._handleMouseButton(pos.x, pos.y, true, 1 << 4);
this._handleMouseButton(pos.x, pos.y, false, 1 << 4);
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 4);
this._handleMouseButton(pos.x, pos.y, bmask);
}
this._accumulatedWheelDeltaY = 0;
@ -1256,8 +1282,8 @@ export default class RFB extends EventTargetMixin {
this._gestureLastTapTime = Date.now();
this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, true, bmask);
this._handleMouseButton(pos.x, pos.y, false, bmask);
this._handleMouseButton(pos.x, pos.y, bmask);
this._handleMouseButton(pos.x, pos.y, 0x0);
}
_handleGesture(ev) {
@ -1278,14 +1304,27 @@ export default class RFB extends EventTargetMixin {
this._handleTapEvent(ev, 0x2);
break;
case 'drag':
if (this.dragViewport) {
this._viewportHasMoved = false;
this._viewportDragging = true;
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
} else {
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, true, 0x1);
this._handleMouseButton(pos.x, pos.y, 0x1);
}
break;
case 'longpress':
if (this.dragViewport) {
// If dragViewport is true, we need to wait to see
// if we have dragged outside the threshold before
// sending any events to the server.
this._viewportHasMoved = false;
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
} else {
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, true, 0x4);
this._handleMouseButton(pos.x, pos.y, 0x4);
}
break;
case 'twodrag':
this._gestureLastMagnitudeX = ev.detail.magnitudeX;
this._gestureLastMagnitudeY = ev.detail.magnitudeY;
@ -1307,7 +1346,21 @@ export default class RFB extends EventTargetMixin {
break;
case 'drag':
case 'longpress':
if (this.dragViewport) {
this._viewportDragging = true;
const deltaX = this._viewportDragPos.x - pos.x;
const deltaY = this._viewportDragPos.y - pos.y;
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold ||
Math.abs(deltaY) > dragThreshold)) {
this._viewportHasMoved = true;
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
this._display.viewportChangePos(deltaX, deltaY);
}
} else {
this._fakeMouseMove(ev, pos.x, pos.y);
}
break;
case 'twodrag':
// Always scroll in the same position.
@ -1315,23 +1368,23 @@ export default class RFB extends EventTargetMixin {
// every update.
this._fakeMouseMove(ev, pos.x, pos.y);
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x8);
this._handleMouseButton(pos.x, pos.y, false, 0x8);
this._handleMouseButton(pos.x, pos.y, 0x8);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
}
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x10);
this._handleMouseButton(pos.x, pos.y, false, 0x10);
this._handleMouseButton(pos.x, pos.y, 0x10);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
}
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x20);
this._handleMouseButton(pos.x, pos.y, false, 0x20);
this._handleMouseButton(pos.x, pos.y, 0x20);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
}
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x40);
this._handleMouseButton(pos.x, pos.y, false, 0x40);
this._handleMouseButton(pos.x, pos.y, 0x40);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
}
break;
@ -1344,13 +1397,13 @@ export default class RFB extends EventTargetMixin {
if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x8);
this._handleMouseButton(pos.x, pos.y, false, 0x8);
this._handleMouseButton(pos.x, pos.y, 0x8);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
}
while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) {
this._handleMouseButton(pos.x, pos.y, true, 0x10);
this._handleMouseButton(pos.x, pos.y, false, 0x10);
this._handleMouseButton(pos.x, pos.y, 0x10);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
}
}
@ -1368,18 +1421,46 @@ export default class RFB extends EventTargetMixin {
case 'twodrag':
break;
case 'drag':
if (this.dragViewport) {
this._viewportDragging = false;
} else {
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, false, 0x1);
this._handleMouseButton(pos.x, pos.y, 0x0);
}
break;
case 'longpress':
if (this._viewportHasMoved) {
// We don't want to send any events if we have moved
// our viewport
break;
}
if (this.dragViewport && !this._viewportHasMoved) {
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, false, 0x4);
// If dragViewport is true, we need to wait to see
// if we have dragged outside the threshold before
// sending any events to the server.
this._handleMouseButton(pos.x, pos.y, 0x4);
this._handleMouseButton(pos.x, pos.y, 0x0);
this._viewportDragging = false;
} else {
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, 0x0);
}
break;
}
break;
}
}
_flushMouseMoveTimer(x, y) {
if (this._mouseMoveTimer !== null) {
clearTimeout(this._mouseMoveTimer);
this._mouseMoveTimer = null;
this._sendMouse(x, y, this._mouseButtonMask);
}
}
// Message handlers
_negotiateProtocolVersion() {

File diff suppressed because it is too large Load Diff