Skip to content

Commit

Permalink
Use MouseEvent.buttons for button state tracking
Browse files Browse the repository at this point in the history
Instead of keeping track of button states ourselves by looking at
MouseEvent.button, we can use the MouseEvent.buttons which already
contains the state of all buttons.
  • Loading branch information
CendioHalim committed Nov 29, 2024
1 parent 52ddb20 commit 278742b
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 37 deletions.
94 changes: 59 additions & 35 deletions core/rfb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1060,15 +1060,15 @@ export default class RFB extends EventTargetMixin {
let pos = clientToElement(ev.clientX, ev.clientY,
this._canvas);

let bmask = RFB.convertButtonMask(ev.buttons);

switch (ev.type) {
case 'mousedown':
setCapture(this._canvas);
this._handleMouseButton(pos.x, pos.y,
true, 1 << ev.button);
this._handleMouseButton(pos.x, pos.y, true, bmask);
break;
case 'mouseup':
this._handleMouseButton(pos.x, pos.y,
false, 1 << ev.button);
this._handleMouseButton(pos.x, pos.y, false, bmask);
break;
case 'mousemove':
this._handleMouseMove(pos.x, pos.y);
Expand Down Expand Up @@ -1097,7 +1097,7 @@ export default class RFB extends EventTargetMixin {
// 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);
this._sendMouse(x, y, this._mouseButtonMask);
}
}

Expand All @@ -1108,13 +1108,8 @@ export default class RFB extends EventTargetMixin {
this._sendMouse(x, y, this._mouseButtonMask);
}

if (down) {
this._mouseButtonMask |= bmask;
} else {
this._mouseButtonMask &= ~bmask;
}

this._sendMouse(x, y, this._mouseButtonMask);
this._sendMouse(x, y, bmask);
this._mouseButtonMask = bmask;
}

_handleMouseMove(x, y) {
Expand Down Expand Up @@ -1200,22 +1195,22 @@ export default class RFB extends EventTargetMixin {
// 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, true, this._mouseButtonMask | 1 << 5);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~(1 << 5));
} 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, true, this._mouseButtonMask | 1 << 6);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~( 1 << 6));
}

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, true, this._mouseButtonMask | 1 << 3);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~( 1 << 3));
} 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, true, this._mouseButtonMask | 1 << 4);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~( 1 << 4));
}

this._accumulatedWheelDeltaY = 0;
Expand Down Expand Up @@ -1255,7 +1250,7 @@ export default class RFB extends EventTargetMixin {

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, false, 0x0);
}

_handleGesture(ev) {
Expand Down Expand Up @@ -1313,23 +1308,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, true, this._mouseButtonMask | 0x8);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x8);
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, true, this._mouseButtonMask | 0x10);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~ 0x10);
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, true, this._mouseButtonMask | 0x20);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~ 0x20);
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, true, this._mouseButtonMask | 0x40);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x40);
this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
}
break;
Expand All @@ -1342,13 +1337,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, true, this._mouseButtonMask | 0x8);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x8);
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, true, this._mouseButtonMask | 0x10);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x10);
this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
}
}
Expand All @@ -1367,11 +1362,11 @@ export default class RFB extends EventTargetMixin {
break;
case 'drag':
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, false, 0x1);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x1);
break;
case 'longpress':
this._fakeMouseMove(ev, pos.x, pos.y);
this._handleMouseButton(pos.x, pos.y, false, 0x4);
this._handleMouseButton(pos.x, pos.y, false, this._mouseButtonMask & ~0x4);
break;
}
break;
Expand Down Expand Up @@ -2941,6 +2936,35 @@ export default class RFB extends EventTargetMixin {
"raw", passwordChars, { name: "DES-ECB" }, false, ["encrypt"]);
return legacyCrypto.encrypt({ name: "DES-ECB" }, key, challenge);
}

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;
}
}

// Class Methods
Expand Down
14 changes: 12 additions & 2 deletions tests/test.rfb.js
Original file line number Diff line number Diff line change
Expand Up @@ -3508,6 +3508,9 @@ describe('Remote Frame Buffer protocol client', function () {
// client coordinate calculations
client.focusOnClick = false;

// We need to keep track of MouseEvent.buttons state
client._buttonsState = 0;

pointerEvent = sinon.spy(RFB.messages, 'pointerEvent');
keyEvent = sinon.spy(RFB.messages, 'keyEvent');
qemuKeyEvent = sinon.spy(RFB.messages, 'QEMUExtendedKeyEvent');
Expand Down Expand Up @@ -3546,21 +3549,28 @@ describe('Remote Frame Buffer protocol client', function () {
{ 'screenX': pos.x + window.screenX,
'screenY': pos.y + window.screenY,
'clientX': pos.x,
'clientY': pos.y });
'clientY': pos.y,
'buttons': client._buttonsState });
client._canvas.dispatchEvent(ev);
}

function sendMouseButtonEvent(x, y, down, button) {
let pos = elementToClient(x, y);
let ev;

if (down) {
client._buttonsState |= RFB.convertButtonMask(1 << button);
} else {
client._buttonsState &= ~RFB.convertButtonMask(1 << button);
}

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 });
'buttons': client._buttonsState });
client._canvas.dispatchEvent(ev);
}

Expand Down

0 comments on commit 278742b

Please sign in to comment.