Emscripten canvas + jQuery - 切换焦点

Emscripten canvas + jQuery - toggle focus

我有一个 HTML 页面,大致将 30% - 70% 分为两个垂直栏。左列包含聊天提要(通过 Node 和 Socket.io 处理),右列包含 emscripten 生成的 canvas(ID 为 canvas)。 canvas 包含一个基本的 3D 世界,用户可以使用标准的第一人称控件(WASD 用于移动,鼠标指向 'look')进行导航。

默认情况下,canvas 吞没所有键盘事件。我在 canvas 初始化过程中使用以下代码解决了这个问题:

Module.preRun.push(function () {
    ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = "#canvas";
});

这让我可以手动关注聊天框,输入消息,然后提交。

我 运行 遇到的问题是,一旦提交了聊天消息,我就会尝试 return 使用以下代码将注意力集中到 canvas (以允许玩家使用 WASD 导航 3d 世界):

 $('#canvas').focus();

这名义上 return 将焦点转移到 canvas,但鼠标和键盘移动不起作用。奇怪的是,点击 tab/browser window 然后进入 canvas 似乎可行 - 焦点 returned 到 canvas,我可以再次导航.手动调用 $(window).blur().focus() 不起作用。

有人知道如何在发送聊天消息后将焦点强制返回到 canvas 吗?

--更新--

我在 canvas 后面添加了一个文本输入字段(ID 为 hiddenField),我正在使用 preRun 函数为 canvas 分配按键事件到该字段(canvas 由于某种原因不能始终如一地工作)。

这很好用 直到 用户点击 canvas - 例如,进入聊天区域 - 于是 canvas 停止响应任何键盘或鼠标输入,即使我触发焦点回到 hiddenField(并且可以看到它正在获取)。

似乎在页面上做 任何事情 与 emscripten 的聚焦行为(我相信与 window 对象相关联)冲突并阻止 canvas从重新获得焦点。

肯定有一些方法可以让 emscripten canvas 与其他 HTML 元素共存?

我找到的最好的方法——事实上,让应用程序的各个方面(聊天和 3D 世界)正常工作的唯一方法——是嵌入 emscripten canvas 在 iframe 中,并在必要时使用跨框架函数调用来触发操作。

Page
    - chat
    - iframe
        -- emscripten-generated page

这不是我的首选解决方案,但它是我设法开始工作的唯一解决方案。

您需要通过添加 tabindex="0" 属性使 canvas 对象可聚焦。

那么应该可以正常触发focus事件了:

document.querySelector("#canvas").focus()

编辑:

通过 CodePen 查看完整演示(包括指向 .js 资源的链接)

结构:

Page
    - emscripten-generated-page
       - loop
    - chat
    - script to handle global key input handlers

必须在canvas元素上设置tabindex(如luke and described on MDN所述),通过[=47附加全局事件监听器=] 的内置 Document 接口,然后调用 .triggerHandler() 以确保 canvas returns 到它的默认状态,由 click:

var chatInputField = $("#message-input");
var canvas = $("#canvas");


canvas.on("click", function(e){
  return document.addEventListener("keyup", game.toggleKeys);
});

chatInputField.on("focusin", function(e) {
    $('#canvas').attr('tabindex', 0);
    return document.removeEventListener("keyup", game.toggleKeys, false);
});

chatInputField.on("focusout", function(e) {
    $("#canvas").triggerHandler('click');
    chatInputField.attr('tabindex', 0);
});

我已经测试过了,它有效。这是我的 app.js 文件,用于管理键输入(参见第 297 行)。

https://gist.github.com/shagamemnon/585df8dd215a949b839f8b02199af31b

注意:您必须明确定义游戏中tab键的行为canvas。