typewriter: бесплатная программа, которая введёт любой текст за вас
Эта статья поможет сэкономить время тем, кто сталкивается с подобными ситуациями - когда нужно перенести некоторые количества текста в такие места, куда он простым буфером обмена не переносится, например - в remote console виртуального или физического сервера, как Proxmox или iBMC / iLO.
Аналогичное решение "ClickPaste" (с гитхаба) показалось мне чуть менее удобным - захотелось доработать идею и сделать ввод более функциональным и наглядным.
Особенности моей реализации:
• запуск из одиночного исполняемого файла (portable) или из легковесного архива;
• многострочный ввод (симулирует нажатие клавиши enter между строк);
• редактирование и превью в окне ввода;
• режим медленного ввода;
• русская локализация
При нажатии на кнопку "Type for me!", программа переключится на предыдущее активное окно и симулирует либо быстрый ввод, либо с задержками между символами при отмеченном чекбоксе "Slow mode". Закрытие окна программы немедленно прекращает её выполнение.
Исходный код (C#)
using System.Text.RegularExpressions;
namespace typewriter
{
public partial class typewriter : Form
{
public typewriter()
{
InitializeComponent();
}
// Обработчик события для закрытия формы
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
// Останавливаем выполнение программы при закрытии окна
Environment.Exit(0);
}
private void button1_Click(object sender, EventArgs e)
{
string inputText = textBox1.Text;
// Переключаемся на предыдущее активное окно (Alt + Tab)
SendKeys.SendWait("%{TAB}");
// Задержка на время переключения окна
Thread.Sleep(1500); // полторы секунды
// Обработка текста
foreach (char c in inputText)
{
if (c == '\n') // Если символ - перенос строки
{
// Ничего не делаем, чтобы заблокировать лишние переносы строки
}
else
{
if (checkBox1.Checked) // Медленный режим
{
// Экранируем проблемные знаки
string txt = Regex.Replace(c.ToString(), "[+^%~(){}]", "{$0}");
SendKeys.SendWait(txt);
Thread.Sleep(100); // 100 миллисекунд между символами, если чекбокс включен
}
else
{
string txt = Regex.Replace(c.ToString(), "[+^%~(){}]", "{$0}");
SendKeys.SendWait(txt);
}
}
}
if (checkBox2.Checked) // Заканчивать клавишей "Ввод"
{
SendKeys.SendWait("{ENTER}");
}
}
private void checkBox3_CheckedChanged(object sender, EventArgs e)
{
this.TopMost = checkBox3.Checked; //Поверх всех окон
}
private void button2_Click(object sender, EventArgs e)
{
textBox1.Clear(); // Очистить
}
}
}
Исходный код (С++)
mainwindow.h
// MAINWINDOW.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void clearTextEdit();
void on_action1_triggered();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.cpp
//MAIN.CPP
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
//MAINWINDOW.CPP
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QThread>
#include <QCoreApplication>
#include <QKeyEvent>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_TranslucentBackground, true); // включаем прозрачность
this->setStyleSheet("background: rgba(255, 255, 255, 0.72);"); // настраиваем прозрачность
connect(ui->action1, &QAction::triggered, this, &MainWindow::on_action1_triggered);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::on_pushButton_clicked);
connect(ui->pushButton_2, &QPushButton::clicked, this, &MainWindow::clearTextEdit); // Добавляем обработчик для кнопки pushButton_2
ui->textEdit->setLineWrapMode(QTextEdit::NoWrap); // отключаем перенос строк
this->setFixedSize(this->size());
this->setWindowFlags(this->windowFlags() & ~Qt::WindowMaximizeButtonHint);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked() // Type for me! button
{
QProcess process;
process.start("xdotool", QStringList() << "key" << "Alt+Tab");
process.waitForFinished();
QThread::msleep(1500);
QString inputText = ui->textEdit->toPlainText();
QStringList lines = inputText.split('\n');
if (ui->checkBox->isChecked())
{
process.start("xdotool", QStringList() << "type" << "--delay" << "333" << lines.first());
process.waitForFinished();
process.start("xdotool", QStringList() << "key" << "Return");
process.waitForFinished();
}
else
{
process.start("xdotool", QStringList() << "type" << lines.first());
process.waitForFinished();
process.start("xdotool", QStringList() << "key" << "Return");
process.waitForFinished();
}
for (int i = 1; i < lines.size(); i++)
{
if (ui->checkBox->isChecked())
{
process.start("xdotool", QStringList() << "type" << "--delay" << "333" << lines[i]);
process.waitForFinished();
process.start("xdotool", QStringList() << "key" << "Return");
process.waitForFinished();
}
else
{
process.start("xdotool", QStringList() << "type" << lines[i]);
process.waitForFinished();
process.start("xdotool", QStringList() << "key" << "Return");
process.waitForFinished();
}
}
}
void MainWindow::clearTextEdit() // Clear button
{
ui->textEdit->clear();
}
void MainWindow::on_action1_triggered() // Drop-down menu button
{
QProcess::startDetached("gnome-terminal", QStringList() << "--" << "bash" << "-c" << "echo 'sudo apt-get install xdotool'; sudo apt-get install xdotool; exec bash");
disconnect(ui->action1, &QAction::triggered, this, &MainWindow::on_action1_triggered);
}
Ссылки на скачивание
Microsoft Windows
.exe file, 69MiB
English
SHA256 hash:
95E87C4BED4B9BA3FDC339D67AD9E4527C403F3102EFEBDF1C5EAAE170723464
Хеш-суммы в два клика
Русский
SHA256 hash:
FE5BC28F43F2ABFAF14BC99627422F167FF0B40C2624CD4E0C18D5CEBFBE18AF
Хеш-суммы в два клика
7Zip archive, 311KB
Русский
SHA256 hash:
FE5BC28F43F2ABFAF14BC99627422F167FF0B40C2624CD4E0C18D5CEBFBE18AF
Хеш-суммы в два клика
English
SHA256 hash:
908A888A5EDC8EC1D0BEAF415D7EFCCBB2DC17AD7343D1CCD274984A6072B3E3
Хеш-суммы в два клика
Linux
Ubuntu
Русский
SHA256 hash:
697D2A05DE35BBEB0B28726ECDC7BAD38EF25D1A6F020B122319DF9750992A53
Хеш-суммы в два клика
English
SHA256 hash:
D77F8272D30A4B208E6AECFB353FF6E5AFA0B999D228D98B73ED644EB605DCD5
Хеш-суммы в два клика
edit 18.07:
Исправил найденные баги, перекомпилировал и обновил ссылки; добавил версии для Linux Ubuntu.
Всем спасибо за обратную связь! Ссылка на проект в GitVerse: https://gitverse.ru/aremys/typewriter