Release v0.6.12: improve continuous correction and resize log viewer

This commit is contained in:
2026-10-30 00:15:09 +02:00
parent c326db7dc5
commit 77f27ea087
17 changed files with 220 additions and 99 deletions
+28 -2
View File
@@ -1,4 +1,4 @@
param([string]$BuildDirectory = (Join-Path $PSScriptRoot '../build/staged'))
param([string]$BuildDirectory = (Join-Path $PSScriptRoot '../build/staged'), [switch]$LogsOnly)
$ErrorActionPreference = 'Stop'
if (Get-Process KSwitcher,'KSwitcher.Config' -ErrorAction SilentlyContinue) {
throw 'Close KSwitcher and its configurator before this isolated process test.'
@@ -38,7 +38,7 @@ $checks=0
function Assert($ok,$label) { if (!$ok) { throw $label }; $script:checks++ }
function Window($class) {
for($i=0;$i -lt 100;$i++) {
$title=switch($class){'KSwitcher.Main'{'KSwitcher'};'KSwitcher.Settings'{'KSwitcher settings'};'KSwitcher.Snippets'{'Text snippets'}}
$title=switch($class){'KSwitcher.Main'{'KSwitcher'};'KSwitcher.Settings'{'KSwitcher settings'};'KSwitcher.Snippets'{'Text snippets'};'KSwitcher.Logs'{'KSwitcher log'}}
$window=[ConfigurationTestUi]::FindWindow($class,$title)
if($window -ne [IntPtr]::Zero){return $window}
Start-Sleep -Milliseconds 50
@@ -56,6 +56,24 @@ function Launch($file,$argument) {
function Click($window,$id) {
$null=[ConfigurationTestUi]::PostMessage($window,0x111,[IntPtr]$id,[IntPtr]::Zero)
}
function TestLogs {
'test-marker' | Set-Content -LiteralPath (Join-Path $root 'data/kswitcher.log')
$config=Launch 'KSwitcher.Config.exe' '--logs'
$logs=Window 'KSwitcher.Logs'
[uint32]$logOwner=0
$null=[ConfigurationTestUi]::GetWindowThreadProcessId($logs,[ref]$logOwner)
Assert ($logOwner -eq $config.Id -and $logOwner -ne $resident.Id) 'logs run outside the resident input-hook process'
$second=Launch 'KSwitcher.Config.exe' '--logs'
Assert ($second.WaitForExit(6000)) 'opening logs again reuses the configurator'
Assert ((Window 'KSwitcher.Logs') -eq $logs) 'log window is reused'
Click $logs 603
Assert (!$resident.HasExited) 'refreshing logs leaves resident running'
Click $logs 606
for($i=0;$i -lt 50 -and (Test-Path -LiteralPath (Join-Path $root 'data/kswitcher.log'));$i++) { Start-Sleep -Milliseconds 50 }
Assert (!(Test-Path -LiteralPath (Join-Path $root 'data/kswitcher.log'))) 'clear log is committed through resident process'
Click $logs 2
Assert ($config.WaitForExit(6000)) 'closing standalone logs exits configurator'
}
try {
New-Item -ItemType Directory -Path (Join-Path $root 'data') -Force | Out-Null
foreach($file in @('KSwitcher.exe','KSwitcher.Config.exe')) {
@@ -67,6 +85,13 @@ try {
ConvertTo-Json | Set-Content -LiteralPath $settingsPath -Encoding utf8
$resident=Launch 'KSwitcher.exe' ''
$main=Window 'KSwitcher.Main'
if ($LogsOnly) {
TestLogs
$null=[ConfigurationTestUi]::PostMessage($main,0x10,[IntPtr]::Zero,[IntPtr]::Zero)
Assert ($resident.WaitForExit(10000)) 'fixture resident exits normally'
"Passed $checks log process checks"
return
}
$config=Launch 'KSwitcher.Config.exe' ''
$settings=Window 'KSwitcher.Settings'
[uint32]$ownerId=0
@@ -110,6 +135,7 @@ try {
$config.Refresh(); Assert (!$config.HasExited) 'closing settings keeps open snippets alive'
Click $snippets 2
Assert ($config.WaitForExit(6000)) 'closing last window exits configurator'
TestLogs
$config=Launch 'KSwitcher.Config.exe' ''
$null=Window 'KSwitcher.Settings'
$null=[ConfigurationTestUi]::PostMessage($main,0x10,[IntPtr]::Zero,[IntPtr]::Zero)
+20
View File
@@ -1,4 +1,5 @@
#include "app.h"
#include <algorithm>
#include <iostream>
#include <fstream>
#include <commctrl.h>
@@ -315,6 +316,25 @@ LRESULT CALLBACK procedure(HWND w, UINT msg, WPARAM wp, LPARAM lp)
case 19:
require(typedDuringCorrection && text() == L"OLDghbdtn fF",
"rejected correction collapses selection before replaying typing in original layout");
ActivateKeyboardLayout(app->layouts[en].handle, 0);
prepare(L"", false);
app->autoPredictor.configure(L"dictionaries", app->settings.autoLanguages);
{
std::vector<INPUT> inputs;
for (WORD key : std::wstring(L"GHBDTN F"))
for (DWORD flags : {DWORD(0), DWORD(KEYEVENTF_KEYUP)})
{
auto input = ks::keyboardInput(key == L' ' ? VK_SPACE : key, flags);
input.ki.dwExtraInfo = 123;
inputs.push_back(input);
}
require(SendInput((UINT)inputs.size(), inputs.data(), sizeof(INPUT)) == inputs.size(),
"continuous typing submitted in a single batch without a pause after Space");
}
stage = 21;
break;
case 21:
require(text() == L"привет а", "automatic correction preserves immediate next-word typing without a pause");
finish();
break;
}
+8
View File
@@ -247,6 +247,14 @@ int main(int argc, char **argv)
options.autoLanguages = {L"en", L"uk", L"ru"};
options.cycle = {L"en", L"uk", L"ru"};
supplemental.configure(L"dictionaries", options.autoLanguages);
for (auto [typed, expected] : {std::pair{L"ntcn ", L"тест "}, std::pair{L"vfkj ", L"мало "}})
{
auto shared = supplemental.suggest(typed, 0, layouts, options);
require(shared && shared->text == expected && shared->target == 2,
"identical Russian and Ukrainian spelling uses preferred Ukrainian layout");
}
require(!supplemental.suggest(L"lsv ", 0, layouts, options),
"different dictionary results remain ambiguous");
auto release = supplemental.suggest(L"релыз ", 1, layouts, options);
require(release && release->text == L"реліз " && release->target == 2,
"supplemental Ukrainian release word corrects from Russian layout");