Release v0.6.0: screenshot notifications with previews and responsive clipboard history
This commit is contained in:
@@ -485,6 +485,20 @@ int main(int argc, char **argv) {
|
||||
fitted=ks::fitWindowRect({2000,2000,2600,2400},{-1920,0,0,1080});
|
||||
require(fitted.left==-600&&fitted.top==680&&fitted.right==0,"negative-coordinate monitor supported");
|
||||
ks::showSettings(app,false);
|
||||
if (!app.history) app.history=std::make_unique<ks::History>(temp/L"history-layout");
|
||||
ks::showHistory(app,false);
|
||||
auto history=app.historyWindow;
|
||||
require(history&&!IsWindowVisible(history),"history layout tested without changing focus");
|
||||
auto childRect=[&](int id) { RECT r{}; GetWindowRect(GetDlgItem(history,id),&r); MapWindowPoints(nullptr,history,(POINT*)&r,2); return r; };
|
||||
RECT historyFrame{}; GetWindowRect(history,&historyFrame);
|
||||
auto listBefore=childRect(102),searchBefore=childRect(101),buttonBefore=childRect(110);
|
||||
SetWindowPos(history,nullptr,0,0,historyFrame.right-historyFrame.left+120,historyFrame.bottom-historyFrame.top+180,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
auto listAfter=childRect(102),searchAfter=childRect(101),buttonAfter=childRect(110);
|
||||
require(listAfter.right-listBefore.right==120 && listAfter.bottom-listBefore.bottom==180,"history list fills added width and height");
|
||||
require(searchAfter.right-searchBefore.right==120 && searchAfter.top==searchBefore.top,"history search grows horizontally only");
|
||||
require(buttonAfter.top-buttonBefore.top==180 && buttonAfter.bottom-listAfter.bottom==buttonBefore.bottom-listBefore.bottom,"history actions stay below list after resize");
|
||||
SetWindowPos(history,nullptr,0,0,historyFrame.right-historyFrame.left,historyFrame.bottom-historyFrame.top,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
|
||||
require(EqualRect(&listBefore,&(listAfter=childRect(102))),"history resize roundtrip restores geometry");
|
||||
auto settings=app.settingsWindow;
|
||||
require(settings&&!IsWindowVisible(settings),"settings layout tested without changing user focus");
|
||||
for(auto pair:{std::pair{207,215},std::pair{207,232},std::pair{207,220},std::pair{232,230},std::pair{230,231},std::pair{231,253}}) {
|
||||
|
||||
@@ -35,24 +35,29 @@ function Select-Region($Window) {
|
||||
Send $Window 0x201 1 ((40 -shl 16) -bor 40)
|
||||
Send $Window 0x200 1 ((240 -shl 16) -bor 360)
|
||||
Send $Window 0x202 0 ((240 -shl 16) -bor 360)
|
||||
Wait-For { [ScreenshotProcessTest]::Title($Window) -match 'Screenshot #' } 'Selection did not become an editor.'
|
||||
Wait-For { (Capture-Windows) -notcontains $Window } 'Selection did not close after copying (notifications may be disabled).'
|
||||
}
|
||||
function Close-Editor($Window) {
|
||||
Send $Window 0x10
|
||||
Wait-For { @([ScreenshotProcessTest]::Windows($script:process.Id,'#32770')).Count -eq 1 } 'Missing close confirmation.'
|
||||
$dialog=[ScreenshotProcessTest]::Windows($script:process.Id,'#32770')[0]
|
||||
Send $dialog (0x400+102) 6 # TDM_CLICK_BUTTON / IDYES; no clipboard writes.
|
||||
Wait-For { (Capture-Windows) -notcontains $Window } 'Editor did not close.'
|
||||
Wait-For { (Capture-Windows) -notcontains $Window } 'Unedited copied screenshot did not close.'
|
||||
}
|
||||
function Latest-Token {
|
||||
(Get-ChildItem -LiteralPath (Join-Path $env:LOCALAPPDATA 'KSwitcher/ScreenshotNotifications') -Filter '*.capture' | Sort-Object LastWriteTimeUtc -Descending | Select-Object -First 1).BaseName
|
||||
}
|
||||
$process=$null
|
||||
try {
|
||||
$process=Start-Process -FilePath $Executable -WindowStyle Hidden -PassThru
|
||||
Wait-For { (Capture-Windows).Count -eq 1 } 'First selection did not open.'
|
||||
$first=(Capture-Windows)[0]; Select-Region $first
|
||||
$secondLaunch=Start-Process -FilePath $Executable -WindowStyle Hidden -PassThru
|
||||
if (!$secondLaunch.WaitForExit(10000) -or $secondLaunch.ExitCode -ne 0) { throw 'Second launch did not hand off.' }
|
||||
Wait-For { (Capture-Windows).Count -eq 2 } 'Second selection did not open in same process.'
|
||||
$second=(Capture-Windows | Where-Object { $_ -ne $first })[0]; Select-Region $second
|
||||
Select-Region (Capture-Windows)[0]
|
||||
if (!$process.WaitForExit(5000)) { throw 'Process remained alive after notification.' }
|
||||
$token=Latest-Token
|
||||
$process=Start-Process -FilePath $Executable -ArgumentList @('--open',"kswitcher-screenshot:$token") -WindowStyle Hidden -PassThru
|
||||
Wait-For { (Capture-Windows).Count -eq 1 } 'Notification activation did not open an editor.'
|
||||
$first=(Capture-Windows)[0]
|
||||
$secondLaunch=Start-Process -FilePath $Executable -ArgumentList @('--open',"kswitcher-screenshot:$token") -WindowStyle Hidden -PassThru
|
||||
if (!$secondLaunch.WaitForExit(10000) -or $secondLaunch.ExitCode -ne 0) { throw 'Second activation did not hand off.' }
|
||||
Wait-For { (Capture-Windows).Count -eq 2 } 'Second editor did not open in same process.'
|
||||
$second=(Capture-Windows | Where-Object { $_ -ne $first })[0]
|
||||
if ([ScreenshotProcessTest]::Title($first) -eq [ScreenshotProcessTest]::Title($second)) { throw 'Editor indices collide.' }
|
||||
Close-Editor $first
|
||||
if ($process.HasExited) { throw 'Process exited with an editor open.' }
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
int main()
|
||||
{
|
||||
CoInitializeEx(nullptr,COINIT_APARTMENTTHREADED);
|
||||
try {
|
||||
INITCOMMONCONTROLSEX controls{sizeof(controls),ICC_STANDARD_CLASSES}; InitCommonControlsEx(&controls);
|
||||
ks::ScreenshotHost app{GetModuleHandleW(nullptr)};
|
||||
@@ -162,7 +163,21 @@ int main()
|
||||
require(IsWindow(window),"Escape does not close the screenshot editor");
|
||||
SendMessageW(window,WM_CLOSE,0,0);
|
||||
require(!IsWindow(window),"copied screenshot closes without confirmation");
|
||||
static bool published=false;
|
||||
app.notify=[](const ks::Clip &) { return published; };
|
||||
ks::Capture selection(app);
|
||||
selection.image=std::make_unique<ks::Surface>(100,100);
|
||||
PatBlt(selection.image->dc,0,0,100,100,WHITENESS);
|
||||
selection.start={10,20}; selection.end={70,60};
|
||||
auto overlay=CreateWindowW(cls.lpszClassName,L"Selection test",WS_POPUP,0,0,100,100,app.window,nullptr,app.instance,&selection);
|
||||
ks::finishSelection(overlay,selection,[](HWND,const ks::Clip &clip)->DWORD {
|
||||
auto pixels=ks::decodeImage(clip);
|
||||
if(pixels.width!=60 || pixels.height!=40) throw std::runtime_error("automatic copy did not crop selection");
|
||||
published=true; return 0;
|
||||
});
|
||||
require(published && selection.copied && !IsWindow(overlay),"selection copies before notification and closes without editor");
|
||||
DestroyWindow(app.window); app.window=nullptr;
|
||||
CoUninitialize();
|
||||
std::cout<<"Passed screenshot editor UI integration checks\n";
|
||||
} catch(const std::exception &e) { std::cerr<<e.what()<<'\n'; return 1; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user