Feature/kasm 2346 extend mouse buttons (#39)
* Extend mouse event button mask to 16 bits * Mouse button mapping (JS -> Xorg) support * Refactor: extract XVNC_BUTTONS * Refactor: XVNC_BUTTONS numbers correspond to X button numbers * Refactor Co-authored-by: Lauri Kasanen <cand@gmx.com>
This commit is contained in:
parent
cac1f25ce4
commit
26c97c1dd3
20
app/ui.js
20
app/ui.js
|
@ -41,6 +41,7 @@ import KeyTable from "../core/input/keysym.js";
|
|||
import keysyms from "../core/input/keysymdef.js";
|
||||
import Keyboard from "../core/input/keyboard.js";
|
||||
import RFB from "../core/rfb.js";
|
||||
import { MouseButtonMapper, XVNC_BUTTONS } from "../core/mousebuttonmapper.js";
|
||||
import * as WebUtil from "./webutil.js";
|
||||
|
||||
const PAGE_TITLE = "KasmVNC";
|
||||
|
@ -264,6 +265,24 @@ const UI = {
|
|||
UI.setupSettingLabels();
|
||||
UI.updateQuality();
|
||||
},
|
||||
initMouseButtonMapper() {
|
||||
const mouseButtonMapper = new MouseButtonMapper();
|
||||
|
||||
const settings = WebUtil.readSetting("mouseButtonMapper");
|
||||
if (settings) {
|
||||
mouseButtonMapper.load(settings);
|
||||
return mouseButtonMapper;
|
||||
}
|
||||
|
||||
mouseButtonMapper.set(0, XVNC_BUTTONS.LEFT_BUTTON);
|
||||
mouseButtonMapper.set(1, XVNC_BUTTONS.MIDDLE_BUTTON);
|
||||
mouseButtonMapper.set(2, XVNC_BUTTONS.RIGHT_BUTTON);
|
||||
mouseButtonMapper.set(3, XVNC_BUTTONS.BACK_BUTTON);
|
||||
mouseButtonMapper.set(4, XVNC_BUTTONS.FORWARD_BUTTON);
|
||||
WebUtil.writeSetting("mouseButtonMapper", mouseButtonMapper.dump());
|
||||
|
||||
return mouseButtonMapper;
|
||||
},
|
||||
// Adds a link to the label elements on the corresponding input elements
|
||||
setupSettingLabels() {
|
||||
const labels = document.getElementsByTagName('LABEL');
|
||||
|
@ -1381,6 +1400,7 @@ const UI = {
|
|||
UI.rfb.keyboard.enableIME = UI.getSetting('enable_ime');
|
||||
UI.rfb.clipboardBinary = supportsBinaryClipboard() && UI.rfb.clipboardSeamless;
|
||||
UI.rfb.enableWebRTC = UI.getSetting('enable_webrtc');
|
||||
UI.rfb.mouseButtonMapper = UI.initMouseButtonMapper();
|
||||
|
||||
//Only explicitly request permission to clipboard on browsers that support binary clipboard access
|
||||
if (supportsBinaryClipboard()) {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
export const XVNC_BUTTONS = {
|
||||
LEFT_BUTTON: 1,
|
||||
MIDDLE_BUTTON: 2,
|
||||
RIGHT_BUTTON: 3,
|
||||
TURN_SCROLL_WHEEL_UP: 4,
|
||||
TURN_SCROLL_WHEEL_DOWN: 5,
|
||||
PUSH_SCROLL_WHEEL_LEFT: 6,
|
||||
PUSH_SCROLL_WHEEL_RIGHT: 7,
|
||||
BACK_BUTTON: 8,
|
||||
FORWARD_BUTTON: 9
|
||||
};
|
||||
|
||||
export function xvncButtonToMask(xvncButton) {
|
||||
return 1 << (xvncButton - 1);
|
||||
}
|
||||
|
||||
export default class MouseButtonMapper {
|
||||
constructor() {
|
||||
this.map = new Map();
|
||||
}
|
||||
|
||||
get(mouseButton) {
|
||||
if (!this.map.has(mouseButton)) {
|
||||
return mouseButton;
|
||||
}
|
||||
|
||||
return this.map.get(mouseButton);
|
||||
}
|
||||
|
||||
set(mouseButton, xorgMouseButton) {
|
||||
return this.map.set(mouseButton, xorgMouseButton);
|
||||
}
|
||||
|
||||
delete(mouseButton) {
|
||||
return this.map.delete(mouseButton);
|
||||
}
|
||||
|
||||
dump() {
|
||||
return JSON.stringify(this.map, this._replacer);
|
||||
}
|
||||
|
||||
load(json) {
|
||||
this.map = JSON.parse(json, this._reviver);
|
||||
}
|
||||
|
||||
_replacer(key, value) {
|
||||
if (!(value instanceof Map)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
dataType: 'Map',
|
||||
value: Array.from(value.entries())
|
||||
};
|
||||
}
|
||||
|
||||
_reviver(key, value) {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (value.dataType === 'Map') {
|
||||
return new Map(value.value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export { MouseButtonMapper };
|
28
core/rfb.js
28
core/rfb.js
|
@ -26,6 +26,7 @@ import DES from "./des.js";
|
|||
import KeyTable from "./input/keysym.js";
|
||||
import XtScancode from "./input/xtscancodes.js";
|
||||
import { encodings } from "./encodings.js";
|
||||
import { MouseButtonMapper, xvncButtonToMask } from "./mousebuttonmapper.js";
|
||||
|
||||
import RawDecoder from "./decoders/raw.js";
|
||||
import CopyRectDecoder from "./decoders/copyrect.js";
|
||||
|
@ -192,6 +193,7 @@ export default class RFB extends EventTargetMixin {
|
|||
this._viewportHasMoved = false;
|
||||
this._accumulatedWheelDeltaX = 0;
|
||||
this._accumulatedWheelDeltaY = 0;
|
||||
this.mouseButtonMapper = null;
|
||||
|
||||
// Gesture state
|
||||
this._gestureLastTapTime = null;
|
||||
|
@ -1558,6 +1560,7 @@ export default class RFB extends EventTargetMixin {
|
|||
this._canvas);
|
||||
}
|
||||
|
||||
const mappedButton = this.mouseButtonMapper.get(ev.button);
|
||||
switch (ev.type) {
|
||||
case 'mousedown':
|
||||
setCapture(this._canvas);
|
||||
|
@ -1575,11 +1578,11 @@ export default class RFB extends EventTargetMixin {
|
|||
this.checkLocalClipboard();
|
||||
|
||||
this._handleMouseButton(pos.x, pos.y,
|
||||
true, 1 << ev.button);
|
||||
true, xvncButtonToMask(mappedButton));
|
||||
break;
|
||||
case 'mouseup':
|
||||
this._handleMouseButton(pos.x, pos.y,
|
||||
false, 1 << ev.button);
|
||||
false, xvncButtonToMask(mappedButton));
|
||||
break;
|
||||
case 'mousemove':
|
||||
this._handleMouseMove(pos.x, pos.y);
|
||||
|
@ -3659,21 +3662,22 @@ RFB.messages = {
|
|||
|
||||
buff[offset] = 5; // msg-type
|
||||
|
||||
buff[offset + 1] = mask;
|
||||
buff[offset + 1] = mask >> 8;
|
||||
buff[offset + 2] = mask;
|
||||
|
||||
buff[offset + 2] = x >> 8;
|
||||
buff[offset + 3] = x;
|
||||
buff[offset + 3] = x >> 8;
|
||||
buff[offset + 4] = x;
|
||||
|
||||
buff[offset + 4] = y >> 8;
|
||||
buff[offset + 5] = y;
|
||||
buff[offset + 5] = y >> 8;
|
||||
buff[offset + 6] = y;
|
||||
|
||||
buff[offset + 6] = dX >> 8;
|
||||
buff[offset + 7] = dX;
|
||||
buff[offset + 7] = dX >> 8;
|
||||
buff[offset + 8] = dX;
|
||||
|
||||
buff[offset + 8] = dY >> 8;
|
||||
buff[offset + 9] = dY;
|
||||
buff[offset + 9] = dY >> 8;
|
||||
buff[offset + 10] = dY;
|
||||
|
||||
sock._sQlen += 10;
|
||||
sock._sQlen += 11;
|
||||
sock.flush();
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue