Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- from pynput import mouse, keyboard
- import time
- import threading
- import shelve
- import os
- from tkinter import messagebox, simpledialog, Listbox
- class MouseRecorderGUI:
- def __init__(self, root):
- self.root = root
- self.recorded_events = []
- self.recording = False
- self.playback_thread = None
- self.playback_stop_requested = False
- self.loop_counter = 0
- self.start_time = None
- self.recordings_dir = self.get_recordings_dir()
- self.create_gui()
- self.create_hotkey_listener()
- def get_recordings_dir(self):
- dir_name = "recordings"
- os.makedirs(dir_name, exist_ok=True)
- return dir_name
- def create_hotkey_listener(self):
- # Define the hotkeys
- self.hotkeys = {
- 'start': '<ctrl>+<alt>+s',
- 'stop': '<ctrl>+<alt>+t',
- 'save': '<ctrl>+<alt>+e',
- 'load': '<ctrl>+<alt>+l',
- 'playback': '<ctrl>+<alt>+p'
- }
- self.keyboard_listener = keyboard.GlobalHotKeys(self.create_hotkey_callbacks())
- self.keyboard_listener.start()
- def create_gui(self):
- # Create the GUI elements here
- self.event_listbox = tk.Listbox(self.root, width=50, height=15)
- self.start_button = tk.Button(self.root, text="Start Recording", command=self.start_recording)
- self.stop_button = tk.Button(self.root, text="Stop Recording", state=tk.DISABLED, command=self.stop_recording)
- self.playback_button = tk.Button(self.root, text="Playback", state=tk.DISABLED, command=self.start_playback)
- self.save_button = tk.Button(self.root, text="Save", state=tk.DISABLED, command=self.save_events)
- self.load_button = tk.Button(self.root, text="Load", command=self.load_events)
- self.loop_counter_label = tk.Label(self.root, text="Loop Count: 0")
- self.repeat_count_spinbox = tk.Spinbox(self.root, from_=1, to=100, width=5)
- self.playback_speed_scale = tk.Scale(self.root, from_=0.1, to=2.0, resolution=0.1, orient=tk.HORIZONTAL)
- self.configure_playback_button = tk.Button(self.root, text="Configure Playback", command=self.configure_playback)
- # Pack GUI elements here
- self.event_listbox.pack()
- self.start_button.pack()
- self.stop_button.pack()
- self.playback_button.pack()
- self.save_button.pack()
- self.load_button.pack()
- self.loop_counter_label.pack()
- self.repeat_count_spinbox.pack()
- self.playback_speed_scale.pack()
- self.configure_playback_button.pack()
- def create_hotkey_callbacks(self):
- # Hotkey callbacks
- return {
- self.hotkeys['start']: self.start_recording,
- self.hotkeys['stop']: self.stop_recording,
- self.hotkeys['save']: self.save_events,
- self.hotkeys['load']: self.load_events,
- self.hotkeys['playback']: self.start_playback_from_hotkey
- }
- def start_recording(self):
- if not self.recording:
- self.recording = True
- self.recorded_events = []
- self.start_time = time.time()
- self.mouse_listener = mouse.Listener(on_click=self.on_click, on_move=self.on_move)
- self.mouse_listener.start()
- self.toggle_buttons_during_recording(True)
- def stop_recording(self):
- if self.recording:
- self.recording = False
- self.mouse_listener.stop()
- self.toggle_buttons_during_recording(False)
- self.update_event_listbox()
- def toggle_buttons_during_recording(self, recording):
- # Enable/Disable buttons based on whether we are recording
- state = tk.DISABLED if recording else tk.NORMAL
- self.start_button.config(state=tk.DISABLED if recording else tk.NORMAL)
- self.stop_button.config(state=tk.NORMAL if recording else tk.DISABLED)
- self.playback_button.config(state=state)
- self.save_button.config(state=state)
- self.load_button.config(state=state)
- def on_click(self, x, y, button, pressed):
- if self.recording:
- event_time = time.time() - self.start_time
- self.recorded_events.append(('click', x, y, button.name, pressed, event_time))
- def on_move(self, x, y):
- if self.recording:
- event_time = time.time() - self.start_time
- self.recorded_events.append(('move', x, y, event_time))
- def start_playback_from_hotkey(self):
- if self.playback_button['state'] == tk.NORMAL:
- self.start_playback()
- def start_playback(self):
- if not self.playback_thread or not self.playback_thread.is_alive():
- repeat_count = int(self.repeat_count_spinbox.get())
- playback_speed = self.playback_speed_scale.get()
- self.playback_thread = threading.Thread(target=self.playback_events, args=(repeat_count, playback_speed))
- self.playback_thread.start()
- def playback_events(self, repeat_count, playback_speed):
- # Logic for playing back the events
- try:
- for i in range(repeat_count):
- if self.playback_stop_requested:
- break
- self.loop_counter = i + 1
- self.root.after(0, self.update_loop_counter_label)
- last_event_time = 0
- for event in self.recorded_events:
- if self.playback_stop_requested:
- break
- event_type = event[0]
- event_time = event[-1] # Event time is always the last element
- time.sleep(max(0, (event_time - last_event_time) / playback_speed))
- last_event_time = event_time
- if event_type == 'click':
- _, x, y, button_name, pressed, _ = event
- button = getattr(mouse.Button, button_name) if button_name else None
- mouse_controller = mouse.Controller()
- mouse_controller.position = (x, y)
- if pressed:
- mouse_controller.press(button)
- else:
- mouse_controller.release(button)
- elif event_type == 'move':
- _, x, y, _ = event
- mouse_controller = mouse.Controller()
- mouse_controller.position = (x, y)
- self.playback_stop_requested = False
- except Exception as e:
- messagebox.showerror("Playback Error", str(e))
- def save_events(self):
- recording_name = simpledialog.askstring("Save Recording", "Enter a name for the recording:")
- if recording_name:
- recording_dir = os.path.join(self.recordings_dir, recording_name.replace(' ', '_'))
- os.makedirs(recording_dir, exist_ok=True)
- filepath = os.path.join(recording_dir, 'events')
- with shelve.open(filepath) as shelf:
- shelf['events'] = self.recorded_events
- messagebox.showinfo("Success", "Events saved successfully.")
- def load_events(self):
- recording_name = self.choose_recording()
- if recording_name:
- filepath = os.path.join(self.recordings_dir, recording_name, 'events')
- with shelve.open(filepath) as shelf:
- self.recorded_events = shelf['events']
- self.update_event_listbox()
- # Enable playback button if events were loaded
- self.playback_button.config(state=tk.NORMAL)
- messagebox.showinfo("Success", "Events loaded successfully.")
- def choose_recording(self):
- recordings = [d for d in os.listdir(self.recordings_dir) if os.path.isdir(os.path.join(self.recordings_dir, d))]
- if not recordings:
- messagebox.showinfo("Load Recording", "No recordings found.")
- return None
- recording_name = simpledialog.askstring("Load Recording", "Enter the recording name:")
- if recording_name in recordings:
- return recording_name
- else:
- messagebox.showerror("Error", "Recording not found.")
- return None
- def update_event_listbox(self):
- self.event_listbox.delete(0, tk.END)
- for event in self.recorded_events:
- event_type, x, y, *rest = event
- event_str = f"{event_type} at ({x}, {y})"
- self.event_listbox.insert(tk.END, event_str)
- def update_loop_counter_label(self):
- self.loop_counter_label.config(text=f"Loop Count: {self.loop_counter}")
- def configure_playback(self):
- config_window = tk.Toplevel(self.root)
- config_window.title("Playback Configuration")
- # Create a listbox to list all recordings
- recordings_listbox = Listbox(config_window, selectmode=tk.EXTENDED)
- recordings_listbox.pack()
- # Populate the listbox with available recordings
- for recording in os.listdir(self.recordings_dir):
- recordings_listbox.insert(tk.END, recording)
- # Add buttons to add recordings to the playback queue
- tk.Button(config_window, text="Add to Playback Queue",
- command=lambda: self.add_to_playback_queue(recordings_listbox)).pack()
- # Add buttons to remove recordings from the playback queue
- tk.Button(config_window, text="Remove from Playback Queue",
- command=lambda: self.remove_from_playback_queue(recordings_listbox)).pack()
- # Add listbox to show current playback queue
- self.playback_queue_listbox = Listbox(config_window)
- self.playback_queue_listbox.pack()
- # Add playback controls for the queue
- tk.Button(config_window, text="Play Queue",
- command=self.playback_queue).pack()
- def add_to_playback_queue(self, recordings_listbox):
- selections = recordings_listbox.curselection()
- for i in selections:
- self.playback_queue_listbox.insert(tk.END, recordings_listbox.get(i))
- def remove_from_playback_queue(self, recordings_listbox):
- selections = self.playback_queue_listbox.curselection()
- # Must delete from the end to avoid index shifting issues
- for i in reversed(selections):
- self.playback_queue_listbox.delete(i)
- def playback_queue(self):
- # Logic to playback the queue
- queue = list(self.playback_queue_listbox.get(0, tk.END))
- for recording_name in queue:
- filepath = os.path.join(self.recordings_dir, recording_name, 'events')
- with shelve.open(filepath) as shelf:
- self.recorded_events = shelf['events']
- # Playback each recording
- self.start_playback()
- if __name__ == "__main__":
- root = tk.Tk()
- app = MouseRecorderGUI(root)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement