Release v0.6.31: verify trailing spaces omitted by editor copy
This commit is contained in:
+60
-3
@@ -76,6 +76,8 @@ class Transaction
|
||||
mutable bool invalidLogged{};
|
||||
unsigned copyNumber{};
|
||||
std::wstring adopted;
|
||||
std::unique_ptr<PasteProbe> selectionProof;
|
||||
std::wstring provenSelection;
|
||||
|
||||
public:
|
||||
Transaction(App &a, HWND t, uint64_t v) : app(a), target(t), version(v)
|
||||
@@ -250,8 +252,27 @@ class Transaction
|
||||
}
|
||||
}
|
||||
}
|
||||
selectionProof.reset();
|
||||
provenSelection.clear();
|
||||
// Viber and some other editors omit trailing ASCII spaces from Ctrl+C.
|
||||
// Recover only from a real selection, never from the recorded keys alone.
|
||||
if (valid() && !text.empty() && text.size() < 8192 && text.back() != L' ')
|
||||
{
|
||||
auto proof = std::make_unique<PasteProbe>(true, target);
|
||||
auto selected = proof->read(1, false);
|
||||
if (selected && selected->size() > text.size() && selected->starts_with(text) &&
|
||||
selected->find_first_not_of(L' ', text.size()) == std::wstring::npos && valid())
|
||||
{
|
||||
diagnosticEvent(L"Copy: trailing spaces verified via accessibility copied=" +
|
||||
diagnosticText(text) + L" selected=" + diagnosticText(*selected));
|
||||
text = *selected;
|
||||
provenSelection = text;
|
||||
selectionProof = std::move(proof);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
bool recoveredSelection() const { return selectionProof != nullptr; }
|
||||
bool select(size_t n)
|
||||
{
|
||||
return selectPrevious(n, [&] { return valid(); });
|
||||
@@ -324,6 +345,15 @@ class Transaction
|
||||
}
|
||||
bool paste(const Clip &clip)
|
||||
{
|
||||
if (selectionProof)
|
||||
{
|
||||
auto selected = selectionProof->read(1, false);
|
||||
if (!selected || *selected != provenSelection || !valid())
|
||||
{
|
||||
diagnosticEvent(L"Paste cancelled: recovered selection changed or unavailable");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!valid())
|
||||
return false;
|
||||
write(clip);
|
||||
@@ -1341,13 +1371,30 @@ void App::transform(int command, int snippet)
|
||||
}
|
||||
}
|
||||
bool sent = false;
|
||||
PasteProbe probe(config.writeLog && manual && result != text, text);
|
||||
const bool requireReadback = tx.recoveredSelection();
|
||||
PasteProbe probe(((config.writeLog && manual) || requireReadback) && result != text, text, target);
|
||||
if (requireReadback && result != text && probe.status != L"ready")
|
||||
{
|
||||
reason = L"recovered-selection-unavailable";
|
||||
std::lock_guard lock(stateMutex);
|
||||
last.reset();
|
||||
run.reset();
|
||||
return;
|
||||
}
|
||||
diagnosticEvent(L"Conversion source=" + std::to_wstring(hint) + L" target=" + std::to_wstring(to) +
|
||||
L" changed=" + std::to_wstring(result != text));
|
||||
if (result != text)
|
||||
sent = tx.paste(textClip(result));
|
||||
else if (automatic && tx.valid())
|
||||
chord(VK_RIGHT);
|
||||
if (requireReadback && result != text && !sent)
|
||||
{
|
||||
reason = L"recovered-selection-paste-cancelled";
|
||||
std::lock_guard lock(stateMutex);
|
||||
last.reset();
|
||||
run.reset();
|
||||
return;
|
||||
}
|
||||
if (sent || result == text)
|
||||
autoSelected = false;
|
||||
reason = result == text ? L"conversion-unchanged" :
|
||||
@@ -1357,7 +1404,7 @@ void App::transform(int command, int snippet)
|
||||
reason = L"Conversion unchanged";
|
||||
verification = L"calculated-result-equals-original";
|
||||
}
|
||||
if (sent && manual && config.writeLog)
|
||||
if (sent && ((manual && config.writeLog) || requireReadback))
|
||||
{
|
||||
verification = probe.status;
|
||||
if (tx.valid())
|
||||
@@ -1388,7 +1435,17 @@ void App::transform(int command, int snippet)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else reason = L"Paste not verified";
|
||||
else
|
||||
{
|
||||
reason = L"Paste not verified";
|
||||
if (requireReadback)
|
||||
{
|
||||
std::lock_guard lock(stateMutex);
|
||||
last.reset();
|
||||
run.reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else verification = L"context-changed-after-paste";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user