如何在PyQt5中捕获当前所有按下的键盘按键?
解决PyQt5捕获持续按下按键的问题
问题描述
尝试用PyQt5编写GUI程序捕获当前所有按下的键盘按键,编写了两段代码:
代码1:使用事件过滤器
import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QEvent class MainWindow(QWidget): def __init__(self): super().__init__() QApplication.instance().installEventFilter(self) self.pressedKeys = [] def eventFilter(self, source, event): if event.type() == QEvent.KeyPress: if int(event.key()) not in self.pressedKeys: self.pressedKeys.append(int(event.key())) print(self.pressedKeys) elif event.type() == QEvent.KeyRelease: if int(event.key()) in self.pressedKeys: self.pressedKeys.remove(int(event.key())) print(self.pressedKeys) return super().eventFilter(source, event) if __name__ == "__main__": app = QApplication(sys.argv) demo = MainWindow() demo.show() sys.exit(app.exec_())
代码2:重写按键事件方法
import sys from PyQt5.QtWidgets import QApplication, QWidget class MainWindow(QWidget): def __init__(self): super().__init__() self.pressedKeys = [] def keyPressEvent(self, event): if int(event.key()) not in self.pressedKeys: self.pressedKeys.append(int(event.key())) print(self.pressedKeys) def keyReleaseEvent(self, event): if int(event.key()) in self.pressedKeys: self.pressedKeys.remove(int(event.key())) print(self.pressedKeys) if __name__ == "__main__": app = QApplication(sys.argv) demo = MainWindow() demo.show() sys.exit(app.exec_())
运行后遇到的问题:
- 按住单个按键时,输出列表会在包含该键值和空列表之间来回切换;
- 按住多个按键时,最后按下的键会反复被添加和移除,看起来按住按键时持续触发了
KeyRelease事件。
解决方案
问题根源是系统的按键自动重复机制:当按住按键不放时,系统会持续发送KeyPress事件(自动重复),而Qt会将这些自动重复的事件标记为isAutoRepeat() == True。如果不区分这些自动重复事件,会导致错误地处理按键状态。
修改代码,在处理按键事件前先判断是否为自动重复事件,若是则跳过处理:
修改后的事件过滤器版本
import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QEvent class MainWindow(QWidget): def __init__(self): super().__init__() QApplication.instance().installEventFilter(self) self.pressedKeys = [] def eventFilter(self, source, event): # 跳过自动重复事件 if event.isAutoRepeat(): return super().eventFilter(source, event) if event.type() == QEvent.KeyPress: key = int(event.key()) if key not in self.pressedKeys: self.pressedKeys.append(key) print(self.pressedKeys) elif event.type() == QEvent.KeyRelease: key = int(event.key()) if key in self.pressedKeys: self.pressedKeys.remove(key) print(self.pressedKeys) return super().eventFilter(source, event) if __name__ == "__main__": app = QApplication(sys.argv) demo = MainWindow() demo.show() sys.exit(app.exec_())
修改后的重写事件方法版本
import sys from PyQt5.QtWidgets import QApplication, QWidget class MainWindow(QWidget): def __init__(self): super().__init__() self.pressedKeys = [] def keyPressEvent(self, event): if event.isAutoRepeat(): return key = int(event.key()) if key not in self.pressedKeys: self.pressedKeys.append(key) print(self.pressedKeys) def keyReleaseEvent(self, event): if event.isAutoRepeat(): return key = int(event.key()) if key in self.pressedKeys: self.pressedKeys.remove(key) print(self.pressedKeys) if __name__ == "__main__": app = QApplication(sys.argv) demo = MainWindow() demo.show() sys.exit(app.exec_())
注意事项
- 上述代码仅能捕获当前GUI程序处于激活状态时的按键事件,如果需要捕获全局按键(即使程序后台运行),PyQt5本身无法直接实现,此时可以考虑使用专门的全局键盘监听库,比如
pynput。
内容的提问来源于stack exchange,提问作者Matt Pitkin
相关产品推荐
相关产品推荐

