如何在执行长按键的同时处理短按键?

How to process short keypress in the same time long keypress is performed?

我尝试用 Python 和 PyQt4 编写简单的游戏。这是简单的平台游戏,我想在 "move" 按键期间处理 "jump" 按键。

这就像我在按住 right arrow 键的同时按下 z(或者任何键,可能是 shift、ctrl、cmd、alt)并且我想要继续向右移动,同时进行跳跃

当我使用 keyPressEvent 时,长按 "move" 可以正常工作,但每次 "jump" 按键都会中断移动,我需要按箭头才能继续。

为了更好地理解我想要完成的事情,让我们看看这个: (> 是移动的右箭头,z 是跳跃)

key: >>>>>>>>>>>>> . z . . o player: oooooooo

如您所见,我正拿着 > 玩家移动。在我按下 z 的同时,即使 > 键仍被按下,播放器也会跳转并停止。

在 pyqt 中可以这样做吗?也许我需要一些外部图书馆?任何帮助将不胜感激!


已解决!

感谢@Brendan Abel 的回答,我已经完成了我需要的一切:) 代码看起来与此类似(为清楚起见,我进行了简化):

class Test(QtGui.QMainWindow):
  pressed_keys = {
    QtCore.Qt.Key_Left: False,
    QtCore.Qt.Key_Right: False,
    QtCore.Qt.Key_Z: False,
  }

  def __init__(self):
    self.timer = QtCore.QTimer(self)
    self.timer.timeout.connect(self.key_action)
    self.timer.start(100)

    # definitions hidden for simplicity
    self.key_actions = {
      QtCore.Qt.Key_Left: self.player_move_backward,
      QtCore.Qt.Key_Right: self.player_move_forward,
      QtCore.Qt.Key_Z: self.player_jump,
    }

  def keyPressEvent(self, e):
    key = e.key()
    self.pressed_keys[key] = True

  def keyReleaseEvent(self, e):
    key = e.key()
    self.pressed_keys[key] = False

  def key_action(self):
    for key, is_pressed in self.pressed_keys.items():
      if is_pressed:
        action = self.key_actions[key]

        action()
        self.update()

我的游戏现在是这样的:

您可能需要对键盘状态进行某种类型的定期轮询以确定要处理的控件。不幸的是,Qt 没有直接的 API 来轮询键盘状态。您必须通过维护具有 keypress 事件但没有 keyrelease 事件的全局键映射来跟踪哪些键已关闭。然后定期轮询该映射以获取按下的键列表。

pressed_keys = set()

def keyPressEvent(self, event):
    pressed_keys.add(event.key())

def keyReleaseEvent(self, event):
    pressed_keys.remove(event.key())

添加按键时,您可以选择是否也添加修饰键(即shift、ctrl、alt)(使用event.modifiers()),以及是应该只应用于他们第一次按下的键,还是应该应用于所有按下的键。

您可以使用 QTimer 进行轮询。基本上,不是 keyPressEvent 触发您的游戏更新,而是您将根据 QTimer.timeout 进行更新。

timer = QTimer()
timer.timeout.connect(self.update_game)
timer.start(100)  # Update rate

@QtCore.pyqtSlot()
def update_game(self):
    if Qt.Key_Space in pressed_keys:
        ...
    if Qt.Key_Up in pressed_keys:
        ...

您也可以选择不使用 QTimer 进行更新并继续使用 keypresskeyrelease 事件来触发更新,但您仍然需要保持按键的持久状态。