Use "input lock" rather than pointer lock
This new API can now be used to support [keyboard lock](https://web.dev/keyboard-lock/), although support for that is limited to Chrome only at the moment.
This commit is contained in:
parent
62a0643ed3
commit
30fda3c948
|
|
@ -1041,7 +1041,7 @@ const UI = {
|
||||||
UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
|
UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
|
||||||
UI.rfb.addEventListener("bell", UI.bell);
|
UI.rfb.addEventListener("bell", UI.bell);
|
||||||
UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
|
UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
|
||||||
UI.rfb.addEventListener("pointerlock", UI.pointerLockChanged);
|
UI.rfb.addEventListener("inputlock", UI.inputLockChanged);
|
||||||
UI.rfb.clipViewport = UI.getSetting('view_clip');
|
UI.rfb.clipViewport = UI.getSetting('view_clip');
|
||||||
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
||||||
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||||
|
|
@ -1324,7 +1324,7 @@ const UI = {
|
||||||
},
|
},
|
||||||
|
|
||||||
requestPointerLock() {
|
requestPointerLock() {
|
||||||
UI.rfb.requestPointerLock();
|
UI.rfb.requestInputLock({ pointer: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ------^-------
|
/* ------^-------
|
||||||
|
|
@ -1695,8 +1695,8 @@ const UI = {
|
||||||
document.title = e.detail.name + " - " + PAGE_TITLE;
|
document.title = e.detail.name + " - " + PAGE_TITLE;
|
||||||
},
|
},
|
||||||
|
|
||||||
pointerLockChanged(e) {
|
inputLockChanged(e) {
|
||||||
if (e.detail.pointerlock) {
|
if (e.detail.pointer) {
|
||||||
document
|
document
|
||||||
.getElementById("noVNC_pointer_lock_button")
|
.getElementById("noVNC_pointer_lock_button")
|
||||||
.classList.add("noVNC_selected");
|
.classList.add("noVNC_selected");
|
||||||
|
|
|
||||||
49
core/rfb.js
49
core/rfb.js
|
|
@ -170,6 +170,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
windowResize: this._windowResize.bind(this),
|
windowResize: this._windowResize.bind(this),
|
||||||
handleMouse: this._handleMouse.bind(this),
|
handleMouse: this._handleMouse.bind(this),
|
||||||
handlePointerLockChange: this._handlePointerLockChange.bind(this),
|
handlePointerLockChange: this._handlePointerLockChange.bind(this),
|
||||||
|
handlePointerLockError: this._handlePointerLockError.bind(this),
|
||||||
handleWheel: this._handleWheel.bind(this),
|
handleWheel: this._handleWheel.bind(this),
|
||||||
handleGesture: this._handleGesture.bind(this),
|
handleGesture: this._handleGesture.bind(this),
|
||||||
};
|
};
|
||||||
|
|
@ -479,12 +480,22 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._canvas.blur();
|
this._canvas.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
requestPointerLock() {
|
requestInputLock(locks) {
|
||||||
if (this._canvas.requestPointerLock) {
|
if (locks.pointer) {
|
||||||
this._canvas.requestPointerLock();
|
if (this._canvas.requestPointerLock) {
|
||||||
} else if (this._canvas.mozRequestPointerLock) {
|
this._canvas.requestPointerLock();
|
||||||
this._canvas.mozRequestPointerLock();
|
return;
|
||||||
|
}
|
||||||
|
if (this._canvas.mozRequestPointerLock) {
|
||||||
|
this._canvas.mozRequestPointerLock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// If we were not able to request any lock, still let the user know
|
||||||
|
// about the result.
|
||||||
|
this.dispatchEvent(new CustomEvent(
|
||||||
|
"inputlock",
|
||||||
|
{ detail: { pointer: this._pointerLock }, }));
|
||||||
}
|
}
|
||||||
|
|
||||||
clipboardPasteFrom(text) {
|
clipboardPasteFrom(text) {
|
||||||
|
|
@ -549,8 +560,14 @@ export default class RFB extends EventTargetMixin {
|
||||||
// preventDefault() on mousedown doesn't stop this event for some
|
// preventDefault() on mousedown doesn't stop this event for some
|
||||||
// reason so we have to explicitly block it
|
// reason so we have to explicitly block it
|
||||||
this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse);
|
this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse);
|
||||||
// This needs to be installed in document instead of the canvas.
|
// Pointer Lock listeners need to be installed in document instead of the canvas.
|
||||||
document.addEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange);
|
if (document.onpointerlockchange !== undefined) {
|
||||||
|
document.addEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange, false);
|
||||||
|
document.addEventListener('pointerlockerror', this._eventHandlers.handlePointerLockError, false);
|
||||||
|
} else if (document.onmozpointerlockchange !== undefined) {
|
||||||
|
document.addEventListener('mozpointerlockchange', this._eventHandlers.handlePointerLockChange, false);
|
||||||
|
document.addEventListener('mozpointerlockerror', this._eventHandlers.handlePointerLockError, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Wheel events
|
// Wheel events
|
||||||
this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);
|
this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);
|
||||||
|
|
@ -575,7 +592,13 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);
|
this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);
|
||||||
this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);
|
this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);
|
||||||
this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);
|
this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);
|
||||||
document.removeEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange);
|
if (document.onpointerlockchange !== undefined) {
|
||||||
|
document.removeEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange);
|
||||||
|
document.removeEventListener('pointerlockerror', this._eventHandlers.handlePointerLockError);
|
||||||
|
} else if (document.onmozpointerlockchange !== undefined) {
|
||||||
|
document.removeEventListener('mozpointerlockchange', this._eventHandlers.handlePointerLockChange);
|
||||||
|
document.removeEventListener('mozpointerlockerror', this._eventHandlers.handlePointerLockError);
|
||||||
|
}
|
||||||
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||||
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||||
window.removeEventListener('resize', this._eventHandlers.windowResize);
|
window.removeEventListener('resize', this._eventHandlers.windowResize);
|
||||||
|
|
@ -1031,8 +1054,14 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._cursor.setEmulateCursor(false);
|
this._cursor.setEmulateCursor(false);
|
||||||
}
|
}
|
||||||
this.dispatchEvent(new CustomEvent(
|
this.dispatchEvent(new CustomEvent(
|
||||||
"pointerlock",
|
"inputlock",
|
||||||
{ detail: { pointerlock: this._pointerLock }, }));
|
{ detail: { pointer: this._pointerLock }, }));
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlePointerLockError() {
|
||||||
|
this.dispatchEvent(new CustomEvent(
|
||||||
|
"inputlock",
|
||||||
|
{ detail: { pointer: this._pointerLock }, }));
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendMouse(x, y, mask) {
|
_sendMouse(x, y, mask) {
|
||||||
|
|
|
||||||
51
docs/API.md
51
docs/API.md
|
|
@ -113,9 +113,9 @@ protocol stream.
|
||||||
- The `capabilities` event is fired when `RFB.capabilities` is
|
- The `capabilities` event is fired when `RFB.capabilities` is
|
||||||
updated.
|
updated.
|
||||||
|
|
||||||
[`pointerlock`](#pointerlock)
|
[`inputlock`](#inputlock)
|
||||||
- The `pointerlock` event is fired when the Pointer Lock is acquired (or
|
- The `inputlock` event is fired when an input lock is acquired (or released)
|
||||||
released) by the canvas.
|
by the canvas.
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
|
|
@ -150,8 +150,8 @@ protocol stream.
|
||||||
[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
|
[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
|
||||||
- Send clipboard contents to server.
|
- Send clipboard contents to server.
|
||||||
|
|
||||||
[`RFB.requestPointerLock()`](#rfbrequestPointerLock)
|
[`RFB.requestInputLock()`](#rfbrequestInputLock)
|
||||||
- Requests that the RFB canvas acquire a Pointer Lock.
|
- Requests that the RFB canvas acquire an input lock.
|
||||||
|
|
||||||
### Details
|
### Details
|
||||||
|
|
||||||
|
|
@ -269,14 +269,14 @@ The `capabilities` event is fired whenever an entry is added or removed
|
||||||
from `RFB.capabilities`. The `detail` property is an `Object` with the
|
from `RFB.capabilities`. The `detail` property is an `Object` with the
|
||||||
property `capabilities` containing the new value of `RFB.capabilities`.
|
property `capabilities` containing the new value of `RFB.capabilities`.
|
||||||
|
|
||||||
#### pointerlock
|
#### inputlock
|
||||||
|
|
||||||
The `pointerlock` event is fired when the state of the canvas' Pointer Lock has
|
The `inputlock` event is fired after a request to acquire an input lock or
|
||||||
changed, either because it has successfully acquired the lock and will have
|
whenever the state of the canvas' input lock has changed, the latter typically
|
||||||
full control of the mouse pointer, or because the lock was released by the user
|
occurs because the lock was released by the user pressing the ESC key or
|
||||||
pressing the ESC key or performing a browser-specific gesture. The `detail`
|
performing a browser-specific gesture. The `detail` property is an `Object`
|
||||||
property is an `Object` with the property `pointerlock` containing whether the
|
with the property `pointer` containing whether the Pointer Lock is currently
|
||||||
lock is currently held or not.
|
held or not.
|
||||||
|
|
||||||
#### RFB.disconnect()
|
#### RFB.disconnect()
|
||||||
|
|
||||||
|
|
@ -400,18 +400,23 @@ to the remote server.
|
||||||
**`text`**
|
**`text`**
|
||||||
- A `DOMString` specifying the clipboard data to send.
|
- A `DOMString` specifying the clipboard data to send.
|
||||||
|
|
||||||
#### RFB.requestPointerLock()
|
#### RFB.requestInputLock()
|
||||||
|
|
||||||
The `RFB.requestPointerLock()` method is used to request that the RFB canvas
|
The `RFB.requestInputLock()` method is used to request that the RFB canvas hold
|
||||||
hold a [Pointer
|
an input lock. An `inputlock` event will be fired with the result of the
|
||||||
Lock](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API), which
|
acquisition of the requested locks.
|
||||||
hides the mouse cursor and provides relative motion events. This must be called
|
|
||||||
directly from an event handler where a user has directly interacted with the
|
|
||||||
browser for the browser to allow this.
|
|
||||||
|
|
||||||
If the acquisition of the pointer lock is successful, a `pointerlock` event
|
|
||||||
will be fired.
|
|
||||||
|
|
||||||
##### Syntax
|
##### Syntax
|
||||||
|
|
||||||
RFB.requestPointerLock( );
|
RFB.requestInputLock( { pointer: true } );
|
||||||
|
|
||||||
|
###### Parameters
|
||||||
|
|
||||||
|
**`pointer`**
|
||||||
|
- Requests to acquire a [Pointer
|
||||||
|
Lock](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API),
|
||||||
|
which hides the local mouse cursor and provides relative motion events.
|
||||||
|
This must be called directly from an event handler where a user has
|
||||||
|
directly interacted with an element through an [engagement
|
||||||
|
gesture](https://w3c.github.io/pointerlock/#dfn-engagement-gesture) (e.g. a
|
||||||
|
click or touch event) for the browser to allow this.
|
||||||
|
|
|
||||||
|
|
@ -2683,14 +2683,14 @@ describe('Remote Frame Buffer Protocol Client', function () {
|
||||||
client._resize(100, 100);
|
client._resize(100, 100);
|
||||||
|
|
||||||
const spy = sinon.spy();
|
const spy = sinon.spy();
|
||||||
client.addEventListener("pointerlock", spy);
|
client.addEventListener("inputlock", spy);
|
||||||
let stub = sinon.stub(document, 'pointerLockElement');
|
let stub = sinon.stub(document, 'pointerLockElement');
|
||||||
stub.get(function () { return client._canvas; });
|
stub.get(function () { return client._canvas; });
|
||||||
client._handlePointerLockChange();
|
client._handlePointerLockChange();
|
||||||
stub.restore();
|
stub.restore();
|
||||||
client._sock._websocket._receiveData(new Uint8Array([0x02, 0x02]));
|
client._sock._websocket._receiveData(new Uint8Array([0x02, 0x02]));
|
||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
expect(spy.args[0][0].detail.pointerlock).to.be.true;
|
expect(spy.args[0][0].detail.pointer).to.be.true;
|
||||||
|
|
||||||
const cursorSpy = sinon.spy(client, '_handleVMwareCursorPosition');
|
const cursorSpy = sinon.spy(client, '_handleVMwareCursorPosition');
|
||||||
client._sock._websocket._receiveData(new Uint8Array(incoming));
|
client._sock._websocket._receiveData(new Uint8Array(incoming));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue