数字小键盘按键截获显示异常,求助完善PyQt6+pynput程序
解决小键盘按键显示错误问题
问题根源
你的程序通过key.vk直接转换为字符,但小键盘按键的虚拟键码(VK)和主键盘字符的ASCII码不匹配。比如小键盘1的VK码是97(对应ASCII的'a'),所以会显示成a而非数字1,其他小键盘符号同理。
修复方案
- 新增小键盘VK码到对应字符的映射字典,覆盖数字、运算符号和小数点
- 在按键处理逻辑中优先判断是否为小键盘按键,匹配正确的显示字符
- 保留原有组合键(Ctrl/Shift/Alt)的处理逻辑,确保小键盘按键和组合键搭配时也能正确显示
修改后的完整代码
from PyQt6 import QtWidgets, QtCore from PyQt6.QtGui import QFont from pynput import keyboard, mouse class KeyLoggerApp(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ctrl_pressed = False # 小键盘虚拟键码到对应字符的映射(Windows系统) self.numpad_vk_map = { 96: '0', 97: '1', 98: '2', 99: '3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9', 111: '/', 106: '*', 109: '-', 107: '+', 110: '.' } self.setMinimumSize(400, 300) font = QFont() font.setPointSize(18) self.layout = QtWidgets.QVBoxLayout() self.ctrl_label = QtWidgets.QLabel(self) self.ctrl_label.setFont(font) self.shift_label = QtWidgets.QLabel(self) self.shift_label.setFont(font) self.alt_label = QtWidgets.QLabel(self) self.alt_label.setFont(font) self.mouse_left_label = QtWidgets.QLabel(self) self.mouse_left_label.setFont(font) self.mouse_middle_label = QtWidgets.QLabel(self) self.mouse_middle_label.setFont(font) self.mouse_right_label = QtWidgets.QLabel(self) self.mouse_right_label.setFont(font) self.key_label = QtWidgets.QLabel(self) self.key_label.setFont(font) self.layout.addWidget(self.ctrl_label) self.layout.addWidget(self.shift_label) self.layout.addWidget(self.alt_label) self.layout.addWidget(self.mouse_left_label) self.layout.addWidget(self.mouse_middle_label) self.layout.addWidget(self.mouse_right_label) self.layout.addWidget(self.key_label) self.central_widget = QtWidgets.QWidget() self.central_widget.setLayout(self.layout) self.setCentralWidget(self.central_widget) self.toggle_button = QtWidgets.QPushButton("Toggle Always on Top", self) self.toggle_button.clicked.connect(self.toggle_on_top) self.addToolBar(QtCore.Qt.ToolBarArea.TopToolBarArea, self.create_toolbar()) self.key_listener = keyboard.Listener( on_press=self.on_key_press, on_release=self.on_key_release) self.key_listener.start() self.mouse_listener = mouse.Listener( on_click=self.on_mouse_click, on_release=self.on_mouse_release) self.mouse_listener.start() def create_toolbar(self): toolbar = QtWidgets.QToolBar() toolbar.addWidget(self.toggle_button) return toolbar def toggle_on_top(self): if self.windowFlags() & QtCore.Qt.WindowType.WindowStaysOnTopHint: self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowStaysOnTopHint) else: self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint) self.show() def on_key_press(self, key): if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r: self.ctrl_label.setText('Ctrl pressed') elif key == keyboard.Key.shift: self.shift_label.setText('Shift pressed') elif key == keyboard.Key.alt_l or key == keyboard.Key.alt_r: self.alt_label.setText('Alt pressed') elif key == keyboard.Key.space: self.key_label.setText('Space pressed') else: try: if isinstance(key, keyboard.KeyCode): # 优先处理小键盘按键 if key.vk in self.numpad_vk_map: self.key_label.setText("'{0}' pressed".format(self.numpad_vk_map[key.vk])) elif key.char is not None and ord(key.char) < 32: self.key_label.setText("'{0}' pressed".format(chr(ord(key.char) + 64).upper())) elif (key.vk >= 48 and key.vk <= 57) or (key.vk >= 65 and key.vk <= 90) or ( key.vk >= 97 and key.vk <= 122): self.key_label.setText("'{0}' pressed".format(chr(key.vk))) else: key_char = self.convert_to_english_layout(key.char) self.key_label.setText("alphanumeric key '{0}' pressed".format(key_char.upper())) except AttributeError: self.key_label.setText("special key '{0}' pressed".format(str(key).upper())) def on_key_release(self, key): if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r: self.ctrl_label.clear() elif key == keyboard.Key.shift: self.shift_label.clear() elif key == keyboard.Key.alt_l or key == keyboard.Key.alt_r: self.alt_label.clear() else: if isinstance(key, keyboard.KeyCode): # 优先处理小键盘按键释放 if key.vk in self.numpad_vk_map: self.key_label.setText("{0} released".format(self.numpad_vk_map[key.vk])) elif key.char is not None and ord(key.char) < 32: self.key_label.setText("{0} released".format(str(chr(ord(key.char) + 64).upper()))) elif (key.vk >= 48 and key.vk <= 57) or (key.vk >= 65 and key.vk <= 90) or ( key.vk >= 97 and key.vk <= 122): self.key_label.setText("{0} released".format(chr(key.vk))) else: key_char = self.convert_to_english_layout(key.char) if key_char is not None: self.key_label.setText("{0} released".format(key_char.upper())) else: self.key_label.setText("None released") elif key == keyboard.Key.space: self.key_label.setText('Space released') else: self.key_label.setText("{0} released".format(str(key).upper())) def convert_to_english_layout(self, char): uk_to_en = { 'й': 'q', 'ц': 'w', 'у': 'e', 'к': 'r', 'е': 't', 'н': 'y', 'г': 'u', 'ш': 'i', 'щ': 'o', 'з': 'p', 'х': '[', 'ї': ']', 'ф': 'a', 'і': 's', 'в': 'd', 'а': 'f', 'п': 'g', 'р': 'h', 'о': 'j', 'л': 'k', 'д': 'l', 'ж': ';', 'є': '\'', 'я': 'z', 'ч': 'x', 'с': 'c', 'м': 'v', 'и': 'b', 'т': 'n', 'ь': 'm', 'б': ',', 'ю': '.', 'ґ': '`' } if char is not None: char = char.lower() return uk_to_en.get(char, char) def on_mouse_click(self, x, y, button, pressed): if button == mouse.Button.left: self.mouse_left_label.setText('Mouse left button pressed' if pressed else '') elif button == mouse.Button.middle: self.mouse_middle_label.setText('Mouse middle button pressed' if pressed else '') elif button == mouse.Button.right: self.mouse_right_label.setText('Mouse right button pressed' if pressed else '') def on_mouse_release(self, x, y, button): if button == mouse.Button.left: self.mouse_left_label.clear() elif button == mouse.Button.middle: self.mouse_middle_label.clear() elif button == mouse.Button.right: self.mouse_right_label.clear() if __name__ == "__main__": app = QtWidgets.QApplication([]) window = KeyLoggerApp() window.show() app.exec()
说明
- 新增了
self.numpad_vk_map字典,对应Windows系统中小键盘按键的虚拟键码和实际显示字符 - 在
on_key_press和on_key_release方法中,优先判断按键是否属于小键盘,匹配正确的显示内容 - 保留了原有功能的完整性,包括组合键检测、鼠标按键监控和输入法布局转换
内容的提问来源于stack exchange,提问作者arachnoden
相关产品推荐
相关产品推荐

