简体   繁体   English

如何在 WebVR/A-Frame 中监听 Android Chrome 上的点击事件?

[英]How to listen to click event on Android Chrome in WebVR/A-Frame?

I'm trying to listen to click events (To be exact, magnet pull from google cardboard) on Android Chrome, but this seems to not work if the device goes into VR mode.我正在尝试在 Android Chrome 上收听点击事件(确切地说,是从谷歌纸板上的磁铁拉动),但是如果设备进入 VR 模式,这似乎不起作用。 I'm using Samsung Galaxy S7 for testing:我正在使用三星 Galaxy S7 进行测试:

JS: JS:

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

On Samsung's built in Android browser, the log is printed both in and out of VR mode.在三星内置的 Android 浏览器上,日志会在 VR 模式内外打印。 In Android Chrome, logging is only shown when the browser is not in VR mode.在 Android Chrome 中,日志仅在浏览器未处于 VR 模式时显示。

HTML: 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>

I'm using A-Frame ver 0.7.0, but this issue is reproducible just from using native WebVR APIs as well.我使用的是 0.7.0 版的 A-Frame,但是这个问题也可以通过使用本机 WebVR API 重现。

I thought the canvas might be consuming the click events, so I tried to add the eventlistener to Canvas directly.我认为画布可能正在消耗点击事件,所以我尝试直接将事件侦听器添加到画布。 This also did not work.这也不起作用。

Is this a bug in Chrome?这是 Chrome 中的错误吗? Is there any workaround?有什么解决方法吗? I just need to be able to listen to button presses.我只需要能够听到按下按钮的声音。

I've finally found an approach that works.我终于找到了一种有效的方法。 We have to use native WebVR APIs:我们必须使用原生 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;
      }
    });
  }

  

Then we can register the click:然后我们可以注册点击:

  addVRClickListener(onClick);

The problem I see in A-frame's code is that it's not accounting for display change (non vr -> vr) for propagating the touch events.我在 A-frame 的代码中看到的问题是它没有考虑用于传播触摸事件的显示更改(非 vr -> vr)。

This seems to be a bug in A-Frame.这似乎是 A-Frame 中的一个错误。

This sounds related to a few issues I've seen with the magnetic button.这听起来与我在磁性按钮上看到的一些问题有关。

First thing to try could be touchstart instead of click:首先要尝试的是 touchstart 而不是点击:

You can try adding this component to the scene and the see if it works:您可以尝试将此组件添加到场景中,看看它是否有效:

<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>

More context in this thread: aframe cardboard button (magnet) click does not trigger此线程中的更多上下文: aframe 纸板按钮(磁铁)点击不会触发

Next if that doesn't work, then perhaps the chrome flag and this thread could help:接下来,如果这不起作用,那么 chrome 标志和这个线程可能会有所帮助:

Detect Google Cardboard Magnetic Button Click in Javascript 在Javascript中检测Google Cardboard磁性按钮点击

chrome://flags/#enable-generic-sensor铬://标志/#enable-generic-sensor

chrome://flags/#enable-generic-sensor-extra-classes铬://标志/#enable-generic-sensor-extra-classes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM