【问题标题】:How to listen to click event on Android Chrome in WebVR/A-Frame?如何在 WebVR/A-Frame 中收听 Android Chrome 上的点击事件?
【发布时间】:2018-08-12 16:09:17
【问题描述】:

我正在尝试在 Android Chrome 上收听点击事件(确切地说,是从 google cardboard 拉出的磁铁),但如果设备进入 VR 模式,这似乎不起作用。我正在使用三星 Galaxy S7 进行测试:

JS:

window.addEventListener('click', function (evt) {
    console.log("test")
});

在三星内置的 Android 浏览器上,日志会在 VR 模式内外打印。在 Android Chrome 中,仅当浏览器未处于 VR 模式时才会显示日志记录。

HTML:

<a-entity camera="userHeight: 1.6" restrict-position look-controls>
    <a-entity cursor="fuse: true; fuseTimeout: 500"
                position="0 0 -1"
                geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
                material="color: black; shader: flat">
    </a-entity>
</a-entity>

我使用的是 A-Frame 0.7.0 版,但这个问题也可以通过使用原生 WebVR API 来重现。

我认为画布可能正在消耗点击事件,所以我尝试将事件监听器直接添加到画布。这也不起作用。

这是 Chrome 中的错误吗?有什么解决方法吗?我只需要能够听到按钮按下的声音。

【问题讨论】:

    标签: javascript android google-chrome aframe webvr


    【解决方案1】:

    我终于找到了一种可行的方法。我们必须使用原生 WebVR API:

    function addVRClickListener(clickCallback) {
        let lastButtonState = [];
        let presentingDisplay = null;
    
        // Set up a loop to check gamepad state while any VRDisplay is presenting.
        function onClickListenerFrame() {
          // Only reschedule the loop if a display is still presenting.
          if (presentingDisplay && presentingDisplay.isPresenting) {
            presentingDisplay.requestAnimationFrame(onClickListenerFrame);
          }
          
          let gamepads = navigator.getGamepads();
          for (let i = 0; i < gamepads.length; ++i) {
            let gamepad = gamepads[i];
            // Ensure the gamepad is valid and has buttons.
            if (gamepad &&
                gamepad.buttons.length) {
              let lastState = lastButtonState[i] || false;
              let newState = gamepad.buttons[0].pressed;
              // If the primary button state has changed from not pressed to pressed 
              // over the last frame then fire the callback.
              if (newState && !lastState) {
                clickCallback(gamepad);
              }
              lastButtonState[i] = newState;
            }
          }
        }
    
        window.addEventListener('vrdisplaypresentchange', (event) => {
          // When using the polyfill, CustomEvents require event properties to
          // be attached to the `detail` property; native implementations
          // are able to attach `display` directly on the event.
          var display = event.detail ? event.detail.display : event.display;
          if (display.isPresenting) {
            let scheduleFrame = !presentingDisplay;
            presentingDisplay = display;
            if (scheduleFrame)
              onClickListenerFrame();
          } else if (presentingDisplay == display) {
            presentingDisplay = null;
          }
        });
      }
    
      
    

    然后我们就可以注册点击了:

      addVRClickListener(onClick);
    

    我在 A-frame 的代码中看到的问题是它没有考虑到传播触摸事件的显示变化(非 vr -> vr)。

    这似乎是 A-Frame 中的一个错误。

    【讨论】:

    • 这真的对你有用吗?我不知道 chrome 是否曾经支持纸板按钮并已将其移除,或者它是否曾经工作过。我的纸板按钮在 android 应用程序中工作得非常好,但在 chrome vr 模式下没有注册任何事件(并且游戏手柄是您在上面给出的函数中的 4 个空格的列表)。在 VR 模式下,触摸事件也被禁用。
    • (只是想补充一下,我用的不是磁扣,我用的是触控式的,应该排除很多并发症)
    【解决方案2】:

    这听起来与我在磁性按钮上看到的一些问题有关。

    首先要尝试的是 touchstart 而不是点击:

    您可以尝试将此组件添加到场景中,看看它是否有效:

    <script>
    AFRAME.registerComponent("click-handler", {
        init: function() {
            const sceneEl = this.el.sceneEl
            const canvasEl = sceneEl.canvas    
            canvasEl.addEventListener('touchstart', () => {
                // code here
            })
        }
    });
    </script>
    
    <a-scene click-handler>...</a-scene>
    

    此线程中的更多上下文: aframe cardboard button (magnet) click does not trigger

    如果这不起作用,那么 chrome 标志和这个线程可能会有所帮助:

    Detect Google Cardboard Magnetic Button Click in Javascript

    chrome://flags/#enable-generic-sensor

    chrome://flags/#enable-generic-sensor-extra-classes

    【讨论】:

    • 我已经尝试了所有的建议......这是我发现的问题: 1. 听“click-handler”不起作用。不发出任何事件。 2. 从磁层读取的传感器值非常不准确。例如,仅在任何 X-Y-Z 轴上倾斜手机都会产生无关值,因为它试图读取所有坐标中的磁场 - 没有真正的方法可以区分手机移动与实际按钮按下。更重要的是,我仍然需要用户能够手动触摸屏幕以触发事件。
    • 嗯,只是好奇,使用 Don 的通用控件是否适用于您的 Cardboard 和 Android Chrome:github.com/donmccurdy/aframe-extras/tree/master/src/controls 如果没有,那么这可能会导致 Chrome 和磁性按钮 i 出现更多问题怀疑。
    • 试过Don的万能控件,还是不行。看源码,它在场景下做的就是监听touchstart事件反正我已经试过了。
    猜你喜欢
    • 2021-02-21
    • 2021-08-23
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多