我决定制作一个原始程序来拦截热键并将其输出到屏幕以创建教程视频。目前,除了小键盘数字和小键盘数学符号(小键盘“0”和“.”也无法正确显示)之外,一切都按我想要的方式工作。帮助完成该计划。与其他键一样,希望数字键盘键可以独立显示,也可以与 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
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.char is not None and ord(key.char) < 32: # check if the key is a control character
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): # check if the key is a digit or a letter
self.key_label.setText("'{0}' pressed".format(chr(key.vk)))
else:
# Convert to English layout
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.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): # check if the key is a digit or a letter
self.key_label.setText("{0} released".format(chr(key.vk)))
else:
# Convert to English layout
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):
# Define a dictionary to map Ukrainian characters to English
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',
'б': ',', 'ю': '.', 'ґ': '`'
}
# Convert the character to lower case
if char is not None:
char = char.lower()
# Check if the character is in the dictionary
if char in uk_to_en:
return uk_to_en[char]
else:
return 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):
print('mouse')
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()
更新: 当我按下数字键盘上的按键时,拦截器会显示字母:“1”=“a”,“2”=“b”,“3”=“c”,“4”=“d”,“5” =“e”、“6”=“f”、“7”=“g”、“8”=“h”、“9”=“i”。除了数学符号之外,小键盘还显示字母:“/”=“o”、“*”=“j”、“-”=“m”、“+”=“k”、“.” =“n” 操作系统 - Windows 11。 我使用的键盘:
您将按键代码与 ascii 代码混淆了。
虽然其中一些实际上是一致的(特别是数字和大写字母),但它们不能用作某种引用转换。这些键码的相似性只是因为出于逻辑原因,使用已知的现有值(ASCII 表)更有意义。
通过虚拟按键代码表(如this),您可以轻松发现数字键盘按键的代码实际上与您错误的输出相匹配:例如,数字键盘上的1对应于虚拟键
97
,如果您尝试将它与 a
一起使用,它会给您 chr()
。
因此,解决方案很简单:不要使用
chr()
;最好使用已知的字母和键映射创建一个字典,可能作为全局常量,并最终使用 vk
和 char
的回退输出来处理意外的键。