viewing paste Unknown #58921 | Python

Posted on the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
import tkinter as tk
import time
import pyautogui
import threading
from pynput import mouse, keyboard
 
 
class MacroRecorder:
    def __init__(self, root):
        self.root = root
        self.root.title("Запись и воспроизведение действий")
        self.recording = False
        self.actions = []
        self.last_position = None
        self.min_distance = 10  # Минимальное расстояние между записываемыми движениями мыши
        self.speed_multiplier = 2.0  # Множитель скорости (больше = быстрее)
 
        # Создаем описание использования
        description = """
        Нажмите F9, чтобы начать запись действий мыши.
        Нажмите F9 снова, чтобы остановить запись.
        Нажмите F10, чтобы воспроизвести записанные действия.
        """
        desc_label = tk.Label(root, text=description, justify=tk.LEFT)
        desc_label.pack(pady=10, padx=10)
 
        # Настройки скорости
        speed_frame = tk.Frame(root)
        speed_frame.pack(pady=5)
 
        tk.Label(speed_frame, text="Скорость воспроизведения:").pack(side=tk.LEFT)
        self.speed_var = tk.DoubleVar(value=self.speed_multiplier)
        self.speed_scale = tk.Scale(speed_frame, from_=0.5, to=10.0, resolution=0.5,
                                    orient=tk.HORIZONTAL, variable=self.speed_var,
                                    command=self.update_speed)
        self.speed_scale.pack(side=tk.LEFT, padx=5)
 
        # Статус
        self.status_label = tk.Label(root, text="Готов к записи")
        self.status_label.pack(pady=10)
 
        # Настройка мониторинга клавиатуры для горячих клавиш
        self.key_listener = keyboard.Listener(on_press=self.on_key_press)
        self.key_listener.start()
 
        # Инициализация слушателя мыши (будет запущен при записи)
        self.mouse_listener = None
 
    def update_speed(self, val):
        self.speed_multiplier = float(val)
 
    def on_key_press(self, key):
        try:
            if key == keyboard.Key.f9:
                self.toggle_recording()
            elif key == keyboard.Key.f10:
                self.playback()
        except AttributeError:
            pass
 
    def on_mouse_move(self, x, y):
        if self.recording:
            # Пропускаем запись мелких движений для оптимизации
            if self.last_position is None or self.calculate_distance(self.last_position, (x, y)) >= self.min_distance:
                self.actions.append(('move', time.time(), (x, y), None))
                self.last_position = (x, y)
 
    def calculate_distance(self, pos1, pos2):
        return ((pos1[0] - pos2[0]) ** 2 + (pos1[1] - pos2[1]) ** 2) ** 0.5
 
    def on_mouse_click(self, x, y, button, pressed):
        if self.recording:
            state = 'down' if pressed else 'up'
            btn = 'left' if button == mouse.Button.left else 'right'
            self.actions.append(('click', time.time(), (x, y), (btn, state)))
            self.last_position = (x, y)  # Обновляем последнюю позицию при клике
 
    def toggle_recording(self):
        if not self.recording:
            self.recording = True
            self.actions = []
            self.last_position = None
            self.status_label.config(text="Запись... (F9 для остановки)")
 
            # Запускаем слушателя мыши
            self.mouse_listener = mouse.Listener(
                on_move=self.on_mouse_move,
                on_click=self.on_mouse_click
            )
            self.mouse_listener.start()
        else:
            self.recording = False
            if self.mouse_listener:
                self.mouse_listener.stop()
                self.mouse_listener = None
            self.status_label.config(text=f"Записано {len(self.actions)} действий")
 
    def playback(self):
        if not self.actions:
            self.status_label.config(text="Нет записанных действий")
            return
 
        self.status_label.config(text="Воспроизведение...")
        playback_thread = threading.Thread(target=self._playback)
        playback_thread.daemon = True
        playback_thread.start()
 
    def _playback(self):
        # Даем пользователю время переключиться из приложения
        time.sleep(1)
 
        # Если это первое действие, нет необходимости ждать
        last_time = self.actions[0][1]
 
        pyautogui.PAUSE = 0.01  # Установим минимальную паузу между действиями PyAutoGUI
 
        for action, timestamp, position, extra in self.actions:
            # Вычисляем, сколько времени нужно подождать, но с учетом скорости
            time_to_wait = (timestamp - last_time) / self.speed_multiplier
            # Ограничиваем максимальное время ожидания
            time_to_wait = min(time_to_wait, 0.2)
 
            if time_to_wait > 0:
                time.sleep(time_to_wait)
 
            x, y = position
 
            if action == 'move':
                pyautogui.moveTo(x, y, duration=0.01)  # Короткая продолжительность для быстрых движений
            elif action == 'click':
                btn, state = extra
                if state == 'down':
                    pyautogui.mouseDown(x=x, y=y, button=btn)
                elif state == 'up':
                    pyautogui.mouseUp(x=x, y=y, button=btn)
 
            last_time = timestamp
 
        # Обновляем статус в главном потоке
        self.root.after(0, lambda: self.status_label.config(text="Воспроизведение завершено"))
 
 
if __name__ == "__main__":
    root = tk.Tk()
    app = MacroRecorder(root)
    root.geometry("400x250")
    root.mainloop()
Viewed 549 times, submitted by Guest.