JavaScript: на Firefox перемещение мыши происходит при изменении размера окна

Когда я нахожусь на Firefox, холст звонит requestPointerLock и я нажимаю F11 для полноэкранного режима - я вижу это событие mousemove срабатывает. Это заставляет некоторые вещи двигаться, которые должны быть статичными, потому что мышь не движется.

Я пытался создать демо, но я получаю ошибку Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set.

Вот пример кода, который вы можете прочитать хотя бы.

HTML часть:

<canvas id="canvas" width="800" height="600"></canvas>

JavaScript часть:

canvas = document.getElementById('canvas');

document.addEventListener("click", function(e) {
  canvas.requestPointerLock = canvas.requestPointerLock    ||
                              canvas.mozRequestPointerLock ||
                              canvas.webkitRequestPointerLock;

  if (canvas.requestPointerLock)
      canvas.requestPointerLock();
}, false);


document.addEventListener("pointerlockchange",    plChange, false);
document.addEventListener("mozpointerlockchange", plChange, false);


function plChange(e) {
  var controlEnabled = (document.mozPointerLockElement ===    canvas ||
                        document.webkitPointerLockElement === canvas ||
                        document.pointerLockElement ===       canvas);

  if (!controlEnabled) {
    window.removeEventListener("mousemove", mouseMove);
  } else {
    window.addEventListener("mousemove", mouseMove, false);
  }
}


function mouseMove(e) {
    // This is being executed on window resize
    console.log(e.movementY);
}

В результате, когда окно работает в полноэкранном режиме (а Firefox делает это неопрятно), я получаю в консоли e.movementY, а значение не всегда равно 0.

Вопрос в том, как я могу предотвратить эту "особенность" Firefox, чтобы не вызывать событие перемещения мыши?

1 ответ

Нашел решение для смягчения проблемы. К сожалению, нет жизнеспособного решения, которое действительно могло бы решить проблему, потому что всякий раз, когда Firefox изменяет размер своего окна, мышь каким-то образом перемещается, так что положение указателя относительно верхнего левого угла остается неизменным. Однако, поскольку он перемещается по экрану, mousemove событие сработало.

Способ смягчить это добавление resize обработчик объекта окна, чтобы проверить, происходит ли изменение размера окна - и если да, установите флаг и используйте его, чтобы обработчик перемещения мыши выручил. К сожалению, вы не можете просто сбросить этот флаг, когда мышь перемещается, потому что вы все равно иногда получаете поддельные mousemove События. Вместо этого вы должны установить тайм-аут, который в конечном итоге сбрасывает флаг, когда вы можете быть относительно уверены, что размер окна браузера был полностью изменен.

Мне удалось сделать это с моим тестовым примером, который выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="en">
<head>
<title>canvas Test Case</title>
<style type="text/css">
body {
  background-color: silver;
  }

canvas {
  background-color: white;
  }
</style>
<script type="application/javascript">
/* <![CDATA[ */
'use strict';

var canvas;
var this_timeout = null;

document.addEventListener('DOMContentLoaded', function (p_event) {
  canvas = document.getElementById('canvas');

  document.addEventListener("click", function (p_event) {
    canvas.requestPointerLock = canvas.requestPointerLock    ||
                                canvas.mozRequestPointerLock ||
                                canvas.webkitRequestPointerLock;

    if (canvas.requestPointerLock)
        canvas.requestPointerLock();
    }, false);

  document.addEventListener("pointerlockchange",    plChange, false);
  document.addEventListener("mozpointerlockchange", plChange, false);

  window.addEventListener('resize', function (p_event) {
// Use this handler to set a flag that a resize event is taking place.
// Using the timeout ID actually hits two birds with one stone: It serves as a
// flag that a resize is actually taking place, plus it allows us to reset the
// timeout if it hasn't expired when another one fires.
    if(this_timeout)
      clearTimeout(this_timeout);
    this_timeout = setTimeout(function () { this_timeout = null; }, 250);
    console.log('Resizing...'); }, true);
  }, false);

function stoppedResize() {
// If the timeout expires, reset the timeout id to show that we are done resizing.
  this_timeout = null;
  }

function plChange(p_event) {
  var controlEnabled = (document.mozPointerLockElement ===    canvas ||
                        document.webkitPointerLockElement === canvas ||
                        document.pointerLockElement ===       canvas);

  if (!controlEnabled) {
    console.log('Disabling mouse tracker...');
    window.removeEventListener("mousemove", mouseMove);
  } else {
    console.log('Enabling mouse tracker...');
    window.addEventListener("mousemove", mouseMove, false);
  }
}

function mouseMove(p_event) {
// Check whether there's a timeout running. If yes, just bail out...
  if(this_timeout)
    {
    console.log('Skipping...');
    return;
    }

  console.log('Mouse movement detected!');
}
/* ]]> */
</script>
</head>
<body>
<header><h1>canvas Test Case</h1></header>
<main>
<canvas id="canvas" width="800" height="600" />
</main>
</body>
</html>

Делая это, вы можете легко смягчить эту проблему. К сожалению, это не чистое решение, которое я бы предпочел, но, учитывая обстоятельства, это лучший способ справиться с проблемой, с которой я мог бы столкнуться.

Что касается вашего другого вопроса, я думаю, вы хотели опубликовать пример здесь на SO? Если да, я думаю, что вы столкнулись с некоторыми ограничениями, наложенными на код. Поскольку, кажется, все происходит в iframeЯ думаю, что определенные действия были запрещены. Присоединение определенных обработчиков событий очевидно затронуто.

Другие вопросы по тегам