allow replacement in regex filter and make names consistent

This commit is contained in:
Akash Mozumdar 2021-01-18 18:58:21 -07:00
parent 4219115a40
commit 084f26a72d
9 changed files with 130 additions and 102 deletions

View File

@ -303,8 +303,8 @@ namespace
QDialog dialog(This, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QCheckBox cjkCheckBox(&dialog);
layout.addRow(SEARCH_CJK, &cjkCheckBox);
QCheckBox CJKCheck(&dialog);
layout.addRow(SEARCH_CJK, &CJKCheck);
QDialogButtonBox confirm(QDialogButtonBox::Ok | QDialogButtonBox::Help | QDialogButtonBox::Retry, &dialog);
layout.addRow(&confirm);
confirm.button(QDialogButtonBox::Ok)->setText(START_HOOK_SEARCH);
@ -323,29 +323,29 @@ namespace
{
QDialog dialog(This, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QLineEdit textInput(&dialog);
layout.addRow(TEXT, &textInput);
QSpinBox codepageInput(&dialog);
codepageInput.setMaximum(INT_MAX);
codepageInput.setValue(sp.codepage);
layout.addRow(CODEPAGE, &codepageInput);
QLineEdit textEdit(&dialog);
layout.addRow(TEXT, &textEdit);
QSpinBox codepageSpin(&dialog);
codepageSpin.setMaximum(INT_MAX);
codepageSpin.setValue(sp.codepage);
layout.addRow(CODEPAGE, &codepageSpin);
QDialogButtonBox confirm(QDialogButtonBox::Ok);
QObject::connect(&confirm, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
layout.addRow(&confirm);
if (!dialog.exec()) return;
wcsncpy_s(sp.text, S(textInput.text()).c_str(), PATTERN_SIZE - 1);
wcsncpy_s(sp.text, S(textEdit.text()).c_str(), PATTERN_SIZE - 1);
try { Host::FindHooks(selectedProcessId, sp); } catch (std::out_of_range) {}
return;
}
filter.setPattern(cjkCheckBox.isChecked() ? "[\\x{3000}-\\x{a000}]{4,}" : "[\\x{0020}-\\x{1000}]{4,}");
filter.setPattern(CJKCheck.isChecked() ? "[\\x{3000}-\\x{a000}]{4,}" : "[\\x{0020}-\\x{1000}]{4,}");
if (customSettings)
{
QDialog dialog(This, Qt::WindowCloseButtonHint);
QFormLayout layout(&dialog);
QLineEdit patternInput(x64 ? "CC CC 48 89" : "55 8B EC", &dialog);
assert(QByteArray::fromHex(patternInput.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length));
layout.addRow(SEARCH_PATTERN, &patternInput);
QLineEdit patternEdit(x64 ? "CC CC 48 89" : "55 8B EC", &dialog);
assert(QByteArray::fromHex(patternEdit.text().toUtf8()) == QByteArray((const char*)sp.pattern, sp.length));
layout.addRow(SEARCH_PATTERN, &patternEdit);
for (auto [value, label] : Array<int&, const char*>{
{ sp.searchTime, SEARCH_DURATION },
{ sp.offset, PATTERN_OFFSET },
@ -359,36 +359,36 @@ namespace
layout.addRow(label, spinBox);
QObject::connect(spinBox, qOverload<int>(&QSpinBox::valueChanged), [&value](int newValue) { value = newValue; });
}
QLineEdit boundInput(QFileInfo(S(GetModuleFilename(selectedProcessId).value_or(L""))).fileName(), &dialog);
layout.addRow(SEARCH_MODULE, &boundInput);
QLineEdit boundEdit(QFileInfo(S(GetModuleFilename(selectedProcessId).value_or(L""))).fileName(), &dialog);
layout.addRow(SEARCH_MODULE, &boundEdit);
for (auto [value, label] : Array<uintptr_t&, const char*>{
{ sp.minAddress, MIN_ADDRESS },
{ sp.maxAddress, MAX_ADDRESS },
{ sp.padding, STRING_OFFSET },
})
{
auto input = new QLineEdit(QString::number(value, 16), &dialog);
layout.addRow(label, input);
QObject::connect(input, &QLineEdit::textEdited, [&value](QString text) { if (uintptr_t newValue = text.toULongLong(&ok, 16); ok) value = newValue; });
auto edit = new QLineEdit(QString::number(value, 16), &dialog);
layout.addRow(label, edit);
QObject::connect(edit, &QLineEdit::textEdited, [&value](QString text) { if (uintptr_t newValue = text.toULongLong(&ok, 16); ok) value = newValue; });
}
QLineEdit filterInput(filter.pattern(), &dialog);
layout.addRow(HOOK_SEARCH_FILTER, &filterInput);
QLineEdit filterEdit(filter.pattern(), &dialog);
layout.addRow(HOOK_SEARCH_FILTER, &filterEdit);
QPushButton startButton(START_HOOK_SEARCH, &dialog);
layout.addWidget(&startButton);
QObject::connect(&startButton, &QPushButton::clicked, &dialog, &QDialog::accept);
if (!dialog.exec()) return;
if (patternInput.text().contains('.'))
if (patternEdit.text().contains('.'))
{
wcsncpy_s(sp.exportModule, S(patternInput.text()).c_str(), MAX_MODULE_SIZE - 1);
wcsncpy_s(sp.exportModule, S(patternEdit.text()).c_str(), MAX_MODULE_SIZE - 1);
sp.length = 1;
}
else
{
QByteArray pattern = QByteArray::fromHex(patternInput.text().replace("??", QString::number(XX, 16)).toUtf8());
QByteArray pattern = QByteArray::fromHex(patternEdit.text().replace("??", QString::number(XX, 16)).toUtf8());
memcpy(sp.pattern, pattern.data(), sp.length = min(pattern.size(), PATTERN_SIZE));
}
wcsncpy_s(sp.boundaryModule, S(boundInput.text()).c_str(), MAX_MODULE_SIZE - 1);
filter.setPattern(filterInput.text());
wcsncpy_s(sp.boundaryModule, S(boundEdit.text()).c_str(), MAX_MODULE_SIZE - 1);
filter.setPattern(filterEdit.text());
if (!filter.isValid()) filter.setPattern(".");
}
else
@ -467,12 +467,12 @@ namespace
layout.addRow(label, spinBox);
QObject::connect(&saveButton, &QPushButton::clicked, [spinBox, label, &settings, &value] { settings.setValue(label, value = spinBox->value()); });
}
QComboBox localeComboBox(&dialog);
QComboBox localeCombo(&dialog);
assert(PROMPT == 0 && ALWAYS == 1 && NEVER == 2);
localeComboBox.addItems({ { "Prompt", "Always", "Never" } });
localeComboBox.setCurrentIndex(settings.value(CONFIG_JP_LOCALE, PROMPT).toInt());
layout.addRow(CONFIG_JP_LOCALE, &localeComboBox);
QObject::connect(&localeComboBox, qOverload<int>(&QComboBox::activated), [&settings](int i) { settings.setValue(CONFIG_JP_LOCALE, i); });
localeCombo.addItems({ { "Prompt", "Always", "Never" } });
localeCombo.setCurrentIndex(settings.value(CONFIG_JP_LOCALE, PROMPT).toInt());
layout.addRow(CONFIG_JP_LOCALE, &localeCombo);
QObject::connect(&localeCombo, qOverload<int>(&QComboBox::activated), [&settings](int i) { settings.setValue(CONFIG_JP_LOCALE, i); });
layout.addWidget(&saveButton);
QObject::connect(&saveButton, &QPushButton::clicked, &dialog, &QDialog::accept);
dialog.setWindowTitle(SETTINGS);

View File

@ -3,7 +3,7 @@
extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo, apiKey;
extern Synchronized<std::wstring> translateTo, authKey;
const char* TRANSLATION_PROVIDER = "Bing Translate";
const char* GET_API_KEY_FROM = "https://www.microsoft.com/en-us/translator/business/trial/#get-started";
@ -84,14 +84,14 @@ int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
std::pair<bool, std::wstring> Translate(const std::wstring& text)
{
if (!apiKey->empty())
if (!authKey->empty())
if (HttpRequest httpRequest{
L"Mozilla/5.0 Textractor",
L"api.cognitive.microsofttranslator.com",
L"POST",
FormatString(L"/translate?api-version=3.0&to=%s", translateTo.Copy()).c_str(),
FormatString(R"([{"text":"%s"}])", JSON::Escape(WideStringToString(text))),
FormatString(L"Content-Type: application/json; charset=UTF-8\r\nOcp-Apim-Subscription-Key:%s", apiKey.Copy()).c_str()
FormatString(L"Content-Type: application/json; charset=UTF-8\r\nOcp-Apim-Subscription-Key:%s", authKey.Copy()).c_str()
})
if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };

View File

@ -5,7 +5,7 @@
extern const wchar_t* TRANSLATION_ERROR;
extern const char* USE_PREV_SENTENCE_CONTEXT;
extern Synchronized<std::wstring> translateTo, apiKey;
extern Synchronized<std::wstring> translateTo, authKey;
const char* TRANSLATION_PROVIDER = "DeepL Translate";
const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html";
@ -32,20 +32,20 @@ int keyType = CAT;
std::pair<bool, std::wstring> Translate(const std::wstring& text)
{
if (!apiKey->empty())
if (!authKey->empty())
if (HttpRequest httpRequest{
L"Mozilla/5.0 Textractor",
L"api.deepl.com",
L"POST",
keyType == CAT ? L"/v1/translate" : L"/v2/translate",
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), apiKey.Copy(), translateTo.Copy()),
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()),
L"Content-Type: application/x-www-form-urlencoded"
}; httpRequest && (!httpRequest.response.empty() || (httpRequest = HttpRequest{
L"Mozilla/5.0 Textractor",
L"api.deepl.com",
L"POST",
(keyType = !keyType) == CAT ? L"/v1/translate" : L"/v2/translate",
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), apiKey.Copy(), translateTo.Copy()),
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()),
L"Content-Type: application/x-www-form-urlencoded"
})))
// Response formatted as JSON: translation starts with text":" and ends with "}]

View File

@ -54,10 +54,10 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
display->addRow(CHROME_LOCATION, chromePathEdit);
auto statusLabel = new QLabel("Stopped");
auto startButton = new QPushButton(START_DEVTOOLS), stopButton = new QPushButton(STOP_DEVTOOLS);
auto headlessCheckBox = new QCheckBox();
headlessCheckBox->setChecked(settings.value(HEADLESS_MODE, true).toBool());
QObject::connect(headlessCheckBox, &QCheckBox::clicked, [](bool headless) { settings.setValue(HEADLESS_MODE, headless); });
QObject::connect(startButton, &QPushButton::clicked, [statusLabel, chromePathEdit, headlessCheckBox] {
auto headlessCheck = new QCheckBox();
headlessCheck->setChecked(settings.value(HEADLESS_MODE, true).toBool());
QObject::connect(headlessCheck, &QCheckBox::clicked, [](bool headless) { settings.setValue(HEADLESS_MODE, headless); });
QObject::connect(startButton, &QPushButton::clicked, [statusLabel, chromePathEdit, headlessCheck] {
DevTools::Start(
S(chromePathEdit->text()),
[statusLabel](QString status)
@ -82,14 +82,14 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
FormatString(LR"({"userAgent":"%s"})", userAgent->replace(userAgent->find(L"Headless"), 8, L"")));
}).detach();
},
headlessCheckBox->isChecked()
headlessCheck->isChecked()
);
});
QObject::connect(stopButton, &QPushButton::clicked, &DevTools::Close);
auto buttons = new QHBoxLayout();
buttons->addWidget(startButton);
buttons->addWidget(stopButton);
display->addRow(HEADLESS_MODE, headlessCheckBox);
display->addRow(HEADLESS_MODE, headlessCheck);
auto autoStartButton = new QCheckBox();
autoStartButton->setChecked(settings.value(AUTO_START, false).toBool());
QObject::connect(autoStartButton, &QCheckBox::clicked, [](bool autoStart) { settings.setValue(AUTO_START, autoStart); });

View File

@ -55,14 +55,14 @@ struct PrettyWindow : QDialog
settings.beginGroup(name);
QFont font = ui.display->font();
if (font.fromString(settings.value(FONT, font.toString()).toString())) ui.display->setFont(font);
setBgColor(settings.value(BG_COLOR, bgColor).value<QColor>());
setTextColor(settings.value(TEXT_COLOR, textColor()).value<QColor>());
SetBackgroundColor(settings.value(BG_COLOR, backgroundColor).value<QColor>());
SetTextColor(settings.value(TEXT_COLOR, TextColor()).value<QColor>());
outliner.color = settings.value(OUTLINE_COLOR, outliner.color).value<QColor>();
outliner.size = settings.value(OUTLINE_SIZE, outliner.size).toDouble();
menu.addAction(FONT, this, &PrettyWindow::RequestFont);
menu.addAction(BG_COLOR, [this] { setBgColor(colorPrompt(this, bgColor, BG_COLOR)); });
menu.addAction(TEXT_COLOR, [this] { setTextColor(colorPrompt(this, textColor(), TEXT_COLOR)); });
QAction* outlineAction = menu.addAction(TEXT_OUTLINE, this, &PrettyWindow::setOutline);
menu.addAction(BG_COLOR, [this] { SetBackgroundColor(colorPrompt(this, backgroundColor, BG_COLOR)); });
menu.addAction(TEXT_COLOR, [this] { SetTextColor(colorPrompt(this, TextColor(), TEXT_COLOR)); });
QAction* outlineAction = menu.addAction(TEXT_OUTLINE, this, &PrettyWindow::SetOutline);
outlineAction->setCheckable(true);
outlineAction->setChecked(outliner.size >= 0);
connect(ui.display, &QLabel::customContextMenuRequested, [this](QPoint point) { menu.exec(mapToGlobal(point)); });
@ -89,28 +89,28 @@ private:
}
};
void setBgColor(QColor color)
void SetBackgroundColor(QColor color)
{
if (!color.isValid()) return;
if (color.alpha() == 0) color.setAlpha(1);
bgColor = color;
backgroundColor = color;
repaint();
settings.setValue(BG_COLOR, color.name(QColor::HexArgb));
};
QColor textColor()
QColor TextColor()
{
return ui.display->palette().color(QPalette::WindowText);
}
void setTextColor(QColor color)
void SetTextColor(QColor color)
{
if (!color.isValid()) return;
ui.display->setPalette(QPalette(color, {}, {}, {}, {}, {}, {}));
settings.setValue(TEXT_COLOR, color.name(QColor::HexArgb));
};
void setOutline(bool enable)
void SetOutline(bool enable)
{
if (enable)
{
@ -125,10 +125,10 @@ private:
void paintEvent(QPaintEvent*) override
{
QPainter(this).fillRect(rect(), bgColor);
QPainter(this).fillRect(rect(), backgroundColor);
}
QColor bgColor{ palette().window().color() };
QColor backgroundColor{ palette().window().color() };
struct : QGraphicsEffect
{
void draw(QPainter* painter) override
@ -163,10 +163,10 @@ public:
maxSentenceSize = settings.value(MAX_SENTENCE_SIZE, maxSentenceSize).toInt();
for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
{ TOPMOST, false, &ExtraWindow::setTopmost },
{ SIZE_LOCK, false, &ExtraWindow::setLock },
{ SHOW_ORIGINAL, true, &ExtraWindow::setShowOriginal },
{ DICTIONARY, false, &ExtraWindow::setUseDictionary },
{ TOPMOST, false, &ExtraWindow::SetTopmost },
{ SIZE_LOCK, false, &ExtraWindow::SetLock },
{ SHOW_ORIGINAL, true, &ExtraWindow::SetShowOriginal },
{ DICTIONARY, false, &ExtraWindow::SetUseDictionary },
})
{
// delay processing anything until Textractor has finished initializing
@ -206,26 +206,26 @@ public:
}
private:
void setTopmost(bool topmost)
void SetTopmost(bool topmost)
{
for (auto window : { winId(), dictionaryWindow.winId() })
SetWindowPos((HWND)window, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
settings.setValue(TOPMOST, topmost);
};
void setLock(bool locked)
void SetLock(bool locked)
{
setSizeGripEnabled(!locked);
settings.setValue(SIZE_LOCK, this->locked = locked);
};
void setShowOriginal(bool showOriginal)
void SetShowOriginal(bool showOriginal)
{
if (!showOriginal && settings.value(SHOW_ORIGINAL, false).toBool()) QMessageBox::information(this, SHOW_ORIGINAL, SHOW_ORIGINAL_INFO);
settings.setValue(SHOW_ORIGINAL, this->showOriginal = showOriginal);
};
void setUseDictionary(bool useDictionary)
void SetUseDictionary(bool useDictionary)
{
if (useDictionary)
{
@ -239,11 +239,11 @@ private:
settings.setValue(DICTIONARY, this->useDictionary = useDictionary);
}
void computeDictionaryPosition(QPoint mouse)
void ComputeDictionaryPosition(QPoint mouse)
{
QString sentence = ui.display->text();
const QFont& font = ui.display->font();
if (cachedDisplayInfo.compareExchange(ui.display))
if (cachedDisplayInfo.CompareExchange(ui.display))
{
QFontMetrics fontMetrics(font, ui.display);
textPositionMap.clear();
@ -269,7 +269,7 @@ private:
if (i == textPositionMap.size() || (mouse - textPositionMap[i]).manhattanLength() > font.pointSize() * 3) return dictionaryWindow.hide();
if (sentence.mid(i) == dictionaryWindow.term) return dictionaryWindow.ShowDefinition();
dictionaryWindow.ui.display->setFixedWidth(ui.display->width() * 3 / 4);
dictionaryWindow.setTerm(sentence.mid(i));
dictionaryWindow.SetTerm(sentence.mid(i));
int left = i == 0 ? 0 : textPositionMap[i - 1].x(), right = textPositionMap[i].x(),
x = textPositionMap[i].x() > ui.display->width() / 2 ? -dictionaryWindow.width() + (right * 3 + left) / 4 : (left * 3 + right) / 4, y = 0;
for (auto point : textPositionMap) if (point.y() > y && point.y() < textPositionMap[i].y()) y = point.y();
@ -278,7 +278,7 @@ private:
bool eventFilter(QObject*, QEvent* event) override
{
if (useDictionary && event->type() == QEvent::MouseMove) computeDictionaryPosition(((QMouseEvent*)event)->localPos().toPoint());
if (useDictionary && event->type() == QEvent::MouseMove) ComputeDictionaryPosition(((QMouseEvent*)event)->localPos().toPoint());
if (event->type() == QEvent::MouseButtonPress) dictionaryWindow.hide();
return false;
}
@ -309,7 +309,7 @@ private:
class
{
public:
bool compareExchange(QLabel* display)
bool CompareExchange(QLabel* display)
{
if (display->text() == text && display->font() == font && display->width() == width) return false;
text = display->text();
@ -389,7 +389,7 @@ private:
}
}
void setTerm(QString term)
void SetTerm(QString term)
{
this->term = term;
UpdateDictionary();

View File

@ -4,7 +4,7 @@
extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo, apiKey;
extern Synchronized<std::wstring> translateTo, authKey;
const char* TRANSLATION_PROVIDER = "Google Translate";
const char* GET_API_KEY_FROM = "https://codelabs.developers.google.com/codelabs/cloud-translation-intro";
@ -126,12 +126,12 @@ int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
std::pair<bool, std::wstring> Translate(const std::wstring& text)
{
if (!apiKey->empty())
if (!authKey->empty())
if (HttpRequest httpRequest{
L"Mozilla/5.0 Textractor",
L"translation.googleapis.com",
L"POST",
FormatString(L"/language/translate/v2?format=text&target=%s&key=%s", translateTo.Copy(), apiKey.Copy()).c_str(),
FormatString(L"/language/translate/v2?format=text&target=%s&key=%s", translateTo.Copy(), authKey.Copy()).c_str(),
FormatString(R"({"q":["%s"]})", JSON::Escape(WideStringToString(text)))
})
if (auto translation = Copy(JSON::Parse(httpRequest.response)[L"data"][L"translations"][0][L"translatedText"].String())) return { true, translation.value() };

View File

@ -12,6 +12,7 @@ extern const char* CURRENT_FILTER;
const char* REGEX_SAVE_FILE = "SavedRegexFilters.txt";
std::optional<std::wregex> regex;
std::wstring replace;
std::shared_mutex m;
DWORD (*GetSelectedProcessId)() = nullptr;
@ -24,16 +25,17 @@ public:
Localize();
ui.setupUi(this);
connect(ui.input, &QLineEdit::textEdited, this, &Window::setRegex);
connect(ui.save, &QPushButton::clicked, this, &Window::saveRegex);
connect(ui.regexEdit, &QLineEdit::textEdited, this, &Window::SetRegex);
connect(ui.replaceEdit, &QLineEdit::textEdited, this, &Window::SetReplace);
connect(ui.saveButton, &QPushButton::clicked, this, &Window::Save);
setWindowTitle(REGEX_FILTER);
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
void setRegex(QString regex)
void SetRegex(QString regex)
{
ui.input->setText(regex);
ui.regexEdit->setText(regex);
std::scoped_lock lock(m);
if (!regex.isEmpty()) try { ::regex = S(regex); }
catch (std::regex_error) { return ui.output->setText(INVALID_REGEX); }
@ -41,13 +43,21 @@ public:
ui.output->setText(QString(CURRENT_FILTER).arg(regex));
}
void SetReplace(QString replace)
{
ui.replaceEdit->setText(replace);
std::scoped_lock lock(m);
::replace = S(replace);
}
private:
void saveRegex()
void Save()
{
auto formatted = FormatString(
L"\xfeff|PROCESS|%s|FILTER|%s|END|\r\n",
L"\xfeff|PROCESS|%s|FILTER|%s|REPLACE|%s|END|\r\n",
GetModuleFilename(GetSelectedProcessId()).value_or(FormatString(L"Error getting name of process 0x%X", GetSelectedProcessId())),
S(ui.input->text())
S(ui.regexEdit->text()),
S(ui.replaceEdit->text())
);
std::ofstream(REGEX_SAVE_FILE, std::ios::binary | std::ios::app).write((const char*)formatted.c_str(), formatted.size() * sizeof(wchar_t));
}
@ -62,12 +72,16 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
if (sentenceInfo["current select"] && !regex) if (auto processName = GetModuleFilename(sentenceInfo["process id"]))
{
std::ifstream stream(REGEX_SAVE_FILE, std::ios::binary);
BlockMarkupIterator savedFilters(stream, Array<std::wstring_view>{ L"|PROCESS|", L"|FILTER|" });
std::vector<std::wstring> regexes;
while (auto read = savedFilters.Next()) if (read->at(0) == processName) regexes.push_back(std::move(read->at(1)));
if (!regexes.empty()) QMetaObject::invokeMethod(&window, [regex = S(regexes.back())] { window.setRegex(regex); }, Qt::BlockingQueuedConnection);
BlockMarkupIterator savedFilters(stream, Array<std::wstring_view>{ L"|PROCESS|", L"|FILTER|", L"|REPLACE|" });
std::vector<std::array<std::wstring, 3>> regexes;
while (auto read = savedFilters.Next()) if (read->at(0) == processName) regexes.push_back(std::move(read.value()));
if (!regexes.empty()) QMetaObject::invokeMethod(&window, [regex = S(regexes.back()[1]), replace = S(regexes.back()[2])]
{
window.SetRegex(regex);
window.SetReplace(replace);
}, Qt::BlockingQueuedConnection);
}
std::shared_lock l(m);
if (regex) sentence = std::regex_replace(sentence, regex.value(), L"");
if (regex) sentence = std::regex_replace(sentence, regex.value(), replace);
return true;
}

View File

@ -6,13 +6,27 @@
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>105</height>
<width>500</width>
<height>107</height>
</rect>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QLineEdit" name="input"/>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="regexEdit"/>
</item>
<item>
<widget class="QLabel">
<property name="text">
<string>=></string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="replaceEdit"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="output">
@ -25,7 +39,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="save">
<widget class="QPushButton" name="saveButton">
<property name="text">
<string>Save</string>
</property>

View File

@ -30,7 +30,7 @@ const std::string TRANSLATION_CACHE_FILE = FormatString("%s Translation Cache.tx
QFormLayout* display;
Settings settings;
Synchronized<std::wstring> translateTo = L"en", apiKey;
Synchronized<std::wstring> translateTo = L"en", authKey;
namespace
{
@ -57,16 +57,16 @@ public:
settings.beginGroup(TRANSLATION_PROVIDER);
auto languageBox = new QComboBox(this);
languageBox->addItems(languages);
auto languageCombo = new QComboBox(this);
languageCombo->addItems(languages);
int language = -1;
if (settings.contains(LANGUAGE)) language = languageBox->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
if (language < 0) language = languageBox->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
if (language < 0) language = languageBox->findText("English", Qt::MatchStartsWith);
languageBox->setCurrentIndex(language);
saveLanguage(languageBox->currentText());
display->addRow(TRANSLATE_TO, languageBox);
connect(languageBox, &QComboBox::currentTextChanged, this, &Window::saveLanguage);
if (settings.contains(LANGUAGE)) language = languageCombo->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
if (language < 0) language = languageCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
if (language < 0) language = languageCombo->findText("English", Qt::MatchStartsWith);
languageCombo->setCurrentIndex(language);
saveLanguage(languageCombo->currentText());
display->addRow(TRANSLATE_TO, languageCombo);
connect(languageCombo, &QComboBox::currentTextChanged, this, &Window::saveLanguage);
for (auto [value, label] : Array<bool&, const char*>{
{ translateSelectedOnly, TRANSLATE_SELECTED_THREAD_ONLY },
{ rateLimitAll, RATE_LIMIT_ALL_THREADS },
@ -95,12 +95,12 @@ public:
}
if (GET_API_KEY_FROM)
{
auto keyInput = new QLineEdit(settings.value(API_KEY).toString(), this);
apiKey->assign(S(keyInput->text()));
QObject::connect(keyInput, &QLineEdit::textChanged, [](QString key) { settings.setValue(API_KEY, S(apiKey->assign(S(key)))); });
auto keyEdit = new QLineEdit(settings.value(API_KEY).toString(), this);
authKey->assign(S(keyEdit->text()));
QObject::connect(keyEdit, &QLineEdit::textChanged, [](QString key) { settings.setValue(API_KEY, S(authKey->assign(S(key)))); });
auto keyLabel = new QLabel(QString("<a href=\"%1\">%2</a>").arg(GET_API_KEY_FROM, API_KEY), this);
keyLabel->setOpenExternalLinks(true);
display->addRow(keyLabel, keyInput);
display->addRow(keyLabel, keyEdit);
}
setWindowTitle(TRANSLATION_PROVIDER);