Release v0.6.43: fix forwarded input and verify snippet pastes

This commit is contained in:
2026-11-04 21:18:39 +02:00
parent a2b88f247c
commit 6621a49022
14 changed files with 239 additions and 33 deletions
+58 -1
View File
@@ -33,6 +33,17 @@ bool trimCopiedSpaces = false;
int trimmedCopies = 0;
bool temporaryClipboardExcluded = true;
bool clipboardAccessTimedOut = false;
uint64_t forwardedVersion{};
int forwardedEvents{};
LRESULT CALLBACK forwardingHook(int code, WPARAM wp, LPARAM lp)
{
if (code == HC_ACTION && reinterpret_cast<KBDLLHOOKSTRUCT *>(lp)->dwExtraInfo == 456)
{
++forwardedEvents;
return 1; // Model MWB consuming source input routed to another machine.
}
return CallNextHookEx(nullptr, code, wp, lp);
}
LRESULT CALLBACK observeEnter(HWND w, UINT message, WPARAM wp, LPARAM lp, UINT_PTR, DWORD_PTR)
{
if (message == WM_KEYDOWN && wp == VK_LEFT && droppedSelectionKeys > 0 &&
@@ -577,10 +588,41 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
require(ks::readClipboard(app->window).text() == sentinel, "selected and repeated conversions restore clipboard");
finish();
break;
case 62:
saved = ks::readClipboard(app->window, 64 * 1024 * 1024);
captured = true;
app->ownSequence = ks::writeClipboard(app->window, ks::textClip(sentinel));
app->settings.snippets = {{L";r", L"unexpected{enter}"}};
ActivateKeyboardLayout(app->layouts[en].handle, 0);
prepare(L"prefix ", false);
forwardedVersion = app->inputVersion.load();
copyRequests = forwardedEvents = 0;
{
std::vector<INPUT> inputs;
for (WORD key : {WORD(VK_OEM_1), WORD('R')})
for (DWORD flags : {DWORD(0), DWORD(KEYEVENTF_KEYUP)})
{
auto input = ks::keyboardInput(key, flags);
input.ki.dwExtraInfo = 456;
inputs.push_back(input);
}
require(SendInput((UINT)inputs.size(),inputs.data(),sizeof(INPUT))==inputs.size(),
"forwarded snippet input submitted to real hook chain");
}
break;
case 63:
require(forwardedEvents==4,"downstream forwarding hook consumed every key event");
require(app->inputVersion==forwardedVersion && copyRequests==0,
"forwarded snippet does not start tracking or clipboard work on source computer");
require(text()==L"prefix " && ks::readClipboard(app->window).text()==sentinel,
"forwarded snippet leaves source editor and clipboard untouched");
stage = 30;
break;
case 30:
case 32:
case 34:
case 37:
case 60:
// Earlier password/word tests replace the original multiline
// editor with a single-line EDIT. Restore the snippet fixture:
// a single-line control cannot insert the tested Enter action.
@@ -609,6 +651,11 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
enterPresses = 0;
copyRequests = 0;
copyFailuresRemaining = stage == 38 ? 10 : stage == 33 ? 1 : 0;
if (stage == 61)
{
pasteBehavior = 2; // Editor inserts unrelated clipboard text.
app->settings.writeLog = false;
}
temporaryClipboardExcluded = true;
ActivateKeyboardLayout(app->layouts[en].handle, 0);
prepare(L"prefix ", false);
@@ -672,6 +719,13 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
require(ks::readClipboard(app->window).text() == sentinel,
"exhausted copy retries restore the clipboard");
copyFailuresRemaining = 0;
stage = 60;
break;
case 61:
require(text() == L"prefix other! x", "incorrect snippet paste preserves following typing");
require(enterPresses == 0, "unverified snippet never submits Enter even without logging");
require(ks::readClipboard(app->window).text() == sentinel, "rejected snippet restores clipboard");
pasteBehavior = 0;
finish();
break;
case 20:
@@ -985,9 +1039,12 @@ int main(int argc, char **argv)
if (typosOnly || (argc > 1 && std::string(argv[1]) == "--typing-only"))
stage = 20;
if (argc > 1 && std::string(argv[1]) == "--snippets-only")
stage = 30;
stage = 62;
SetTimer(host, 1, 100, nullptr);
auto forwarding = SetWindowsHookExW(WH_KEYBOARD_LL,forwardingHook,GetModuleHandleW(nullptr),0);
require(forwarding!=nullptr,"downstream forwarding fixture installed before application hook");
app->execute();
UnhookWindowsHookEx(forwarding);
}
std::filesystem::remove_all(root);
}