指针锁定 2.0

W3C 工作草案

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2024/WD-pointerlock-2-20240617/
最新发布版本:
https://www.w3.org/TR/pointerlock-2/
最新编辑草案:
https://w3c.github.io/pointerlock/
历史记录:
https://www.w3.org/standards/history/pointerlock-2/
提交历史
测试套件:
https://github.com/web-platform-tests/wpt/tree/master/pointerlock
编辑:
Mustaq Ahmed (谷歌)
Vincent Scheib (谷歌)
前编辑:
Navid Zolghadr (谷歌)
反馈:
GitHub w3c/pointerlock (拉取请求, 新问题, 打开的问题)
浏览器支持:
caniuse.com

摘要

本规范定义了一个 API,提供了脚本化访问原始鼠标移动数据的功能,同时将鼠标事件的目标锁定在单个元素上,并将光标从视图中移除。对于某些类别的应用程序,尤其是第一人称视角的 3D 应用程序和 3D 建模软件,这是一个必不可少的输入模式。

本文档的状态

本节描述了本文档在发布时的状态。当前的 W3C 出版物列表和本技术报告的最新修订版可在 W3C 技术报告索引 中找到:https://www.w3.org/TR/。

本文档的更改历史可在 https://github.com/w3c/pointerlock/commits/gh-pages/index.html 查看。

W3C 2016年10月27日推荐 以来的更改摘要:

本文档由 Web 应用程序工作组 作为工作草案发布, 使用了推荐路线

作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一个草案文件,可能会随时更新、替换或被其他文件淘汰。在此文件不应被引用为其他用途,而应被视为进行中的工作。

本文档由一个根据 W3C 专利政策 运营的工作组生产。W3C 维护一个公开的专利披露列表,列出了与该组交付物有关的任何专利披露信息;该页面还包括披露专利的说明。任何个人如果知道某项专利并认为其包含必要权利要求,必须根据 W3C 专利政策第6节披露相关信息。

本文档受 2023年11月3日 W3C 进程文档 管辖。

1. 引言

本节为非规范性内容。

Pointer Lock API 允许应用程序直接解释鼠标移动作为输入方式,而不仅仅是读取鼠标光标的位置。一个流行的例子是 第一人称视角的三维图形应用程序(如游戏)中的运动控制:鼠标移动用于控制玩家摄像头的旋转/方向;不显示鼠标光标, 并且移动不受传统边界(如用户代理窗口或整个屏幕)的限制,这意味着鼠标移动可以在任何方向上无限跟踪。

Pointer Lock 与 Mouse Capture 相关 [MDN-SETCAPTURE](Mouse Capture 未指定:bug 14600)。 Capture 提供了在拖动鼠标时持续向目标元素传递事件的能力,但在鼠标按钮释放时停止。 Pointer Lock 的区别在于它是持久的,不受屏幕边界限制,无论鼠标按钮状态如何都发送事件,隐藏光标, 并且直到通过 API 调用或用户执行特定的 默认解锁手势 才会释放。

Pointer Lock 处理捕获单个资源并将其与单个元素关联。这类似于 Fullscreen API [FULLSCREEN], 它将单个元素提升为全屏。Pointer Lock API 选择尽可能紧密地仿照 Fullscreen API 的资源捕获、状态更改和释放 API。

Pointer Lock 交互模式以前称为鼠标锁定。名称更改的原因是,除了鼠标之外,许多不同的控制器类型都可以操纵屏幕上的指针光标, 并且它们都会受到影响。

2. 指针锁定和接口

2.1 指针锁定状态 定义

指针锁定状态 是一个状态, 在该状态下,单个 DOM 元素(我们称之为 指针锁定目标)接收所有鼠标事件,并且光标被隐藏。

一旦进入 指针锁定状态用户代理 将有一个 指针锁定目标、 一个 指针锁定选项, 它是 PointerLockOptions, 以及 光标位置,这是代表进入指针锁定状态时系统鼠标光标位置的一对数字 (与 screenXscreenY 中报告的位置相同)。指针锁定目标 将接收所有相关的用户生成的MouseEvent事件, 即所有用户生成的mousemovemousedownmouseupclickdblclickauxclickwheel [ui-events]。 在 指针锁定状态 下,其他元素不会接收这些事件。 不会分派需要鼠标光标概念的事件:即 mouseentermouseleavemouseovermouseoutdragdrop

Issue 97 :第 2.1 节应提及锁定对 PointerEvents 的影响

这是在 此线程中提出的: #49

是否可以以规范的方式列出这些事件,而不仅仅是举一些例子?

我认为当前文本是可以的,因为这里缺乏精确性只是鼠标事件规范中更大问题的症状。该问题在某些方面正在得到改善, 例如在 w3c/uievents#200 中有一些进展, 如果它被实现,那么最终这段内容可以作为 UI 事件规范的一部分。

但是,在此期间,如果您能准确列出这些事件,将有助于实现互操作性。

例如,我不确定指针事件是否会受到此更改的影响。

当处于 指针锁定状态 时, 如果 指针锁定选项中的 unadjustedMovement成员为true, 则事件坐标不会受到底层平台行为(如鼠标加速)的影响。换句话说,用户代理使用底层平台提供的 API 来确保获取原始事件。 如果PointerLockOptionsunadjustedMovement成员为false, 则用户代理依赖底层平台的默认鼠标加速行为。

指针锁定状态 中, 系统鼠标光标被隐藏,并且窗口将保持焦点,不会因鼠标移动或按键操作而失去焦点。这是通过底层操作系统 API 直接或间接实现的。

由应用程序脚本创建的合成鼠标事件,无论锁定状态如何,行为都是一样的。

2.2 PointerLockOptions 字典

WebIDLdictionary PointerLockOptions {
          boolean unadjustedMovement = false;
        };
PointerLockOptions 字典

此选项字典用于自定义指针在锁定模式下的行为。

unadjustedMovement 成员

如果此值设置为true,则指针移动将不受底层平台的修改(如鼠标加速)的影响。

2.3 pointerlockchangepointerlockerror 事件

两种事件用于传达指针锁定状态的变化或更改状态时的错误。它们分别命名为 pointerlockchangepointerlockerror。 有关详细信息,请参阅 3. Element 接口的扩展 中的算法。

放大软件会增加屏幕上内容的大小。它使用鼠标移动放大的焦点。当启动指针锁定时,放大软件需要切换为使用键盘移动放大焦点。 当触发pointerlockchange事件时, 浏览器需要确保事件传达给辅助技术,如屏幕放大器。

2.4 退出指针锁定

退出指针锁定的过程如下:

  1. 系统鼠标光标必须重新显示,并定位在光标位置
  2. 用户交互任务源触发一个事件名为 pointerlockchange 在 给定的 元素节点文档 中。
  3. 通过将指针锁定目标指针锁定选项光标位置 设置为 null 来退出 指针锁定状态

3. Element 接口的扩展

Element 接口被扩展,以提供 请求指针锁定的能力。

WebIDLpartial interface Element {
      Promise<undefined> requestPointerLock(optional PointerLockOptions options = {});
    };
const lock_element = document.getElementById("lock_element");
    const lock_button = document.getElementById("lock");
    lock_button.addEventListener("click", async (event) => {
        try {
            await lock_element.requestPointerLock({ unadjustedMovement: true });
            console.log("successfully locked!");
        } catch (e) {
            console.log("lock failed with error: ", e);
        }
    });
requestPointerLock(PointerLockOptions options) 方法

一个名为 并行队列锁请求队列 用于排队所有请求。当 requestPointerLock() 被调用时,执行以下步骤:

  1. promise 设为 一个新的 promise
  2. 当一个 window 处于 焦点 时,如果 thisshadow-including root活动文档,并且属于某个 浏览上下文 (或具有不在焦点中的 祖先 浏览上下文):
    1. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
      1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
      2. 拒绝 promise,并抛出 "WrongDocumentError" DOMException
    2. 返回 promise
    Issue 93:可见状态检查

    该规范不应允许隐藏文档请求指针锁定。

    此外,当文档变为隐藏时,应该释放指针锁定。

  3. 如果“相关全局对象”没有 短暂激活,并且 Document尚未释放成功的指针锁定,使用 exitPointerLock()
    1. 排队一个元素任务,在 用户交互任务源中, 给定 this,执行以下步骤:
      1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
      2. 拒绝 promise,并抛出 "NotAllowedError" DOMException
    2. 返回 promise
    注意
  4. 如果 this节点文档活动沙盒标志集 含有 已沙盒化的指针锁定浏览上下文标志
    1. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
      1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
      2. 拒绝 promise,并抛出 "SecurityError" DOMException
    2. 返回 promise
  5. 如果 options["unadjustedMovement"] 为 true,且平台不支持 unadjustedMovement
    1. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
      1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
      2. 拒绝 promise,并抛出 "NotSupportedError" DOMException
    2. 返回 promise
    Issue 90:建议添加静态字段以指示是否支持 `unadjustedMovement`。

    在 PR #49 中引入了 PointerLockOptions。然而,PointerLockOptions 中的 unadjustedMovement 并不一定在所有平台上都支持。一个静态字段可能有助于在直接使用 PointerLockOptions 之前确定是否支持该功能,以避免不支持错误。

  6. 将以下步骤加入 锁请求队列
    1. 如果用户代理的 指针锁定目标 是某个元素, 其 shadow-including root 不等于 thisshadow-including root,那么:
      1. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
        1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
        2. 拒绝 promise,并抛出 "InvalidStateError" DOMException
    2. 如果用户代理的 指针锁定目标shadow-including root 等于 thisshadow-including root,并且 options 等同于当前的 指针锁定选项,那么:
      1. 指针锁定目标 设置为 this
      2. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
        1. 触发一个事件, 名为 pointerlockchange, 目标是 this节点文档
        2. 解决 promise
    3. 如果 指针锁定目标 为 null,或者 options 不等同于当前的 指针锁定选项,则处理锁请求并在完成时处理响应:
      1. 如果锁请求失败:
        1. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
          1. 触发一个事件, 名为 pointerlockerror, 目标是 this节点文档
          2. 拒绝 promise,并抛出 "NotSupportedError" DOMException
        Issue 91:当后续的 requestPointerLock 被拒绝时,已锁定的目标是否应退出锁定状态?

        在 PR #49requestPointerLock 算法中,目前缺少对以下场景的描述:
        当后续请求失败(无论出于何种原因)时,已锁定的目标是否应退出锁定状态?

      2. 如果锁请求成功:
        1. 进入 指针锁定状态,执行以下操作:
          1. 将用户代理的 指针锁定目标 设置为 this
          2. 将用户代理的 光标位置设置为当前系统鼠标位置。
          3. 指针锁定选项 设置为 options。
        2. 用户交互任务源中, 通过给定的 this,排队一个元素任务,执行以下步骤:
          1. 触发一个事件, 名为 pointerlockchange, 目标是 this节点文档
          2. 解决 promise
    Issue 96:锁请求队列处理不完整

    在 PR#49 的 requestPointerLock 算法中,目前缺少对如何处理锁请求队列中条目的描述。如果没有明确的文本,可能会导致错误的(?)假设,即所有条目将在最后同步出列。

  7. 返回 promise
注意

4. Document 接口的扩展

WebIDLpartial interface Document {
          attribute EventHandler onpointerlockchange;
          attribute EventHandler onpointerlockerror;
          undefined exitPointerLock();
        };
onpointerlockchange 属性

一个用于 事件处理器 idl 属性pointerlockchange 事件。

onpointerlockerror 属性

一个用于 事件处理器 idl 属性pointerlockerror 事件。

exitPointerLock() 方法
  1. 如果用户代理的指针锁定目标为 null,则返回。
  2. 如果 指针锁定目标shadow-including root 不等于 this节点文档,则返回。
  3. 使用用户代理的 指针锁定目标 退出指针锁定。

5. DocumentOrShadowRoot 混入的扩展

WebIDLpartial interface mixin DocumentOrShadowRoot {
      readonly attribute Element? pointerLockElement;
    };
pointerLockElement

当指针被锁定时,返回通过重新定向到元素的结果, 该元素是鼠标事件的目标,如果该结果和this元素在同一棵树中, 否则返回 null。

如果锁定正在进行或指针未锁定,则返回 null。

<body>
      <div id="host1">
        <shadow-root id="root1">
          <canvas id="canvas1"></canvas>
        </shadow-root>
      </div>
      <div id="host2">
        <shadow-root id="root2">
          <canvas id="canvas2"></canvas>
        </shadow-root>
      </div>
    </body>
注意

此示例使用虚构的 shadow-root 元素表示一个 shadow root 实例。

如果 #canvas1 是目标,document.pointerLockElement 返回 #host1,而 root1.pointerLockElement 返回 #canvas1。 将 #canvas1 重新定向到 #root2 的结果是 #host1, 但由于 #host1 不在与 #root2 相同的树中, 因此对于 root2.pointerLockElement 将返回 null。

6. MouseEvent 接口的扩展

WebIDLpartial interface MouseEvent {
      readonly attribute double movementX;
      readonly attribute double movementY;
    };
movementX 属性
movementY 属性

movementXmovementY 属性必须提供指针位置的变化,类似于在两个连续的 mousemove 事件 eNowePrevious 之间存储 screenXscreenY 的值并计算差异:movementX = eNow.screenX - ePrevious.screenX

对于除 mousemove 以外的所有鼠标事件,movementXmovementY 必须为零。所有运动数据必须通过 mousemove 事件传递,以便在任何两个鼠标事件 earlierEventcurrentEvent 之间, currentEvent.screenX - earlierEvent.screenX 的值与 movementX 的所有事件的总和相等,除非指针被 用户代理 屏幕边界限制而无法更新 screenX

movementXmovementY 必须在不管指针锁定状态下更新。

当未锁定时,系统光标可以退出并重新进入 用户代理 窗口。 如果发生这种情况且 用户代理 不是操作系统鼠标移动事件的目标, 那么 用户代理 将无法知道最新的指针位置, movementXmovementY 无法计算,必须设为零。

当启用指针锁定时,clientXclientYscreenXscreenY 必须保持恒定值,仿佛在进入指针锁定后指针没有移动。 但是 movementXmovementY 必须继续提供指针位置的变化,类似于指针未锁定时的情况。如果鼠标持续向一个方向移动, 则 movementXmovementY 的值将没有限制。鼠标光标的概念将被移除,光标不会移出窗口或受到屏幕边界的限制。

movementXmovementY 的未初始化值必须为 0

当鼠标输入中断(例如鼠标光标离开窗口并在另一个位置重新进入)时,不应出现大的移动值。 如果 用户代理 在接收操作系统鼠标输入数据时遇到间隙, 则生成的下一个 mousemove 事件的 movementXmovementY 必须设置为 0。这些间隙可能出现在例如当 用户代理 在窗口系统 API 接收到鼠标离开事件时。作为例外,鼠标捕获可能允许 用户代理 在光标移出窗口时继续接收鼠标事件。

7. MouseEventInit 字典的扩展

WebIDLpartial dictionary MouseEventInit {
      double movementX = 0;
      double movementY = 0;
    };
movementX 成员
movementY 成员
movementXmovementY 成员用于初始化 MouseEvent 的相应成员。

8. 要求

必须始终提供一个 默认解锁手势, 用于通过 退出指针锁定, 使用 用户代理指针锁定目标

注意

如果 指针锁定目标 断开连接, 或者 用户代理、 窗口或标签页失去焦点,则必须退出指针锁定。在 活动文档 元素之间移动焦点, 包括在 浏览上下文 之间, 不会导致 退出指针锁定。 例如,使用键盘在框架或 iframe 的内容之间移动焦点不会退出。

当进入或退出全屏 [FULLSCREEN] 时, 除非指针需要启用与 用户代理 图形用户界面的交互, 使用 默认解锁手势 退出了全屏和指针锁定,或者窗口或标签页失去焦点,则不得退出指针锁定。

9. 用例

本节为非规范性内容。

9.1 自由移动虚拟角色的相对视口旋转

玩家在第一/第三人称游戏中需要控制视口的方向。一个广泛使用的方法是使用鼠标移动来控制视角。 这种应用可以使用 Pointer Lock API 来允许对视口的偏航和俯仰进行完全自由的控制,即使用户没有按下鼠标按钮。 这些按钮可以用于其他操作,而鼠标移动可以持续提供导航。

9.2 自由旋转 3D 模型或平移 2D 层

三维建模应用的用户需要旋转模型。应用程序可以使用 Pointer Lock API 允许作者在拖动操作中自由旋转模型,而不会限制运动。 如果没有指针锁定,当鼠标光标受到屏幕边缘的限制时,拖动将停止提供运动数据。

同样,绝对运动的平移操作可以在不受光标/屏幕限制的单次拖动中完成,适用于大的二维图像。

9.3 角色的相对运动

在快速反应游戏中,玩家控制一个球拍将球反弹回对手,同时允许该球拍根据按下的不同鼠标按钮执行动作。 应用程序可以使用 Pointer Lock API 允许玩家快速反应,而无需担心鼠标光标离开游戏区域并点击其他系统应用程序,从而打断游戏流程。

9.4 在旋转控制器上的快进运动

在应用程序中修改数值时,有时用户会更喜欢通过拖动按钮手柄来增减数值。 例如,一个带有数字输入文本框和上下箭头的旋转器,可以点击或拖动来改变数值。 应用程序可以使用 Pointer Lock API 允许修改数值超过逻辑屏幕边界。这个方法同样适用于类似“快进”或“倒退”视频或音频流的控制。

9.5 与 HTML DOM UI 进行合成光标交互

一些游戏使用经典光标,但他们希望对其进行限制或控制。例如,限制在游戏范围内,或者由游戏进行移动。 锁定指针使这一点成为可能,如果应用程序创建自己的光标。但是 HTML 和 DOM 仍应可用于用户界面。 应该允许合成鼠标事件使应用定义的光标能够与 DOM 交互。例如,以下代码应允许自定义光标在指针锁定时发送点击事件:

document.addEventListener("click", function (e) {
      if (e._isSynthetic)
        return;
      // 发送一个合成点击
      var ee = document.createEvent("MouseEvents");
      ee._isSynthetic = true;
      x = myCursor.x;
      y = myCursor.y;
      ee.initMouseEvent("click", true, true, null, 1,
                        x + e.screenX - e.clientX,
                        y + e.screenY - e.clientY,
                        x,
                        y);
      var target = document.elementFromPoint(x, y);
      if (target)
        target.dispatchEvent(ee);
    });

注意,合成点击可能不被 用户代理 允许产生与非合成点击相同的默认操作。 但是,应用程序处理程序仍然可以采取行动,并使用现有的 HTML 和 DOM 机制提供用户界面。

9.6 通过将鼠标光标移动到视口边界来进行视口平移

即时战略游戏通常使用这种技术。当玩家将光标移动到视口边界时,如果他们通过鼠标移动“推动”边界, 视口将根据他们移动鼠标的距离在游戏区域内平移。当在视口范围内移动鼠标光标时,它的行为与通常系统中的行为类似。 应用程序可以选择使用指针锁定和之前的用例“与 HTML DOM UI 进行合成光标交互”来完全控制光标行为。

9.7 游戏大厅中基于计时器的指针锁定

使用指针锁定的游戏可能希望在玩家在游戏大厅准备时拥有传统的用户界面和系统光标。 游戏通常在所有玩家准备好后经过短时间的计时器后开始。理想情况下,游戏可以在不需要 用户激活的情况下切换到指针锁定模式。 玩家应能够无缝地从游戏大厅过渡到游戏导航。

9.8 游戏门户

游戏门户和其他网站(如 Facebook 和 Google Plus)托管供用户玩的游戏。 这些游戏可能托管在与门户网站不同的来源。嵌入式游戏应能够在非全屏模式下锁定指针。

10. 安全

本节为非规范性内容。

安全问题:

应对措施:

建议:

指针锁定是某些应用程序类型所需的用户交互模式,但如果被恶意使用,可能会带来可用性问题。 攻击者可能会移除用户在其系统上控制鼠标光标的能力。用户代理 将通过始终提供退出机制、告知用户如何退出并限制指针锁定的进入方式来防止这种情况。

用户代理 将根据设备或用户选项自行确定适当的策略,这些策略可能因设备或用户选项而有所不同。

11. 常见问题解答

本节为非规范性内容。

11.1 为什么不与 Mouse Capture: setCapture() 合并?

Mouse Capture [MDN-SETCAPTURE] 处理了鼠标拖动手势期间低安全风险的鼠标事件目标锁定。 指针锁定移除了光标的概念,并将所有事件指向给定的目标。它们是相关的,但不同。

如果浏览器实现了两者,支持功能组合是合理的:自动释放锁定的安全简化功能,以及对鼠标输入的完全控制和移除系统光标的增强功能。 该安全特性允许应用程序在拖动事件期间仅需短暂的指针锁定时,更宽松地使用该功能。

这种功能在该规范的初始版本中被省略,因为它仅帮助了窗口模式下的小众用例,但我们仍然没有解决主要用例的实现方案。 而且,要实现这一点,浏览器必须同时实现这两者,而目前没有浏览器这样做。尚不清楚该功能应属于 .lock 还是 .setCapture。 如果两者都实现了,任何 API 都可以很容易地扩展以提供混合功能。

11.2 为什么不重新利用 MouseEvent 的 .clientX/Y .screenX/Y?

即使在非锁定状态下,鼠标移动的增量值也是有用的。根据锁定状态改变 .client 或 .screen 的含义还会导致代码中容易出现错误, 特别是在不仔细监控锁定状态时。

11.3 为什么使用 .movementX/Y 而不是 .deltaX/Y?

当指针锁定时,“wheel”事件应与“mousemove”事件一样发送到 指针锁定目标 元素。 与 DOM 3 “wheel”事件中定义的 .deltaX/Y/Z 存在命名冲突。

11.4 为什么将所有功能(隐藏光标、提供鼠标增量)捆绑在一起,而不是使用 CSS 隐藏光标、始终提供增量值并提供限制光标移动到网页某部分的 API?

提供更精细控制的方法是合理的。例如,“通过将鼠标光标移动到视口边界来进行视口平移”这一用例并不需要隐藏光标, 只需限制光标并始终提供增量值即可。此外,本规范定义了从系统鼠标光标移动中获取的运动增量, 该增量包含操作系统对鼠标移动数据的过滤和加速。应用程序可能希望访问更原始的移动数据形式, 即在适合鼠标光标的调整之前的数据。此外,原始数据可能提供比像素级别更高的移动精度,以及更高频率的更新。 提供原始增量运动不需要用户的特殊权限或模式,对于不需要限制光标的一些应用程序来说,可能会减少所需的安全屏障和提示。

推迟这种精细控制方法的原因有两个。首先是关于鼠标移动数据的单位问题。 本规范定义了 .movementX/Y 与鼠标未锁定时的 .screenX/Y 变化相同的值。各个 用户代理 和操作系统可以轻松满足这一要求,并为应用程序开发者和用户提供一致的体验。 此外,用户已预先配置了硬件输入和操作系统选项,从而使得系统鼠标光标控制更为舒适。 通过将 .movementX/Y 规定为与鼠标锁定 API 应用程序相同的单位,所有用户都可以立即使用这些应用程序,因为他们已经调整了他们的偏好。

其次,实现精细控制方法的运动数据和光标限制更为困难。捆绑这些功能为实现提供了自由, 使其可以根据每个操作系统使用各种技术,并且更容易实现。在主要桌面平台(Windows、Mac OS X、Linux)上没有直接的 API 来将光标限制到特定的矩形区域,并且尚未开发出通过例如使用 不可见窗口Xlib 进行原型构建来演示这一行为。未加速的增量值已经提出通过读取原始人机界面设备(HID)数据来访问。 例如,Windows 上的 WM_INPUT 消息,以及 Mac OS X / Linux 上的 USB 设备 API。 挑战在于解释和规范单位为一致且可指定的尺度。此外,迄今为止考虑的大多数 API 都仅限于 USB 设备。

考虑到当前规范的指针锁定 API 在未来实现这些精细控制的增量和限制功能时可以轻松继续支持, 添加这些功能在未来是合理的。

捆绑的 API 选择了实现的实用性,因为支持了预期的用例,并且不会与此处讨论的未来改进发生冲突。

11.5 高分辨率增量/高频更新?

还没有,原因与上一个问题相同:“为什么将所有功能(隐藏光标、提供鼠标增量)捆绑在一起,而不是使用 CSS 隐藏光标、 始终提供增量值并提供限制光标移动到网页某部分的 API?”

11.6 为什么修改 MouseEvent 并重用现有鼠标事件而不是创建 Mouse Delta 事件?

在指针锁定时,许多鼠标事件仍然相关,例如 click、mousedown 等。它们都共享相同的事件数据结构 MouseEvent。 如果通过一个新数据结构报告移动数据,那么将需要一个新事件来报告增量移动。 新的数据结构将与 MouseEvent 有许多相似之处,例如按钮和修改键状态的便利性。 在处理 click、down 和 up 事件时是否使用现有的 mousedown 和 mouseup? 如果是,它们将提供无用的 .clientX/Y 和 .screenX/Y 数据,但缺乏包含当前运动数据的便利性。 否则,当鼠标锁定时,将需要新的事件。

此外,即使鼠标未锁定,movementX/Y 也是方便的。本规范要求即使光标存在,运动成员始终有效。 这减少了在应用程序希望利用鼠标的增量运动时,跟踪最后的光标状态和 mouseover/mouseout 过渡所需的代码。

将 movementX/Y 添加到 MouseEvent 的唯一缺点似乎是在指针锁定时 clientX/Y 和 screenX/Y 中的未使用值。 这似乎不是一个重要问题。

因此,选择了向 MouseEvent 添加 movementX/Y 这一最小变更,以减少 API 和实现的复杂性。

11.7 为什么在指针锁定下为鼠标事件和键盘输入焦点分离目标?

考虑一个通过移动鼠标光标控制 3D 视图的游戏,同时用户仍可以通过文本控制台与其他用户聊天。 应用程序接受文本输入到与分派鼠标事件的元素不同的元素是合理的。这类似于在页面上填写表单时接收 mousemove 事件的预先行为。

12. 一致性

与标记为非规范的章节一样,本规范中的所有作者指南、图表、示例和注释都是非规范的。除此之外,本规范中的所有内容都是规范性的。

本规范定义了一些一致性标准,适用于单个产品:用户代理,即实现了其中包含的接口的用户代理。

A. 致谢

本节为非规范性内容。

非常感谢众多对本规范讨论做出贡献的人们:

B. 参考文献

B.1 规范性参考

[dom]
DOM 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://dom.spec.whatwg.org/
[FULLSCREEN]
全屏 API 标准。Philip Jägenstedt。WHATWG。 现行标准。URL:https://fullscreen.spec.whatwg.org/
[html]
HTML 标准。Anne van Kesteren; Domenic Denicola;Ian Hickson;Philip Jägenstedt;Simon Pieters。WHATWG。 现行标准。URL:https://html.spec.whatwg.org/multipage/
[ui-events]
UI 事件。Gary Kacmarcik;Travis Leithead。W3C。 2024年2月21日。W3C工作草案。URL:https://www.w3.org/TR/uievents/
[WEBIDL]
Web IDL 标准。Edgar Chen;Timothy Gu。WHATWG。 现行标准。URL:https://webidl.spec.whatwg.org/

B.2 信息性参考

[MDN-SETCAPTURE]
Element.setCapture()。 Eric Shepherd 等人。URL:https://developer.mozilla.org/en-US/docs/Web/API/Element/setCapture