Release v0.6.10: preserve typing during correction and add personal dictionaries
This commit is contained in:
@@ -3,6 +3,17 @@
|
||||
#include <fstream>
|
||||
#include <commctrl.h>
|
||||
|
||||
namespace ks
|
||||
{
|
||||
struct InputRegressionAccess
|
||||
{
|
||||
static bool deferring(App &app)
|
||||
{
|
||||
std::lock_guard lock(app.stateMutex);
|
||||
return app.typingTarget != nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace
|
||||
{
|
||||
ks::App *app{};
|
||||
@@ -11,6 +22,7 @@ ks::Clip saved;
|
||||
bool captured = false, failed = false;
|
||||
int stage = 0, ru = -1, en = -1;
|
||||
size_t punctuationCase = 0;
|
||||
bool typeDuringCorrection = false, typedDuringCorrection = false;
|
||||
const std::vector<std::pair<std::wstring, std::wstring>> punctuationCases{
|
||||
{L"(ljvf) ", L"(дома) "}, {L"[ljvf] ", L"[дома] "}, {L"{ljvf} ", L"{дома} "},
|
||||
{L"ljvf: ", L"дома: "}, {L"ljvf; ", L"дома; "}, {L"#ljvf%; ", L"#дома%; "}};
|
||||
@@ -25,7 +37,14 @@ size_t diagnosticStart{};
|
||||
void require(bool ok, const char *name)
|
||||
{
|
||||
if (!ok)
|
||||
{
|
||||
wchar_t observed[2048]{};
|
||||
GetWindowTextW(field, observed, 2048);
|
||||
std::cerr << "Editor at failure: " << ks::utf8(observed)
|
||||
<< "; foregroundSame=" << (GetForegroundWindow() == host)
|
||||
<< "; inputVersion=" << app->inputVersion.load() << '\n';
|
||||
throw std::runtime_error(name);
|
||||
}
|
||||
std::cout << "PASS " << name << '\n';
|
||||
}
|
||||
std::wstring text()
|
||||
@@ -80,7 +99,26 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
|
||||
if (GetTickCount64() > deadline)
|
||||
throw std::runtime_error("Native integration timed out");
|
||||
if (app->busy)
|
||||
{
|
||||
if (typeDuringCorrection && ks::InputRegressionAccess::deferring(*app))
|
||||
{
|
||||
typeDuringCorrection = false;
|
||||
typedDuringCorrection = true;
|
||||
std::vector<INPUT> inputs;
|
||||
for (auto [key, up] : std::vector<std::pair<WORD, bool>>{
|
||||
{'F', false}, {'F', true}, {VK_LSHIFT, false},
|
||||
{'F', false}, {'F', true}, {VK_LSHIFT, true},
|
||||
{'B', false}, {'B', true}, {VK_BACK, false}, {VK_BACK, true}})
|
||||
{
|
||||
auto input = ks::keyboardInput(key, up ? KEYEVENTF_KEYUP : 0);
|
||||
input.ki.dwExtraInfo = 123; // External input must traverse the actual hook.
|
||||
inputs.push_back(input);
|
||||
}
|
||||
require(SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)) == inputs.size(),
|
||||
"concurrent typing submitted during selection/paste transaction");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
switch (stage++)
|
||||
{
|
||||
case 0:
|
||||
@@ -242,6 +280,41 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
|
||||
break;
|
||||
case 17:
|
||||
require(text() == punctuationCases.back().first, "undo preserves custom punctuation");
|
||||
[[fallthrough]];
|
||||
case 20:
|
||||
if (!captured)
|
||||
{
|
||||
saved = ks::readClipboard(app->window, 64 * 1024 * 1024);
|
||||
captured = true;
|
||||
app->ownSequence = ks::writeClipboard(app->window, ks::textClip(sentinel));
|
||||
}
|
||||
app->settings.autoCorrect = true;
|
||||
app->settings.switchLayout = true;
|
||||
app->settings.autoLanguages = {L"en", L"ru"};
|
||||
app->settings.cycle = {app->layouts[en].id, app->layouts[ru].id};
|
||||
app->autoCorrector = ks::AutoCorrector{};
|
||||
ActivateKeyboardLayout(app->layouts[en].handle, 0);
|
||||
prepare(L"ghbdtn ", false);
|
||||
record(L"ghbdtn ");
|
||||
typeDuringCorrection = true;
|
||||
app->transform(ks::AutoCorrect);
|
||||
stage = 18;
|
||||
break;
|
||||
case 18:
|
||||
require(typedDuringCorrection && text() == L"привет аА",
|
||||
"typing during correction replays in order with shift and backspace in new layout");
|
||||
require(ks::readClipboard(app->window).text() == sentinel,
|
||||
"concurrent typing preserves clipboard restoration");
|
||||
ActivateKeyboardLayout(app->layouts[en].handle, 0);
|
||||
prepare(L"OLDghbdtn ", false);
|
||||
record(L"ghbdtn ");
|
||||
typedDuringCorrection = false;
|
||||
typeDuringCorrection = true;
|
||||
app->transform(ks::AutoCorrect);
|
||||
break;
|
||||
case 19:
|
||||
require(typedDuringCorrection && text() == L"OLDghbdtn fF",
|
||||
"rejected correction collapses selection before replaying typing in original layout");
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
@@ -366,6 +439,8 @@ int main(int argc, char **argv)
|
||||
CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_WANTRETURN,
|
||||
20, 20, 590, 230, host, nullptr, cls.hInstance, nullptr);
|
||||
deadline = GetTickCount64() + 30000;
|
||||
if (argc > 1 && std::string(argv[1]) == "--typing-only")
|
||||
stage = 20;
|
||||
SetTimer(host, 1, 100, nullptr);
|
||||
app->execute();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user