Compare commits

..

1 Commits
master ... qt6

Author SHA1 Message Date
Gres
6eb5a6d9f1 Port to qt6 2023-01-28 12:29:59 +03:00
20 changed files with 85 additions and 79 deletions

View File

@ -78,7 +78,7 @@ jobs:
- name: Download release url
if: contains(github.ref, '/tags/')
uses: actions/download-artifact@v4.1.7
uses: actions/download-artifact@v1
with:
name: release_upload_url
path: ./

View File

@ -1,7 +1,5 @@
# Screen Translator
**The project is almost abandoned. I don't have time for it and I can only fix minor issues**
## Introduction
This software allows you to translate any text on screen.
@ -29,7 +27,7 @@ file and place it into the `translations` folder next to `screen-translator.exe`
The app doesn't have a main window.
After start it shows only the tray icon.
If the app detects invalid settings, it will show the error message via system tray.
If the app detects invalid settings, it will show the error message via system tray.
It will also highlight the section name in red on the left panel of the settings window.
Clicking on that section name will show a more detailed error message in the right panel (also in red).

View File

@ -14,7 +14,7 @@ win32{
LIBS += -lUser32
}
linux{
QT += x11extras
# QT += x11extras
LIBS += -lX11
}

View File

@ -7,7 +7,7 @@
#include <QDir>
#include <QRegularExpression>
#include <QTextCodec>
#include <QStringConverter>
static int levenshteinDistance(const QString &source, const QString &target)
{
@ -106,19 +106,21 @@ QString HunspellCorrector::correct(const QString &original)
{
SOFT_ASSERT(engine_, return original);
const auto codec =
QTextCodec::codecForName(engine_->get_dict_encoding().c_str());
SOFT_ASSERT(codec, return original);
const auto encoding =
QStringConverter::encodingForName(engine_->get_dict_encoding().c_str());
SOFT_ASSERT(encoding, return original);
auto codec = QStringEncoder(*encoding);
QString result;
QString word;
QString separator;
for (auto i = 0, end = original.size(); i < end; ++i) {
for (auto i = 0ll, end = original.size(); i < end; ++i) {
const auto ch = original[i];
if (ch.isPunct() || ch.isSpace()) {
if (!word.isEmpty()) {
correctWord(word, *codec);
correctWord(word, codec);
result += word;
word.clear();
}
@ -139,7 +141,7 @@ QString HunspellCorrector::correct(const QString &original)
}
if (!word.isEmpty()) {
correctWord(word, *codec);
correctWord(word, codec);
result += word;
}
result += separator;
@ -147,12 +149,12 @@ QString HunspellCorrector::correct(const QString &original)
return result;
}
void HunspellCorrector::correctWord(QString &word, QTextCodec &codec) const
void HunspellCorrector::correctWord(QString &word, QStringEncoder &codec) const
{
if (word.isEmpty())
return;
const auto stdWord = codec.fromUnicode(word).toStdString();
const auto stdWord = codec(word).data.toStdString();
if (engine_->spell(stdWord))
return;

View File

@ -5,6 +5,7 @@
#include <QString>
class Hunspell;
class QStringEncoder;
class HunspellCorrector
{
@ -19,7 +20,7 @@ public:
private:
void init(const QString& path);
void correctWord(QString& word, QTextCodec& codec) const;
void correctWord(QString& word, QStringEncoder& codec) const;
std::unique_ptr<Hunspell> engine_;
QString error_;

View File

@ -16,6 +16,7 @@
#include <QFileInfo>
#include <QMessageBox>
#include <QNetworkProxy>
#include <QStandardPaths>
#include <QThread>
namespace
@ -187,7 +188,8 @@ bool Manager::setupTrace(bool isOn)
const auto traceFile =
QStandardPaths::writableLocation(QStandardPaths::TempLocation) +
QLatin1String("/screen-translator-") +
QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss");
QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") +
QLatin1String(".txt");
if (!debug::setTraceFileName(traceFile)) {
QMessageBox::warning(

View File

@ -4,6 +4,8 @@
#include <QObject>
Q_MOC_INCLUDE("tesseract.h")
class Tesseract;
class RecognizeWorker : public QObject

View File

@ -7,7 +7,6 @@
#include <QApplication>
#include <QBoxLayout>
#include <QDesktopWidget>
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
@ -70,7 +69,7 @@ ResultWidget::ResultWidget(Manager &manager, Representer &representer,
layout->addWidget(separator_);
layout->addWidget(translated_);
layout->setMargin(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
updateSettings();

View File

@ -77,7 +77,7 @@ void GlobalAction::triggerHotKey(quint32 nativeKey, quint32 nativeMods)
#ifdef Q_OS_LINUX
#include <X11/Xlib.h>
#include <xcb/xcb_event.h>
#include <QX11Info>
#include <QWindow>
namespace service
{
@ -101,18 +101,22 @@ static int customHandler(Display *display, XErrorEvent *event)
bool GlobalAction::registerHotKey(quint32 nativeKey, quint32 nativeMods)
{
Display *display = QX11Info::display();
Window window = QX11Info::appRootWindow();
auto nativeInterface =
qApp->nativeInterface<QNativeInterface::QX11Application>();
SOFT_ASSERT(nativeInterface, return false);
Display *display = nativeInterface->display();
SOFT_ASSERT(display, return false);
Bool owner = True;
int pointer = GrabModeAsync;
int keyboard = GrabModeAsync;
error = false;
int (*handler)(Display * display, XErrorEvent * event) =
XSetErrorHandler(customHandler);
XGrabKey(display, nativeKey, nativeMods, window, owner, pointer, keyboard);
XGrabKey(display, nativeKey, nativeMods, DefaultRootWindow(display), owner,
pointer, keyboard);
// allow numlock
XGrabKey(display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer,
keyboard);
XGrabKey(display, nativeKey, nativeMods | Mod2Mask,
DefaultRootWindow(display), owner, pointer, keyboard);
XSync(display, False);
XSetErrorHandler(handler);
return !error;
@ -120,21 +124,25 @@ bool GlobalAction::registerHotKey(quint32 nativeKey, quint32 nativeMods)
bool GlobalAction::unregisterHotKey(quint32 nativeKey, quint32 nativeMods)
{
Display *display = QX11Info::display();
Window window = QX11Info::appRootWindow();
auto nativeInterface =
qApp->nativeInterface<QNativeInterface::QX11Application>();
SOFT_ASSERT(nativeInterface, return false);
Display *display = nativeInterface->display();
SOFT_ASSERT(display, return false);
error = false;
int (*handler)(Display * display, XErrorEvent * event) =
XSetErrorHandler(customHandler);
XUngrabKey(display, nativeKey, nativeMods, window);
XUngrabKey(display, nativeKey, nativeMods, DefaultRootWindow(display));
// allow numlock
XUngrabKey(display, nativeKey, nativeMods | Mod2Mask, window);
XUngrabKey(display, nativeKey, nativeMods | Mod2Mask,
DefaultRootWindow(display));
XSync(display, False);
XSetErrorHandler(handler);
return !error;
}
bool GlobalAction::nativeEventFilter(const QByteArray &eventType, void *message,
long *result)
qintptr *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
@ -151,7 +159,9 @@ bool GlobalAction::nativeEventFilter(const QByteArray &eventType, void *message,
quint32 GlobalAction::nativeKeycode(Qt::Key key)
{
Display *display = QX11Info::display();
auto nativeInterface =
qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *display = nativeInterface->display();
KeySym keySym = XStringToKeysym(qPrintable(QKeySequence(key).toString()));
if (XKeysymToString(keySym) == nullptr) {
keySym = QChar(key).unicode();
@ -191,7 +201,7 @@ bool GlobalAction::unregisterHotKey(quint32 nativeKey, quint32 nativeMods)
}
bool GlobalAction::nativeEventFilter(const QByteArray &eventType, void *message,
long *result)
qintptr *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
@ -407,8 +417,8 @@ bool GlobalAction::unregisterHotKey(quint32 nativeKey, quint32 nativeMods)
}
}
bool GlobalAction::nativeEventFilter(const QByteArray & /*eventType*/,
void * /*message*/, long * /*result*/)
bool GlobalAction::nativeEventFilter(const QByteArray &eventType, void *message,
qintptr *result)
{
return false;
}

View File

@ -11,7 +11,7 @@ class GlobalAction : public QAbstractNativeEventFilter
{
public:
bool nativeEventFilter(const QByteArray &eventType, void *message,
long *result);
qintptr *result) override;
static void init();
static bool makeGlobal(QAction *action);

View File

@ -63,7 +63,7 @@ void KeySequenceEdit::keyPressEvent(QKeyEvent *event)
return;
}
QKeySequence seq = event->modifiers() + event->key();
QKeySequence seq(QKeyCombination(event->modifiers(), Qt::Key(event->key())));
setKeySequence(seq, false);
event->accept();
}

View File

@ -85,7 +85,7 @@ Substitutions unpackSubstitutions(const QStringList& raw)
return {};
Substitutions result;
for (auto i = 0, end = raw.size(); i < end; i += 3) {
for (auto i = 0ll, end = raw.size(); i < end; i += 3) {
result.emplace(raw[i], Substitution{raw[i + 1], raw[i + 2]});
}
return result;

View File

@ -9,6 +9,7 @@
#include "widgetstate.h"
#include <QColorDialog>
#include <QRegularExpression>
#include <QStandardItemModel>
namespace
@ -112,10 +113,10 @@ SettingsEditor::SettingsEditor(Manager &manager, update::Updater &updater)
proxyTypes.insert(ProxyType::Http, tr("HTTP"));
ui->proxyTypeCombo->addItems(proxyTypes.values());
QRegExp urlRegexp(
QRegularExpression urlRegexp(
R"(^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$)");
ui->proxyHostEdit->setValidator(
new QRegExpValidator(urlRegexp, ui->proxyHostEdit));
new QRegularExpressionValidator(urlRegexp, ui->proxyHostEdit));
ui->proxyPassEdit->setEchoMode(QLineEdit::PasswordEchoOnEdit);
}

View File

@ -3,7 +3,9 @@
#include <memory>
class QString;
class QStringList;
template <class T>
class QList;
using QStringList = QList<QString>;
class Manager;
class Settings;

View File

@ -55,7 +55,7 @@ public:
{"\\\\", "\\"},
{"\\n", "\n"},
};
for (auto i = 0, end = text.size() - 1; i < end; ++i) {
for (auto i = 0ll, end = text.size() - 1; i < end; ++i) {
const auto pair = text.mid(i, 2);
const auto replaced = replacements.value(pair);
if (replaced.isEmpty())

View File

@ -14,6 +14,7 @@
#include <QLineEdit>
#include <QSplitter>
#include <QTabWidget>
#include <QTcpSocket>
#include <QTextEdit>
#include <QToolBar>

View File

@ -33,6 +33,9 @@ WebPage::WebPage(Translator &translator, const QString &script,
channel->registerObject("proxy", proxy_.get());
setWebChannel(channel, QWebEngineScript::ScriptWorldId::UserWorld);
connect(this, &QWebEnginePage::certificateError, //
this, &WebPage::handleCertificateError);
// to load scripts
setUrl(QUrl::fromUserInput("about:blank"));
}
@ -186,11 +189,15 @@ void WebPage::javaScriptConsoleMessage(
emit log(QString("%1: %2 %3").arg(sourceID).arg(lineNumber).arg(message));
}
bool WebPage::certificateError(const QWebEngineCertificateError &error)
void WebPage::handleCertificateError(const QWebEngineCertificateError &error)
{
qDebug() << "certificateError" << error.url() << error.error()
<< error.errorDescription();
return ignoreSslErrors_;
qDebug() << "certificateError" << error.url() << error.type()
<< error.description();
if (ignoreSslErrors_) {
const_cast<QWebEngineCertificateError &>(error).acceptCertificate();
return;
}
const_cast<QWebEngineCertificateError &>(error).rejectCertificate();
}
void WebPage::authenticateProxy(const QUrl & /*requestUrl*/,

View File

@ -34,7 +34,7 @@ protected:
void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level,
const QString &message, int lineNumber,
const QString &sourceID) override;
bool certificateError(const QWebEngineCertificateError &error) override;
void handleCertificateError(const QWebEngineCertificateError &error);
private:
void authenticateProxy(const QUrl &requestUrl, QAuthenticator *authenticator,

View File

@ -4,16 +4,8 @@ var active = window.location.href !== "about:blank";
function checkFinished() {
if (!active) return;
let area = document.querySelector('div#target-dummydiv');
let text = area ? area.innerHTML.trim() : '';
if (area == null) {
area = document.querySelector('d-textarea.lmt__target_textarea p');
text = area ? area.innerText.trim() : '';
}
if (area == null) {
area = document.querySelector('d-textarea[data-testid=translator-target-input] p');
text = area ? area.innerText.trim() : '';
}
let area = document.querySelector('textarea[dl-test=translator-target-input]');
let text = area ? area.value : '';
if (text === lastText || text === '')
return;
@ -28,16 +20,16 @@ function translate(text, from, to) {
console.log('start translate', text, from, to)
if (text.trim().length == 0) {
proxy.setTranslated('');
return;
proxy.setTranslated('');
return;
}
from = from == 'zh-CN' ? 'zh' : from;
to = to == 'zh-CN' ? 'zh' : to;
let supported = ['ru', 'en', 'de', 'fr', 'es', 'pt', 'it', 'nl', 'pl', 'ja', 'zh',
'uk', 'bg', 'hu', 'el', 'da', 'id', 'lt', 'pt', 'ro', 'sk', 'sk', 'tr', 'fi', 'cs',
'sv', 'et']
'uk', 'bg', 'hu', 'el', 'da', 'id', 'lt', 'pt', 'ro', 'sk', 'sk', 'tr', 'fi', 'cs',
'sv', 'et']
if (supported.indexOf(from) == -1) {
proxy.setFailed('Source language not supported');
return;
@ -49,32 +41,21 @@ function translate(text, from, to) {
active = true;
var singleLineText = text.replace(/(?:\r\n|\r|\n)/g, ' ');
let langs = from + '/' + to + '/';
if (window.location.href.indexOf('www.deepl.com/translator') !== -1
&& window.location.href.indexOf(langs) !== -1) {
var input = document.querySelector('d-textarea[dl-test=translator-source-input] p');
if (input == null)
input = document.querySelector('d-textarea.lmt__source_textarea p');
if (input == null)
input = document.querySelector('d-textarea[data-testid=translator-source-input] p');
if (input.innerText == singleLineText) {
console.log('using cached result');
lastText = '';
return;
var input = document.querySelector('textarea[dl-test=translator-source-input]');
if (input.value == text) {
console.log('using cached result');
lastText = '';
return;
}
input.innerText = singleLineText;
if (areaCopy = document.querySelector('div#source-dummydiv'))
areaCopy.innerHTML = singleLineText;
setTimeout(function () {
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
}, 300);
input.value = text;
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
return;
}
let url = 'https://www.deepl.com/translator#' + langs + encodeURIComponent(singleLineText);
let url = 'https://www.deepl.com/translator#' + langs + encodeURIComponent(text);
console.log("setting url", url);
window.location = url;
}

View File

@ -594,7 +594,7 @@
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/bing.js", "path":"$translators$/bing.js", "md5":"a982e9aa6cac598f4c9bf4a56386d13e", "size":1481}
]}
,"deepl": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"76856af9b80c3d0e852ca73f8f1ebbdb", "size":2611}
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"6f1c5cd1ccd18cd663f65e6a9bf8462a", "size":1854}
]}
,"google": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js", "path":"$translators$/google.js", "md5":"793d6628ac9e26a1f3cc00fa9c863495", "size":1508}