PAYATHON 2026

Android libGDX 项目按键时弹出软键盘,如何阻止?

数据小许

如果游戏窗口只需接收键盘按键,完全不需要通过输入法输入文本,可以在 MainActivity 中添加 FLAG_ALT_FOCUSABLE_IM。窗口保持可聚焦时,这个标志会阻止它成为输入法的目标,同时保留接收按键焦点的能力。Android API 文档说明了这一行为。

现有材料不足以确定是哪一次系统或输入法调用触发了弹出,因此不能直接认定这是 ScrCpy 或 libGDX 1.14.0 的已知缺陷。以下修改适用于明确不需要 IME 的游戏窗口,还需要在出现问题的设备上验证。

为什么没有文本框,也可能涉及输入法?

libGDX 的渲染 View 也可能提供文本输入接口。1.14.0 的 GLSurfaceView20 实现了 onCreateInputConnection(),会设置 EditorInfo.inputType 并返回 BaseInputConnection。因此,仅凭示例中没有 EditText,无法排除输入法参与的可能。libGDX 1.14.0 源码

这只能说明该 View 具备输入法连接能力,不能单独证明按下字母、数字或空格后一定会显示软键盘。触发条件还可能与 Android 版本、当前输入法、键盘识别方式及输入事件来源有关,而现有描述没有提供这些信息。

在 Activity 中禁止当前窗口与 IME 交互

可以将 MainActivity.kt 改为:

import android.os.Bundle
import android.view.WindowManager
import com.badlogic.gdx.backends.android.AndroidApplication
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration

class MainActivity : AndroidApplication() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        window.addFlags(
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
        )

        val config = AndroidApplicationConfiguration().apply {
            useImmersiveMode = true
        }

        initialize(HelloWorldGame(), config)
    }
}

不要同时添加 FLAG_NOT_FOCUSABLE:它会使窗口无法获得按键输入焦点,也会改变 FLAG_ALT_FOCUSABLE_IM 的作用条件。这里需要保持窗口可聚焦,同时阻止当前窗口与输入法交互。窗口标志说明

这项修改不需要调整 SpriteBatch、BitmapFont 或 Gradle 中的 native 库复制任务。

为什么之前的处理没有解决?

stateAlwaysHidden 不会永久禁用软键盘

SOFT_INPUT_STATE_ALWAYS_HIDDEN 指定窗口获得焦点时应隐藏软键盘,但不会关闭窗口使用输入法的能力。窗口获得焦点后,软键盘仍可能因后续输入法交互再次显示。状态标志说明

按键捕获和输入法可见性属于不同的控制环节

Gdx.input.setCatchKey(...) 用于控制指定按键是否被捕获;InputProcessor 用于处理交给游戏的输入事件。它们都没有提供禁止窗口连接 IME 的设置。

在 Activity 的 onKeyDown() 或 onKeyUp() 中返回 true,也不能保证影响已经由输入法处理的事件。为所有按键统一返回 true 还可能吞掉游戏需要的输入。建议撤掉排查时添加的这些拦截,再验证窗口标志的效果。

如何确认修改有效?

在原先能够复现的环境中重新启动 Activity,依次按下 [、]、字母、数字和空格,检查软键盘是否仍然出现,同时确认游戏仍能收到按键。

可以临时在 HelloWorldGame.create() 中添加以下日志,观察交给 libGDX 的事件:

Gdx.input.inputProcessor = object : InputAdapter() {
    override fun keyDown(keycode: Int): Boolean {
        Gdx.app.log("Keyboard", "keyDown=$keycode")
        return true
    }

    override fun keyTyped(character: Char): Boolean {
        Gdx.app.log("Keyboard", "keyTyped=$character")
        return true
    }
}

需要导入 com.badlogic.gdx.Gdx 和 com.badlogic.gdx.InputAdapter。如果已有输入处理器,应将日志加入现有处理流程,避免直接替换。这里的返回值表示事件在 libGDX 输入处理链中已被处理,不代表关闭了系统输入法。

若仍然复现,下一步应记录 Android 版本、输入法名称,以及输入来自实体键盘、ScrCpy 还是 emulator。对照测试时每次只改变一个条件,并留意弹出的内容是否确实属于当前 Activity 的 IME;这个窗口标志不负责禁止其他窗口显示输入法。

后续需要输入昵称或聊天怎么办?

FLAG_ALT_FOCUSABLE_IM 会阻止当前窗口与输入法交互,因此会影响中文候选词、组合输入等依赖 IME 的文本输入能力。如果同一窗口后续需要文本输入,应先在 Android UI 线程清除该标志,再按实际输入组件的流程请求焦点、显示输入法:

runOnUiThread {
    window.clearFlags(
        WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
    )
}

清除标志只恢复窗口使用输入法的条件,不会自动显示键盘。若 ScrCpy 的输入方式依赖文本注入而非直接发送按键,也应单独验证禁用 IME 后的输入表现。

备注:内容仅供参考。