Android 在按下多个键时不调用 onKeyUp
Android is not calling onKeyUp when multiple keys pressed
我正在 Java
中为 Android
编写一个小游戏,但我在处理输入时遇到了问题。对于早期测试,我使用的是硬件键盘输入,但我最终打算使用游戏手柄控件。
我遇到的问题是:当用户按住一个 key
超过 10 秒,同时按下并释放其他一些键时,onKeyUp()
函数因为第一个键在最终释放时不会被调用。
我还没有找到完全最小的重现,但我可以在两个不同的 emulators
和一个物理 Nexus 5(带有一个显示为键盘的游戏手柄)上可靠地触发它。
相关代码,已删除冗余和日志语句:
public class GameSurfaceView extends GLSurfaceView {
public final static short VBTN_FORWARD = 0;
public final static short VBTN_BACKWARD = 1;
// snipped several more similar constants
public AtomicIntegerArray virtual_button_state = new AtomicIntegerArray(7);
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event){
if (event.isLongPress() || event.getRepeatCount() > 0){
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_W:
virtual_button_state.incrementAndGet(GameRenderer.VBTN_FORWARD);
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_S:
virtual_button_state.incrementAndGet(GameRenderer.VBTN_BACKWARD);
return true;
// snipped several more similar cases
}
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event){
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_W:
virtual_button_state.decrementAndGet(GameRenderer.VBTN_FORWARD);
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_S:
virtual_button_state.decrementAndGet(GameRenderer.VBTN_BACKWARD);
return true;
// snipped several more similar cases
}
}
}
我做了广泛的测试,跟踪语句显示 onKeyUp() 没有被调用 at all。不管是什么问题,它首先阻止了事件到达我的 GLSurfaceView。
Possibly-relevant其他信息:
- 我的 activity 是全屏的,没有标题
- 我的渲染器是 运行 在 RENDERMODE_CONTINUOUSLY
- 我的渲染器还没有well-optimized并且经常跳帧
- 我同时在处理触摸事件
- 这个问题在正常游戏中经常出现。如果不能解决这个问题,项目就死了。
问题已解决 - 错误与我最初描述的不完全相同。我编写的用于检测焦点是否丢失的测试代码中存在一个微妙的错误,这导致我对问题的原因得出了错误的结论。
在触摸事件期间,焦点实际上丢失了,有时在触发 keyUp 事件时没有重新获得焦点。多个同时发生的按键事件使这种情况更有可能发生,这就是为什么它被错误地包含在重现中,以及为什么我错误地关注多个按键而不是同时发生的触摸事件。
问题的最终原因是在我的视图构造函数中调用 setFocusableInTouchMode(true) 失败。
我正在 Java
中为 Android
编写一个小游戏,但我在处理输入时遇到了问题。对于早期测试,我使用的是硬件键盘输入,但我最终打算使用游戏手柄控件。
我遇到的问题是:当用户按住一个 key
超过 10 秒,同时按下并释放其他一些键时,onKeyUp()
函数因为第一个键在最终释放时不会被调用。
我还没有找到完全最小的重现,但我可以在两个不同的 emulators
和一个物理 Nexus 5(带有一个显示为键盘的游戏手柄)上可靠地触发它。
相关代码,已删除冗余和日志语句:
public class GameSurfaceView extends GLSurfaceView {
public final static short VBTN_FORWARD = 0;
public final static short VBTN_BACKWARD = 1;
// snipped several more similar constants
public AtomicIntegerArray virtual_button_state = new AtomicIntegerArray(7);
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event){
if (event.isLongPress() || event.getRepeatCount() > 0){
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_W:
virtual_button_state.incrementAndGet(GameRenderer.VBTN_FORWARD);
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_S:
virtual_button_state.incrementAndGet(GameRenderer.VBTN_BACKWARD);
return true;
// snipped several more similar cases
}
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event){
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_W:
virtual_button_state.decrementAndGet(GameRenderer.VBTN_FORWARD);
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_S:
virtual_button_state.decrementAndGet(GameRenderer.VBTN_BACKWARD);
return true;
// snipped several more similar cases
}
}
}
我做了广泛的测试,跟踪语句显示 onKeyUp() 没有被调用 at all。不管是什么问题,它首先阻止了事件到达我的 GLSurfaceView。
Possibly-relevant其他信息:
- 我的 activity 是全屏的,没有标题
- 我的渲染器是 运行 在 RENDERMODE_CONTINUOUSLY
- 我的渲染器还没有well-optimized并且经常跳帧
- 我同时在处理触摸事件
- 这个问题在正常游戏中经常出现。如果不能解决这个问题,项目就死了。
问题已解决 - 错误与我最初描述的不完全相同。我编写的用于检测焦点是否丢失的测试代码中存在一个微妙的错误,这导致我对问题的原因得出了错误的结论。
在触摸事件期间,焦点实际上丢失了,有时在触发 keyUp 事件时没有重新获得焦点。多个同时发生的按键事件使这种情况更有可能发生,这就是为什么它被错误地包含在重现中,以及为什么我错误地关注多个按键而不是同时发生的触摸事件。
问题的最终原因是在我的视图构造函数中调用 setFocusableInTouchMode(true) 失败。