【发布时间】:2019-02-10 22:57:54
【问题描述】:
这也适用于其他浏览器,但主要目标是 Firefox 和 Chrome。
我已经注册了所有指针事件监听器,并且必须注册鼠标按下和鼠标上移监听器才能获得按钮状态更改(指针事件中的按钮状态不准确或“和弦”)
但即使我在所有指针上执行 event.preventDefault():over,enter,down,up,out,and,leave 事件(pointerType mouse for down 除外,因为它会禁用 mousedown 和 mouse up 监听器)我还有其他问题:
多点触控(多于一根手指)将被接管并执行页面缩放操作,使我的应用程序中的多点触控无效。
如果页面上有滚动条,则触摸平移/滚动操作将接管单次触摸。
preventDefault() 未在操作系统(即:Windows 10)中正确实现,并且在我的元素上向下的指针也会生成合成鼠标向下并将鼠标合成移动到触摸的位置。我可以用混乱的代码忽略合成的向下和向上事件),但它会将鼠标放在意想不到的位置,并防止在需要时同时使用鼠标和触摸作为单独的输入。 (解决这个问题可能需要在 DOM 元素本身上设置一个标志,而不是基于每个事件,因为内部事件队列会在操作系统和浏览器调度的事件之间放置延迟 - 我已经在我的本机应用程序中解决了这个问题)
我正在使用 Web 开发者控制台进行测试,以便记录状态 - 我不知道这是否会影响事情。
我在 Chrome 上也有同样的触摸平移/缩放缺乏控制。 Chrome 和 Firefox 上的鼠标上/下行为明显不同,因此需要单独的代码路径。 PK
对于代码迷 - 请注意,这是一个接口设备“前端”,用于 “webasm”(游戏或生活游戏)引擎:)
目标是为进入画布元素的任何指针(未被另一个元素的处理程序捕获)获取“干净的原始”事件流 使用捕获的指针镜像所有受支持设备上所有按钮的状态,直到捕获丢失。还能够将鼠标和触摸(以及任何其他支持的设备)用作单独的设备,忽略所有合成事件并希望关闭我正在收听的一个设备被我正在收听的另一台设备模拟的任何设备(所以他们不不要打架)。还可以完全控制事件的处理方式,直到丢失指针的事件流捕获。我想捕获所有在触摸设备(平板电脑、面板、屏幕等)的元素上发生“主要”触摸之后和同时下降的所有触摸,如果不使用我们的 UI,可以选择让它们“通过” .
以下是附加到“画布”元素的事件处理程序。除了将数据转发到 webasm 应用程序之外,他们什么都不做。当然,它工作后会被清理干净。这是火狐代码。 :)
canvas.addEventListener('pointerover', this.onPeOED, false);
canvas.addEventListener('pointerenter', this.onPeOED, false);
canvas.addEventListener('pointerdown', this.onPeOED, false);
canvas.addEventListener('pointermove', this.onPeMove, false);
canvas.addEventListener('pointerup', this.onPeUOCL, false);
canvas.addEventListener('pointerout', this.onPeUOCL, false);
canvas.addEventListener('pointercancel', this.onPeUOCL, false);
canvas.addEventListener('pointerleave', this.onPeUOCL, false);
canvas.addEventListener('mousedown', this.onMouseDown, false);
canvas.addEventListener('mouseup', this.onMouseUp, false);
onPeOED: (function(e) {
var handled = 0;
var code = e.type.charCodeAt(7);
var target = e.currentTarget;
var posX = e.clientX;
var posY = e.clientY;
var flags = (1 << (9 + 16)); // fPointerInside
if(posX < 0 || posY < 0 || posX >= target.width || posY >= target.height) {
flags = 0;
}
// o == over, e == enter, d == down,
if(code == 100) { // 100 == 'd'
flags |= (1 << (10 + 16)); // in contact << 16
}
target._mousePointerId_ = -1;
switch(e.pointerType) {
case 'mouse':
target._mousePointerId_ = e.pointerId;
if(code == 100) { // 100 == 'd' handled by onMouseDown
target.setPointerCapture(e.pointerId);
return;
}
flags |= 0x0100; // UID_MOUSE << 8
break;
case 'pen':
flags |= 0x0200; // UID_STYLUS << 8
break;
case 'touch':
flags |= 0x0300; // UID_FINGER << 8
break;
default:
Module.print("unknown UID");
break;
}
if(code == 100) { // 100 == 'd'
target.setPointerCapture(e.pointerId);
}
// Module.print("ON uid " + e.pointerType + " " + e.type + " buttons " + e.which + " inside " + ((flags & (1 << (9 + 16))) != 0));
if(e.buttons != 0) {
flags |= (e.buttons << 16) | (1 << (10 + 16)); // fPointerInContact
}
handled = ccall('onPointerFlagsOn', 'number', EngineConnector.number_11_Sig,
// target type|flags time id screenX screenY pageX pageY targetX targetY pressure
[ target._CPPHandle_,
(code | flags),
e.timeStamp,
e.pointerId,
e.screenX,
e.screenY,
e.pageX,
e.pageY,
posX,
posY,
e.pressure
]);
e.preventDefault();
}),
onMouseDown: (function(e) {
var target = e.currentTarget;
var posX = e.clientX;
var posY = e.clientY;
// Module.print("mouse ME down " + target._mousePointerId_);
if(target._mousePointerId_ < 0 || posX < 0 || posY < 0 || posX >= target.width || posY >= target.height) {
Module.print("mouse ignored");
e.preventDefault();
return; // ignore downs while outide element
}
var wentDown = (e.buttons & (~(target._mouseButtons_)));
target._mouseButtons_ = e.buttons;
// Module.print("mouse down " + e.buttons + " went down " + wentDown);
handled = ccall('onPointerFlagsOn', 'number', EngineConnector.number_11_Sig,
// target type time id screenX screenY pageX pageY targetX targetY pressure
[ target._CPPHandle_,
// 'd' UID_MOUSE fPointerInside fPointerInContact
(100 | 0x0100 | (1 << (9 + 16)) | (1 << (10 + 16)) | (wentDown << 16)),
e.timeStamp,
e.pointerId,
e.screenX,
e.screenY,
e.pageX,
e.pageY,
posX,
posY,
e.pressure
]);
// e.preventDefault();
}),
fireButtonUp: (function(e, buttons) {
// Module.print("ME fire up true " + buttons );
var ptrId = e.currentTarget._mousePointerId_;
if(ptrId < 0) {
return;
}
ccall('onPointerFlagsOff', 'number', EngineConnector.number_11_Sig,
// target type time id screenX screenY pageX pageY targetX targetY pressure
[e.currentTarget._CPPHandle_,
(117 | 0x0100 | (buttons << 16)), // 117 == 'u' == 'up', 1 == UID_MOUSE
e.timeStamp,
ptrId,
e.screenX,
e.screenY,
e.pageX,
e.pageY,
e.clientX,
e.clientY,
0,
]);
}),
// up/leave
onMouseUp: (function(e) {
var target = e.currentTarget;
var posX = e.clientX;
var posY = e.clientY;
if(posX < 0 || posY < 0 || posX >= target.width || posY >= target.height) {
// we have to kill ALL the buttons
EngineConnector.fireButtonUp(e,target._mouseButtons_ | (1 << 10));
target._mouseButtons_ = 0;
} else {
var released = (target._mouseButtons_ & (~e.buttons)); // will leave the one we released
target._mouseButtons_ = e.buttons;
if(e.buttons == 0) {
released |= (1 << 10); // fPointerInContact
}
EngineConnector.fireButtonUp(e,(released | (1 << 9)));
}
e.preventDefault();
}),
onPeMove: (function(e) {
var target = e.currentTarget;
var posX = e.clientX;
var posY = e.clientY;
var flags = (1 << 9);
if(posX < 0 || posY < 0 || posX >= target.width || posY >= target.height) {
flags = 0;
}
var pType = e.pointerType.charCodeAt(0);
if(pType == 109) { // 'm' == 109
// MOUSE
if(target._mousePointerId_ < 0) {
e.preventDefault();
return;
}
} else {
Module.print("move !!!");
}
flags |= pType; // 'm', 'p', 't'
handled = ccall('onPointerMove', 'number', EngineConnector.number_11_Sig,
// target flags time id screenX screenY pageX pageY targetX targetY pressure
[ target._CPPHandle_,
flags,
e.timeStamp,
e.pointerId,
e.screenX,
e.screenY,
e.pageX,
e.pageY,
posX,
posY,
e.pressure
]);
}),
onPeUOCL: (function(e) {
var code = e.type.charCodeAt(7);
var target = e.currentTarget;
target._poinsePointerId_ = -1;
switch(e.pointerType) {
case 'mouse':
target._poinsePointerId_ = e.pointerId;
if(code == 117) { // 117 == 'u' mouseup handled by mouse event handler
return;
}
code |= 0x0100; // UID_MOUSE << 8
// let leave and cancel get reported
break;
case 'pen':
code |= 0x0200; // UID_STYLUS << 8
if(code == 117) {
code |= ((1 << 16) << e.which);
}
break;
case 'touch':
code |= 0x0300; // UID_FINGER << 8
if(code == 117) {
code |= ((1 << 16) << e.which);
}
break;
default:
Module.print("unknown UID");
break;
}
var posX = e.clientX;
var posY = e.clientY;
if(posX >= 0 && posY >= 0 || posX < target.width || posY < target.height) {
code |= (1 << (9 + 16));
}
// Module.print("off uid " + e.pointerType + " " + e.type + " buttons " + e.which + " inside " + ((code & (1 << (9 + 16))) != 0));
var handled = 0;
handled = ccall('onPointerFlagsOff', 'number', EngineConnector.number_11_Sig,
// target type time id screenX screenY pageX pageY targetX targetY pressure
[e.currentTarget._CPPHandle_,
code,
e.timeStamp,
e.pointerId,
e.screenX,
e.screenY,
e.pageX,
e.pageY,
posX,
posY,
e.pressure,
]);
e.preventDefault();
}),
大约 30 年前,当我致力于让 Microsoft 创建 DirectX 时,我的一句话 - 又是似曾相识 :)
“要使任何系统真正灵活,就必须能够利用它提供的设施从头开始实施该系统。”
【问题讨论】:
-
你能提供一些你遇到问题的代码吗?处理鼠标、触摸和其他用户生成的事件有时可能很复杂,尤其是在触摸设备上。有没有更简单的方法? PreventDefault() 并非旨在传播到浏览器沙箱之外,即操作系统不可见。
-
此外,标准控制台方法不应影响代码的行为。这只有在一些奇怪的情况下才有可能,当您使用非标准的替换控制台对象和执行此操作的方法时。
标签: javascript firefox