自定义鼠标光标 + IE 困境

发布于 2024-10-31 06:20:28 字数 2792 浏览 0 评论 0原文

我正在开发一个具有以下属性的项目:

  1. jQuery 驱动页面
  2. Unity 3d 播放器使用 jQuery 和 unityobject.js 嵌入到页面中(根据 Unity 的指令)
  3. 当用户的光标时,Unity 具有自定义鼠标光标位于 Unity 画布区域内

问题:Unity 捕获鼠标光标,但当包含鼠标光标的网页变为非活动状态时不会释放它。这意味着如果用户切换到不同的选项卡(或打开一个新窗口),当用户将鼠标悬停在 Unity 本来所在的区域上时,鼠标光标就会消失。这是 Unity 3d 论坛中描述的一个 Unity 错误: http://forum .unity3d.com/threads/4565-Unity-Web-player-issue-mouse-hidden-for-all-new-windows

不,它在最新版本的 Unity Web 客户端中仍未修复。

为了缓解这个问题,我们决定让 Unity 通过 Javascript 监听当前浏览器窗口状态,并根据收到的状态捕获/释放自定义鼠标光标。但还有其他问题:

Unity 如何接收窗口状态:

// GetUnity returns the Unity object in the DOM<br>
NAMESPACE.windowStatus = function( statusStr ) {
    GetUnity().SendMessage( "_AppShell", "OnRecieveWindowStatusFromWebPage", statusStr );
}

我尝试了以下方法...

方法一:将事件绑定到“窗口”对象

$( window ).live( 'focus', function() {
    NAMESPACE.windowStatus( 'active' );
} );

$( window ).live( 'blur', function() {
    NAMESPACE.windowStatus( 'inactive' );
} );

问题:在 IE7 和 IE8 中,新的浏览器选项卡不被视为不同的“窗口”,因此代码对 Unity 没有影响。它仅在打开真正的单独浏览器窗口时才有效。


方法二:将事件绑定到“文档”对象
像这样: $( document ).live(...);

问题: jQuery 中的 $( document ) 实际上什么也没做。艰难地发现了。
来源: http://forum.jquery .com/topic/should-document-live-map-to-document-bind-window-too


方法3:将事件绑定到对象
像这样: $( 'body' ).live(...);

问题: IE 不知何故无法识别 Unity 对象是 DOM 的一部分(尽管使用了 .live() 方法)。因此,每次用户单击嵌入式 Unity 播放器时,浏览器都会向 Unity 发送一个 blur 事件,并且鼠标光标会被锁定(console.log() 打印出 < code>inactive(当单击 Unity 时)。而且在某些情况下它甚至不会释放鼠标光标,导致整个浏览器对鼠标事件没有响应;释放光标的唯一方法是在浏览器窗口外部单击,然后再次单击浏览器)。


我尝试过的其他事情:

window.addEventListener( 'focus', function() {...} );
document.addEventListener( 'focus', function() {...} );
document.body.addEventListener( 'focus', function() {...} );
document.getElementsByTagName('body')[0].addEventListener( 'focus', function() {...} );

问题: IE 中根本不支持这些元素上的 .addEventListener() 方法! GAH!


奖金:
细心的您可能会插话,“嘿,为什么不检测 Unity 对象本身上的鼠标单击事件并忽略 blur 事件,.live().bind() 事件。”试过了。 IE也不喜欢它。它完全忽略该事件并表示这些事件对该对象不可用。

所以我的 Javascript 专家们。我不知道如何以优雅的方式最好地解决这个问题。任何指示将不胜感激。

I'm working on a project that has these attributes:

  1. jQuery driving the page
  2. Unity 3d player embedded to the page using jQuery and unityobject.js (per instruction from Unity)
  3. Unity has custom mouse cursor when user's cursor is inside of Unity's canvas area

Issue: Unity captures the mouse cursor but won't release it when the web page that contains it becomes inactive. This means if the user switches to a different tab (or opens a new window), the mouse cursor disappears when the user mouses over the area where Unity would have been. This is a unity bug described here in Unity 3d forum:
http://forum.unity3d.com/threads/4565-Unity-Web-player-issue-mouse-hidden-for-all-new-windows

And no, it's still not fixed in the latest version of Unity web client.

To mitigate the issue, we decided to have Unity listen to the current browser window status via Javascript and capture/release the custom mouse cursor based on the status it receives. But there are other issues:

How Unity receives window status:

// GetUnity returns the Unity object in the DOM<br>
NAMESPACE.windowStatus = function( statusStr ) {
    GetUnity().SendMessage( "_AppShell", "OnRecieveWindowStatusFromWebPage", statusStr );
}

I've tried the following methods...

Method 1: Binding events to the "window" object

$( window ).live( 'focus', function() {
    NAMESPACE.windowStatus( 'active' );
} );

$( window ).live( 'blur', function() {
    NAMESPACE.windowStatus( 'inactive' );
} );

The problem: in IE7 and IE8, new browser tabs aren't considered different "window", so the code has no effect on Unity. It only works if a true separate browser window was open.


Method 2: Binding events to the "document" object
Like such: $( document ).live(...);

The problem: $( document ) in jQuery actually does nothing. Found out the hard way.
Source: http://forum.jquery.com/topic/should-document-live-map-to-document-bind-window-too


Method 3: Binding events to the <body> object
Like such: $( 'body' ).live(...);

The problem: Somehow IE doesn't recognize that the Unity object is part of the DOM (despite the use of the .live() method). So every time user clicks on the embedded Unity player, the browser sends a blur event to Unity, and the mouse cursor gets locked up (console.log() prints out inactive when Unity is clicked on). And in some cases it won't even release the mouse cursor, rendering the entire browser unresponsive to mouse events; the only way to release the cursor is to click outside of the browser window and click on the browser again).


Other things I've tried:

window.addEventListener( 'focus', function() {...} );
document.addEventListener( 'focus', function() {...} );
document.body.addEventListener( 'focus', function() {...} );
document.getElementsByTagName('body')[0].addEventListener( 'focus', function() {...} );

The problem: .addEventListener() method is not supported in IE on those elements at all! GAH!


Bonus:
The more observant of you may chime in a say, "Hey, why not detect the mouse click event on the Unity object itself and ignore the blur event, .live() or .bind() events." Tried that. IE doesn't like it either. It completely ignores the event and says those events are not available for the object.

So my fellow Javascript gurus. I'm out of ideas as how to best approach this problem in an elegant way. Any pointers would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暗藏城府 2024-11-07 06:20:28

问题解决了。 Unity3d 的论坛上提供了一个解决方案,埋在某处......
http://forum.unity3d.com/threads/ 27516-Mouse-input-possible-from- Different-tab

其要点是:框架并不总是答案。回到根源。

我忘记了 .addEventListener() 不是 IE 原生的,.attachEvent() 是。因此,如果我在检测到 IE 时将所有事件侦听器替换为 IE 特定的事件侦听器,那么我上面的代码就会起作用。

因此修改后的代码如下:

if ( navigator.appName == 'Microsoft Internet Explorer' ) {
    GetUnity().attachEvent( 'onmouseover', onFocus, false );
    GetUnity().attachEvent( 'onfocusin', onFocus, false );
    GetUnity().attachEvent( 'onmouseout', onBlur, false );
} else {
    // Netscape, Firefox, Mozilla, Chrome and Safari.
    GetUnity().addEventListener( 'mouseover', onFocus, false );
    GetUnity().addEventListener( 'focus', onFocus, false );
    GetUnity().addEventListener( 'mouseout', onBlur, false );
}

function onFocus() {
    NAMESPACE.WindowStatus( 'active' );
}

function onBlur() {
    NAMESPACE.WindowStatus( 'inactive' );
}

要真正实现此功能,您必须在 unityobject.embedUnity() 方法的回调函数中添加事件附件。如果您尝试在加载 Unity 之前附加事件,浏览器将抱怨 GetUnity()nullundefined

希望这可以帮助那些遇到同样问题的人。

Problem solved. A solution was provide on Unity3d's forum buried down somewhere...
http://forum.unity3d.com/threads/27516-Mouse-input-possible-from-different-tab

The gist of it is: Frameworks are not always the answer. Go back to the roots.

I'd forgotten that the .addEventListener() is not native to IE, .attachEvent() is. So my code above would have worked had I just replaced all the event listeners with IE-specific ones when IE is detected.

So the modified code is as follow:

if ( navigator.appName == 'Microsoft Internet Explorer' ) {
    GetUnity().attachEvent( 'onmouseover', onFocus, false );
    GetUnity().attachEvent( 'onfocusin', onFocus, false );
    GetUnity().attachEvent( 'onmouseout', onBlur, false );
} else {
    // Netscape, Firefox, Mozilla, Chrome and Safari.
    GetUnity().addEventListener( 'mouseover', onFocus, false );
    GetUnity().addEventListener( 'focus', onFocus, false );
    GetUnity().addEventListener( 'mouseout', onBlur, false );
}

function onFocus() {
    NAMESPACE.WindowStatus( 'active' );
}

function onBlur() {
    NAMESPACE.WindowStatus( 'inactive' );
}

To truly make this work, you'd have to make the event attachments in a callback function of the unityobject.embedUnity() method. If you try to attach the events prior to Unity being loaded, the browser will complain that GetUnity() is null or undefined.

Hope this helps someone scratching his head out there with the same issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文