如何在WebVR/A-Frame中监听AndroidChrome上的点击事件?
How to listen to click event on Android Chrome in WebVR/A-Frame?
我正在尝试监听 Android Chrome 上的点击事件(确切地说,磁铁从 google 硬纸板上拉动),但这似乎无法正常工作,如果设备进入 VR 模式。我正在使用三星 Galaxy S7 进行测试:
JS:
window.addEventListener('click', function (evt) {
console.log("test")
});
在三星的内置 Android 浏览器上,无论在 VR 模式下还是在 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 ver 0.7.0,但这个问题也可以通过使用本机 WebVR API 重现。
我认为 canvas 可能会消耗点击事件,所以我尝试将事件监听器直接添加到 Canvas。这也没有用。
这是 Chrome 中的错误吗?有什么解决方法吗?我只需要能够听到按钮按下的声音。
这听起来与我在磁性按钮上看到的一些问题有关。
首先要尝试的是触摸启动而不是点击:
您可以尝试将此组件添加到场景中,看看它是否有效:
<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 标志和这个线程可能会有所帮助:
chrome://flags/#enable-generic-sensor
chrome://flags/#enable-generic-sensor-extra-类
我终于找到了一种可行的方法。我们必须使用本机 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 中的错误。
我正在尝试监听 Android Chrome 上的点击事件(确切地说,磁铁从 google 硬纸板上拉动),但这似乎无法正常工作,如果设备进入 VR 模式。我正在使用三星 Galaxy S7 进行测试:
JS:
window.addEventListener('click', function (evt) {
console.log("test")
});
在三星的内置 Android 浏览器上,无论在 VR 模式下还是在 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 ver 0.7.0,但这个问题也可以通过使用本机 WebVR API 重现。
我认为 canvas 可能会消耗点击事件,所以我尝试将事件监听器直接添加到 Canvas。这也没有用。
这是 Chrome 中的错误吗?有什么解决方法吗?我只需要能够听到按钮按下的声音。
这听起来与我在磁性按钮上看到的一些问题有关。
首先要尝试的是触摸启动而不是点击:
您可以尝试将此组件添加到场景中,看看它是否有效:
<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 标志和这个线程可能会有所帮助:
chrome://flags/#enable-generic-sensor
chrome://flags/#enable-generic-sensor-extra-类
我终于找到了一种可行的方法。我们必须使用本机 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 中的错误。