Новая версия программы - infill
Эта статья поможет сэкономить время тем, кто сталкивается с подобными ситуациями - когда нужно перенести некоторые количества текста в такие места, куда он простым буфером обмена не переносится, например - в 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
