Загрузка данных
import sys
import keyboard
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPainter, QPen, QColor, QCursor
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSpinBox, QPushButton
class DrawingOverlay(QWidget):
def __init__(self):
super().__init__()
# Базовые флаги для работы поверх всех окон
self.setWindowFlags(
Qt.WindowType.FramelessWindowHint |
Qt.WindowType.WindowStaysOnTopHint |
Qt.WindowType.SubWindow
)
self.start_point = None
self.end_point = None
self.line_thickness = 5
self.is_active = False
self.line_color = QColor(0, 255, 128, 255)
def resize_to_screen(self):
screen = QApplication.primaryScreen().geometry()
self.setGeometry(screen)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
# Дымка во время выбора точек
if self.is_active and (not self.start_point or not self.end_point):
painter.fillRect(self.rect(), QColor(0, 0, 0, 40)) # Чуть затемняем для надежности
return
# Рисование линии
if self.start_point and self.end_point:
pen = QPen(self.line_color, self.line_thickness)
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
painter.setPen(pen)
painter.drawLine(self.start_point, self.end_point)
class SettingsWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Настройки Линии")
self.setFixedSize(320, 160)
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
self.overlay = DrawingOverlay()
self.overlay.resize_to_screen()
# Изначально окно полностью прозрачно и невидимо для мыши
self.overlay.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True)
self.overlay.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
self.overlay.show()
self.current_hotkey = "f4"
self.is_recording_hotkey = False
keyboard.add_hotkey(self.current_hotkey, self.toggle_drawing_mode)
self.init_ui()
self.click_count = 0
def init_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
thick_layout = QHBoxLayout()
thick_label = QLabel("Толщина линии (px):")
self.thick_spin = QSpinBox()
self.thick_spin.setRange(1, 50)
self.thick_spin.setValue(5)
self.thick_spin.valueChanged.connect(self.change_thickness)
thick_layout.addWidget(thick_label)
thick_layout.addWidget(self.thick_spin)
layout.addLayout(thick_layout)
hk_layout = QHBoxLayout()
hk_label = QLabel("Клавиша активации:")
self.hk_button = QPushButton(self.current_hotkey.upper())
self.hk_button.clicked.connect(self.start_hotkey_recording)
hk_layout.addWidget(hk_label)
hk_layout.addWidget(self.hk_button)
layout.addLayout(hk_layout)
self.status_label = QLabel(f"Статус: Ожидание. Нажмите {self.current_hotkey.upper()}")
self.status_label.setStyleSheet("color: gray;")
layout.addWidget(self.status_label)
def change_thickness(self, value):
self.overlay.line_thickness = value
self.overlay.update()
def start_hotkey_recording(self):
self.is_recording_hotkey = True
self.hk_button.setText("Нажмите клавишу...")
self.status_label.setText("Жду нажатия на клавиатуре...")
try:
keyboard.remove_hotkey(self.current_hotkey)
except Exception:
pass
keyboard.hook(self.on_key_pressed)
def on_key_pressed(self, event):
if self.is_recording_hotkey and event.event_type == keyboard.KEY_DOWN:
new_key = event.name
keyboard.unhook(self.on_key_pressed)
self.current_hotkey = new_key
self.is_recording_hotkey = False
keyboard.add_hotkey(self.current_hotkey, self.toggle_drawing_mode)
self.hk_button.setText(new_key.upper())
self.status_label.setText(f"Клавиша изменена на {new_key.upper()}")
def toggle_drawing_mode(self):
if self.is_recording_hotkey:
return
if not self.overlay.is_active:
# АКТИВАЦИЯ РЕЖИМА ВЫБОРА ТОЧЕК
self.overlay.is_active = True
self.click_count = 0
self.overlay.start_point = None
self.overlay.end_point = None
# Меняем системные флаги окна: убираем сквозной клик (теперь окно ЛОВИТ мышь)
self.overlay.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, False)
# Принудительно заставляем Windows передать фокус ввода на наше окно
self.overlay.setWindowFlags(self.overlay.windowFlags() & ~Qt.WindowType.WindowTransparentForInput)
# Показываем стрелку курсора
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.ArrowCursor))
self.overlay.mousePressEvent = self.handle_overlay_click
# Показываем оверлей во весь экран поверх игры
self.overlay.showFullScreen()
self.overlay.raise_()
self.overlay.activateWindow()
self.overlay.update()
self.status_label.setText("Режим включен! Кликни точку 1")
self.status_label.setStyleSheet("color: green;")
else:
self.reset_overlay()
def handle_overlay_click(self, event):
if event.button() == Qt.MouseButton.LeftButton:
if self.click_count == 0:
self.overlay.start_point = event.position().toPoint()
self.click_count += 1
self.status_label.setText("Точка 1 есть. Кликни точку 2")
self.overlay.update()
elif self.click_count == 1:
self.overlay.end_point = event.position().toPoint()
# ЛИНИЯ ГОТОВА: Возвращаем полную сквозную прозрачность для кликов
self.overlay.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
# Возвращаем управление курсором игре
QApplication.restoreOverrideCursor()
self.overlay.update()
self.status_label.setText(f"Линия готова! {self.current_hotkey.upper()} — стереть")
self.status_label.setStyleSheet("color: blue;")
self.click_count += 1
def reset_overlay(self):
self.overlay.is_active = False
self.overlay.start_point = None
self.overlay.end_point = None
# Включаем сквозной клик обратно
self.overlay.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
# Сбрасываем курсор на всякий случай
while QApplication.overrideCursor() is not None:
QApplication.restoreOverrideCursor()
self.overlay.update()
self.status_label.setText(f"Сброшено. Нажмите {self.current_hotkey.upper()}")
self.status_label.setStyleSheet("color: gray;")
def closeEvent(self, event):
self.overlay.close()
keyboard.unhook_all()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = SettingsWindow()
window.show()
sys.exit(app.exec())