Grabador y reproductor de teclado y mouse

Un pequeño programa desarrollado con Python 2.7, PyQt 4 y AutoPy para grabar la entrada del usuario (mouse y teclado), y luego simularla. Utiliza Qt para la interfaz gráfica, como también para capturar los eventos de presión de teclas, y AutoPy para reproducirlas. Gracias a la portabilidad de estos módulos, el código corre en las distintas plataformas. Puedes descargar el código de fuente como archivo ZIP desde este enlace.

Vista previa

Vista previa

Puedes ver el video del programa en funcionamiento en nuestra página de Google+.

Utilización

Sencillamente se presiona el botón «Record» para comenzar con la grabación. El programa torna a pantalla completa para capturar la totalidad de los eventos. Una vez finalizado, se presiona la tecla asignada para detener la grabación (Esc por defecto). El botón «Play» estará ahora habilitado para reproducir los eventos.

Limitaciones

Las teclas Alt, Control, Shift y Meta son soportadas como pulsaciones convencionales, no así como modificadores. Algunos programas pueden obtener la entrada del usuario por otros métodos, especialmente los juegos, por lo que las pulsaciones enviadas serán ignoradas.

Código de fuente

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from threading import Thread
from time import sleep, time

import autopy
from PyQt4.QtCore import Qt, QEvent
from PyQt4.QtGui import (QApplication, QMainWindow, QLabel, QLineEdit,
                         QPainter, QPushButton, QKeyEvent, QKeySequence,
                         QSlider, QVBoxLayout, QWidget)


additional_key_names = {
    Qt.Key_Control: "Ctrl",
    Qt.Key_Alt: "Alt",
    Qt.Key_AltGr: "Alt Gr",
    Qt.Key_Shift: "Shift",
    Qt.Key_Meta: "Meta"
}

# Nombres de teclas de Qt a AutoPy
autopy_keys = {
    "F1": autopy.key.K_F1,
    "F2": autopy.key.K_F2,
    "F3": autopy.key.K_F3,
    "F4": autopy.key.K_F4,
    "F5": autopy.key.K_F5,
    "F6": autopy.key.K_F6,
    "F7": autopy.key.K_F7,
    "F8": autopy.key.K_F8,
    "F9": autopy.key.K_F9,
    "F10": autopy.key.K_F10,
    "F11": autopy.key.K_F11,
    "F12": autopy.key.K_F12,
    "Meta": autopy.key.K_META,
    "Shift": autopy.key.K_SHIFT,
    "CapsLock": autopy.key.K_CAPSLOCK,
    "Return": autopy.key.K_RETURN,
    "Esc": autopy.key.K_ESCAPE,
    "Space": " ",
    "PgUp": autopy.key.K_PAGEUP,
    "PgDown": autopy.key.K_PAGEDOWN,
    "Del": autopy.key.K_DELETE,
    "End": autopy.key.K_END,
    "Alt": autopy.key.K_ALT,
    "Ctrl": autopy.key.K_CONTROL,
    "Backspace": autopy.key.K_BACKSPACE,
}

EVENT_KEYBOARD = 0
EVENT_MOUSE = 1


class Ellipse(QWidget):
    """
    Simple círculo.
    """
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawEllipse(0, 0, 50, 50)


class KeySelector(QLineEdit):
    """
    Caja de texto para seleccionar una tecla.
    """
    
    def __init__(self, parent, prompt, default_key):
        self.prompt = prompt
        self.key = default_key
        QLineEdit.__init__(self, parent)
        self.keyReleaseEvent(
            QKeyEvent(QEvent.KeyRelease, default_key,
                      Qt.KeyboardModifiers())
        )
    
    def keyPressEvent(self, event):
        pass
    
    def keyReleaseEvent(self, event):
        key_name = (additional_key_names[event.key()] if
                event.key() in additional_key_names
            else
                QKeySequence(event.key()).toString())
        self.key = event.key()
        self.setText(self.prompt.format(key_name))


class Window(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setWindowTitle("Input Recorder")
        
        self.recording = False
        self.recorded_events = []
        
        self.record_button = QPushButton("Record", self)
        self.record_button.clicked.connect(self.start_record)
        
        self.play_button = QPushButton("Play", self)
        self.play_button.clicked.connect(self.play)
        self.play_button.setEnabled(False)
        
        self.key_label = QLabel(self)
        self.key_label.setGeometry(10, 10, 250, 50)
        self.key_label.setStyleSheet("font-size: 30px;")
        
        self.transparency_slider = QSlider(Qt.Horizontal, self)
        self.transparency_slider.setMaximum(80)
        self.transparency_slider.setSliderPosition(40)
        self.transparency_slider.valueChanged.connect(
            self.set_transparency_value)
        
        self.transparency_label = QLabel("Transparency: 40%.", self)
        
        self.key_selector = KeySelector(self, "Stop recording with: {0}",
                                        Qt.Key_Escape)
        
        self.ellipse = Ellipse(self)
        self.ellipse.resize(60, 60)
        self.ellipse.hide()
        
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.record_button)
        self.layout.addWidget(self.play_button)
        self.layout.addWidget(self.transparency_slider)
        self.layout.addWidget(self.transparency_label)
        self.layout.addWidget(self.key_selector)
        
        self.central_widget = QWidget(self)
        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)
        
        self.resize(500, 400)
    
    def add_event(self, event, *params):
        sleep_time = time() - self.last_time
        self.last_time = time()
        self.recorded_events.append((sleep_time, event, params))
    
    def events_player_thread(self):
        self.showMinimized()
        for event in self.recorded_events:
            sleep_time, event_type, params = event
            sleep(sleep_time)
            
            if event_type == EVENT_KEYBOARD:
                qt_key = str(params[0])
                # Enviar pulsación de tecla.
                autopy.key.tap(
                    autopy_keys[qt_key] if qt_key in autopy_keys else
                    qt_key.lower()
                )
            elif event_type == EVENT_MOUSE:
                x, y = params
                # Enviar pulsación del ratón.
                autopy.mouse.move(x + 10, y)
                autopy.mouse.click()
        # Restaurar ventana.
        self.showNormal()
    
    def mousePressEvent(self, event):
        if self.recording:
            # Dibujar un círculo donde se haya presionado.
            self.ellipse.move(event.x() - 25, event.y() - 25)
            self.ellipse.show()
            self.add_event(EVENT_MOUSE, event.x(), event.y())
        return QMainWindow.mousePressEvent(self, event)
    
    def mouseReleaseEvent(self, event):
        if self.recording:
            self.ellipse.hide()
        return QMainWindow.mouseReleaseEvent(self, event)
    
    def keyPressEvent(self, event):
        if self.recording:
            if event.key() == self.key_selector.key:
                self.stop_record()
            else:
                # Buscar un nombre predefinido disponible.
                # De no encontrarlo, utilizar el nombre de la tecla de Qt.
                key_name = (additional_key_names[event.key()] if
                            event.key() in additional_key_names else
                            QKeySequence(event.key()).toString())
                self.key_label.setText(key_name)
                self.add_event(EVENT_KEYBOARD, key_name)
        return QMainWindow.keyPressEvent(self, event)
    
    def play(self):
        # Evitar bloquear el bucle principal.
        Thread(target=self.events_player_thread).start()
    
    def set_transparency_value(self, value):
        self.transparency_label.setText("Transparency: %d%%." % value)
    
    def start_record(self):
        self.recording = True
        self.recorded_events = []
        self.last_time = time()
        # Ocultar controles.
        self.central_widget.hide()
        # Establecer transparencia.
        self.setWindowOpacity(
            (100. - self.transparency_slider.value()) / 100.
        )
        # Pantalla completa.
        self.showFullScreen()
    
    def stop_record(self):
        # Restaurar la configuración inicial.
        self.recording = False
        self.central_widget.show()
        self.setWindowOpacity(1.0)
        self.showNormal()
        self.key_label.setText("")
        if self.recorded_events:
            self.play_button.setEnabled(True)


if __name__ == "__main__":
    app = QApplication([])
    window = Window()
    window.show()
    sys.exit(app.exec_())

Curso online 👨‍💻

¡Ya lanzamos el curso oficial de Recursos Python en Udemy! Un curso moderno para aprender Python desde cero con programación orientada a objetos, SQL y tkinter en 2024.

Consultoría 💡

Ofrecemos servicios profesionales de desarrollo y capacitación en Python a personas y empresas. Consultanos por tu proyecto.

1 comentario.

Deja una respuesta